@scion/components 19.0.0 → 19.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, Input, inject, ElementRef, NgZone, EventEmitter, Component, HostBinding, Output, ContentChildren, NgModule } from '@angular/core';
3
- import { switchMap, map, startWith, takeUntil } from 'rxjs/operators';
4
- import { BehaviorSubject, merge, Subject } from 'rxjs';
2
+ import { input, inject, TemplateRef, computed, signal, linkedSignal, Directive, ElementRef, effect, output, contentChildren, NgZone, Component, HostBinding, NgModule } from '@angular/core';
5
3
  import { SciSplitterComponent } from '@scion/components/splitter';
6
- import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
4
+ import { NgTemplateOutlet } from '@angular/common';
7
5
 
8
6
  /**
9
7
  * Allows accessing the sashbox component from sashes.
@@ -40,130 +38,139 @@ class SciSashBoxAccessor {
40
38
  * </sci-sashbox>
41
39
  */
42
40
  class SciSashDirective {
43
- sashTemplate;
44
- _sashBoxAccessor;
45
- _size = '1';
46
- _flexGrow$ = new BehaviorSubject(0);
47
41
  /**
48
42
  * Specifies the sash size, either as fixed size with an explicit unit,
49
- * or as a unitless proportion to distibute remaining space. A proportional
43
+ * or as a unitless proportion to distribute remaining space. A proportional
50
44
  * sash has the ability to grow or shrink if necessary, and must be >= 1.
51
45
  *
52
46
  * If not set, remaining space is distributed equally.
53
47
  */
54
- set size(size) {
55
- this._size = size ?? '1';
56
- }
57
- get size() {
58
- return this._size;
59
- }
48
+ size = input('1', { transform: (size) => size ?? '1' });
60
49
  /**
61
50
  * Specifies the minimal sash size in pixel or percent.
62
51
  * The min-size prevents the user from shrinking the sash below this minimal size.
63
52
  *
64
53
  * If the unit is omitted, the value is interpreted as a pixel value.
65
54
  */
66
- minSize;
55
+ minSize = input();
67
56
  /**
68
- * @internal
57
+ * Optional key to identify this sash.
58
+ *
59
+ * If set, this key is used as the property key in the object emitted by {@link SciSashboxComponent.sashEnd2} to associate the size of this sash.
69
60
  */
70
- element;
61
+ key = input();
71
62
  /**
63
+ * Represents the template used as sash content.
64
+ *
72
65
  * @internal
73
66
  */
74
- set flexGrow(flexGrow) {
75
- this._flexGrow$.next(flexGrow);
76
- }
67
+ sashTemplate = inject(TemplateRef);
68
+ _sashBoxAccessor = inject(SciSashBoxAccessor);
69
+ /**
70
+ * Flex properties computed based on the configured {@link size}. Properties are updated when moving this sash.
71
+ */
72
+ _flexProperties = this.computeFlexProperties();
77
73
  /**
74
+ * Flex properties with normalized 'flex-grow' to ensure the sashes fill the entire sash-box space.
75
+ *
76
+ * Use these properties to lay out this sash in the sashbox's flex layout.
77
+ *
78
78
  * @internal
79
79
  */
80
- get flexGrow() {
81
- return this._flexGrow$.value;
82
- }
80
+ flexProperties = this.normalizeFlexGrow(this._flexProperties);
83
81
  /**
82
+ * Returns if this sash has a fixed size, meaning that it has not the ability to grow or shrink.
83
+ *
84
84
  * @internal
85
85
  */
86
- flexShrink;
86
+ isFixedSize = computed(() => Number.isNaN(+this.size()));
87
87
  /**
88
+ * Gets the DOM element that renders this sash.
89
+ *
88
90
  * @internal
89
91
  */
90
- flexBasis;
92
+ element = signal(undefined);
91
93
  /**
92
- * Normalized flex-grow proportion of this sash, which is a value >= 1.
94
+ * Gets the effective size of this sash in the DOM.
93
95
  *
94
96
  * @internal
95
97
  */
96
- flexGrowNormalized$;
97
- constructor(sashTemplate, _sashBoxAccessor) {
98
- this.sashTemplate = sashTemplate;
99
- this._sashBoxAccessor = _sashBoxAccessor;
100
- this.flexGrowNormalized$ = this._sashBoxAccessor.sashes$
101
- .pipe(switchMap(sashes => merge(...sashes.map(sash => sash._flexGrow$))), map(() => this.normalizeFlexGrow(this.flexGrow)));
102
- }
103
- ngOnInit() {
104
- this.setFlexItemProperties();
105
- }
106
- ngOnChanges(changes) {
107
- this.setFlexItemProperties();
98
+ get elementSize() {
99
+ const element = this.element();
100
+ if (!element) {
101
+ return 0;
102
+ }
103
+ if (this._sashBoxAccessor.direction() === 'row') {
104
+ return element.getBoundingClientRect().width;
105
+ }
106
+ else {
107
+ return element.getBoundingClientRect().height;
108
+ }
108
109
  }
109
110
  /**
110
- * Returns if this sash has a fixed size, meaning that it has not the ability to grow or shrink if necessary.
111
+ * Returns the identity of this sash, or the passed index if not configured.
111
112
  *
112
113
  * @internal
113
114
  */
114
- get isFixedSize() {
115
- return Number.isNaN(+this.size);
115
+ computeKey(index) {
116
+ return this.key() ?? `${index}`;
116
117
  }
117
118
  /**
118
- * Returns the effective sash size as rendered in the DOM.
119
+ * Updates the flex properties of this sash for layout in the sashbox's flex layout.
119
120
  *
120
121
  * @internal
121
122
  */
122
- get computedSize() {
123
- // Note: Use `boundingClientRect` to get the fractional size.
124
- // see https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth
125
- return this._sashBoxAccessor.direction === 'row' ? this.element.getBoundingClientRect().width : this.element.getBoundingClientRect().height;
123
+ updateFlexProperties(flexProperties) {
124
+ this._flexProperties.update(previousFlexProperties => ({ ...previousFlexProperties, ...flexProperties }));
126
125
  }
127
126
  /**
128
- * Computes and sets the flex item properties based on the modelled size.
127
+ * Computes the flex properties to lay out this sash in the sashbox's flex layout based on the configured {@link size}.
129
128
  */
130
- setFlexItemProperties() {
131
- if (this.isFixedSize) {
132
- // fixed-sized sash
133
- this.flexGrow = 0;
134
- this.flexShrink = 0;
135
- this.flexBasis = `${this.size}`;
136
- }
137
- else {
138
- // remaining space is distributed according to given proportion
139
- const proportion = +this.size;
140
- if (proportion < 1) {
141
- throw Error(`[IllegalSashSizeError] The proportion for flexible sized sashes must be >=1 [size=${this.size}]`);
129
+ computeFlexProperties() {
130
+ return linkedSignal(() => {
131
+ const size = this.size();
132
+ if (this.isFixedSize()) {
133
+ // fixed-sized sash
134
+ return {
135
+ flexGrow: 0,
136
+ flexShrink: 0,
137
+ flexBasis: `${size}`,
138
+ };
142
139
  }
143
- this.flexGrow = proportion;
144
- this.flexShrink = 1;
145
- this.flexBasis = '0';
146
- }
140
+ else {
141
+ // remaining space is distributed according to given proportion
142
+ const proportion = +size;
143
+ if (proportion < 1) {
144
+ throw Error(`[IllegalSashSizeError] The proportion for flexible sized sashes must be >=1 [size=${this.size()}]`);
145
+ }
146
+ return {
147
+ flexGrow: proportion,
148
+ flexShrink: 1,
149
+ flexBasis: '0',
150
+ };
151
+ }
152
+ });
147
153
  }
148
154
  /**
149
- * Computes the normalized flex-grow proportion of the given sash, which is a value >= 1.
155
+ * Normalizes the 'flex-grow' of the passed {@link FlexProperties} to ensure that the sum of the 'flex-grow' proportions of all sashes is 1.
150
156
  *
151
- * If the sum of all flex-grow proportions would be less than 1, then, the sashes would not fill the entire sash-box space.
152
- * Without normalization in place, e.g., this could happen when removing a sash.
157
+ * If the sum of all flex-grow proportions were less than 1, the sashes would not fill the entire sash-box space.
158
+ * Without normalization, this could occur when a sash is removed.
153
159
  */
154
- normalizeFlexGrow(flexGrow) {
155
- if (flexGrow === 0) {
156
- return 0;
157
- }
158
- const sashes = this._sashBoxAccessor.sashes;
159
- const flexGrowSum = sashes.reduce((sum, sash) => sum + sash.flexGrow, 0);
160
- if (flexGrowSum === 0) {
161
- return 0;
162
- }
163
- return flexGrow / flexGrowSum;
160
+ normalizeFlexGrow(flexProperties) {
161
+ return computed(() => {
162
+ const sashes = this._sashBoxAccessor.sashes();
163
+ const { flexGrow, flexShrink, flexBasis } = flexProperties();
164
+ const flexGrowSum = sashes.reduce((sum, sash) => sum + sash._flexProperties().flexGrow, 0);
165
+ return {
166
+ flexGrow: flexGrow === 0 || flexGrowSum === 0 ? 0 : flexGrow / flexGrowSum, // Sum of normalized flex-grow proportions must be 1;
167
+ flexShrink,
168
+ flexBasis,
169
+ };
170
+ });
164
171
  }
165
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashDirective, deps: [{ token: i0.TemplateRef }, { token: SciSashBoxAccessor }], target: i0.ɵɵFactoryTarget.Directive });
166
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.0", type: SciSashDirective, isStandalone: true, selector: "ng-template[sciSash]", inputs: { size: "size", minSize: "minSize" }, exportAs: ["sciSash"], usesOnChanges: true, ngImport: i0 });
172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
173
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.0", type: SciSashDirective, isStandalone: true, selector: "ng-template[sciSash]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, minSize: { classPropertyName: "minSize", publicName: "minSize", isSignal: true, isRequired: false, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["sciSash"], ngImport: i0 });
167
174
  }
168
175
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashDirective, decorators: [{
169
176
  type: Directive,
@@ -171,11 +178,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
171
178
  selector: 'ng-template[sciSash]',
172
179
  exportAs: 'sciSash',
173
180
  }]
174
- }], ctorParameters: () => [{ type: i0.TemplateRef }, { type: SciSashBoxAccessor }], propDecorators: { size: [{
175
- type: Input
176
- }], minSize: [{
177
- type: Input
178
- }] } });
181
+ }] });
179
182
 
