@@ -13,9 +13,9 @@ import {
13
13
effect ,
14
14
inject ,
15
15
input ,
16
+ isDevMode ,
16
17
output ,
17
18
signal ,
18
- untracked ,
19
19
} from '@angular/core'
20
20
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'
21
21
import type { SplitAreaComponent } from '../split-area/split-area.component'
@@ -31,6 +31,7 @@ import {
31
31
numberAttributeWithFallback ,
32
32
sum ,
33
33
toRecord ,
34
+ assertUnreachable ,
34
35
} from '../utils'
35
36
import { DOCUMENT , NgStyle , NgTemplateOutlet } from '@angular/common'
36
37
import { SplitGutterInteractionEvent , SplitAreaSize } from '../models'
@@ -115,56 +116,11 @@ export class SplitComponent {
115
116
116
117
readonly dragProgress$ = this . dragProgressSubject . asObservable ( )
117
118
118
- private readonly visibleAreas = computed ( ( ) => this . _areas ( ) . filter ( ( area ) => area . visible ( ) ) )
119
- private readonly gridTemplateColumnsStyle = computed ( ( ) => {
120
- const columns : string [ ] = [ ]
121
- const sumNonWildcardSizes = sum ( this . visibleAreas ( ) , ( area ) => {
122
- const size = area . _internalSize ( )
123
- return size === '*' ? 0 : size
124
- } )
125
- const visibleAreasCount = this . visibleAreas ( ) . length
126
-
127
- let visitedVisibleAreas = 0
128
-
129
- this . _areas ( ) . forEach ( ( area , index , areas ) => {
130
- const unit = this . unit ( )
131
- const areaSize = area . _internalSize ( )
132
-
133
- // Add area size column
134
- if ( ! area . visible ( ) ) {
135
- columns . push ( unit === 'percent' || areaSize === '*' ? '0fr' : '0px' )
136
- } else {
137
- if ( unit === 'pixel' ) {
138
- const columnValue = areaSize === '*' ? '1fr' : `${ areaSize } px`
139
- columns . push ( columnValue )
140
- } else {
141
- const percentSize = areaSize === '*' ? 100 - sumNonWildcardSizes : areaSize
142
- const columnValue = `${ percentSize } fr`
143
- columns . push ( columnValue )
144
- }
145
-
146
- visitedVisibleAreas ++
147
- }
148
-
149
- const isLastArea = index === areas . length - 1
150
-
151
- if ( isLastArea ) {
152
- return
153
- }
154
-
155
- const remainingVisibleAreas = visibleAreasCount - visitedVisibleAreas
156
-
157
- // Only add gutter with size if this area is visible and there are more visible areas after this one
158
- // to avoid ghost gutters
159
- if ( area . visible ( ) && remainingVisibleAreas > 0 ) {
160
- columns . push ( `${ this . gutterSize ( ) } px` )
161
- } else {
162
- columns . push ( '0px' )
163
- }
164
- } )
165
-
166
- return this . direction ( ) === 'horizontal' ? `1fr / ${ columns . join ( ' ' ) } ` : `${ columns . join ( ' ' ) } / 1fr`
167
- } )
119
+ /**
120
+ * @internal
121
+ */
122
+ readonly _visibleAreas = computed ( ( ) => this . _areas ( ) . filter ( ( area ) => area . visible ( ) ) )
123
+ private readonly gridTemplateColumnsStyle = computed ( ( ) => this . createGridTemplateColumnsStyle ( ) )
168
124
private readonly hostClasses = computed ( ( ) =>
169
125
createClassesString ( {
170
126
[ `as-${ this . direction ( ) } ` ] : true ,
@@ -179,6 +135,11 @@ export class SplitComponent {
179
135
* @internal
180
136
*/
181
137
readonly _isDragging = computed ( ( ) => this . draggedGutterIndex ( ) !== undefined )
138
+ /**
139
+ * @internal
140
+ * Should only be used by {@link SplitAreaComponent._internalSize}
141
+ */
142
+ readonly _alignedVisibleAreasSizes = computed ( ( ) => this . createAlignedVisibleAreasSize ( ) )
182
143
183
144
@HostBinding ( 'class' ) protected get hostClassesBinding ( ) {
184
145
return this . hostClasses ( )
@@ -189,45 +150,17 @@ export class SplitComponent {
189
150
}
190
151
191
152
constructor ( ) {
192
- effect (
193
- ( ) => {
194
- const visibleAreas = this . visibleAreas ( )
195
- const unit = this . unit ( )
196
- const isInAutoMode = visibleAreas . every ( ( area ) => area . size ( ) === 'auto' )
197
-
198
- untracked ( ( ) => {
199
- // Special mode when no size input was declared which is a valid mode
200
- if ( unit === 'percent' && visibleAreas . length > 1 && isInAutoMode ) {
201
- visibleAreas . forEach ( ( area ) => area . _internalSize . set ( 100 / visibleAreas . length ) )
202
- return
203
- }
204
-
205
- visibleAreas . forEach ( ( area ) => area . _internalSize . reset ( ) )
206
-
207
- const isValid = areAreasValid ( visibleAreas , unit )
208
-
209
- if ( isValid ) {
210
- return
211
- }
153
+ if ( isDevMode ( ) ) {
154
+ // Logs warnings to console when the provided areas sizes are invalid
155
+ effect ( ( ) => {
156
+ // Special mode when no size input was declared which is a valid mode
157
+ if ( this . unit ( ) === 'percent' && this . _visibleAreas ( ) . every ( ( area ) => area . size ( ) === 'auto' ) ) {
158
+ return
159
+ }
212
160
213
- if ( unit === 'percent' ) {
214
- // Distribute sizes equally
215
- const defaultSize = 100 / visibleAreas . length
216
- visibleAreas . forEach ( ( area ) => area . _internalSize . set ( defaultSize ) )
217
- } else if ( unit === 'pixel' ) {
218
- const wildcardAreas = visibleAreas . filter ( ( area ) => area . _internalSize ( ) === '*' )
219
-
220
- // Make sure only one wildcard area
221
- if ( wildcardAreas . length === 0 ) {
222
- visibleAreas [ 0 ] . _internalSize . set ( '*' )
223
- } else if ( wildcardAreas . length > 1 ) {
224
- wildcardAreas . filter ( ( _ , i ) => i !== 0 ) . forEach ( ( area ) => area . _internalSize . set ( 100 ) )
225
- }
226
- }
227
- } )
228
- } ,
229
- { allowSignalWrites : true } ,
230
- )
161
+ areAreasValid ( this . _visibleAreas ( ) , this . unit ( ) , true )
162
+ } )
163
+ }
231
164
232
165
// Responsible for updating grid template style. Must be this way and not based on HostBinding
233
166
// as change detection for host binding is bound to the parent component and this style
@@ -450,7 +383,7 @@ export class SplitComponent {
450
383
}
451
384
452
385
private createAreaSizes ( ) {
453
- return this . visibleAreas ( ) . map ( ( area ) => area . _internalSize ( ) )
386
+ return this . _visibleAreas ( ) . map ( ( area ) => area . _internalSize ( ) )
454
387
}
455
388
456
389
private createDragStartContext (
@@ -460,7 +393,7 @@ export class SplitComponent {
460
393
) : DragStartContext {
461
394
const splitBoundingRect = this . elementRef . nativeElement . getBoundingClientRect ( )
462
395
const splitSize = this . direction ( ) === 'horizontal' ? splitBoundingRect . width : splitBoundingRect . height
463
- const totalAreasPixelSize = splitSize - ( this . visibleAreas ( ) . length - 1 ) * this . gutterSize ( )
396
+ const totalAreasPixelSize = splitSize - ( this . _visibleAreas ( ) . length - 1 ) * this . gutterSize ( )
464
397
// Use the internal size and split size to calculate the pixel size from wildcard and percent areas
465
398
const areaPixelSizesWithWildcard = this . _areas ( ) . map ( ( area ) => {
466
399
if ( this . unit ( ) === 'pixel' ) {
@@ -598,4 +531,92 @@ export class SplitComponent {
598
531
599
532
this . dragProgressSubject . next ( this . createDragInteractionEvent ( this . draggedGutterIndex ( ) ) )
600
533
}
534
+
535
+ private createGridTemplateColumnsStyle ( ) : string {
536
+ const columns : string [ ] = [ ]
537
+ const sumNonWildcardSizes = sum ( this . _visibleAreas ( ) , ( area ) => {
538
+ const size = area . _internalSize ( )
539
+ return size === '*' ? 0 : size
540
+ } )
541
+ const visibleAreasCount = this . _visibleAreas ( ) . length
542
+
543
+ let visitedVisibleAreas = 0
544
+
545
+ this . _areas ( ) . forEach ( ( area , index , areas ) => {
546
+ const unit = this . unit ( )
547
+ const areaSize = area . _internalSize ( )
548
+
549
+ // Add area size column
550
+ if ( ! area . visible ( ) ) {
551
+ columns . push ( unit === 'percent' || areaSize === '*' ? '0fr' : '0px' )
552
+ } else {
553
+ if ( unit === 'pixel' ) {
554
+ const columnValue = areaSize === '*' ? '1fr' : `${ areaSize } px`
555
+ columns . push ( columnValue )
556
+ } else {
557
+ const percentSize = areaSize === '*' ? 100 - sumNonWildcardSizes : areaSize
558
+ const columnValue = `${ percentSize } fr`
559
+ columns . push ( columnValue )
560
+ }
561
+
562
+ visitedVisibleAreas ++
563
+ }
564
+
565
+ const isLastArea = index === areas . length - 1
566
+
567
+ if ( isLastArea ) {
568
+ return
569
+ }
570
+
571
+ const remainingVisibleAreas = visibleAreasCount - visitedVisibleAreas
572
+
573
+ // Only add gutter with size if this area is visible and there are more visible areas after this one
574
+ // to avoid ghost gutters
575
+ if ( area . visible ( ) && remainingVisibleAreas > 0 ) {
576
+ columns . push ( `${ this . gutterSize ( ) } px` )
577
+ } else {
578
+ columns . push ( '0px' )
579
+ }
580
+ } )
581
+
582
+ return this . direction ( ) === 'horizontal' ? `1fr / ${ columns . join ( ' ' ) } ` : `${ columns . join ( ' ' ) } / 1fr`
583
+ }
584
+
585
+ private createAlignedVisibleAreasSize ( ) : SplitAreaSize [ ] {
586
+ const visibleAreasSizes = this . _visibleAreas ( ) . map ( ( area ) : SplitAreaSize => {
587
+ const size = area . size ( )
588
+ return size === 'auto' ? '*' : size
589
+ } )
590
+ const isValid = areAreasValid ( this . _visibleAreas ( ) , this . unit ( ) , false )
591
+
592
+ if ( isValid ) {
593
+ return visibleAreasSizes
594
+ }
595
+
596
+ const unit = this . unit ( )
597
+
598
+ if ( unit === 'percent' ) {
599
+ // Distribute sizes equally
600
+ const defaultPercentSize = 100 / visibleAreasSizes . length
601
+ return visibleAreasSizes . map ( ( ) => defaultPercentSize )
602
+ }
603
+
604
+ if ( unit === 'pixel' ) {
605
+ // Make sure only one wildcard area
606
+ const wildcardAreas = visibleAreasSizes . filter ( ( areaSize ) => areaSize === '*' )
607
+
608
+ if ( wildcardAreas . length === 0 ) {
609
+ return [ '*' , ...visibleAreasSizes . slice ( 1 ) ]
610
+ } else {
611
+ const firstWildcardIndex = visibleAreasSizes . findIndex ( ( areaSize ) => areaSize === '*' )
612
+ const defaultPxSize = 100
613
+
614
+ return visibleAreasSizes . map ( ( areaSize , index ) =>
615
+ index === firstWildcardIndex || areaSize !== '*' ? areaSize : defaultPxSize ,
616
+ )
617
+ }
618
+ }
619
+
620
+ return assertUnreachable ( unit , 'SplitUnit' )
621
+ }
601
622
}
0 commit comments