180
183
  /*
181
184
  * Copyright (c) 2018-2019 Swiss Federal Railways
@@ -190,26 +193,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
190
193
  * Initializes {SashDirective} with the target {HTMLDivElement}.
191
194
  */
192
195
  class SciSashInitializerDirective {
193
- _host;
194
- sash;
195
- constructor(_host) {
196
- this._host = _host;
196
+ sash = input.required({ alias: 'sciSashInitializer' });
197
+ constructor() {
198
+ const host = inject(ElementRef).nativeElement;
199
+ effect(() => this.sash().element.set(host));
197
200
  }
198
- ngOnChanges(changes) {
199
- this.sash.element = this._host.nativeElement;
200
- }
201
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashInitializerDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
202
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.0", type: SciSashInitializerDirective, isStandalone: true, selector: "div[sciSashInitializer].sash", inputs: { sash: ["sciSashInitializer", "sash"] }, usesOnChanges: true, ngImport: i0 });
201
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashInitializerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
202
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.0", type: SciSashInitializerDirective, isStandalone: true, selector: "div[sciSashInitializer].sash", inputs: { sash: { classPropertyName: "sash", publicName: "sciSashInitializer", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
203
203
  }
204
204
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashInitializerDirective, decorators: [{
205
205
  type: Directive,
206
206
  args: [{
207
207
  selector: 'div[sciSashInitializer].sash',
208
208
  }]
209
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { sash: [{
210
- type: Input,
211
- args: [{ alias: 'sciSashInitializer', required: true }]
212
- }] } });
209
+ }], ctorParameters: () => [] });
213
210
 
214
211
  /*
215
212
  * Copyright (c) 2018-2019 Swiss Federal Railways
@@ -224,13 +221,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
224
221
  * Provides access to the native {@link HTMLElement} of the host.
225
222
  */
226
223
  class SciElementRefDirective {
227
- host;
228
- nativeElement;
229
- constructor(host) {
230
- this.host = host;
231
- this.nativeElement = host.nativeElement;
232
- }
233
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciElementRefDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
224
+ host = inject(ElementRef).nativeElement;
225
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciElementRefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
234
226
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.0", type: SciElementRefDirective, isStandalone: true, selector: "[sciElementRef]", exportAs: ["sciElementRef"], ngImport: i0 });
235
227
  }
236
228
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciElementRefDirective, decorators: [{
@@ -239,7 +231,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
239
231
  selector: '[sciElementRef]',
240
232
  exportAs: 'sciElementRef',
241
233
  }]
242
- }], ctorParameters: () => [{ type: i0.ElementRef }] });
234
+ }] });
243
235
 
244
236
  /*
245
237
  * Copyright (c) 2018-2019 Swiss Federal Railways
@@ -255,10 +247,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
255
247
  * or column arrangement (as specified by the direction property). A splitter is added between each child to allow the user to
256
248
  * shrink or stretch the individual sashes.
257
249
  *
258
- * Sashes are modelled as content children inside a <ng-template> decorated with the 'sciSash' directive.
259
- * A sash can have a fixed size with an explicit unit, or a unitless proportion to distibute remaining space.
250
+ * Sashes are modelled as <ng-template> decorated with the 'sciSash' directive.
251
+ * A sash can have a fixed size with an explicit unit, or a unitless proportion to distribute remaining space.
260
252
  * A proportional sash has the ability to grow or shrink if necessary.
261
253
  *
254
+ * Sash content is added to a CSS grid container with a single column, stretching the content vertically and horizontally.
262
255
  *
263
256
  * ### Usage
264
257
  *
@@ -304,33 +297,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
304
297
  * ```
305
298
  */
306
299
  class SciSashboxComponent {
307
- _destroy$ = new Subject();
308
- _host = inject((ElementRef)).nativeElement;
309
- _zone = inject(NgZone);
310
- sashes$ = new BehaviorSubject([]);
311
- sashing = false;
312
- maxHeight;
313
- maxWidth;
314
300
  /**
315
301
  * Specifies if to lay out sashes in a row (which is by default) or column arrangement.
316
302
  */
317
- direction = 'row';
303
+ direction = input('row');
304
+ /**
305
+ * Notifies when start sashing.
306
+ */
307
+ sashStart = output();
318
308
  /**
319
- * Emits when start sashing.
309
+ * Emits an array with new sash sizes when sashing ends.
310
+ *
311
+ * The array contains the sash sizes in display order.
312
+ *
313
+ * TODO [Angular 20] BREAKING CHANGE: Change signature from `number[]` to `{[key: string]: number}` and remove {@link sashEnd2}.
320
314
  */
321
- sashStart = new EventEmitter();
315
+ sashEnd = output();
322
316
  /**
323
- * Emits the absolute sash sizes (px) when finished sashing.
317
+ * Emits an object with new sash sizes when sashing ends.
318
+ *
319
+ * Each sash size is associated with its {@link SciSashDirective.key} or its display position (zero-based) if not set.
320
+ *
321
+ * Note: This output will be renamed to `sashEnd` in version 20, changing the signature of {@link sashEnd} from `number[]` to `{[key: string]: number}`.
322
+ *
323
+ * TODO [Angular 20] BREAKING CHANGE: Replace with {@link sashEnd}.
324
324
  */
325
- sashEnd = new EventEmitter();
325
+ sashEnd2 = output();
326
+ _host = inject(ElementRef).nativeElement;
326
327
  /** @internal */
327
- set setSashes(queryList) {
328
- queryList.changes
329
- .pipe(startWith(queryList), takeUntil(this._destroy$))
330
- .subscribe((sashes) => {
331
- this.sashes$.next(sashes.toArray());
332
- });
333
- }
328
+ sashes = contentChildren(SciSashDirective);
329
+ sashing = false;
330
+ maxHeight;
331
+ maxWidth;
334
332
  onSashStart() {
335
333
  this.sashing = true;
336
334
  // Avoid overflow when sashing.
@@ -338,12 +336,14 @@ class SciSashboxComponent {
338
336
  this.maxHeight = hostBounds.height;
339
337
  this.maxWidth = hostBounds.width;
340
338
  this.sashStart.emit();
341
- // set the effective sash size as the flex-basis for non-fixed sashes (as sashing operates on pixel deltas)
342
- this.sashes.forEach(sash => {
343
- if (!sash.isFixedSize) {
344
- sash.flexGrow = 0;
345
- sash.flexShrink = 1;
346
- sash.flexBasis = `${sash.computedSize}px`;
339
+ // Set the effective sash size as the flex-basis for non-fixed sashes (as sashing operates on pixel deltas).
340
+ this.sashes().forEach(sash => {
341
+ if (!sash.isFixedSize()) {
342
+ sash.updateFlexProperties({
343
+ flexGrow: 0,
344
+ flexShrink: 1,
345
+ flexBasis: `${sash.elementSize}px`,
346
+ });
347
347
  }
348
348
  });
349
349
  }
@@ -351,86 +351,80 @@ class SciSashboxComponent {
351
351
  this.sashing = false;
352
352
  this.maxHeight = undefined;
353
353
  this.maxWidth = undefined;
354
- // unset the flex-basis for non-fixed sashes and set the flex-grow accordingly
355
- const pixelToFlexGrowFactor = computePixelToFlexGrowFactor(this.sashes);
356
- const absoluteSashSizes = this.sashes.map(sash => sash.computedSize);
357
- this.sashes.forEach((sash, i) => {
358
- if (!sash.isFixedSize) {
359
- sash.flexGrow = pixelToFlexGrowFactor * absoluteSashSizes[i];
360
- sash.flexShrink = 1;
361
- sash.flexBasis = '0';
354
+ // Unset the flex-basis for non-fixed sashes and set the flex-grow accordingly.
355
+ const pixelToFlexGrowFactor = computePixelToFlexGrowFactor(this.sashes());
356
+ const sashSizes = this.sashes().reduce((acc, sash, i) => acc.set(sash.computeKey(i), sash.elementSize), new Map());
357
+ this.sashes().forEach((sash, i) => {
358
+ if (!sash.isFixedSize()) {
359
+ sash.updateFlexProperties({
360
+ flexGrow: pixelToFlexGrowFactor * sashSizes.get(sash.computeKey(i)),
361
+ flexShrink: 1,
362
+ flexBasis: '0',
363
+ });
362
364
  }
363
365
  });
364
- this.sashEnd.emit(absoluteSashSizes);
366
+ this.sashEnd.emit(Array.from(sashSizes.values()));
367
+ this.sashEnd2.emit(Object.fromEntries(sashSizes));
365
368
  }
366
369
  onSash(splitter, sashIndex, moveEvent) {
370
+ NgZone.assertNotInAngularZone();
367
371
  const distance = moveEvent.distance;
368
372
  if (distance === 0) {
369
373
  return;
370
374
  }
371
- NgZone.assertNotInAngularZone();
372
- // compute the splitter position
375
+ // Compute the splitter position.
373
376
  const splitterRect = splitter.getBoundingClientRect();
374
377
  const splitterStart = (this.isRowDirection ? splitterRect.left : splitterRect.top);
375
378
  const splitterEnd = (this.isRowDirection ? splitterRect.left + splitterRect.width : splitterRect.top + splitterRect.height);
376
- // ignore the event if outside of the splitter's action scope
379
+ // Ignore the event if outside the splitter's action scope.
377
380
  const eventPos = moveEvent.position.clientPos;
378
- // i.e. the sash should not grow if moved the mouse pointer beyond the left bounds of the sash, and if now moving the mouse pointer back toward the current sash.
381
+ // The sash should not grow after moved the mouse pointer beyond the left bounds of the sash and now moving the mouse pointer back toward the current sash.
379
382
  if (distance > 0 && eventPos < splitterStart) {
380
383
  return;
381
384
  }
382
- // i.e. the sash should not shrink if moved the mouse pointer beyond the right bounds of the sash, and if now moving the mouse pointer back toward the current sash.
385
+ // The sash should not shrink after moved the mouse pointer beyond the right bounds of the sash and now moving the mouse pointer back toward the current sash.
383
386
  if (distance < 0 && eventPos > splitterEnd) {
384
387
  return;
385
388
  }
386
- // compute the new sash sizes
387
- const sash1 = this.sashes[sashIndex];
388
- const sash2 = this.sashes[sashIndex + 1];
389
- const sashSize1 = sash1.computedSize;
390
- const sashSize2 = sash2.computedSize;
391
- const sashMinSize1 = sash1.minSize ? this.toPixel(sash1.minSize) : 0;
392
- const sashMinSize2 = sash2.minSize ? this.toPixel(sash2.minSize) : 0;
389
+ // Compute the new sash sizes.
390
+ const sash1 = this.sashes()[sashIndex];
391
+ const sash2 = this.sashes()[sashIndex + 1];
392
+ const sashSize1 = sash1.elementSize;
393
+ const sashSize2 = sash2.elementSize;
394
+ const sashMinSize1 = sash1.minSize() ? this.toPixel(sash1.minSize()) : 0;
395
+ const sashMinSize2 = sash2.minSize() ? this.toPixel(sash2.minSize()) : 0;
393
396
  const newSashSize1 = between(Math.round(sashSize1 + distance), { min: sashMinSize1, max: sashSize1 + sashSize2 - sashMinSize2 });
394
397
  const newSashSize2 = between(Math.round(sashSize2 - distance), { min: sashMinSize2, max: sashSize1 + sashSize2 - sashMinSize1 });
395
- // set the new computed sash sizes
396
- this._zone.run(() => {
397
- sash1.flexBasis = `${newSashSize1}px`;
398
- sash2.flexBasis = `${newSashSize2}px`;
399
- });
398
+ // Set the new computed sash sizes.
399
+ sash1.updateFlexProperties({ flexBasis: `${newSashSize1}px` });
400
+ sash2.updateFlexProperties({ flexBasis: `${newSashSize2}px` });
400
401
  }
401
402
  onSashReset(sashIndex) {
402
- const sash1 = this.sashes[sashIndex];
403
- const sash2 = this.sashes[sashIndex + 1];
404
- const equalSashSize = (sash1.computedSize + sash2.computedSize) / 2;
405
- const pixelToFlexGrowFactor = computePixelToFlexGrowFactor(this.sashes);
406
- const absoluteSashSizesAfterReset = this.sashes.map((sash, index) => {
407
- if (index === sashIndex || index === sashIndex + 1) {
408
- return equalSashSize;
409
- }
410
- return sash.computedSize;
411
- });
403
+ const sash1 = this.sashes()[sashIndex];
404
+ const sash2 = this.sashes()[sashIndex + 1];
405
+ const equalSashSize = (sash1.elementSize + sash2.elementSize) / 2;
406
+ const pixelToFlexGrowFactor = computePixelToFlexGrowFactor(this.sashes());
407
+ const sashSizesAfterReset = this.sashes().reduce((acc, sash, index) => {
408
+ const size = index === sashIndex || index === sashIndex + 1 ? equalSashSize : sash.elementSize;
409
+ return acc.set(sash.computeKey(index), size);
410
+ }, new Map());
412
411
  [sash1, sash2].forEach(sash => {
413
- if (sash.isFixedSize) {
414
- sash.flexBasis = `${equalSashSize}px`;
412
+ if (sash.isFixedSize()) {
413
+ sash.updateFlexProperties({ flexBasis: `${equalSashSize}px` });
415
414
  }
416
415
  else {
417
- sash.flexGrow = pixelToFlexGrowFactor * equalSashSize;
416
+ sash.updateFlexProperties({ flexGrow: pixelToFlexGrowFactor * equalSashSize });
418
417
  }
419
418
  });
420
419
  this.sashStart.emit();
421
- this.sashEnd.emit(absoluteSashSizesAfterReset);
420
+ this.sashEnd.emit(Array.from(sashSizesAfterReset.values()));
421
+ this.sashEnd2.emit(Object.fromEntries(sashSizesAfterReset));
422
422
  }
423
423
  get isColumnDirection() {
424
- return this.direction === 'column';
424
+ return this.direction() === 'column';
425
425
  }
426
426
  get isRowDirection() {
427
- return this.direction === 'row';
428
- }
429
- get sashes() {
430
- return this.sashes$.value;
431
- }
432
- ngOnDestroy() {
433
- this._destroy$.next();
427
+ return this.direction() === 'row';
434
428
  }
435
429
  toPixel(value) {
436
430
  if (typeof value === 'number') {
@@ -444,15 +438,14 @@ class SciSashboxComponent {
444
438
  return parseInt(value, 10);
445
439
  }
446
440
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
447
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.0", type: SciSashboxComponent, isStandalone: true, selector: "sci-sashbox", inputs: { direction: "direction" }, outputs: { sashStart: "sashStart", sashEnd: "sashEnd" }, host: { properties: { "class.sashing": "this.sashing", "style.--\u0275sci-sashbox-max-height": "this.maxHeight", "style.--\u0275sci-sashbox-max-width": "this.maxWidth", "class.column": "this.isColumnDirection", "class.row": "this.isRowDirection" } }, providers: [{
441
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.0", type: SciSashboxComponent, isStandalone: true, selector: "sci-sashbox", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sashStart: "sashStart", sashEnd: "sashEnd", sashEnd2: "sashEnd2" }, host: { properties: { "class.sashing": "this.sashing", "style.--\u0275sci-sashbox-max-height": "this.maxHeight", "style.--\u0275sci-sashbox-max-width": "this.maxWidth", "class.column": "this.isColumnDirection", "class.row": "this.isRowDirection" } }, providers: [{
448
442
  provide: SciSashBoxAccessor,
449
443
  useFactory: provideSashBoxAccessor,
450
- }], queries: [{ propertyName: "setSashes", predicate: SciSashDirective }], ngImport: i0, template: "@for (sash of sashes$ | async; track sash; let i = $index; let first = $first; let last = $last) {\n <div class=\"sash\"\n [class.first]=\"first\"\n [class.last]=\"last\"\n [sciSashInitializer]=\"sash\"\n [style.flex-grow]=\"sash.flexGrowNormalized$ | async\"\n [style.flex-shrink]=\"sash.flexShrink\"\n [style.flex-basis]=\"sash.flexBasis\">\n <ng-container *ngTemplateOutlet=\"sash.sashTemplate\"/>\n </div>\n @if (!last) {\n <sci-splitter sciElementRef #sciElementRef=\"sciElementRef\"\n [orientation]=\"isRowDirection ? 'vertical' : 'horizontal'\"\n (start)=\"onSashStart()\"\n (move)=\"onSash(sciElementRef.nativeElement, i, $event)\"\n (end)=\"onSashEnd()\"\n (reset)=\"onSashReset(i)\"/>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;box-sizing:border-box;overflow:hidden;z-index:0}:host *{box-sizing:border-box}:host.column{flex-direction:column}:host.row{flex-direction:row}:host>div.sash{overflow:hidden;display:grid;grid-auto-rows:100%;grid-auto-columns:100%}:host.row>div.sash{margin:0 var(--sci-sashbox-gap)}:host.row>div.sash.first{margin-left:0}:host.row>div.sash.last{margin-right:0}:host.column>div.sash{margin:var(--sci-sashbox-gap) 0}:host.column>div.sash.first{margin-top:0}:host.column>div.sash.last{margin-bottom:0}:host.sashing{max-height:calc(var(--\\275sci-sashbox-max-height) * 1px);max-width:calc(var(--\\275sci-sashbox-max-width) * 1px)}:host.sashing>div.sash{pointer-events:none}:host>sci-splitter{--sci-splitter-background-color: var(--sci-sashbox-splitter-background-color);--sci-splitter-background-color-hover: var(--sci-sashbox-splitter-background-color-hover);--sci-splitter-size: var(--sci-sashbox-splitter-size);--sci-splitter-size-hover: var(--sci-sashbox-splitter-size-hover);--sci-splitter-touch-target-size: var(--sci-sashbox-splitter-touch-target-size);--sci-splitter-cross-axis-size: var(--sci-sashbox-splitter-cross-axis-size);--sci-splitter-border-radius: var(--sci-sashbox-splitter-border-radius);--sci-splitter-opacity-active: var(--sci-sashbox-splitter-opacity-active);--sci-splitter-opacity-hover: var(--sci-sashbox-splitter-opacity-hover);flex:none;z-index:1}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: SciSashInitializerDirective, selector: "div[sciSashInitializer].sash", inputs: ["sciSashInitializer"] }, { kind: "component", type: SciSplitterComponent, selector: "sci-splitter", inputs: ["orientation"], outputs: ["start", "move", "end", "reset"] }, { kind: "directive", type: SciElementRefDirective, selector: "[sciElementRef]", exportAs: ["sciElementRef"] }] });
444
+ }], queries: [{ propertyName: "sashes", predicate: SciSashDirective, isSignal: true }], ngImport: i0, template: "@for (sash of sashes(); track sash; let i = $index; let first = $first; let last = $last) {\n <div class=\"sash\"\n [class.first]=\"first\"\n [class.last]=\"last\"\n [sciSashInitializer]=\"sash\"\n [style.flex-grow]=\"sash.flexProperties().flexGrow\"\n [style.flex-shrink]=\"sash.flexProperties().flexShrink\"\n [style.flex-basis]=\"sash.flexProperties().flexBasis\">\n <ng-container *ngTemplateOutlet=\"sash.sashTemplate\"/>\n </div>\n @if (!last) {\n <sci-splitter sciElementRef #sciElementRef=\"sciElementRef\"\n [orientation]=\"isRowDirection ? 'vertical' : 'horizontal'\"\n (start)=\"onSashStart()\"\n (move)=\"onSash(sciElementRef.host, i, $event)\"\n (end)=\"onSashEnd()\"\n (reset)=\"onSashReset(i)\"/>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;box-sizing:border-box;overflow:hidden;z-index:0}:host *{box-sizing:border-box}:host.column{flex-direction:column}:host.row{flex-direction:row}:host>div.sash{overflow:hidden;display:grid;grid-auto-rows:100%;grid-auto-columns:100%}:host.row>div.sash{margin:0 var(--sci-sashbox-gap)}:host.row>div.sash.first{margin-left:0}:host.row>div.sash.last{margin-right:0}:host.column>div.sash{margin:var(--sci-sashbox-gap) 0}:host.column>div.sash.first{margin-top:0}:host.column>div.sash.last{margin-bottom:0}:host.sashing{max-height:calc(var(--\\275sci-sashbox-max-height) * 1px);max-width:calc(var(--\\275sci-sashbox-max-width) * 1px)}:host.sashing>div.sash{pointer-events:none}:host>sci-splitter{--sci-splitter-background-color: var(--sci-sashbox-splitter-background-color);--sci-splitter-background-color-hover: var(--sci-sashbox-splitter-background-color-hover);--sci-splitter-size: var(--sci-sashbox-splitter-size);--sci-splitter-size-hover: var(--sci-sashbox-splitter-size-hover);--sci-splitter-touch-target-size: var(--sci-sashbox-splitter-touch-target-size);--sci-splitter-cross-axis-size: var(--sci-sashbox-splitter-cross-axis-size);--sci-splitter-border-radius: var(--sci-sashbox-splitter-border-radius);--sci-splitter-opacity-active: var(--sci-sashbox-splitter-opacity-active);--sci-splitter-opacity-hover: var(--sci-sashbox-splitter-opacity-hover);flex:none;z-index:1}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: SciSashInitializerDirective, selector: "div[sciSashInitializer].sash", inputs: ["sciSashInitializer"] }, { kind: "component", type: SciSplitterComponent, selector: "sci-splitter", inputs: ["orientation"], outputs: ["start", "move", "end", "reset"] }, { kind: "directive", type: SciElementRefDirective, selector: "[sciElementRef]", exportAs: ["sciElementRef"] }] });
451
445
  }
452
446
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: SciSashboxComponent, decorators: [{
453
447
  type: Component,
454
448
  args: [{ selector: 'sci-sashbox', imports: [
455
- AsyncPipe,
456
449
  NgTemplateOutlet,
457
450
  SciSashInitializerDirective,
458
451
  SciSplitterComponent,
@@ -460,7 +453,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
460
453
  ], providers: [{
461
454
  provide: SciSashBoxAccessor,
462
455
  useFactory: provideSashBoxAccessor,
463
- }], template: "@for (sash of sashes$ | async; track sash; let i = $index; let first = $first; let last = $last) {\n <div class=\"sash\"\n [class.first]=\"first\"\n [class.last]=\"last\"\n [sciSashInitializer]=\"sash\"\n [style.flex-grow]=\"sash.flexGrowNormalized$ | async\"\n [style.flex-shrink]=\"sash.flexShrink\"\n [style.flex-basis]=\"sash.flexBasis\">\n <ng-container *ngTemplateOutlet=\"sash.sashTemplate\"/>\n </div>\n @if (!last) {\n <sci-splitter sciElementRef #sciElementRef=\"sciElementRef\"\n [orientation]=\"isRowDirection ? 'vertical' : 'horizontal'\"\n (start)=\"onSashStart()\"\n (move)=\"onSash(sciElementRef.nativeElement, i, $event)\"\n (end)=\"onSashEnd()\"\n (reset)=\"onSashReset(i)\"/>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;box-sizing:border-box;overflow:hidden;z-index:0}:host *{box-sizing:border-box}:host.column{flex-direction:column}:host.row{flex-direction:row}:host>div.sash{overflow:hidden;display:grid;grid-auto-rows:100%;grid-auto-columns:100%}:host.row>div.sash{margin:0 var(--sci-sashbox-gap)}:host.row>div.sash.first{margin-left:0}:host.row>div.sash.last{margin-right:0}:host.column>div.sash{margin:var(--sci-sashbox-gap) 0}:host.column>div.sash.first{margin-top:0}:host.column>div.sash.last{margin-bottom:0}:host.sashing{max-height:calc(var(--\\275sci-sashbox-max-height) * 1px);max-width:calc(var(--\\275sci-sashbox-max-width) * 1px)}:host.sashing>div.sash{pointer-events:none}:host>sci-splitter{--sci-splitter-background-color: var(--sci-sashbox-splitter-background-color);--sci-splitter-background-color-hover: var(--sci-sashbox-splitter-background-color-hover);--sci-splitter-size: var(--sci-sashbox-splitter-size);--sci-splitter-size-hover: var(--sci-sashbox-splitter-size-hover);--sci-splitter-touch-target-size: var(--sci-sashbox-splitter-touch-target-size);--sci-splitter-cross-axis-size: var(--sci-sashbox-splitter-cross-axis-size);--sci-splitter-border-radius: var(--sci-sashbox-splitter-border-radius);--sci-splitter-opacity-active: var(--sci-sashbox-splitter-opacity-active);--sci-splitter-opacity-hover: var(--sci-sashbox-splitter-opacity-hover);flex:none;z-index:1}\n"] }]
456
+ }], template: "@for (sash of sashes(); track sash; let i = $index; let first = $first; let last = $last) {\n <div class=\"sash\"\n [class.first]=\"first\"\n [class.last]=\"last\"\n [sciSashInitializer]=\"sash\"\n [style.flex-grow]=\"sash.flexProperties().flexGrow\"\n [style.flex-shrink]=\"sash.flexProperties().flexShrink\"\n [style.flex-basis]=\"sash.flexProperties().flexBasis\">\n <ng-container *ngTemplateOutlet=\"sash.sashTemplate\"/>\n </div>\n @if (!last) {\n <sci-splitter sciElementRef #sciElementRef=\"sciElementRef\"\n [orientation]=\"isRowDirection ? 'vertical' : 'horizontal'\"\n (start)=\"onSashStart()\"\n (move)=\"onSash(sciElementRef.host, i, $event)\"\n (end)=\"onSashEnd()\"\n (reset)=\"onSashReset(i)\"/>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;box-sizing:border-box;overflow:hidden;z-index:0}:host *{box-sizing:border-box}:host.column{flex-direction:column}:host.row{flex-direction:row}:host>div.sash{overflow:hidden;display:grid;grid-auto-rows:100%;grid-auto-columns:100%}:host.row>div.sash{margin:0 var(--sci-sashbox-gap)}:host.row>div.sash.first{margin-left:0}:host.row>div.sash.last{margin-right:0}:host.column>div.sash{margin:var(--sci-sashbox-gap) 0}:host.column>div.sash.first{margin-top:0}:host.column>div.sash.last{margin-bottom:0}:host.sashing{max-height:calc(var(--\\275sci-sashbox-max-height) * 1px);max-width:calc(var(--\\275sci-sashbox-max-width) * 1px)}:host.sashing>div.sash{pointer-events:none}:host>sci-splitter{--sci-splitter-background-color: var(--sci-sashbox-splitter-background-color);--sci-splitter-background-color-hover: var(--sci-sashbox-splitter-background-color-hover);--sci-splitter-size: var(--sci-sashbox-splitter-size);--sci-splitter-size-hover: var(--sci-sashbox-splitter-size-hover);--sci-splitter-touch-target-size: var(--sci-sashbox-splitter-touch-target-size);--sci-splitter-cross-axis-size: var(--sci-sashbox-splitter-cross-axis-size);--sci-splitter-border-radius: var(--sci-sashbox-splitter-border-radius);--sci-splitter-opacity-active: var(--sci-sashbox-splitter-opacity-active);--sci-splitter-opacity-hover: var(--sci-sashbox-splitter-opacity-hover);flex:none;z-index:1}\n"] }]
464
457
  }], propDecorators: { sashing: [{
465
458
  type: HostBinding,
466
459
  args: ['class.sashing']
@@ -470,15 +463,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
470
463
  }], maxWidth: [{
471
464
  type: HostBinding,
472
465
  args: ['style.--ɵsci-sashbox-max-width']
473
- }], direction: [{
474
- type: Input
475
- }], sashStart: [{
476
- type: Output
477
- }], sashEnd: [{
478
- type: Output
479
- }], setSashes: [{
480
- type: ContentChildren,
481
- args: [SciSashDirective]
482
466
  }], isColumnDirection: [{
483
467
  type: HostBinding,
484
468
  args: ['class.column']
@@ -493,24 +477,17 @@ function between(value, minmax) {
493
477
  * Returns the factor to compute the flex-grow proportion from the pixel size of a sash.
494
478
  */
495
479
  function computePixelToFlexGrowFactor(sashes) {
496
- const flexibleSashes = sashes.filter(sash => !sash.isFixedSize);
497
- const proportionSum = flexibleSashes.reduce((sum, sash) => sum + Number(sash.size), 0);
498
- const pixelSum = flexibleSashes.reduce((sum, sash) => sum + sash.computedSize, 0);
480
+ const flexibleSashes = sashes.filter(sash => !sash.isFixedSize());
481
+ const proportionSum = flexibleSashes.reduce((sum, sash) => sum + Number(sash.size()), 0);
482
+ const pixelSum = flexibleSashes.reduce((sum, sash) => sum + sash.elementSize, 0);
499
483
  return proportionSum / pixelSum;
500
484
  }
501
485
  function provideSashBoxAccessor() {
502
486
  const component = inject(SciSashboxComponent);
503
487
  return new class {
504
- get direction() {
505
- return component.direction;
506
- }
507
- get sashes$() {
508
- return component.sashes$;
509
- }
510
- get sashes() {
511
- return component.sashes$.value;
512
- }
513
- };
488
+ direction = component.direction;
489
+ sashes = component.sashes;
490
+ }();
514
491
  }
515
492
 
516
493
  /*