ember-primitives 0.61.0 → 0.61.1

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.
package/README.md CHANGED
@@ -32,17 +32,17 @@ See the [Contributing](CONTRIBUTING.md) guide for details.
32
32
  </a>
33
33
  </td>
34
34
  <td align="center">
35
- <a href="https://github.com/evoactivity">
36
- <img src="https://avatars.githubusercontent.com/u/83799?v=4" width="100;" alt="evoactivity"/>
35
+ <a href="https://github.com/NullVoxPopuli-ai-agent">
36
+ <img src="https://avatars.githubusercontent.com/u/268630448?v=4" width="100;" alt="NullVoxPopuli-ai-agent"/>
37
37
  <br />
38
- <sub><b>Liam Potter</b></sub>
38
+ <sub><b>@NullVoxPopuli's reduced-access machine account for AI usage</b></sub>
39
39
  </a>
40
40
  </td>
41
41
  <td align="center">
42
- <a href="https://github.com/NullVoxPopuli-ai-agent">
43
- <img src="https://avatars.githubusercontent.com/u/268630448?v=4" width="100;" alt="NullVoxPopuli-ai-agent"/>
42
+ <a href="https://github.com/evoactivity">
43
+ <img src="https://avatars.githubusercontent.com/u/83799?v=4" width="100;" alt="evoactivity"/>
44
44
  <br />
45
- <sub><b>@NullVoxPopuli's reduced-access machine account for AI usage</b></sub>
45
+ <sub><b>Liam Potter</b></sub>
46
46
  </a>
47
47
  </td>
48
48
  <td align="center">
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/components/resizable/state.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,CAAC;AAiGpD,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC/D;AAED,qBAAa,UAAU;;IACrB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAQ;gBAsCvB,OAAO,EAAE,YAAY;IAIjC,IAAI,WAAW,IAAI,WAAW,CAE7B;IAMD;;;OAGG;IACH,IAAI,MAAM,IAAI,WAAW,EAAE,CAE1B;IAED,IAAI,OAAO,IAAI,WAAW,EAAE,CAE3B;IAYD,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IA0FD;;;;OAIG;IACH,MAAM,GAAI,SAAS,WAAW,KAAG,CAAC,MAAM,IAAI,CAAC,CAW3C;IAqTF,SAAS,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IA6EhE;;OAEG;IACH,aAAa,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;CAwFtE"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/components/resizable/state.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,CAAC;AAwJpD,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;IAC3C,cAAc,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC/D;AAED,qBAAa,UAAU;;IACrB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAQ;gBAsCvB,OAAO,EAAE,YAAY;IAIjC,IAAI,WAAW,IAAI,WAAW,CAE7B;IAMD;;;OAGG;IACH,IAAI,MAAM,IAAI,WAAW,EAAE,CAE1B;IAED,IAAI,OAAO,IAAI,WAAW,EAAE,CAE3B;IAkBD,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IA4FD;;;;OAIG;IACH,MAAM,GAAI,SAAS,WAAW,KAAG,CAAC,MAAM,IAAI,CAAC,CAW3C;IA+RF,SAAS,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAwFhE;;OAEG;IACH,aAAa,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;CA0FtE"}
@@ -1,6 +1,7 @@
1
1
  const GROUP_SELECTOR = '.ember-primitives__resizable';
2
- const PANEL_SELECTOR = '.ember-primitives__resizable__panel';
3
- const HANDLE_SELECTOR = '.ember-primitives__resizable__handle';
2
+ const PANEL_CLASS = 'ember-primitives__resizable__panel';
3
+ const HANDLE_CLASS = 'ember-primitives__resizable__handle';
4
+ const MEMBER_SELECTOR = `.${PANEL_CLASS}, .${HANDLE_CLASS}`;
4
5
  const DEFAULT_MIN = 0;
5
6
  const DEFAULT_MAX = 100;
6
7
 
@@ -40,6 +41,44 @@ function isCollapsible(panel) {
40
41
  function sameMembers(a, b) {
41
42
  return a.length === b.length && a.every((element, index) => element === b[index]);
42
43
  }
44
+ function precedes(a, b) {
45
+ return Boolean(b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING);
46
+ }
47
+
48
+ /**
49
+ * The `data-collapsed` attribute is the source of truth for collapse
50
+ * state (it is also the styling hook consumers use).
51
+ */
52
+ function isCollapsed(panel) {
53
+ return isCollapsible(panel) && panel.hasAttribute('data-collapsed');
54
+ }
55
+ function setCollapsed(panel, collapsed) {
56
+ if (collapsed === panel.hasAttribute('data-collapsed')) return;
57
+ if (collapsed) {
58
+ panel.setAttribute('data-collapsed', '');
59
+ } else {
60
+ panel.removeAttribute('data-collapsed');
61
+ }
62
+ }
63
+
64
+ /**
65
+ * The panels immediately before and after the given handle element,
66
+ * in document order.
67
+ */
68
+ function neighborsOf(handleElement, panels) {
69
+ let prev = null;
70
+ let next = null;
71
+ for (const panel of panels) {
72
+ const position = handleElement.compareDocumentPosition(panel);
73
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
74
+ prev = panel;
75
+ } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
76
+ next = panel;
77
+ break;
78
+ }
79
+ }
80
+ return [prev, next];
81
+ }
43
82
 
44
83
  /**
45
84
  * Sizes are floats that get re-derived (measurement, normalization),
@@ -119,16 +158,27 @@ class GroupState {
119
158
  * Panels of nested groups belong to their own group, not this one.
120
159
  */
121
160
  get panels() {
122
- return this.#query(PANEL_SELECTOR);
161
+ return this.#members().panels;
123
162
  }
124
163
  get handles() {
125
- return this.#query(HANDLE_SELECTOR);
164
+ return this.#members().handles;
126
165
  }
127
- #query(selector) {
166
+ #members() {
167
+ const panels = [];
168
+ const handles = [];
128
169
  const element = this.element;
129
- if (!element) return [];
130
- const all = Array.from(element.querySelectorAll(selector));
131
- return all.filter(candidate => candidate.closest(GROUP_SELECTOR) === element);
170
+ if (!element) return {
171
+ panels,
172
+ handles
173
+ };
174
+ for (const member of element.querySelectorAll(MEMBER_SELECTOR)) {
175
+ if (member.closest(GROUP_SELECTOR) !== element) continue;
176
+ (member.classList.contains(PANEL_CLASS) ? panels : handles).push(member);
177
+ }
178
+ return {
179
+ panels,
180
+ handles
181
+ };
132
182
  }
133
183
  get sizes() {
134
184
  return this.panels.map(panel => this.#sizes.get(panel) ?? 0);
@@ -175,7 +225,8 @@ class GroupState {
175
225
  if (group && !affected.has(group)) affected.set(group, false);
176
226
  }
177
227
  for (const [group, orientationChanged] of affected) {
178
- if (orientationChanged || group.#membershipChanged()) group.#layout();
228
+ const members = group.#members();
229
+ if (orientationChanged || group.#membershipChanged(members)) group.#layout(members);
179
230
  }
180
231
  }
181
232
  static #observe(element, group) {
@@ -216,8 +267,8 @@ class GroupState {
216
267
  this.element = null;
217
268
  };
218
269
  };
219
- #membershipChanged() {
220
- return !sameMembers(this.panels, this.#knownPanels) || !sameMembers(this.handles, this.#knownHandles);
270
+ #membershipChanged(members) {
271
+ return !sameMembers(members.panels, this.#knownPanels) || !sameMembers(members.handles, this.#knownHandles);
221
272
  }
222
273
 
223
274
  /**
@@ -225,17 +276,21 @@ class GroupState {
225
276
  * keep it; new panels take a share of the remaining space; everything
226
277
  * is normalized to 100.
227
278
  */
228
- #layout() {
229
- const panels = this.panels;
230
- const handles = this.handles;
231
- if (!sameMembers(panels, this.#knownPanels)) this.#knownPanels = panels;
232
- if (!sameMembers(handles, this.#knownHandles)) this.#knownHandles = handles;
279
+ #layout(members = this.#members()) {
280
+ const {
281
+ panels,
282
+ handles
283
+ } = members;
284
+ if (this.#drag) this.#drag.members = members;
285
+ this.#knownPanels = panels;
286
+ this.#knownHandles = handles;
233
287
  if (panels.length === 0) return;
234
288
  let changed = false;
235
289
 
236
290
  // forget sizes of panels that left the DOM
237
- for (const known of Array.from(this.#sizes.keys())) {
238
- if (!panels.includes(known)) {
291
+ const current = new Set(panels);
292
+ for (const known of this.#sizes.keys()) {
293
+ if (!current.has(known)) {
239
294
  this.#sizes.delete(known);
240
295
  changed = true;
241
296
  }
@@ -252,7 +307,7 @@ class GroupState {
252
307
  unspecified.push(panel);
253
308
  continue;
254
309
  }
255
- const size = this.#isCollapsed(panel) ? preferred : clamp(preferred, minSizeOf(panel), maxSizeOf(panel));
310
+ const size = isCollapsed(panel) ? preferred : clamp(preferred, minSizeOf(panel), maxSizeOf(panel));
256
311
  computed.set(panel, size);
257
312
  specifiedTotal += size;
258
313
  }
@@ -302,8 +357,8 @@ class GroupState {
302
357
  changed = true;
303
358
  }
304
359
  }
305
- this.#apply(changedPanels);
306
- if (changed) this.#notify();
360
+ this.#apply(changedPanels, members);
361
+ if (changed) this.#notify(panels);
307
362
  }
308
363
 
309
364
  /**
@@ -314,24 +369,22 @@ class GroupState {
314
369
  * points, not derived from sizes -- rendered pixel sizes include
315
370
  * borders/padding, so a collapsed panel rarely measures exactly 0.)
316
371
  */
317
- #apply(candidates) {
318
- if (candidates.length > 0) {
319
- /**
320
- * With no unit fixed yet, nothing has ever been written, so every
321
- * panel renders at the CSS default -- an equal 1/n share.
322
- */
323
- const unit = this.#unit ?? 100 / this.panels.length;
324
- for (const panel of candidates) {
325
- const size = this.#sizes.get(panel);
326
- if (size === undefined) continue;
327
- const inlineGrow = panel.style.flexGrow;
328
- const impliedPercent = (inlineGrow === '' ? 1 : parseFloat(inlineGrow)) * unit;
329
- if (isSameSize(impliedPercent, size)) continue;
330
- this.#unit ??= unit;
331
- panel.style.flex = `${size / unit} 1 0px`;
332
- }
372
+ #apply(candidates, members) {
373
+ /**
374
+ * With no unit fixed yet, nothing has ever been written, so every
375
+ * panel renders at the CSS default -- an equal 1/n share.
376
+ */
377
+ const unit = this.#unit ?? 100 / members.panels.length;
378
+ for (const panel of candidates) {
379
+ const size = this.#sizes.get(panel);
380
+ if (size === undefined) continue;
381
+ const inlineGrow = panel.style.flexGrow;
382
+ const impliedPercent = (inlineGrow === '' ? 1 : parseFloat(inlineGrow)) * unit;
383
+ if (isSameSize(impliedPercent, size)) continue;
384
+ this.#unit ??= unit;
385
+ panel.style.flex = `${size / unit} 1 0px`;
333
386
  }
334
- this.#syncHandles();
387
+ this.#syncHandles(members);
335
388
  }
336
389
 
337
390
  /**
@@ -339,10 +392,21 @@ class GroupState {
339
392
  * immediately before it. (A splitter between two side-by-side panes
340
393
  * is oriented *vertically*, and vice-versa.)
341
394
  */
342
- #syncHandles() {
343
- for (const handle of this.handles) {
344
- const [prev] = this.#neighborsOf(handle);
345
- setAttribute(handle, 'aria-orientation', this.#isHorizontal ? 'vertical' : 'horizontal');
395
+ #syncHandles(members) {
396
+ const {
397
+ panels,
398
+ handles
399
+ } = members;
400
+ const ariaOrientation = this.#isHorizontal ? 'vertical' : 'horizontal';
401
+ let index = 0;
402
+ for (const handle of handles) {
403
+ let following = panels[index];
404
+ while (following && precedes(following, handle)) {
405
+ index++;
406
+ following = panels[index];
407
+ }
408
+ const prev = panels[index - 1];
409
+ setAttribute(handle, 'aria-orientation', ariaOrientation);
346
410
  if (!prev) continue;
347
411
 
348
412
  // Panels render their own (component-owned, incrementing) id
@@ -352,34 +416,17 @@ class GroupState {
352
416
  setAttribute(handle, 'aria-valuenow', `${Math.round(this.#sizes.get(prev) ?? 0)}`);
353
417
  }
354
418
  }
355
- #notify() {
356
- this.#options.onLayoutChange()?.(this.sizes);
357
- }
358
-
359
- /**
360
- * The `data-collapsed` attribute is the source of truth for collapse
361
- * state (it is also the styling hook consumers use).
362
- */
363
- #isCollapsed(panel) {
364
- return isCollapsible(panel) && panel.hasAttribute('data-collapsed');
365
- }
366
- #setCollapsed(panel, collapsed) {
367
- if (collapsed === panel.hasAttribute('data-collapsed')) return;
368
- if (collapsed) {
369
- panel.setAttribute('data-collapsed', '');
370
- } else {
371
- panel.removeAttribute('data-collapsed');
372
- }
419
+ #notify(panels) {
420
+ this.#options.onLayoutChange()?.(panels.map(panel => this.#sizes.get(panel) ?? 0));
373
421
  }
374
422
 
375
423
  /**
376
424
  * Re-derive percentage sizes from actual rendered pixels.
377
425
  * Corrects any drift (e.g. from CSS min-sizes) before an interaction.
378
426
  */
379
- #syncSizesFromDOM() {
380
- const panels = this.panels;
427
+ #syncSizesFromDOM(panels, measured) {
381
428
  // collapsed panels are 0 even though their borders/padding measure larger
382
- const px = panels.map(panel => this.#isCollapsed(panel) ? 0 : this.#pixelSizeOf(panel));
429
+ const px = panels.map((panel, index) => isCollapsed(panel) ? 0 : measured?.[index] ?? this.#pixelSizeOf(panel));
383
430
  const total = px.reduce((sum, value) => sum + value, 0);
384
431
  if (total <= 0) return;
385
432
  panels.forEach((panel, index) => {
@@ -395,42 +442,26 @@ class GroupState {
395
442
  return this.#isHorizontal ? box.width : box.height;
396
443
  }
397
444
 
398
- /**
399
- * The panels immediately before and after the given handle element,
400
- * in document order.
401
- */
402
- #neighborsOf(handleElement) {
403
- let prev = null;
404
- let next = null;
405
- for (const panel of this.panels) {
406
- const position = handleElement.compareDocumentPosition(panel);
407
- if (position & Node.DOCUMENT_POSITION_PRECEDING) {
408
- prev = panel;
409
- } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
410
- next = panel;
411
- break;
412
- }
413
- }
414
- return [prev, next];
415
- }
416
-
417
445
  /**
418
446
  * Moves the boundary between the two panels by `requestedDelta` (%),
419
447
  * respecting both panels' min/max constraints.
420
448
  */
421
- #applyDelta(prev, next, basePrevSize, baseNextSize, requestedDelta) {
449
+ #applyDelta(prev, next, basePrevSize, baseNextSize, requestedDelta, members) {
422
450
  const total = basePrevSize + baseNextSize;
451
+ const prevMin = minSizeOf(prev);
452
+ const prevMax = maxSizeOf(prev);
453
+ const prevCollapsible = isCollapsible(prev);
423
454
  let target = basePrevSize + requestedDelta;
424
- if (isCollapsible(prev) && target < minSizeOf(prev)) {
455
+ if (prevCollapsible && target < prevMin) {
425
456
  /**
426
457
  * Collapsible panels snap: below half the minimum they close
427
458
  * entirely; between half and the minimum they hold at the minimum.
428
459
  * (This also keeps a collapsed panel closed when its handle is
429
460
  * dragged further in the closing direction.)
430
461
  */
431
- target = target < minSizeOf(prev) / 2 ? 0 : minSizeOf(prev);
462
+ target = target < prevMin / 2 ? 0 : prevMin;
432
463
  } else {
433
- target = clamp(target, minSizeOf(prev), maxSizeOf(prev));
464
+ target = clamp(target, prevMin, prevMax);
434
465
  }
435
466
 
436
467
  /**
@@ -443,7 +474,7 @@ class GroupState {
443
474
  target = clamp(target, nextMin, nextMax);
444
475
 
445
476
  // both panels' constraints cannot be satisfied at once
446
- if (!isCollapsible(prev) && (target < minSizeOf(prev) || target > maxSizeOf(prev))) return;
477
+ if (!prevCollapsible && (target < prevMin || target > prevMax)) return;
447
478
 
448
479
  /**
449
480
  * Nothing to do when the clamped result matches the current sizes
@@ -452,23 +483,25 @@ class GroupState {
452
483
  if (isSameSize(this.#sizes.get(prev), target) && isSameSize(this.#sizes.get(next), total - target)) {
453
484
  return;
454
485
  }
455
- if (isCollapsible(prev)) {
456
- if (target === 0 && !this.#isCollapsed(prev)) {
486
+ if (prevCollapsible) {
487
+ if (target === 0 && !isCollapsed(prev)) {
457
488
  this.#previousSizes.set(prev, basePrevSize);
458
489
  }
459
- this.#setCollapsed(prev, target === 0);
490
+ setCollapsed(prev, target === 0);
460
491
  }
461
492
  this.#sizes.set(prev, target);
462
493
  this.#sizes.set(next, total - target);
463
- this.#apply([prev, next]);
464
- this.#notify();
494
+ this.#apply([prev, next], members);
495
+ this.#notify(members.panels);
465
496
  }
466
497
  startDrag(handleElement, event) {
467
498
  if (event.button !== 0) return;
468
499
  if (this.#drag) return;
469
- const [prev, next] = this.#neighborsOf(handleElement);
500
+ const members = this.#members();
501
+ const [prev, next] = neighborsOf(handleElement, members.panels);
470
502
  if (!prev || !next) return;
471
- this.#syncSizesFromDOM();
503
+ const measured = members.panels.map(panel => this.#pixelSizeOf(panel));
504
+ this.#syncSizesFromDOM(members.panels, measured);
472
505
  const move = moveEvent => this.#dragMove(moveEvent);
473
506
  const end = endEvent => this.#endDrag(handleElement, endEvent);
474
507
  this.#drag = {
@@ -477,7 +510,8 @@ class GroupState {
477
510
  startPrevSize: this.#sizes.get(prev) ?? 0,
478
511
  startNextSize: this.#sizes.get(next) ?? 0,
479
512
  startCoordinate: this.#isHorizontal ? event.clientX : event.clientY,
480
- totalPx: this.panels.reduce((sum, panel) => sum + this.#pixelSizeOf(panel), 0),
513
+ totalPx: measured.reduce((sum, value) => sum + value, 0),
514
+ members,
481
515
  move,
482
516
  end
483
517
  };
@@ -490,9 +524,9 @@ class GroupState {
490
524
  } catch {
491
525
  // synthetic events (tests) may not have an active pointer
492
526
  }
493
- handleElement.addEventListener('pointermove', this.#drag.move);
494
- handleElement.addEventListener('pointerup', this.#drag.end);
495
- handleElement.addEventListener('pointercancel', this.#drag.end);
527
+ handleElement.addEventListener('pointermove', move);
528
+ handleElement.addEventListener('pointerup', end);
529
+ handleElement.addEventListener('pointercancel', end);
496
530
  handleElement.setAttribute('data-resizing', '');
497
531
  document.body.style.cursor = this.#isHorizontal ? 'col-resize' : 'row-resize';
498
532
  document.body.style.userSelect = 'none';
@@ -503,7 +537,7 @@ class GroupState {
503
537
  if (drag.totalPx <= 0) return;
504
538
  const coordinate = this.#isHorizontal ? event.clientX : event.clientY;
505
539
  const deltaPercent = (coordinate - drag.startCoordinate) / drag.totalPx * 100;
506
- this.#applyDelta(drag.prev, drag.next, drag.startPrevSize, drag.startNextSize, deltaPercent);
540
+ this.#applyDelta(drag.prev, drag.next, drag.startPrevSize, drag.startNextSize, deltaPercent, drag.members);
507
541
  }
508
542
  #endDrag(handleElement, event) {
509
543
  const drag = this.#drag;
@@ -526,41 +560,41 @@ class GroupState {
526
560
  * Keyboard support for the WAI-ARIA window-splitter pattern.
527
561
  */
528
562
  handleKeyDown(handleElement, event) {
529
- const [prev, next] = this.#neighborsOf(handleElement);
563
+ const members = this.#members();
564
+ const [prev, next] = neighborsOf(handleElement, members.panels);
530
565
  if (!prev || !next) return;
531
566
  if (event.key === 'Enter') {
532
- this.#toggleCollapse(prev, next);
567
+ this.#toggleCollapse(prev, next, members);
533
568
  return;
534
569
  }
535
570
  const step = event.shiftKey ? KEYBOARD_STEP_COARSE : KEYBOARD_STEP;
536
571
  const isHorizontal = this.#isHorizontal;
537
- let delta = null;
572
+ let toDelta = null;
538
573
  switch (event.key) {
539
574
  case 'ArrowLeft':
540
- if (isHorizontal) delta = -step;
575
+ if (isHorizontal) toDelta = () => -step;
541
576
  break;
542
577
  case 'ArrowRight':
543
- if (isHorizontal) delta = step;
578
+ if (isHorizontal) toDelta = () => step;
544
579
  break;
545
580
  case 'ArrowUp':
546
- if (!isHorizontal) delta = -step;
581
+ if (!isHorizontal) toDelta = () => -step;
547
582
  break;
548
583
  case 'ArrowDown':
549
- if (!isHorizontal) delta = step;
584
+ if (!isHorizontal) toDelta = () => step;
550
585
  break;
551
586
  case 'Home':
552
- this.#syncSizesFromDOM();
553
- delta = minSizeOf(prev) - (this.#sizes.get(prev) ?? 0);
587
+ toDelta = prevSize => minSizeOf(prev) - prevSize;
554
588
  break;
555
589
  case 'End':
556
- this.#syncSizesFromDOM();
557
- delta = maxSizeOf(prev) - (this.#sizes.get(prev) ?? 0);
590
+ toDelta = prevSize => maxSizeOf(prev) - prevSize;
558
591
  break;
559
592
  }
560
- if (delta === null) return;
593
+ if (!toDelta) return;
561
594
  event.preventDefault();
562
- this.#syncSizesFromDOM();
563
- this.#applyDelta(prev, next, this.#sizes.get(prev) ?? 0, this.#sizes.get(next) ?? 0, delta);
595
+ this.#syncSizesFromDOM(members.panels);
596
+ const prevSize = this.#sizes.get(prev) ?? 0;
597
+ this.#applyDelta(prev, next, prevSize, this.#sizes.get(next) ?? 0, toDelta(prevSize), members);
564
598
  }
565
599
 
566
600
  /**
@@ -569,27 +603,27 @@ class GroupState {
569
603
  *
570
604
  * Only does anything when the preceding panel is `@collapsible`.
571
605
  */
572
- #toggleCollapse(prev, next) {
606
+ #toggleCollapse(prev, next, members) {
573
607
  if (!isCollapsible(prev)) return;
574
- this.#syncSizesFromDOM();
608
+ this.#syncSizesFromDOM(members.panels);
575
609
  const prevSize = this.#sizes.get(prev) ?? 0;
576
610
  const nextSize = this.#sizes.get(next) ?? 0;
577
- if (this.#isCollapsed(prev)) {
611
+ if (isCollapsed(prev)) {
578
612
  const preferred = this.#previousSizes.get(prev) ?? requestedSizeOf(prev) ?? Math.max(minSizeOf(prev), 10);
579
613
  const available = nextSize - minSizeOf(next);
580
614
  const restored = Math.min(preferred, available);
581
615
  if (restored <= 0) return;
582
- this.#setCollapsed(prev, false);
616
+ setCollapsed(prev, false);
583
617
  this.#sizes.set(prev, restored);
584
618
  this.#sizes.set(next, nextSize - restored);
585
619
  } else {
586
620
  this.#previousSizes.set(prev, prevSize);
587
- this.#setCollapsed(prev, true);
621
+ setCollapsed(prev, true);
588
622
  this.#sizes.set(prev, 0);
589
623
  this.#sizes.set(next, nextSize + prevSize);
590
624
  }
591
- this.#apply([prev, next]);
592
- this.#notify();
625
+ this.#apply([prev, next], members);
626
+ this.#notify(members.panels);
593
627
  }
594
628
  }
595
629
 
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sources":["../../../src/components/resizable/state.ts"],"sourcesContent":["export type Orientation = 'horizontal' | 'vertical';\n\nconst GROUP_SELECTOR = '.ember-primitives__resizable';\nconst PANEL_SELECTOR = '.ember-primitives__resizable__panel';\nconst HANDLE_SELECTOR = '.ember-primitives__resizable__handle';\n\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\n/**\n * How far (in %) one keyboard arrow press moves a handle.\n * Holding Shift moves in coarser increments.\n */\nconst KEYBOARD_STEP = 1;\nconst KEYBOARD_STEP_COARSE = 10;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction numberAttribute(element: Element, name: string): number | undefined {\n const raw = element.getAttribute(name);\n\n if (raw === null) return undefined;\n\n const value = parseFloat(raw);\n\n return Number.isFinite(value) ? value : undefined;\n}\n\n/**\n * Panels declare their constraints in the DOM (via data attributes),\n * so the group can discover everything it needs with queries --\n * no registration required.\n */\nfunction minSizeOf(panel: Element): number {\n return numberAttribute(panel, 'data-min-size') ?? DEFAULT_MIN;\n}\n\nfunction maxSizeOf(panel: Element): number {\n return numberAttribute(panel, 'data-max-size') ?? DEFAULT_MAX;\n}\n\nfunction requestedSizeOf(panel: Element): number | undefined {\n return numberAttribute(panel, 'data-size');\n}\n\nfunction isCollapsible(panel: Element): boolean {\n return panel.hasAttribute('data-collapsible');\n}\n\nfunction sameMembers(a: HTMLElement[], b: HTMLElement[]): boolean {\n return a.length === b.length && a.every((element, index) => element === b[index]);\n}\n\n/**\n * Sizes are floats that get re-derived (measurement, normalization),\n * so \"unchanged\" means within a small tolerance.\n */\nfunction isSameSize(existing: number | undefined, size: number): boolean {\n return existing !== undefined && Math.abs(existing - size) < 0.0001;\n}\n\n/**\n * Pixel measurements round to device pixels, so re-measuring a layout\n * yields values that differ from the stored ones by sub-pixel noise.\n * Only differences beyond this (in %) count as real drift worth\n * adopting -- re-encoding identical pixels as slightly different\n * percentages would dirty every panel for no visual change.\n */\nconst MEASUREMENT_TOLERANCE = 0.25;\n\n/**\n * Skips the write when the attribute already has the desired value,\n * so unchanged elements are left untouched.\n */\nfunction setAttribute(element: Element, name: string, value: string): void {\n if (element.getAttribute(name) !== value) {\n element.setAttribute(name, value);\n }\n}\n\ninterface DragState {\n prev: HTMLElement;\n next: HTMLElement;\n startPrevSize: number;\n startNextSize: number;\n startCoordinate: number;\n /**\n * Total px occupied by the panels (excluding handles) at drag start,\n * used to convert px deltas to % deltas.\n */\n totalPx: number;\n move: (event: PointerEvent) => void;\n end: (event: PointerEvent) => void;\n}\n\ninterface GroupOptions {\n orientation: () => Orientation | undefined;\n onLayoutChange: () => ((sizes: number[]) => void) | undefined;\n}\n\nexport class GroupState {\n element: HTMLElement | null = null;\n\n #options: GroupOptions;\n #drag: DragState | null = null;\n\n /**\n * Current size (%) per panel element.\n * The DOM is the source of truth for membership; this only remembers\n * sizes across relayouts.\n */\n #sizes = new Map<HTMLElement, number>();\n\n /**\n * The size (%) a collapsible panel had before it was collapsed,\n * so that expanding restores it.\n */\n #previousSizes = new WeakMap<HTMLElement, number>();\n\n /**\n * Membership as of the last layout, so mutation batches that don't\n * change membership (e.g. content changes inside a panel, or churn\n * within a nested group) can be ignored.\n */\n #knownPanels: HTMLElement[] = [];\n #knownHandles: HTMLElement[] = [];\n\n /**\n * The percentage that a flex-grow of 1 represents in this group.\n *\n * Panels without an inline style render at the CSS default\n * (`flex: 1 1 0px`), so an all-equal group needs no styles at all --\n * mounting one writes nothing. The unit is fixed the first time a\n * panel actually diverges, and from then on grow values are written\n * relative to it, so panels whose share doesn't change keep their\n * (possibly absent) style untouched.\n */\n #unit: number | null = null;\n\n constructor(options: GroupOptions) {\n this.#options = options;\n }\n\n get orientation(): Orientation {\n return this.#options.orientation() ?? 'horizontal';\n }\n\n get #isHorizontal(): boolean {\n return this.orientation === 'horizontal';\n }\n\n /**\n * This group's panels, in document order.\n * Panels of nested groups belong to their own group, not this one.\n */\n get panels(): HTMLElement[] {\n return this.#query(PANEL_SELECTOR);\n }\n\n get handles(): HTMLElement[] {\n return this.#query(HANDLE_SELECTOR);\n }\n\n #query(selector: string): HTMLElement[] {\n const element = this.element;\n\n if (!element) return [];\n\n const all = Array.from(element.querySelectorAll<HTMLElement>(selector));\n\n return all.filter((candidate) => candidate.closest(GROUP_SELECTOR) === element);\n }\n\n get sizes(): number[] {\n return this.panels.map((panel) => this.#sizes.get(panel) ?? 0);\n }\n\n /**\n * One MutationObserver for every group on the page. Each record is\n * routed to the group that owns it (the nearest group ancestor), so\n * churn inside a nested group never even pings its ancestors.\n */\n static #observed = new Map<HTMLElement, GroupState>();\n static #observer: MutationObserver | null = null;\n\n static #observerOptions: MutationObserverInit = {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['data-orientation'],\n // to distinguish real changes from same-value writes (see below)\n attributeOldValue: true,\n };\n\n static #handleMutations(mutations: MutationRecord[]): void {\n /**\n * true = the group's own data-orientation changed,\n * false = something in its subtree changed (membership check needed)\n */\n const affected = new Map<GroupState, boolean>();\n\n for (const mutation of mutations) {\n const target = mutation.target;\n\n if (!(target instanceof Element)) continue;\n\n if (mutation.type === 'attributes') {\n const group = GroupState.#observed.get(target as HTMLElement);\n\n /**\n * setAttribute queues a record even when the value is\n * unchanged (renderers do rewrite attributes with the same\n * value); only actual changes warrant a relayout.\n */\n const changed =\n mutation.attributeName &&\n mutation.oldValue !== target.getAttribute(mutation.attributeName);\n\n if (group && changed) affected.set(group, true);\n continue;\n }\n\n const groupElement = target.closest<HTMLElement>(GROUP_SELECTOR);\n const group = groupElement && GroupState.#observed.get(groupElement);\n\n if (group && !affected.has(group)) affected.set(group, false);\n }\n\n for (const [group, orientationChanged] of affected) {\n if (orientationChanged || group.#membershipChanged()) group.#layout();\n }\n }\n\n static #observe(element: HTMLElement, group: GroupState): void {\n GroupState.#observed.set(element, group);\n GroupState.#observer ??= new MutationObserver((mutations) =>\n GroupState.#handleMutations(mutations)\n );\n GroupState.#observer.observe(element, GroupState.#observerOptions);\n }\n\n static #unobserve(element: HTMLElement): void {\n GroupState.#observed.delete(element);\n\n const observer = GroupState.#observer;\n\n if (!observer) return;\n\n /**\n * MutationObserver has no per-target unobserve; disconnect and\n * re-observe the remaining groups (rare -- teardown only).\n */\n observer.disconnect();\n\n if (GroupState.#observed.size === 0) {\n GroupState.#observer = null;\n\n return;\n }\n\n for (const remaining of GroupState.#observed.keys()) {\n observer.observe(remaining, GroupState.#observerOptions);\n }\n }\n\n /**\n * Called (via modifier) when the group element is inserted.\n * Watches for panels being added/removed (and the orientation\n * changing) and performs the initial layout.\n */\n attach = (element: HTMLElement): (() => void) => {\n this.element = element;\n\n GroupState.#observe(element, this);\n\n this.#layout();\n\n return () => {\n GroupState.#unobserve(element);\n this.element = null;\n };\n };\n\n #membershipChanged(): boolean {\n return (\n !sameMembers(this.panels, this.#knownPanels) || !sameMembers(this.handles, this.#knownHandles)\n );\n }\n\n /**\n * Panels that already have a size (or request one via `data-size`)\n * keep it; new panels take a share of the remaining space; everything\n * is normalized to 100.\n */\n #layout(): void {\n const panels = this.panels;\n const handles = this.handles;\n\n if (!sameMembers(panels, this.#knownPanels)) this.#knownPanels = panels;\n if (!sameMembers(handles, this.#knownHandles)) this.#knownHandles = handles;\n\n if (panels.length === 0) return;\n\n let changed = false;\n\n // forget sizes of panels that left the DOM\n for (const known of Array.from(this.#sizes.keys())) {\n if (!panels.includes(known)) {\n this.#sizes.delete(known);\n changed = true;\n }\n }\n\n // scratch space for the math below; #sizes itself is only\n // touched at the end, and only where values actually changed\n const computed = new Map<HTMLElement, number>();\n const unspecified: HTMLElement[] = [];\n let specifiedTotal = 0;\n\n for (const panel of panels) {\n const preferred = this.#sizes.get(panel) ?? requestedSizeOf(panel);\n\n if (preferred === undefined) {\n unspecified.push(panel);\n continue;\n }\n\n const size = this.#isCollapsed(panel)\n ? preferred\n : clamp(preferred, minSizeOf(panel), maxSizeOf(panel));\n\n computed.set(panel, size);\n specifiedTotal += size;\n }\n\n if (unspecified.length > 0) {\n /**\n * Panels without a size share the remaining space.\n * When there is none left (e.g. a panel was added to an\n * already-full group), each takes an equal 1/n share and the\n * existing panels scale down to make room -- like a new window\n * opening in a tiling window manager.\n */\n const remaining = 100 - specifiedTotal;\n let share = remaining / unspecified.length;\n\n if (remaining < 1) {\n share = 100 / panels.length;\n\n if (specifiedTotal > 0) {\n const scale = Math.max(100 - share * unspecified.length, 0) / specifiedTotal;\n\n for (const [panel, size] of computed) {\n computed.set(panel, size * scale);\n }\n }\n }\n\n for (const panel of unspecified) {\n computed.set(panel, clamp(share, minSizeOf(panel), maxSizeOf(panel)));\n }\n }\n\n // normalize to 100\n let total = 0;\n\n for (const size of computed.values()) total += size;\n\n if (total > 0 && Math.abs(total - 100) > 0.01) {\n for (const [panel, size] of computed) {\n computed.set(panel, (size / total) * 100);\n }\n }\n\n /**\n * Commit minimally: keep the #sizes map, update only entries whose\n * value actually changed (with a small tolerance, so float dust\n * from re-normalizing doesn't count as a change).\n */\n const changedPanels: HTMLElement[] = [];\n\n for (const [panel, size] of computed) {\n if (!isSameSize(this.#sizes.get(panel), size)) {\n this.#sizes.set(panel, size);\n changedPanels.push(panel);\n changed = true;\n }\n }\n\n this.#apply(changedPanels);\n\n if (changed) this.#notify();\n }\n\n /**\n * Writes the layout back to the DOM: flex sizing for exactly the\n * candidate panels whose rendered share would actually change, plus\n * the handles' ARIA attributes (which are guarded per-attribute).\n * (`data-collapsed` is managed at the explicit collapse/expand\n * points, not derived from sizes -- rendered pixel sizes include\n * borders/padding, so a collapsed panel rarely measures exactly 0.)\n */\n #apply(candidates: HTMLElement[]): void {\n if (candidates.length > 0) {\n /**\n * With no unit fixed yet, nothing has ever been written, so every\n * panel renders at the CSS default -- an equal 1/n share.\n */\n const unit = this.#unit ?? 100 / this.panels.length;\n\n for (const panel of candidates) {\n const size = this.#sizes.get(panel);\n\n if (size === undefined) continue;\n\n const inlineGrow = panel.style.flexGrow;\n const impliedPercent = (inlineGrow === '' ? 1 : parseFloat(inlineGrow)) * unit;\n\n if (isSameSize(impliedPercent, size)) continue;\n\n this.#unit ??= unit;\n panel.style.flex = `${size / unit} 1 0px`;\n }\n }\n\n this.#syncHandles();\n }\n\n /**\n * Per the window-splitter pattern, each handle describes the panel\n * immediately before it. (A splitter between two side-by-side panes\n * is oriented *vertically*, and vice-versa.)\n */\n #syncHandles(): void {\n for (const handle of this.handles) {\n const [prev] = this.#neighborsOf(handle);\n\n setAttribute(handle, 'aria-orientation', this.#isHorizontal ? 'vertical' : 'horizontal');\n\n if (!prev) continue;\n\n // Panels render their own (component-owned, incrementing) id\n if (prev.id) setAttribute(handle, 'aria-controls', prev.id);\n\n setAttribute(handle, 'aria-valuemin', `${minSizeOf(prev)}`);\n setAttribute(handle, 'aria-valuemax', `${maxSizeOf(prev)}`);\n setAttribute(handle, 'aria-valuenow', `${Math.round(this.#sizes.get(prev) ?? 0)}`);\n }\n }\n\n #notify(): void {\n this.#options.onLayoutChange()?.(this.sizes);\n }\n\n /**\n * The `data-collapsed` attribute is the source of truth for collapse\n * state (it is also the styling hook consumers use).\n */\n #isCollapsed(panel: HTMLElement): boolean {\n return isCollapsible(panel) && panel.hasAttribute('data-collapsed');\n }\n\n #setCollapsed(panel: HTMLElement, collapsed: boolean): void {\n if (collapsed === panel.hasAttribute('data-collapsed')) return;\n\n if (collapsed) {\n panel.setAttribute('data-collapsed', '');\n } else {\n panel.removeAttribute('data-collapsed');\n }\n }\n\n /**\n * Re-derive percentage sizes from actual rendered pixels.\n * Corrects any drift (e.g. from CSS min-sizes) before an interaction.\n */\n #syncSizesFromDOM(): void {\n const panels = this.panels;\n // collapsed panels are 0 even though their borders/padding measure larger\n const px = panels.map((panel) => (this.#isCollapsed(panel) ? 0 : this.#pixelSizeOf(panel)));\n const total = px.reduce((sum, value) => sum + value, 0);\n\n if (total <= 0) return;\n\n panels.forEach((panel, index) => {\n const size = ((px[index] ?? 0) / total) * 100;\n const existing = this.#sizes.get(panel);\n\n if (existing === undefined || Math.abs(existing - size) > MEASUREMENT_TOLERANCE) {\n this.#sizes.set(panel, size);\n }\n });\n }\n\n #pixelSizeOf(panel: HTMLElement): number {\n const box = panel.getBoundingClientRect();\n\n return this.#isHorizontal ? box.width : box.height;\n }\n\n /**\n * The panels immediately before and after the given handle element,\n * in document order.\n */\n #neighborsOf(handleElement: HTMLElement): [HTMLElement | null, HTMLElement | null] {\n let prev: HTMLElement | null = null;\n let next: HTMLElement | null = null;\n\n for (const panel of this.panels) {\n const position = handleElement.compareDocumentPosition(panel);\n\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n prev = panel;\n } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n next = panel;\n\n break;\n }\n }\n\n return [prev, next];\n }\n\n /**\n * Moves the boundary between the two panels by `requestedDelta` (%),\n * respecting both panels' min/max constraints.\n */\n #applyDelta(\n prev: HTMLElement,\n next: HTMLElement,\n basePrevSize: number,\n baseNextSize: number,\n requestedDelta: number\n ): void {\n const total = basePrevSize + baseNextSize;\n\n let target = basePrevSize + requestedDelta;\n\n if (isCollapsible(prev) && target < minSizeOf(prev)) {\n /**\n * Collapsible panels snap: below half the minimum they close\n * entirely; between half and the minimum they hold at the minimum.\n * (This also keeps a collapsed panel closed when its handle is\n * dragged further in the closing direction.)\n */\n target = target < minSizeOf(prev) / 2 ? 0 : minSizeOf(prev);\n } else {\n target = clamp(target, minSizeOf(prev), maxSizeOf(prev));\n }\n\n /**\n * The neighbor absorbs whatever the target panel gives or takes,\n * so its constraints bound the target too.\n */\n const nextMin = total - maxSizeOf(next);\n const nextMax = total - minSizeOf(next);\n\n if (nextMin > nextMax) return;\n\n target = clamp(target, nextMin, nextMax);\n\n // both panels' constraints cannot be satisfied at once\n if (!isCollapsible(prev) && (target < minSizeOf(prev) || target > maxSizeOf(prev))) return;\n\n /**\n * Nothing to do when the clamped result matches the current sizes\n * (e.g. every pointermove past a min/max limit).\n */\n if (\n isSameSize(this.#sizes.get(prev), target) &&\n isSameSize(this.#sizes.get(next), total - target)\n ) {\n return;\n }\n\n if (isCollapsible(prev)) {\n if (target === 0 && !this.#isCollapsed(prev)) {\n this.#previousSizes.set(prev, basePrevSize);\n }\n\n this.#setCollapsed(prev, target === 0);\n }\n\n this.#sizes.set(prev, target);\n this.#sizes.set(next, total - target);\n\n this.#apply([prev, next]);\n this.#notify();\n }\n\n startDrag(handleElement: HTMLElement, event: PointerEvent): void {\n if (event.button !== 0) return;\n if (this.#drag) return;\n\n const [prev, next] = this.#neighborsOf(handleElement);\n\n if (!prev || !next) return;\n\n this.#syncSizesFromDOM();\n\n const move = (moveEvent: PointerEvent) => this.#dragMove(moveEvent);\n const end = (endEvent: PointerEvent) => this.#endDrag(handleElement, endEvent);\n\n this.#drag = {\n prev,\n next,\n startPrevSize: this.#sizes.get(prev) ?? 0,\n startNextSize: this.#sizes.get(next) ?? 0,\n startCoordinate: this.#isHorizontal ? event.clientX : event.clientY,\n totalPx: this.panels.reduce((sum, panel) => sum + this.#pixelSizeOf(panel), 0),\n move,\n end,\n };\n\n try {\n /**\n * Retargets all subsequent pointer events to the handle,\n * even when the pointer is over an iframe.\n */\n handleElement.setPointerCapture(event.pointerId);\n } catch {\n // synthetic events (tests) may not have an active pointer\n }\n\n handleElement.addEventListener('pointermove', this.#drag.move);\n handleElement.addEventListener('pointerup', this.#drag.end);\n handleElement.addEventListener('pointercancel', this.#drag.end);\n handleElement.setAttribute('data-resizing', '');\n\n document.body.style.cursor = this.#isHorizontal ? 'col-resize' : 'row-resize';\n document.body.style.userSelect = 'none';\n }\n\n #dragMove(event: PointerEvent): void {\n const drag = this.#drag;\n\n if (!drag) return;\n if (drag.totalPx <= 0) return;\n\n const coordinate = this.#isHorizontal ? event.clientX : event.clientY;\n const deltaPercent = ((coordinate - drag.startCoordinate) / drag.totalPx) * 100;\n\n this.#applyDelta(drag.prev, drag.next, drag.startPrevSize, drag.startNextSize, deltaPercent);\n }\n\n #endDrag(handleElement: HTMLElement, event: PointerEvent): void {\n const drag = this.#drag;\n\n if (!drag) return;\n\n this.#drag = null;\n\n try {\n handleElement.releasePointerCapture(event.pointerId);\n } catch {\n // may not have been captured (tests)\n }\n\n handleElement.removeEventListener('pointermove', drag.move);\n handleElement.removeEventListener('pointerup', drag.end);\n handleElement.removeEventListener('pointercancel', drag.end);\n handleElement.removeAttribute('data-resizing');\n\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n\n /**\n * Keyboard support for the WAI-ARIA window-splitter pattern.\n */\n handleKeyDown(handleElement: HTMLElement, event: KeyboardEvent): void {\n const [prev, next] = this.#neighborsOf(handleElement);\n\n if (!prev || !next) return;\n\n if (event.key === 'Enter') {\n this.#toggleCollapse(prev, next);\n\n return;\n }\n\n const step = event.shiftKey ? KEYBOARD_STEP_COARSE : KEYBOARD_STEP;\n const isHorizontal = this.#isHorizontal;\n\n let delta: number | null = null;\n\n switch (event.key) {\n case 'ArrowLeft':\n if (isHorizontal) delta = -step;\n\n break;\n case 'ArrowRight':\n if (isHorizontal) delta = step;\n\n break;\n case 'ArrowUp':\n if (!isHorizontal) delta = -step;\n\n break;\n case 'ArrowDown':\n if (!isHorizontal) delta = step;\n\n break;\n case 'Home':\n this.#syncSizesFromDOM();\n delta = minSizeOf(prev) - (this.#sizes.get(prev) ?? 0);\n\n break;\n case 'End':\n this.#syncSizesFromDOM();\n delta = maxSizeOf(prev) - (this.#sizes.get(prev) ?? 0);\n\n break;\n }\n\n if (delta === null) return;\n\n event.preventDefault();\n\n this.#syncSizesFromDOM();\n this.#applyDelta(prev, next, this.#sizes.get(prev) ?? 0, this.#sizes.get(next) ?? 0, delta);\n }\n\n /**\n * Collapses (or restores) the panel before the handle,\n * giving the space to (or taking it from) the panel after it.\n *\n * Only does anything when the preceding panel is `@collapsible`.\n */\n #toggleCollapse(prev: HTMLElement, next: HTMLElement): void {\n if (!isCollapsible(prev)) return;\n\n this.#syncSizesFromDOM();\n\n const prevSize = this.#sizes.get(prev) ?? 0;\n const nextSize = this.#sizes.get(next) ?? 0;\n\n if (this.#isCollapsed(prev)) {\n const preferred =\n this.#previousSizes.get(prev) ?? requestedSizeOf(prev) ?? Math.max(minSizeOf(prev), 10);\n const available = nextSize - minSizeOf(next);\n const restored = Math.min(preferred, available);\n\n if (restored <= 0) return;\n\n this.#setCollapsed(prev, false);\n this.#sizes.set(prev, restored);\n this.#sizes.set(next, nextSize - restored);\n } else {\n this.#previousSizes.set(prev, prevSize);\n this.#setCollapsed(prev, true);\n this.#sizes.set(prev, 0);\n this.#sizes.set(next, nextSize + prevSize);\n }\n\n this.#apply([prev, next]);\n this.#notify();\n }\n}\n"],"names":["GROUP_SELECTOR","PANEL_SELECTOR","HANDLE_SELECTOR","DEFAULT_MIN","DEFAULT_MAX","KEYBOARD_STEP","KEYBOARD_STEP_COARSE","clamp","value","min","max","Math","numberAttribute","element","name","raw","getAttribute","undefined","parseFloat","Number","isFinite","minSizeOf","panel","maxSizeOf","requestedSizeOf","isCollapsible","hasAttribute","sameMembers","a","b","length","every","index","isSameSize","existing","size","abs","MEASUREMENT_TOLERANCE","setAttribute","GroupState","Map","WeakMap","constructor","options","orientation","#isHorizontal","panels","handles","#query","selector","all","Array","from","querySelectorAll","filter","candidate","closest","sizes","map","get","childList","subtree","attributes","attributeFilter","attributeOldValue","#handleMutations","mutations","affected","mutation","target","Element","type","group","changed","attributeName","oldValue","set","groupElement","has","orientationChanged","#observe","MutationObserver","observe","#unobserve","delete","observer","disconnect","remaining","keys","attach","#membershipChanged","#layout","known","includes","computed","unspecified","specifiedTotal","preferred","push","share","scale","total","values","changedPanels","#apply","candidates","unit","inlineGrow","style","flexGrow","impliedPercent","flex","#syncHandles","handle","prev","id","round","#notify","onLayoutChange","#isCollapsed","#setCollapsed","collapsed","removeAttribute","#syncSizesFromDOM","px","reduce","sum","forEach","#pixelSizeOf","box","getBoundingClientRect","width","height","#neighborsOf","handleElement","next","position","compareDocumentPosition","Node","DOCUMENT_POSITION_PRECEDING","DOCUMENT_POSITION_FOLLOWING","#applyDelta","basePrevSize","baseNextSize","requestedDelta","nextMin","nextMax","startDrag","event","button","move","moveEvent","end","endEvent","startPrevSize","startNextSize","startCoordinate","clientX","clientY","totalPx","setPointerCapture","pointerId","addEventListener","document","body","cursor","userSelect","#dragMove","drag","coordinate","deltaPercent","#endDrag","releasePointerCapture","removeEventListener","handleKeyDown","key","step","shiftKey","isHorizontal","delta","preventDefault","#toggleCollapse","prevSize","nextSize","available","restored"],"mappings":"AAEA,MAAMA,cAAc,GAAG,8BAA8B;AACrD,MAAMC,cAAc,GAAG,qCAAqC;AAC5D,MAAMC,eAAe,GAAG,sCAAsC;AAE9D,MAAMC,WAAW,GAAG,CAAC;AACrB,MAAMC,WAAW,GAAG,GAAG;;AAEvB;AACA;AACA;AACA;AACA,MAAMC,aAAa,GAAG,CAAC;AACvB,MAAMC,oBAAoB,GAAG,EAAE;AAE/B,SAASC,KAAKA,CAACC,KAAa,EAAEC,GAAW,EAAEC,GAAW,EAAU;AAC9D,EAAA,OAAOC,IAAI,CAACF,GAAG,CAACE,IAAI,CAACD,GAAG,CAACF,KAAK,EAAEC,GAAG,CAAC,EAAEC,GAAG,CAAC;AAC5C;AAEA,SAASE,eAAeA,CAACC,OAAgB,EAAEC,IAAY,EAAsB;AAC3E,EAAA,MAAMC,GAAG,GAAGF,OAAO,CAACG,YAAY,CAACF,IAAI,CAAC;AAEtC,EAAA,IAAIC,GAAG,KAAK,IAAI,EAAE,OAAOE,SAAS;AAElC,EAAA,MAAMT,KAAK,GAAGU,UAAU,CAACH,GAAG,CAAC;EAE7B,OAAOI,MAAM,CAACC,QAAQ,CAACZ,KAAK,CAAC,GAAGA,KAAK,GAAGS,SAAS;AACnD;;AAEA;AACA;AACA;AACA;AACA;AACA,SAASI,SAASA,CAACC,KAAc,EAAU;AACzC,EAAA,OAAOV,eAAe,CAACU,KAAK,EAAE,eAAe,CAAC,IAAInB,WAAW;AAC/D;AAEA,SAASoB,SAASA,CAACD,KAAc,EAAU;AACzC,EAAA,OAAOV,eAAe,CAACU,KAAK,EAAE,eAAe,CAAC,IAAIlB,WAAW;AAC/D;AAEA,SAASoB,eAAeA,CAACF,KAAc,EAAsB;AAC3D,EAAA,OAAOV,eAAe,CAACU,KAAK,EAAE,WAAW,CAAC;AAC5C;AAEA,SAASG,aAAaA,CAACH,KAAc,EAAW;AAC9C,EAAA,OAAOA,KAAK,CAACI,YAAY,CAAC,kBAAkB,CAAC;AAC/C;AAEA,SAASC,WAAWA,CAACC,CAAgB,EAAEC,CAAgB,EAAW;EAChE,OAAOD,CAAC,CAACE,MAAM,KAAKD,CAAC,CAACC,MAAM,IAAIF,CAAC,CAACG,KAAK,CAAC,CAAClB,OAAO,EAAEmB,KAAK,KAAKnB,OAAO,KAAKgB,CAAC,CAACG,KAAK,CAAC,CAAC;AACnF;;AAEA;AACA;AACA;AACA;AACA,SAASC,UAAUA,CAACC,QAA4B,EAAEC,IAAY,EAAW;AACvE,EAAA,OAAOD,QAAQ,KAAKjB,SAAS,IAAIN,IAAI,CAACyB,GAAG,CAACF,QAAQ,GAAGC,IAAI,CAAC,GAAG,MAAM;AACrE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAME,qBAAqB,GAAG,IAAI;;AAElC;AACA;AACA;AACA;AACA,SAASC,YAAYA,CAACzB,OAAgB,EAAEC,IAAY,EAAEN,KAAa,EAAQ;EACzE,IAAIK,OAAO,CAACG,YAAY,CAACF,IAAI,CAAC,KAAKN,KAAK,EAAE;AACxCK,IAAAA,OAAO,CAACyB,YAAY,CAACxB,IAAI,EAAEN,KAAK,CAAC;AACnC,EAAA;AACF;AAsBO,MAAM+B,UAAU,CAAC;AACtB1B,EAAAA,OAAO,GAAuB,IAAI;AAElC,EAAA,QAAQ;EACR,KAAK,GAAqB,IAAI;;AAE9B;AACF;AACA;AACA;AACA;AACE,EAAA,MAAM,GAAG,IAAI2B,GAAG,EAAuB;;AAEvC;AACF;AACA;AACA;AACE,EAAA,cAAc,GAAG,IAAIC,OAAO,EAAuB;;AAEnD;AACF;AACA;AACA;AACA;EACE,YAAY,GAAkB,EAAE;EAChC,aAAa,GAAkB,EAAE;;AAEjC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,KAAK,GAAkB,IAAI;EAE3BC,WAAWA,CAACC,OAAqB,EAAE;AACjC,IAAA,IAAI,CAAC,QAAQ,GAAGA,OAAO;AACzB,EAAA;EAEA,IAAIC,WAAWA,GAAgB;IAC7B,OAAO,IAAI,CAAC,QAAQ,CAACA,WAAW,EAAE,IAAI,YAAY;AACpD,EAAA;EAEA,IAAI,aAAaC,GAAY;AAC3B,IAAA,OAAO,IAAI,CAACD,WAAW,KAAK,YAAY;AAC1C,EAAA;;AAEA;AACF;AACA;AACA;EACE,IAAIE,MAAMA,GAAkB;AAC1B,IAAA,OAAO,IAAI,CAAC,MAAM,CAAC7C,cAAc,CAAC;AACpC,EAAA;EAEA,IAAI8C,OAAOA,GAAkB;AAC3B,IAAA,OAAO,IAAI,CAAC,MAAM,CAAC7C,eAAe,CAAC;AACrC,EAAA;EAEA,MAAM8C,CAACC,QAAgB,EAAiB;AACtC,IAAA,MAAMpC,OAAO,GAAG,IAAI,CAACA,OAAO;AAE5B,IAAA,IAAI,CAACA,OAAO,EAAE,OAAO,EAAE;AAEvB,IAAA,MAAMqC,GAAG,GAAGC,KAAK,CAACC,IAAI,CAACvC,OAAO,CAACwC,gBAAgB,CAAcJ,QAAQ,CAAC,CAAC;AAEvE,IAAA,OAAOC,GAAG,CAACI,MAAM,CAAEC,SAAS,IAAKA,SAAS,CAACC,OAAO,CAACxD,cAAc,CAAC,KAAKa,OAAO,CAAC;AACjF,EAAA;EAEA,IAAI4C,KAAKA,GAAa;AACpB,IAAA,OAAO,IAAI,CAACX,MAAM,CAACY,GAAG,CAAEpC,KAAK,IAAK,IAAI,CAAC,MAAM,CAACqC,GAAG,CAACrC,KAAK,CAAC,IAAI,CAAC,CAAC;AAChE,EAAA;;AAEA;AACF;AACA;AACA;AACA;AACE,EAAA,OAAO,SAAS,GAAG,IAAIkB,GAAG,EAA2B;EACrD,OAAO,SAAS,GAA4B,IAAI;EAEhD,OAAO,gBAAgB,GAAyB;AAC9CoB,IAAAA,SAAS,EAAE,IAAI;AACfC,IAAAA,OAAO,EAAE,IAAI;AACbC,IAAAA,UAAU,EAAE,IAAI;IAChBC,eAAe,EAAE,CAAC,kBAAkB,CAAC;AACrC;AACAC,IAAAA,iBAAiB,EAAE;GACpB;AAED,EAAA,OAAO,gBAAgBC,CAACC,SAA2B,EAAQ;AACzD;AACJ;AACA;AACA;AACI,IAAA,MAAMC,QAAQ,GAAG,IAAI3B,GAAG,EAAuB;AAE/C,IAAA,KAAK,MAAM4B,QAAQ,IAAIF,SAAS,EAAE;AAChC,MAAA,MAAMG,MAAM,GAAGD,QAAQ,CAACC,MAAM;AAE9B,MAAA,IAAI,EAAEA,MAAM,YAAYC,OAAO,CAAC,EAAE;AAElC,MAAA,IAAIF,QAAQ,CAACG,IAAI,KAAK,YAAY,EAAE;QAClC,MAAMC,KAAK,GAAGjC,UAAU,CAAC,SAAS,CAACoB,GAAG,CAACU,MAAqB,CAAC;;AAE7D;AACR;AACA;AACA;AACA;AACQ,QAAA,MAAMI,OAAO,GACXL,QAAQ,CAACM,aAAa,IACtBN,QAAQ,CAACO,QAAQ,KAAKN,MAAM,CAACrD,YAAY,CAACoD,QAAQ,CAACM,aAAa,CAAC;QAEnE,IAAIF,KAAK,IAAIC,OAAO,EAAEN,QAAQ,CAACS,GAAG,CAACJ,KAAK,EAAE,IAAI,CAAC;AAC/C,QAAA;AACF,MAAA;AAEA,MAAA,MAAMK,YAAY,GAAGR,MAAM,CAACb,OAAO,CAAcxD,cAAc,CAAC;AAChE,MAAA,MAAMwE,KAAK,GAAGK,YAAY,IAAItC,UAAU,CAAC,SAAS,CAACoB,GAAG,CAACkB,YAAY,CAAC;AAEpE,MAAA,IAAIL,KAAK,IAAI,CAACL,QAAQ,CAACW,GAAG,CAACN,KAAK,CAAC,EAAEL,QAAQ,CAACS,GAAG,CAACJ,KAAK,EAAE,KAAK,CAAC;AAC/D,IAAA;IAEA,KAAK,MAAM,CAACA,KAAK,EAAEO,kBAAkB,CAAC,IAAIZ,QAAQ,EAAE;AAClD,MAAA,IAAIY,kBAAkB,IAAIP,KAAK,CAAC,kBAAkB,EAAE,EAAEA,KAAK,CAAC,OAAO,EAAE;AACvE,IAAA;AACF,EAAA;AAEA,EAAA,OAAO,QAAQQ,CAACnE,OAAoB,EAAE2D,KAAiB,EAAQ;IAC7DjC,UAAU,CAAC,SAAS,CAACqC,GAAG,CAAC/D,OAAO,EAAE2D,KAAK,CAAC;AACxCjC,IAAAA,UAAU,CAAC,SAAS,KAAK,IAAI0C,gBAAgB,CAAEf,SAAS,IACtD3B,UAAU,CAAC,gBAAgB,CAAC2B,SAAS,CACvC,CAAC;AACD3B,IAAAA,UAAU,CAAC,SAAS,CAAC2C,OAAO,CAACrE,OAAO,EAAE0B,UAAU,CAAC,gBAAgB,CAAC;AACpE,EAAA;AAEA,EAAA,OAAO,UAAU4C,CAACtE,OAAoB,EAAQ;AAC5C0B,IAAAA,UAAU,CAAC,SAAS,CAAC6C,MAAM,CAACvE,OAAO,CAAC;AAEpC,IAAA,MAAMwE,QAAQ,GAAG9C,UAAU,CAAC,SAAS;IAErC,IAAI,CAAC8C,QAAQ,EAAE;;AAEf;AACJ;AACA;AACA;IACIA,QAAQ,CAACC,UAAU,EAAE;IAErB,IAAI/C,UAAU,CAAC,SAAS,CAACJ,IAAI,KAAK,CAAC,EAAE;AACnCI,MAAAA,UAAU,CAAC,SAAS,GAAG,IAAI;AAE3B,MAAA;AACF,IAAA;IAEA,KAAK,MAAMgD,SAAS,IAAIhD,UAAU,CAAC,SAAS,CAACiD,IAAI,EAAE,EAAE;MACnDH,QAAQ,CAACH,OAAO,CAACK,SAAS,EAAEhD,UAAU,CAAC,gBAAgB,CAAC;AAC1D,IAAA;AACF,EAAA;;AAEA;AACF;AACA;AACA;AACA;EACEkD,MAAM,GAAI5E,OAAoB,IAAmB;IAC/C,IAAI,CAACA,OAAO,GAAGA,OAAO;AAEtB0B,IAAAA,UAAU,CAAC,QAAQ,CAAC1B,OAAO,EAAE,IAAI,CAAC;AAElC,IAAA,IAAI,CAAC,OAAO,EAAE;AAEd,IAAA,OAAO,MAAM;AACX0B,MAAAA,UAAU,CAAC,UAAU,CAAC1B,OAAO,CAAC;MAC9B,IAAI,CAACA,OAAO,GAAG,IAAI;IACrB,CAAC;EACH,CAAC;EAED,kBAAkB6E,GAAY;IAC5B,OACE,CAAC/D,WAAW,CAAC,IAAI,CAACmB,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAACnB,WAAW,CAAC,IAAI,CAACoB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;AAElG,EAAA;;AAEA;AACF;AACA;AACA;AACA;EACE,OAAO4C,GAAS;AACd,IAAA,MAAM7C,MAAM,GAAG,IAAI,CAACA,MAAM;AAC1B,IAAA,MAAMC,OAAO,GAAG,IAAI,CAACA,OAAO;AAE5B,IAAA,IAAI,CAACpB,WAAW,CAACmB,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,YAAY,GAAGA,MAAM;AACvE,IAAA,IAAI,CAACnB,WAAW,CAACoB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,GAAGA,OAAO;AAE3E,IAAA,IAAID,MAAM,CAAChB,MAAM,KAAK,CAAC,EAAE;IAEzB,IAAI2C,OAAO,GAAG,KAAK;;AAEnB;AACA,IAAA,KAAK,MAAMmB,KAAK,IAAIzC,KAAK,CAACC,IAAI,CAAC,IAAI,CAAC,MAAM,CAACoC,IAAI,EAAE,CAAC,EAAE;AAClD,MAAA,IAAI,CAAC1C,MAAM,CAAC+C,QAAQ,CAACD,KAAK,CAAC,EAAE;AAC3B,QAAA,IAAI,CAAC,MAAM,CAACR,MAAM,CAACQ,KAAK,CAAC;AACzBnB,QAAAA,OAAO,GAAG,IAAI;AAChB,MAAA;AACF,IAAA;;AAEA;AACA;AACA,IAAA,MAAMqB,QAAQ,GAAG,IAAItD,GAAG,EAAuB;IAC/C,MAAMuD,WAA0B,GAAG,EAAE;IACrC,IAAIC,cAAc,GAAG,CAAC;AAEtB,IAAA,KAAK,MAAM1E,KAAK,IAAIwB,MAAM,EAAE;AAC1B,MAAA,MAAMmD,SAAS,GAAG,IAAI,CAAC,MAAM,CAACtC,GAAG,CAACrC,KAAK,CAAC,IAAIE,eAAe,CAACF,KAAK,CAAC;MAElE,IAAI2E,SAAS,KAAKhF,SAAS,EAAE;AAC3B8E,QAAAA,WAAW,CAACG,IAAI,CAAC5E,KAAK,CAAC;AACvB,QAAA;AACF,MAAA;MAEA,MAAMa,IAAI,GAAG,IAAI,CAAC,YAAY,CAACb,KAAK,CAAC,GACjC2E,SAAS,GACT1F,KAAK,CAAC0F,SAAS,EAAE5E,SAAS,CAACC,KAAK,CAAC,EAAEC,SAAS,CAACD,KAAK,CAAC,CAAC;AAExDwE,MAAAA,QAAQ,CAAClB,GAAG,CAACtD,KAAK,EAAEa,IAAI,CAAC;AACzB6D,MAAAA,cAAc,IAAI7D,IAAI;AACxB,IAAA;AAEA,IAAA,IAAI4D,WAAW,CAACjE,MAAM,GAAG,CAAC,EAAE;AAC1B;AACN;AACA;AACA;AACA;AACA;AACA;AACM,MAAA,MAAMyD,SAAS,GAAG,GAAG,GAAGS,cAAc;AACtC,MAAA,IAAIG,KAAK,GAAGZ,SAAS,GAAGQ,WAAW,CAACjE,MAAM;MAE1C,IAAIyD,SAAS,GAAG,CAAC,EAAE;AACjBY,QAAAA,KAAK,GAAG,GAAG,GAAGrD,MAAM,CAAChB,MAAM;QAE3B,IAAIkE,cAAc,GAAG,CAAC,EAAE;AACtB,UAAA,MAAMI,KAAK,GAAGzF,IAAI,CAACD,GAAG,CAAC,GAAG,GAAGyF,KAAK,GAAGJ,WAAW,CAACjE,MAAM,EAAE,CAAC,CAAC,GAAGkE,cAAc;UAE5E,KAAK,MAAM,CAAC1E,KAAK,EAAEa,IAAI,CAAC,IAAI2D,QAAQ,EAAE;YACpCA,QAAQ,CAAClB,GAAG,CAACtD,KAAK,EAAEa,IAAI,GAAGiE,KAAK,CAAC;AACnC,UAAA;AACF,QAAA;AACF,MAAA;AAEA,MAAA,KAAK,MAAM9E,KAAK,IAAIyE,WAAW,EAAE;AAC/BD,QAAAA,QAAQ,CAAClB,GAAG,CAACtD,KAAK,EAAEf,KAAK,CAAC4F,KAAK,EAAE9E,SAAS,CAACC,KAAK,CAAC,EAAEC,SAAS,CAACD,KAAK,CAAC,CAAC,CAAC;AACvE,MAAA;AACF,IAAA;;AAEA;IACA,IAAI+E,KAAK,GAAG,CAAC;IAEb,KAAK,MAAMlE,IAAI,IAAI2D,QAAQ,CAACQ,MAAM,EAAE,EAAED,KAAK,IAAIlE,IAAI;AAEnD,IAAA,IAAIkE,KAAK,GAAG,CAAC,IAAI1F,IAAI,CAACyB,GAAG,CAACiE,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE;MAC7C,KAAK,MAAM,CAAC/E,KAAK,EAAEa,IAAI,CAAC,IAAI2D,QAAQ,EAAE;QACpCA,QAAQ,CAAClB,GAAG,CAACtD,KAAK,EAAGa,IAAI,GAAGkE,KAAK,GAAI,GAAG,CAAC;AAC3C,MAAA;AACF,IAAA;;AAEA;AACJ;AACA;AACA;AACA;IACI,MAAME,aAA4B,GAAG,EAAE;IAEvC,KAAK,MAAM,CAACjF,KAAK,EAAEa,IAAI,CAAC,IAAI2D,QAAQ,EAAE;AACpC,MAAA,IAAI,CAAC7D,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC0B,GAAG,CAACrC,KAAK,CAAC,EAAEa,IAAI,CAAC,EAAE;QAC7C,IAAI,CAAC,MAAM,CAACyC,GAAG,CAACtD,KAAK,EAAEa,IAAI,CAAC;AAC5BoE,QAAAA,aAAa,CAACL,IAAI,CAAC5E,KAAK,CAAC;AACzBmD,QAAAA,OAAO,GAAG,IAAI;AAChB,MAAA;AACF,IAAA;AAEA,IAAA,IAAI,CAAC,MAAM,CAAC8B,aAAa,CAAC;AAE1B,IAAA,IAAI9B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;AAC7B,EAAA;;AAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAM+B,CAACC,UAAyB,EAAQ;AACtC,IAAA,IAAIA,UAAU,CAAC3E,MAAM,GAAG,CAAC,EAAE;AACzB;AACN;AACA;AACA;AACM,MAAA,MAAM4E,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC5D,MAAM,CAAChB,MAAM;AAEnD,MAAA,KAAK,MAAMR,KAAK,IAAImF,UAAU,EAAE;QAC9B,MAAMtE,IAAI,GAAG,IAAI,CAAC,MAAM,CAACwB,GAAG,CAACrC,KAAK,CAAC;QAEnC,IAAIa,IAAI,KAAKlB,SAAS,EAAE;AAExB,QAAA,MAAM0F,UAAU,GAAGrF,KAAK,CAACsF,KAAK,CAACC,QAAQ;AACvC,QAAA,MAAMC,cAAc,GAAG,CAACH,UAAU,KAAK,EAAE,GAAG,CAAC,GAAGzF,UAAU,CAACyF,UAAU,CAAC,IAAID,IAAI;AAE9E,QAAA,IAAIzE,UAAU,CAAC6E,cAAc,EAAE3E,IAAI,CAAC,EAAE;AAEtC,QAAA,IAAI,CAAC,KAAK,KAAKuE,IAAI;QACnBpF,KAAK,CAACsF,KAAK,CAACG,IAAI,GAAG,CAAA,EAAG5E,IAAI,GAAGuE,IAAI,CAAA,MAAA,CAAQ;AAC3C,MAAA;AACF,IAAA;AAEA,IAAA,IAAI,CAAC,YAAY,EAAE;AACrB,EAAA;;AAEA;AACF;AACA;AACA;AACA;EACE,YAAYM,GAAS;AACnB,IAAA,KAAK,MAAMC,MAAM,IAAI,IAAI,CAAClE,OAAO,EAAE;MACjC,MAAM,CAACmE,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAACD,MAAM,CAAC;AAExC3E,MAAAA,YAAY,CAAC2E,MAAM,EAAE,kBAAkB,EAAE,IAAI,CAAC,aAAa,GAAG,UAAU,GAAG,YAAY,CAAC;MAExF,IAAI,CAACC,IAAI,EAAE;;AAEX;AACA,MAAA,IAAIA,IAAI,CAACC,EAAE,EAAE7E,YAAY,CAAC2E,MAAM,EAAE,eAAe,EAAEC,IAAI,CAACC,EAAE,CAAC;MAE3D7E,YAAY,CAAC2E,MAAM,EAAE,eAAe,EAAE,CAAA,EAAG5F,SAAS,CAAC6F,IAAI,CAAC,CAAA,CAAE,CAAC;MAC3D5E,YAAY,CAAC2E,MAAM,EAAE,eAAe,EAAE,CAAA,EAAG1F,SAAS,CAAC2F,IAAI,CAAC,CAAA,CAAE,CAAC;MAC3D5E,YAAY,CAAC2E,MAAM,EAAE,eAAe,EAAE,CAAA,EAAGtG,IAAI,CAACyG,KAAK,CAAC,IAAI,CAAC,MAAM,CAACzD,GAAG,CAACuD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA,CAAE,CAAC;AACpF,IAAA;AACF,EAAA;EAEA,OAAOG,GAAS;IACd,IAAI,CAAC,QAAQ,CAACC,cAAc,EAAE,GAAG,IAAI,CAAC7D,KAAK,CAAC;AAC9C,EAAA;;AAEA;AACF;AACA;AACA;EACE,YAAY8D,CAACjG,KAAkB,EAAW;IACxC,OAAOG,aAAa,CAACH,KAAK,CAAC,IAAIA,KAAK,CAACI,YAAY,CAAC,gBAAgB,CAAC;AACrE,EAAA;AAEA,EAAA,aAAa8F,CAAClG,KAAkB,EAAEmG,SAAkB,EAAQ;IAC1D,IAAIA,SAAS,KAAKnG,KAAK,CAACI,YAAY,CAAC,gBAAgB,CAAC,EAAE;AAExD,IAAA,IAAI+F,SAAS,EAAE;AACbnG,MAAAA,KAAK,CAACgB,YAAY,CAAC,gBAAgB,EAAE,EAAE,CAAC;AAC1C,IAAA,CAAC,MAAM;AACLhB,MAAAA,KAAK,CAACoG,eAAe,CAAC,gBAAgB,CAAC;AACzC,IAAA;AACF,EAAA;;AAEA;AACF;AACA;AACA;EACE,iBAAiBC,GAAS;AACxB,IAAA,MAAM7E,MAAM,GAAG,IAAI,CAACA,MAAM;AAC1B;IACA,MAAM8E,EAAE,GAAG9E,MAAM,CAACY,GAAG,CAAEpC,KAAK,IAAM,IAAI,CAAC,YAAY,CAACA,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAACA,KAAK,CAAE,CAAC;AAC3F,IAAA,MAAM+E,KAAK,GAAGuB,EAAE,CAACC,MAAM,CAAC,CAACC,GAAG,EAAEtH,KAAK,KAAKsH,GAAG,GAAGtH,KAAK,EAAE,CAAC,CAAC;IAEvD,IAAI6F,KAAK,IAAI,CAAC,EAAE;AAEhBvD,IAAAA,MAAM,CAACiF,OAAO,CAAC,CAACzG,KAAK,EAAEU,KAAK,KAAK;AAC/B,MAAA,MAAMG,IAAI,GAAI,CAACyF,EAAE,CAAC5F,KAAK,CAAC,IAAI,CAAC,IAAIqE,KAAK,GAAI,GAAG;MAC7C,MAAMnE,QAAQ,GAAG,IAAI,CAAC,MAAM,CAACyB,GAAG,CAACrC,KAAK,CAAC;AAEvC,MAAA,IAAIY,QAAQ,KAAKjB,SAAS,IAAIN,IAAI,CAACyB,GAAG,CAACF,QAAQ,GAAGC,IAAI,CAAC,GAAGE,qBAAqB,EAAE;QAC/E,IAAI,CAAC,MAAM,CAACuC,GAAG,CAACtD,KAAK,EAAEa,IAAI,CAAC;AAC9B,MAAA;AACF,IAAA,CAAC,CAAC;AACJ,EAAA;EAEA,YAAY6F,CAAC1G,KAAkB,EAAU;AACvC,IAAA,MAAM2G,GAAG,GAAG3G,KAAK,CAAC4G,qBAAqB,EAAE;IAEzC,OAAO,IAAI,CAAC,aAAa,GAAGD,GAAG,CAACE,KAAK,GAAGF,GAAG,CAACG,MAAM;AACpD,EAAA;;AAEA;AACF;AACA;AACA;EACE,YAAYC,CAACC,aAA0B,EAA4C;IACjF,IAAIpB,IAAwB,GAAG,IAAI;IACnC,IAAIqB,IAAwB,GAAG,IAAI;AAEnC,IAAA,KAAK,MAAMjH,KAAK,IAAI,IAAI,CAACwB,MAAM,EAAE;AAC/B,MAAA,MAAM0F,QAAQ,GAAGF,aAAa,CAACG,uBAAuB,CAACnH,KAAK,CAAC;AAE7D,MAAA,IAAIkH,QAAQ,GAAGE,IAAI,CAACC,2BAA2B,EAAE;AAC/CzB,QAAAA,IAAI,GAAG5F,KAAK;AACd,MAAA,CAAC,MAAM,IAAIkH,QAAQ,GAAGE,IAAI,CAACE,2BAA2B,EAAE;AACtDL,QAAAA,IAAI,GAAGjH,KAAK;AAEZ,QAAA;AACF,MAAA;AACF,IAAA;AAEA,IAAA,OAAO,CAAC4F,IAAI,EAAEqB,IAAI,CAAC;AACrB,EAAA;;AAEA;AACF;AACA;AACA;EACE,WAAWM,CACT3B,IAAiB,EACjBqB,IAAiB,EACjBO,YAAoB,EACpBC,YAAoB,EACpBC,cAAsB,EAChB;AACN,IAAA,MAAM3C,KAAK,GAAGyC,YAAY,GAAGC,YAAY;AAEzC,IAAA,IAAI1E,MAAM,GAAGyE,YAAY,GAAGE,cAAc;IAE1C,IAAIvH,aAAa,CAACyF,IAAI,CAAC,IAAI7C,MAAM,GAAGhD,SAAS,CAAC6F,IAAI,CAAC,EAAE;AACnD;AACN;AACA;AACA;AACA;AACA;AACM7C,MAAAA,MAAM,GAAGA,MAAM,GAAGhD,SAAS,CAAC6F,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG7F,SAAS,CAAC6F,IAAI,CAAC;AAC7D,IAAA,CAAC,MAAM;AACL7C,MAAAA,MAAM,GAAG9D,KAAK,CAAC8D,MAAM,EAAEhD,SAAS,CAAC6F,IAAI,CAAC,EAAE3F,SAAS,CAAC2F,IAAI,CAAC,CAAC;AAC1D,IAAA;;AAEA;AACJ;AACA;AACA;AACI,IAAA,MAAM+B,OAAO,GAAG5C,KAAK,GAAG9E,SAAS,CAACgH,IAAI,CAAC;AACvC,IAAA,MAAMW,OAAO,GAAG7C,KAAK,GAAGhF,SAAS,CAACkH,IAAI,CAAC;IAEvC,IAAIU,OAAO,GAAGC,OAAO,EAAE;IAEvB7E,MAAM,GAAG9D,KAAK,CAAC8D,MAAM,EAAE4E,OAAO,EAAEC,OAAO,CAAC;;AAExC;IACA,IAAI,CAACzH,aAAa,CAACyF,IAAI,CAAC,KAAK7C,MAAM,GAAGhD,SAAS,CAAC6F,IAAI,CAAC,IAAI7C,MAAM,GAAG9C,SAAS,CAAC2F,IAAI,CAAC,CAAC,EAAE;;AAEpF;AACJ;AACA;AACA;AACI,IAAA,IACEjF,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC0B,GAAG,CAACuD,IAAI,CAAC,EAAE7C,MAAM,CAAC,IACzCpC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC0B,GAAG,CAAC4E,IAAI,CAAC,EAAElC,KAAK,GAAGhC,MAAM,CAAC,EACjD;AACA,MAAA;AACF,IAAA;AAEA,IAAA,IAAI5C,aAAa,CAACyF,IAAI,CAAC,EAAE;AACvB,MAAA,IAAI7C,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC6C,IAAI,CAAC,EAAE;QAC5C,IAAI,CAAC,cAAc,CAACtC,GAAG,CAACsC,IAAI,EAAE4B,YAAY,CAAC;AAC7C,MAAA;MAEA,IAAI,CAAC,aAAa,CAAC5B,IAAI,EAAE7C,MAAM,KAAK,CAAC,CAAC;AACxC,IAAA;IAEA,IAAI,CAAC,MAAM,CAACO,GAAG,CAACsC,IAAI,EAAE7C,MAAM,CAAC;IAC7B,IAAI,CAAC,MAAM,CAACO,GAAG,CAAC2D,IAAI,EAAElC,KAAK,GAAGhC,MAAM,CAAC;IAErC,IAAI,CAAC,MAAM,CAAC,CAAC6C,IAAI,EAAEqB,IAAI,CAAC,CAAC;AACzB,IAAA,IAAI,CAAC,OAAO,EAAE;AAChB,EAAA;AAEAY,EAAAA,SAASA,CAACb,aAA0B,EAAEc,KAAmB,EAAQ;AAC/D,IAAA,IAAIA,KAAK,CAACC,MAAM,KAAK,CAAC,EAAE;AACxB,IAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AAEhB,IAAA,MAAM,CAACnC,IAAI,EAAEqB,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAACD,aAAa,CAAC;AAErD,IAAA,IAAI,CAACpB,IAAI,IAAI,CAACqB,IAAI,EAAE;AAEpB,IAAA,IAAI,CAAC,iBAAiB,EAAE;IAExB,MAAMe,IAAI,GAAIC,SAAuB,IAAK,IAAI,CAAC,SAAS,CAACA,SAAS,CAAC;AACnE,IAAA,MAAMC,GAAG,GAAIC,QAAsB,IAAK,IAAI,CAAC,QAAQ,CAACnB,aAAa,EAAEmB,QAAQ,CAAC;IAE9E,IAAI,CAAC,KAAK,GAAG;MACXvC,IAAI;MACJqB,IAAI;MACJmB,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC/F,GAAG,CAACuD,IAAI,CAAC,IAAI,CAAC;MACzCyC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAChG,GAAG,CAAC4E,IAAI,CAAC,IAAI,CAAC;AACzCqB,MAAAA,eAAe,EAAE,IAAI,CAAC,aAAa,GAAGR,KAAK,CAACS,OAAO,GAAGT,KAAK,CAACU,OAAO;MACnEC,OAAO,EAAE,IAAI,CAACjH,MAAM,CAAC+E,MAAM,CAAC,CAACC,GAAG,EAAExG,KAAK,KAAKwG,GAAG,GAAG,IAAI,CAAC,YAAY,CAACxG,KAAK,CAAC,EAAE,CAAC,CAAC;MAC9EgI,IAAI;AACJE,MAAAA;KACD;IAED,IAAI;AACF;AACN;AACA;AACA;AACMlB,MAAAA,aAAa,CAAC0B,iBAAiB,CAACZ,KAAK,CAACa,SAAS,CAAC;AAClD,IAAA,CAAC,CAAC,MAAM;AACN;AAAA,IAAA;IAGF3B,aAAa,CAAC4B,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,KAAK,CAACZ,IAAI,CAAC;IAC9DhB,aAAa,CAAC4B,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAACV,GAAG,CAAC;IAC3DlB,aAAa,CAAC4B,gBAAgB,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,CAACV,GAAG,CAAC;AAC/DlB,IAAAA,aAAa,CAAChG,YAAY,CAAC,eAAe,EAAE,EAAE,CAAC;AAE/C6H,IAAAA,QAAQ,CAACC,IAAI,CAACxD,KAAK,CAACyD,MAAM,GAAG,IAAI,CAAC,aAAa,GAAG,YAAY,GAAG,YAAY;AAC7EF,IAAAA,QAAQ,CAACC,IAAI,CAACxD,KAAK,CAAC0D,UAAU,GAAG,MAAM;AACzC,EAAA;EAEA,SAASC,CAACnB,KAAmB,EAAQ;AACnC,IAAA,MAAMoB,IAAI,GAAG,IAAI,CAAC,KAAK;IAEvB,IAAI,CAACA,IAAI,EAAE;AACX,IAAA,IAAIA,IAAI,CAACT,OAAO,IAAI,CAAC,EAAE;AAEvB,IAAA,MAAMU,UAAU,GAAG,IAAI,CAAC,aAAa,GAAGrB,KAAK,CAACS,OAAO,GAAGT,KAAK,CAACU,OAAO;AACrE,IAAA,MAAMY,YAAY,GAAI,CAACD,UAAU,GAAGD,IAAI,CAACZ,eAAe,IAAIY,IAAI,CAACT,OAAO,GAAI,GAAG;IAE/E,IAAI,CAAC,WAAW,CAACS,IAAI,CAACtD,IAAI,EAAEsD,IAAI,CAACjC,IAAI,EAAEiC,IAAI,CAACd,aAAa,EAAEc,IAAI,CAACb,aAAa,EAAEe,YAAY,CAAC;AAC9F,EAAA;AAEA,EAAA,QAAQC,CAACrC,aAA0B,EAAEc,KAAmB,EAAQ;AAC9D,IAAA,MAAMoB,IAAI,GAAG,IAAI,CAAC,KAAK;IAEvB,IAAI,CAACA,IAAI,EAAE;AAEX,IAAA,IAAI,CAAC,KAAK,GAAG,IAAI;IAEjB,IAAI;AACFlC,MAAAA,aAAa,CAACsC,qBAAqB,CAACxB,KAAK,CAACa,SAAS,CAAC;AACtD,IAAA,CAAC,CAAC,MAAM;AACN;AAAA,IAAA;IAGF3B,aAAa,CAACuC,mBAAmB,CAAC,aAAa,EAAEL,IAAI,CAAClB,IAAI,CAAC;IAC3DhB,aAAa,CAACuC,mBAAmB,CAAC,WAAW,EAAEL,IAAI,CAAChB,GAAG,CAAC;IACxDlB,aAAa,CAACuC,mBAAmB,CAAC,eAAe,EAAEL,IAAI,CAAChB,GAAG,CAAC;AAC5DlB,IAAAA,aAAa,CAACZ,eAAe,CAAC,eAAe,CAAC;AAE9CyC,IAAAA,QAAQ,CAACC,IAAI,CAACxD,KAAK,CAACyD,MAAM,GAAG,EAAE;AAC/BF,IAAAA,QAAQ,CAACC,IAAI,CAACxD,KAAK,CAAC0D,UAAU,GAAG,EAAE;AACrC,EAAA;;AAEA;AACF;AACA;AACEQ,EAAAA,aAAaA,CAACxC,aAA0B,EAAEc,KAAoB,EAAQ;AACpE,IAAA,MAAM,CAAClC,IAAI,EAAEqB,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAACD,aAAa,CAAC;AAErD,IAAA,IAAI,CAACpB,IAAI,IAAI,CAACqB,IAAI,EAAE;AAEpB,IAAA,IAAIa,KAAK,CAAC2B,GAAG,KAAK,OAAO,EAAE;AACzB,MAAA,IAAI,CAAC,eAAe,CAAC7D,IAAI,EAAEqB,IAAI,CAAC;AAEhC,MAAA;AACF,IAAA;IAEA,MAAMyC,IAAI,GAAG5B,KAAK,CAAC6B,QAAQ,GAAG3K,oBAAoB,GAAGD,aAAa;AAClE,IAAA,MAAM6K,YAAY,GAAG,IAAI,CAAC,aAAa;IAEvC,IAAIC,KAAoB,GAAG,IAAI;IAE/B,QAAQ/B,KAAK,CAAC2B,GAAG;AACf,MAAA,KAAK,WAAW;AACd,QAAA,IAAIG,YAAY,EAAEC,KAAK,GAAG,CAACH,IAAI;AAE/B,QAAA;AACF,MAAA,KAAK,YAAY;AACf,QAAA,IAAIE,YAAY,EAAEC,KAAK,GAAGH,IAAI;AAE9B,QAAA;AACF,MAAA,KAAK,SAAS;AACZ,QAAA,IAAI,CAACE,YAAY,EAAEC,KAAK,GAAG,CAACH,IAAI;AAEhC,QAAA;AACF,MAAA,KAAK,WAAW;AACd,QAAA,IAAI,CAACE,YAAY,EAAEC,KAAK,GAAGH,IAAI;AAE/B,QAAA;AACF,MAAA,KAAK,MAAM;AACT,QAAA,IAAI,CAAC,iBAAiB,EAAE;AACxBG,QAAAA,KAAK,GAAG9J,SAAS,CAAC6F,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAACvD,GAAG,CAACuD,IAAI,CAAC,IAAI,CAAC,CAAC;AAEtD,QAAA;AACF,MAAA,KAAK,KAAK;AACR,QAAA,IAAI,CAAC,iBAAiB,EAAE;AACxBiE,QAAAA,KAAK,GAAG5J,SAAS,CAAC2F,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAACvD,GAAG,CAACuD,IAAI,CAAC,IAAI,CAAC,CAAC;AAEtD,QAAA;AACJ;IAEA,IAAIiE,KAAK,KAAK,IAAI,EAAE;IAEpB/B,KAAK,CAACgC,cAAc,EAAE;AAEtB,IAAA,IAAI,CAAC,iBAAiB,EAAE;AACxB,IAAA,IAAI,CAAC,WAAW,CAAClE,IAAI,EAAEqB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC5E,GAAG,CAACuD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAACvD,GAAG,CAAC4E,IAAI,CAAC,IAAI,CAAC,EAAE4C,KAAK,CAAC;AAC7F,EAAA;;AAEA;AACF;AACA;AACA;AACA;AACA;AACE,EAAA,eAAeE,CAACnE,IAAiB,EAAEqB,IAAiB,EAAQ;AAC1D,IAAA,IAAI,CAAC9G,aAAa,CAACyF,IAAI,CAAC,EAAE;AAE1B,IAAA,IAAI,CAAC,iBAAiB,EAAE;AAExB,IAAA,MAAMoE,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC3H,GAAG,CAACuD,IAAI,CAAC,IAAI,CAAC;AAC3C,IAAA,MAAMqE,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC5H,GAAG,CAAC4E,IAAI,CAAC,IAAI,CAAC;AAE3C,IAAA,IAAI,IAAI,CAAC,YAAY,CAACrB,IAAI,CAAC,EAAE;MAC3B,MAAMjB,SAAS,GACb,IAAI,CAAC,cAAc,CAACtC,GAAG,CAACuD,IAAI,CAAC,IAAI1F,eAAe,CAAC0F,IAAI,CAAC,IAAIvG,IAAI,CAACD,GAAG,CAACW,SAAS,CAAC6F,IAAI,CAAC,EAAE,EAAE,CAAC;AACzF,MAAA,MAAMsE,SAAS,GAAGD,QAAQ,GAAGlK,SAAS,CAACkH,IAAI,CAAC;MAC5C,MAAMkD,QAAQ,GAAG9K,IAAI,CAACF,GAAG,CAACwF,SAAS,EAAEuF,SAAS,CAAC;MAE/C,IAAIC,QAAQ,IAAI,CAAC,EAAE;AAEnB,MAAA,IAAI,CAAC,aAAa,CAACvE,IAAI,EAAE,KAAK,CAAC;MAC/B,IAAI,CAAC,MAAM,CAACtC,GAAG,CAACsC,IAAI,EAAEuE,QAAQ,CAAC;MAC/B,IAAI,CAAC,MAAM,CAAC7G,GAAG,CAAC2D,IAAI,EAAEgD,QAAQ,GAAGE,QAAQ,CAAC;AAC5C,IAAA,CAAC,MAAM;MACL,IAAI,CAAC,cAAc,CAAC7G,GAAG,CAACsC,IAAI,EAAEoE,QAAQ,CAAC;AACvC,MAAA,IAAI,CAAC,aAAa,CAACpE,IAAI,EAAE,IAAI,CAAC;MAC9B,IAAI,CAAC,MAAM,CAACtC,GAAG,CAACsC,IAAI,EAAE,CAAC,CAAC;MACxB,IAAI,CAAC,MAAM,CAACtC,GAAG,CAAC2D,IAAI,EAAEgD,QAAQ,GAAGD,QAAQ,CAAC;AAC5C,IAAA;IAEA,IAAI,CAAC,MAAM,CAAC,CAACpE,IAAI,EAAEqB,IAAI,CAAC,CAAC;AACzB,IAAA,IAAI,CAAC,OAAO,EAAE;AAChB,EAAA;AACF;;;;"}
1
+ {"version":3,"file":"state.js","sources":["../../../src/components/resizable/state.ts"],"sourcesContent":["export type Orientation = 'horizontal' | 'vertical';\n\nconst GROUP_SELECTOR = '.ember-primitives__resizable';\nconst PANEL_CLASS = 'ember-primitives__resizable__panel';\nconst HANDLE_CLASS = 'ember-primitives__resizable__handle';\nconst MEMBER_SELECTOR = `.${PANEL_CLASS}, .${HANDLE_CLASS}`;\n\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\n/**\n * How far (in %) one keyboard arrow press moves a handle.\n * Holding Shift moves in coarser increments.\n */\nconst KEYBOARD_STEP = 1;\nconst KEYBOARD_STEP_COARSE = 10;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction numberAttribute(element: Element, name: string): number | undefined {\n const raw = element.getAttribute(name);\n\n if (raw === null) return undefined;\n\n const value = parseFloat(raw);\n\n return Number.isFinite(value) ? value : undefined;\n}\n\n/**\n * Panels declare their constraints in the DOM (via data attributes),\n * so the group can discover everything it needs with queries --\n * no registration required.\n */\nfunction minSizeOf(panel: Element): number {\n return numberAttribute(panel, 'data-min-size') ?? DEFAULT_MIN;\n}\n\nfunction maxSizeOf(panel: Element): number {\n return numberAttribute(panel, 'data-max-size') ?? DEFAULT_MAX;\n}\n\nfunction requestedSizeOf(panel: Element): number | undefined {\n return numberAttribute(panel, 'data-size');\n}\n\nfunction isCollapsible(panel: Element): boolean {\n return panel.hasAttribute('data-collapsible');\n}\n\nfunction sameMembers(a: HTMLElement[], b: HTMLElement[]): boolean {\n return a.length === b.length && a.every((element, index) => element === b[index]);\n}\n\nfunction precedes(a: Element, b: Element): boolean {\n return Boolean(b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING);\n}\n\n/**\n * The `data-collapsed` attribute is the source of truth for collapse\n * state (it is also the styling hook consumers use).\n */\nfunction isCollapsed(panel: HTMLElement): boolean {\n return isCollapsible(panel) && panel.hasAttribute('data-collapsed');\n}\n\nfunction setCollapsed(panel: HTMLElement, collapsed: boolean): void {\n if (collapsed === panel.hasAttribute('data-collapsed')) return;\n\n if (collapsed) {\n panel.setAttribute('data-collapsed', '');\n } else {\n panel.removeAttribute('data-collapsed');\n }\n}\n\n/**\n * The panels immediately before and after the given handle element,\n * in document order.\n */\nfunction neighborsOf(\n handleElement: HTMLElement,\n panels: HTMLElement[]\n): [HTMLElement | null, HTMLElement | null] {\n let prev: HTMLElement | null = null;\n let next: HTMLElement | null = null;\n\n for (const panel of panels) {\n const position = handleElement.compareDocumentPosition(panel);\n\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n prev = panel;\n } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n next = panel;\n\n break;\n }\n }\n\n return [prev, next];\n}\n\n/**\n * Sizes are floats that get re-derived (measurement, normalization),\n * so \"unchanged\" means within a small tolerance.\n */\nfunction isSameSize(existing: number | undefined, size: number): boolean {\n return existing !== undefined && Math.abs(existing - size) < 0.0001;\n}\n\n/**\n * Pixel measurements round to device pixels, so re-measuring a layout\n * yields values that differ from the stored ones by sub-pixel noise.\n * Only differences beyond this (in %) count as real drift worth\n * adopting -- re-encoding identical pixels as slightly different\n * percentages would dirty every panel for no visual change.\n */\nconst MEASUREMENT_TOLERANCE = 0.25;\n\n/**\n * Skips the write when the attribute already has the desired value,\n * so unchanged elements are left untouched.\n */\nfunction setAttribute(element: Element, name: string, value: string): void {\n if (element.getAttribute(name) !== value) {\n element.setAttribute(name, value);\n }\n}\n\ninterface Members {\n panels: HTMLElement[];\n handles: HTMLElement[];\n}\n\ninterface DragState {\n prev: HTMLElement;\n next: HTMLElement;\n startPrevSize: number;\n startNextSize: number;\n startCoordinate: number;\n /**\n * Total px occupied by the panels (excluding handles) at drag start,\n * used to convert px deltas to % deltas.\n */\n totalPx: number;\n members: Members;\n move: (event: PointerEvent) => void;\n end: (event: PointerEvent) => void;\n}\n\ninterface GroupOptions {\n orientation: () => Orientation | undefined;\n onLayoutChange: () => ((sizes: number[]) => void) | undefined;\n}\n\nexport class GroupState {\n element: HTMLElement | null = null;\n\n #options: GroupOptions;\n #drag: DragState | null = null;\n\n /**\n * Current size (%) per panel element.\n * The DOM is the source of truth for membership; this only remembers\n * sizes across relayouts.\n */\n #sizes = new Map<HTMLElement, number>();\n\n /**\n * The size (%) a collapsible panel had before it was collapsed,\n * so that expanding restores it.\n */\n #previousSizes = new WeakMap<HTMLElement, number>();\n\n /**\n * Membership as of the last layout, so mutation batches that don't\n * change membership (e.g. content changes inside a panel, or churn\n * within a nested group) can be ignored.\n */\n #knownPanels: HTMLElement[] = [];\n #knownHandles: HTMLElement[] = [];\n\n /**\n * The percentage that a flex-grow of 1 represents in this group.\n *\n * Panels without an inline style render at the CSS default\n * (`flex: 1 1 0px`), so an all-equal group needs no styles at all --\n * mounting one writes nothing. The unit is fixed the first time a\n * panel actually diverges, and from then on grow values are written\n * relative to it, so panels whose share doesn't change keep their\n * (possibly absent) style untouched.\n */\n #unit: number | null = null;\n\n constructor(options: GroupOptions) {\n this.#options = options;\n }\n\n get orientation(): Orientation {\n return this.#options.orientation() ?? 'horizontal';\n }\n\n get #isHorizontal(): boolean {\n return this.orientation === 'horizontal';\n }\n\n /**\n * This group's panels, in document order.\n * Panels of nested groups belong to their own group, not this one.\n */\n get panels(): HTMLElement[] {\n return this.#members().panels;\n }\n\n get handles(): HTMLElement[] {\n return this.#members().handles;\n }\n\n #members(): Members {\n const panels: HTMLElement[] = [];\n const handles: HTMLElement[] = [];\n const element = this.element;\n\n if (!element) return { panels, handles };\n\n for (const member of element.querySelectorAll<HTMLElement>(MEMBER_SELECTOR)) {\n if (member.closest(GROUP_SELECTOR) !== element) continue;\n\n (member.classList.contains(PANEL_CLASS) ? panels : handles).push(member);\n }\n\n return { panels, handles };\n }\n\n get sizes(): number[] {\n return this.panels.map((panel) => this.#sizes.get(panel) ?? 0);\n }\n\n /**\n * One MutationObserver for every group on the page. Each record is\n * routed to the group that owns it (the nearest group ancestor), so\n * churn inside a nested group never even pings its ancestors.\n */\n static #observed = new Map<HTMLElement, GroupState>();\n static #observer: MutationObserver | null = null;\n\n static #observerOptions: MutationObserverInit = {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['data-orientation'],\n // to distinguish real changes from same-value writes (see below)\n attributeOldValue: true,\n };\n\n static #handleMutations(mutations: MutationRecord[]): void {\n /**\n * true = the group's own data-orientation changed,\n * false = something in its subtree changed (membership check needed)\n */\n const affected = new Map<GroupState, boolean>();\n\n for (const mutation of mutations) {\n const target = mutation.target;\n\n if (!(target instanceof Element)) continue;\n\n if (mutation.type === 'attributes') {\n const group = GroupState.#observed.get(target as HTMLElement);\n\n /**\n * setAttribute queues a record even when the value is\n * unchanged (renderers do rewrite attributes with the same\n * value); only actual changes warrant a relayout.\n */\n const changed =\n mutation.attributeName &&\n mutation.oldValue !== target.getAttribute(mutation.attributeName);\n\n if (group && changed) affected.set(group, true);\n continue;\n }\n\n const groupElement = target.closest<HTMLElement>(GROUP_SELECTOR);\n const group = groupElement && GroupState.#observed.get(groupElement);\n\n if (group && !affected.has(group)) affected.set(group, false);\n }\n\n for (const [group, orientationChanged] of affected) {\n const members = group.#members();\n\n if (orientationChanged || group.#membershipChanged(members)) group.#layout(members);\n }\n }\n\n static #observe(element: HTMLElement, group: GroupState): void {\n GroupState.#observed.set(element, group);\n GroupState.#observer ??= new MutationObserver((mutations) =>\n GroupState.#handleMutations(mutations)\n );\n GroupState.#observer.observe(element, GroupState.#observerOptions);\n }\n\n static #unobserve(element: HTMLElement): void {\n GroupState.#observed.delete(element);\n\n const observer = GroupState.#observer;\n\n if (!observer) return;\n\n /**\n * MutationObserver has no per-target unobserve; disconnect and\n * re-observe the remaining groups (rare -- teardown only).\n */\n observer.disconnect();\n\n if (GroupState.#observed.size === 0) {\n GroupState.#observer = null;\n\n return;\n }\n\n for (const remaining of GroupState.#observed.keys()) {\n observer.observe(remaining, GroupState.#observerOptions);\n }\n }\n\n /**\n * Called (via modifier) when the group element is inserted.\n * Watches for panels being added/removed (and the orientation\n * changing) and performs the initial layout.\n */\n attach = (element: HTMLElement): (() => void) => {\n this.element = element;\n\n GroupState.#observe(element, this);\n\n this.#layout();\n\n return () => {\n GroupState.#unobserve(element);\n this.element = null;\n };\n };\n\n #membershipChanged(members: Members): boolean {\n return (\n !sameMembers(members.panels, this.#knownPanels) ||\n !sameMembers(members.handles, this.#knownHandles)\n );\n }\n\n /**\n * Panels that already have a size (or request one via `data-size`)\n * keep it; new panels take a share of the remaining space; everything\n * is normalized to 100.\n */\n #layout(members: Members = this.#members()): void {\n const { panels, handles } = members;\n\n if (this.#drag) this.#drag.members = members;\n\n this.#knownPanels = panels;\n this.#knownHandles = handles;\n\n if (panels.length === 0) return;\n\n let changed = false;\n\n // forget sizes of panels that left the DOM\n const current = new Set(panels);\n\n for (const known of this.#sizes.keys()) {\n if (!current.has(known)) {\n this.#sizes.delete(known);\n changed = true;\n }\n }\n\n // scratch space for the math below; #sizes itself is only\n // touched at the end, and only where values actually changed\n const computed = new Map<HTMLElement, number>();\n const unspecified: HTMLElement[] = [];\n let specifiedTotal = 0;\n\n for (const panel of panels) {\n const preferred = this.#sizes.get(panel) ?? requestedSizeOf(panel);\n\n if (preferred === undefined) {\n unspecified.push(panel);\n continue;\n }\n\n const size = isCollapsed(panel)\n ? preferred\n : clamp(preferred, minSizeOf(panel), maxSizeOf(panel));\n\n computed.set(panel, size);\n specifiedTotal += size;\n }\n\n if (unspecified.length > 0) {\n /**\n * Panels without a size share the remaining space.\n * When there is none left (e.g. a panel was added to an\n * already-full group), each takes an equal 1/n share and the\n * existing panels scale down to make room -- like a new window\n * opening in a tiling window manager.\n */\n const remaining = 100 - specifiedTotal;\n let share = remaining / unspecified.length;\n\n if (remaining < 1) {\n share = 100 / panels.length;\n\n if (specifiedTotal > 0) {\n const scale = Math.max(100 - share * unspecified.length, 0) / specifiedTotal;\n\n for (const [panel, size] of computed) {\n computed.set(panel, size * scale);\n }\n }\n }\n\n for (const panel of unspecified) {\n computed.set(panel, clamp(share, minSizeOf(panel), maxSizeOf(panel)));\n }\n }\n\n // normalize to 100\n let total = 0;\n\n for (const size of computed.values()) total += size;\n\n if (total > 0 && Math.abs(total - 100) > 0.01) {\n for (const [panel, size] of computed) {\n computed.set(panel, (size / total) * 100);\n }\n }\n\n /**\n * Commit minimally: keep the #sizes map, update only entries whose\n * value actually changed (with a small tolerance, so float dust\n * from re-normalizing doesn't count as a change).\n */\n const changedPanels: HTMLElement[] = [];\n\n for (const [panel, size] of computed) {\n if (!isSameSize(this.#sizes.get(panel), size)) {\n this.#sizes.set(panel, size);\n changedPanels.push(panel);\n changed = true;\n }\n }\n\n this.#apply(changedPanels, members);\n\n if (changed) this.#notify(panels);\n }\n\n /**\n * Writes the layout back to the DOM: flex sizing for exactly the\n * candidate panels whose rendered share would actually change, plus\n * the handles' ARIA attributes (which are guarded per-attribute).\n * (`data-collapsed` is managed at the explicit collapse/expand\n * points, not derived from sizes -- rendered pixel sizes include\n * borders/padding, so a collapsed panel rarely measures exactly 0.)\n */\n #apply(candidates: HTMLElement[], members: Members): void {\n /**\n * With no unit fixed yet, nothing has ever been written, so every\n * panel renders at the CSS default -- an equal 1/n share.\n */\n const unit = this.#unit ?? 100 / members.panels.length;\n\n for (const panel of candidates) {\n const size = this.#sizes.get(panel);\n\n if (size === undefined) continue;\n\n const inlineGrow = panel.style.flexGrow;\n const impliedPercent = (inlineGrow === '' ? 1 : parseFloat(inlineGrow)) * unit;\n\n if (isSameSize(impliedPercent, size)) continue;\n\n this.#unit ??= unit;\n panel.style.flex = `${size / unit} 1 0px`;\n }\n\n this.#syncHandles(members);\n }\n\n /**\n * Per the window-splitter pattern, each handle describes the panel\n * immediately before it. (A splitter between two side-by-side panes\n * is oriented *vertically*, and vice-versa.)\n */\n #syncHandles(members: Members): void {\n const { panels, handles } = members;\n const ariaOrientation = this.#isHorizontal ? 'vertical' : 'horizontal';\n\n let index = 0;\n\n for (const handle of handles) {\n let following = panels[index];\n\n while (following && precedes(following, handle)) {\n index++;\n following = panels[index];\n }\n\n const prev = panels[index - 1];\n\n setAttribute(handle, 'aria-orientation', ariaOrientation);\n\n if (!prev) continue;\n\n // Panels render their own (component-owned, incrementing) id\n if (prev.id) setAttribute(handle, 'aria-controls', prev.id);\n\n setAttribute(handle, 'aria-valuemin', `${minSizeOf(prev)}`);\n setAttribute(handle, 'aria-valuemax', `${maxSizeOf(prev)}`);\n setAttribute(handle, 'aria-valuenow', `${Math.round(this.#sizes.get(prev) ?? 0)}`);\n }\n }\n\n #notify(panels: HTMLElement[]): void {\n this.#options.onLayoutChange()?.(panels.map((panel) => this.#sizes.get(panel) ?? 0));\n }\n\n /**\n * Re-derive percentage sizes from actual rendered pixels.\n * Corrects any drift (e.g. from CSS min-sizes) before an interaction.\n */\n #syncSizesFromDOM(panels: HTMLElement[], measured?: number[]): void {\n // collapsed panels are 0 even though their borders/padding measure larger\n const px = panels.map((panel, index) =>\n isCollapsed(panel) ? 0 : (measured?.[index] ?? this.#pixelSizeOf(panel))\n );\n const total = px.reduce((sum, value) => sum + value, 0);\n\n if (total <= 0) return;\n\n panels.forEach((panel, index) => {\n const size = ((px[index] ?? 0) / total) * 100;\n const existing = this.#sizes.get(panel);\n\n if (existing === undefined || Math.abs(existing - size) > MEASUREMENT_TOLERANCE) {\n this.#sizes.set(panel, size);\n }\n });\n }\n\n #pixelSizeOf(panel: HTMLElement): number {\n const box = panel.getBoundingClientRect();\n\n return this.#isHorizontal ? box.width : box.height;\n }\n\n /**\n * Moves the boundary between the two panels by `requestedDelta` (%),\n * respecting both panels' min/max constraints.\n */\n #applyDelta(\n prev: HTMLElement,\n next: HTMLElement,\n basePrevSize: number,\n baseNextSize: number,\n requestedDelta: number,\n members: Members\n ): void {\n const total = basePrevSize + baseNextSize;\n const prevMin = minSizeOf(prev);\n const prevMax = maxSizeOf(prev);\n const prevCollapsible = isCollapsible(prev);\n\n let target = basePrevSize + requestedDelta;\n\n if (prevCollapsible && target < prevMin) {\n /**\n * Collapsible panels snap: below half the minimum they close\n * entirely; between half and the minimum they hold at the minimum.\n * (This also keeps a collapsed panel closed when its handle is\n * dragged further in the closing direction.)\n */\n target = target < prevMin / 2 ? 0 : prevMin;\n } else {\n target = clamp(target, prevMin, prevMax);\n }\n\n /**\n * The neighbor absorbs whatever the target panel gives or takes,\n * so its constraints bound the target too.\n */\n const nextMin = total - maxSizeOf(next);\n const nextMax = total - minSizeOf(next);\n\n if (nextMin > nextMax) return;\n\n target = clamp(target, nextMin, nextMax);\n\n // both panels' constraints cannot be satisfied at once\n if (!prevCollapsible && (target < prevMin || target > prevMax)) return;\n\n /**\n * Nothing to do when the clamped result matches the current sizes\n * (e.g. every pointermove past a min/max limit).\n */\n if (\n isSameSize(this.#sizes.get(prev), target) &&\n isSameSize(this.#sizes.get(next), total - target)\n ) {\n return;\n }\n\n if (prevCollapsible) {\n if (target === 0 && !isCollapsed(prev)) {\n this.#previousSizes.set(prev, basePrevSize);\n }\n\n setCollapsed(prev, target === 0);\n }\n\n this.#sizes.set(prev, target);\n this.#sizes.set(next, total - target);\n\n this.#apply([prev, next], members);\n this.#notify(members.panels);\n }\n\n startDrag(handleElement: HTMLElement, event: PointerEvent): void {\n if (event.button !== 0) return;\n if (this.#drag) return;\n\n const members = this.#members();\n const [prev, next] = neighborsOf(handleElement, members.panels);\n\n if (!prev || !next) return;\n\n const measured = members.panels.map((panel) => this.#pixelSizeOf(panel));\n\n this.#syncSizesFromDOM(members.panels, measured);\n\n const move = (moveEvent: PointerEvent) => this.#dragMove(moveEvent);\n const end = (endEvent: PointerEvent) => this.#endDrag(handleElement, endEvent);\n\n this.#drag = {\n prev,\n next,\n startPrevSize: this.#sizes.get(prev) ?? 0,\n startNextSize: this.#sizes.get(next) ?? 0,\n startCoordinate: this.#isHorizontal ? event.clientX : event.clientY,\n totalPx: measured.reduce((sum, value) => sum + value, 0),\n members,\n move,\n end,\n };\n\n try {\n /**\n * Retargets all subsequent pointer events to the handle,\n * even when the pointer is over an iframe.\n */\n handleElement.setPointerCapture(event.pointerId);\n } catch {\n // synthetic events (tests) may not have an active pointer\n }\n\n handleElement.addEventListener('pointermove', move);\n handleElement.addEventListener('pointerup', end);\n handleElement.addEventListener('pointercancel', end);\n handleElement.setAttribute('data-resizing', '');\n\n document.body.style.cursor = this.#isHorizontal ? 'col-resize' : 'row-resize';\n document.body.style.userSelect = 'none';\n }\n\n #dragMove(event: PointerEvent): void {\n const drag = this.#drag;\n\n if (!drag) return;\n if (drag.totalPx <= 0) return;\n\n const coordinate = this.#isHorizontal ? event.clientX : event.clientY;\n const deltaPercent = ((coordinate - drag.startCoordinate) / drag.totalPx) * 100;\n\n this.#applyDelta(\n drag.prev,\n drag.next,\n drag.startPrevSize,\n drag.startNextSize,\n deltaPercent,\n drag.members\n );\n }\n\n #endDrag(handleElement: HTMLElement, event: PointerEvent): void {\n const drag = this.#drag;\n\n if (!drag) return;\n\n this.#drag = null;\n\n try {\n handleElement.releasePointerCapture(event.pointerId);\n } catch {\n // may not have been captured (tests)\n }\n\n handleElement.removeEventListener('pointermove', drag.move);\n handleElement.removeEventListener('pointerup', drag.end);\n handleElement.removeEventListener('pointercancel', drag.end);\n handleElement.removeAttribute('data-resizing');\n\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n\n /**\n * Keyboard support for the WAI-ARIA window-splitter pattern.\n */\n handleKeyDown(handleElement: HTMLElement, event: KeyboardEvent): void {\n const members = this.#members();\n const [prev, next] = neighborsOf(handleElement, members.panels);\n\n if (!prev || !next) return;\n\n if (event.key === 'Enter') {\n this.#toggleCollapse(prev, next, members);\n\n return;\n }\n\n const step = event.shiftKey ? KEYBOARD_STEP_COARSE : KEYBOARD_STEP;\n const isHorizontal = this.#isHorizontal;\n\n let toDelta: ((prevSize: number) => number) | null = null;\n\n switch (event.key) {\n case 'ArrowLeft':\n if (isHorizontal) toDelta = () => -step;\n\n break;\n case 'ArrowRight':\n if (isHorizontal) toDelta = () => step;\n\n break;\n case 'ArrowUp':\n if (!isHorizontal) toDelta = () => -step;\n\n break;\n case 'ArrowDown':\n if (!isHorizontal) toDelta = () => step;\n\n break;\n case 'Home':\n toDelta = (prevSize) => minSizeOf(prev) - prevSize;\n\n break;\n case 'End':\n toDelta = (prevSize) => maxSizeOf(prev) - prevSize;\n\n break;\n }\n\n if (!toDelta) return;\n\n event.preventDefault();\n\n this.#syncSizesFromDOM(members.panels);\n\n const prevSize = this.#sizes.get(prev) ?? 0;\n\n this.#applyDelta(prev, next, prevSize, this.#sizes.get(next) ?? 0, toDelta(prevSize), members);\n }\n\n /**\n * Collapses (or restores) the panel before the handle,\n * giving the space to (or taking it from) the panel after it.\n *\n * Only does anything when the preceding panel is `@collapsible`.\n */\n #toggleCollapse(prev: HTMLElement, next: HTMLElement, members: Members): void {\n if (!isCollapsible(prev)) return;\n\n this.#syncSizesFromDOM(members.panels);\n\n const prevSize = this.#sizes.get(prev) ?? 0;\n const nextSize = this.#sizes.get(next) ?? 0;\n\n if (isCollapsed(prev)) {\n const preferred =\n this.#previousSizes.get(prev) ?? requestedSizeOf(prev) ?? Math.max(minSizeOf(prev), 10);\n const available = nextSize - minSizeOf(next);\n const restored = Math.min(preferred, available);\n\n if (restored <= 0) return;\n\n setCollapsed(prev, false);\n this.#sizes.set(prev, restored);\n this.#sizes.set(next, nextSize - restored);\n } else {\n this.#previousSizes.set(prev, prevSize);\n setCollapsed(prev, true);\n this.#sizes.set(prev, 0);\n this.#sizes.set(next, nextSize + prevSize);\n }\n\n this.#apply([prev, next], members);\n this.#notify(members.panels);\n }\n}\n"],"names":["GROUP_SELECTOR","PANEL_CLASS","HANDLE_CLASS","MEMBER_SELECTOR","DEFAULT_MIN","DEFAULT_MAX","KEYBOARD_STEP","KEYBOARD_STEP_COARSE","clamp","value","min","max","Math","numberAttribute","element","name","raw","getAttribute","undefined","parseFloat","Number","isFinite","minSizeOf","panel","maxSizeOf","requestedSizeOf","isCollapsible","hasAttribute","sameMembers","a","b","length","every","index","precedes","Boolean","compareDocumentPosition","Node","DOCUMENT_POSITION_PRECEDING","isCollapsed","setCollapsed","collapsed","setAttribute","removeAttribute","neighborsOf","handleElement","panels","prev","next","position","DOCUMENT_POSITION_FOLLOWING","isSameSize","existing","size","abs","MEASUREMENT_TOLERANCE","GroupState","Map","WeakMap","constructor","options","orientation","#isHorizontal","handles","#members","member","querySelectorAll","closest","classList","contains","push","sizes","map","get","childList","subtree","attributes","attributeFilter","attributeOldValue","#handleMutations","mutations","affected","mutation","target","Element","type","group","changed","attributeName","oldValue","set","groupElement","has","orientationChanged","members","#observe","MutationObserver","observe","#unobserve","delete","observer","disconnect","remaining","keys","attach","#membershipChanged","#layout","current","Set","known","computed","unspecified","specifiedTotal","preferred","share","scale","total","values","changedPanels","#apply","candidates","unit","inlineGrow","style","flexGrow","impliedPercent","flex","#syncHandles","ariaOrientation","handle","following","id","round","#notify","onLayoutChange","#syncSizesFromDOM","measured","px","reduce","sum","forEach","#pixelSizeOf","box","getBoundingClientRect","width","height","#applyDelta","basePrevSize","baseNextSize","requestedDelta","prevMin","prevMax","prevCollapsible","nextMin","nextMax","startDrag","event","button","move","moveEvent","end","endEvent","startPrevSize","startNextSize","startCoordinate","clientX","clientY","totalPx","setPointerCapture","pointerId","addEventListener","document","body","cursor","userSelect","#dragMove","drag","coordinate","deltaPercent","#endDrag","releasePointerCapture","removeEventListener","handleKeyDown","key","step","shiftKey","isHorizontal","toDelta","prevSize","preventDefault","#toggleCollapse","nextSize","available","restored"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-primitives",
3
- "version": "0.61.0",
3
+ "version": "0.61.1",
4
4
  "description": "Making apps easier to build",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -1,8 +1,9 @@
1
1
  export type Orientation = 'horizontal' | 'vertical';
2
2
 
3
3
  const GROUP_SELECTOR = '.ember-primitives__resizable';
4
- const PANEL_SELECTOR = '.ember-primitives__resizable__panel';
5
- const HANDLE_SELECTOR = '.ember-primitives__resizable__handle';
4
+ const PANEL_CLASS = 'ember-primitives__resizable__panel';
5
+ const HANDLE_CLASS = 'ember-primitives__resizable__handle';
6
+ const MEMBER_SELECTOR = `.${PANEL_CLASS}, .${HANDLE_CLASS}`;
6
7
 
7
8
  const DEFAULT_MIN = 0;
8
9
  const DEFAULT_MAX = 100;
@@ -53,6 +54,54 @@ function sameMembers(a: HTMLElement[], b: HTMLElement[]): boolean {
53
54
  return a.length === b.length && a.every((element, index) => element === b[index]);
54
55
  }
55
56
 
57
+ function precedes(a: Element, b: Element): boolean {
58
+ return Boolean(b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING);
59
+ }
60
+
61
+ /**
62
+ * The `data-collapsed` attribute is the source of truth for collapse
63
+ * state (it is also the styling hook consumers use).
64
+ */
65
+ function isCollapsed(panel: HTMLElement): boolean {
66
+ return isCollapsible(panel) && panel.hasAttribute('data-collapsed');
67
+ }
68
+
69
+ function setCollapsed(panel: HTMLElement, collapsed: boolean): void {
70
+ if (collapsed === panel.hasAttribute('data-collapsed')) return;
71
+
72
+ if (collapsed) {
73
+ panel.setAttribute('data-collapsed', '');
74
+ } else {
75
+ panel.removeAttribute('data-collapsed');
76
+ }
77
+ }
78
+
79
+ /**
80
+ * The panels immediately before and after the given handle element,
81
+ * in document order.
82
+ */
83
+ function neighborsOf(
84
+ handleElement: HTMLElement,
85
+ panels: HTMLElement[]
86
+ ): [HTMLElement | null, HTMLElement | null] {
87
+ let prev: HTMLElement | null = null;
88
+ let next: HTMLElement | null = null;
89
+
90
+ for (const panel of panels) {
91
+ const position = handleElement.compareDocumentPosition(panel);
92
+
93
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
94
+ prev = panel;
95
+ } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
96
+ next = panel;
97
+
98
+ break;
99
+ }
100
+ }
101
+
102
+ return [prev, next];
103
+ }
104
+
56
105
  /**
57
106
  * Sizes are floats that get re-derived (measurement, normalization),
58
107
  * so "unchanged" means within a small tolerance.
@@ -80,6 +129,11 @@ function setAttribute(element: Element, name: string, value: string): void {
80
129
  }
81
130
  }
82
131
 
132
+ interface Members {
133
+ panels: HTMLElement[];
134
+ handles: HTMLElement[];
135
+ }
136
+
83
137
  interface DragState {
84
138
  prev: HTMLElement;
85
139
  next: HTMLElement;
@@ -91,6 +145,7 @@ interface DragState {
91
145
  * used to convert px deltas to % deltas.
92
146
  */
93
147
  totalPx: number;
148
+ members: Members;
94
149
  move: (event: PointerEvent) => void;
95
150
  end: (event: PointerEvent) => void;
96
151
  }
@@ -156,21 +211,27 @@ export class GroupState {
156
211
  * Panels of nested groups belong to their own group, not this one.
157
212
  */
158
213
  get panels(): HTMLElement[] {
159
- return this.#query(PANEL_SELECTOR);
214
+ return this.#members().panels;
160
215
  }
161
216
 
162
217
  get handles(): HTMLElement[] {
163
- return this.#query(HANDLE_SELECTOR);
218
+ return this.#members().handles;
164
219
  }
165
220
 
166
- #query(selector: string): HTMLElement[] {
221
+ #members(): Members {
222
+ const panels: HTMLElement[] = [];
223
+ const handles: HTMLElement[] = [];
167
224
  const element = this.element;
168
225
 
169
- if (!element) return [];
226
+ if (!element) return { panels, handles };
170
227
 
171
- const all = Array.from(element.querySelectorAll<HTMLElement>(selector));
228
+ for (const member of element.querySelectorAll<HTMLElement>(MEMBER_SELECTOR)) {
229
+ if (member.closest(GROUP_SELECTOR) !== element) continue;
172
230
 
173
- return all.filter((candidate) => candidate.closest(GROUP_SELECTOR) === element);
231
+ (member.classList.contains(PANEL_CLASS) ? panels : handles).push(member);
232
+ }
233
+
234
+ return { panels, handles };
174
235
  }
175
236
 
176
237
  get sizes(): number[] {
@@ -229,7 +290,9 @@ export class GroupState {
229
290
  }
230
291
 
231
292
  for (const [group, orientationChanged] of affected) {
232
- if (orientationChanged || group.#membershipChanged()) group.#layout();
293
+ const members = group.#members();
294
+
295
+ if (orientationChanged || group.#membershipChanged(members)) group.#layout(members);
233
296
  }
234
297
  }
235
298
 
@@ -283,9 +346,10 @@ export class GroupState {
283
346
  };
284
347
  };
285
348
 
286
- #membershipChanged(): boolean {
349
+ #membershipChanged(members: Members): boolean {
287
350
  return (
288
- !sameMembers(this.panels, this.#knownPanels) || !sameMembers(this.handles, this.#knownHandles)
351
+ !sameMembers(members.panels, this.#knownPanels) ||
352
+ !sameMembers(members.handles, this.#knownHandles)
289
353
  );
290
354
  }
291
355
 
@@ -294,20 +358,23 @@ export class GroupState {
294
358
  * keep it; new panels take a share of the remaining space; everything
295
359
  * is normalized to 100.
296
360
  */
297
- #layout(): void {
298
- const panels = this.panels;
299
- const handles = this.handles;
361
+ #layout(members: Members = this.#members()): void {
362
+ const { panels, handles } = members;
363
+
364
+ if (this.#drag) this.#drag.members = members;
300
365
 
301
- if (!sameMembers(panels, this.#knownPanels)) this.#knownPanels = panels;
302
- if (!sameMembers(handles, this.#knownHandles)) this.#knownHandles = handles;
366
+ this.#knownPanels = panels;
367
+ this.#knownHandles = handles;
303
368
 
304
369
  if (panels.length === 0) return;
305
370
 
306
371
  let changed = false;
307
372
 
308
373
  // forget sizes of panels that left the DOM
309
- for (const known of Array.from(this.#sizes.keys())) {
310
- if (!panels.includes(known)) {
374
+ const current = new Set(panels);
375
+
376
+ for (const known of this.#sizes.keys()) {
377
+ if (!current.has(known)) {
311
378
  this.#sizes.delete(known);
312
379
  changed = true;
313
380
  }
@@ -327,7 +394,7 @@ export class GroupState {
327
394
  continue;
328
395
  }
329
396
 
330
- const size = this.#isCollapsed(panel)
397
+ const size = isCollapsed(panel)
331
398
  ? preferred
332
399
  : clamp(preferred, minSizeOf(panel), maxSizeOf(panel));
333
400
 
@@ -389,9 +456,9 @@ export class GroupState {
389
456
  }
390
457
  }
391
458
 
392
- this.#apply(changedPanels);
459
+ this.#apply(changedPanels, members);
393
460
 
394
- if (changed) this.#notify();
461
+ if (changed) this.#notify(panels);
395
462
  }
396
463
 
397
464
  /**
@@ -402,30 +469,28 @@ export class GroupState {
402
469
  * points, not derived from sizes -- rendered pixel sizes include
403
470
  * borders/padding, so a collapsed panel rarely measures exactly 0.)
404
471
  */
405
- #apply(candidates: HTMLElement[]): void {
406
- if (candidates.length > 0) {
407
- /**
408
- * With no unit fixed yet, nothing has ever been written, so every
409
- * panel renders at the CSS default -- an equal 1/n share.
410
- */
411
- const unit = this.#unit ?? 100 / this.panels.length;
472
+ #apply(candidates: HTMLElement[], members: Members): void {
473
+ /**
474
+ * With no unit fixed yet, nothing has ever been written, so every
475
+ * panel renders at the CSS default -- an equal 1/n share.
476
+ */
477
+ const unit = this.#unit ?? 100 / members.panels.length;
412
478
 
413
- for (const panel of candidates) {
414
- const size = this.#sizes.get(panel);
479
+ for (const panel of candidates) {
480
+ const size = this.#sizes.get(panel);
415
481
 
416
- if (size === undefined) continue;
482
+ if (size === undefined) continue;
417
483
 
418
- const inlineGrow = panel.style.flexGrow;
419
- const impliedPercent = (inlineGrow === '' ? 1 : parseFloat(inlineGrow)) * unit;
484
+ const inlineGrow = panel.style.flexGrow;
485
+ const impliedPercent = (inlineGrow === '' ? 1 : parseFloat(inlineGrow)) * unit;
420
486
 
421
- if (isSameSize(impliedPercent, size)) continue;
487
+ if (isSameSize(impliedPercent, size)) continue;
422
488
 
423
- this.#unit ??= unit;
424
- panel.style.flex = `${size / unit} 1 0px`;
425
- }
489
+ this.#unit ??= unit;
490
+ panel.style.flex = `${size / unit} 1 0px`;
426
491
  }
427
492
 
428
- this.#syncHandles();
493
+ this.#syncHandles(members);
429
494
  }
430
495
 
431
496
  /**
@@ -433,11 +498,23 @@ export class GroupState {
433
498
  * immediately before it. (A splitter between two side-by-side panes
434
499
  * is oriented *vertically*, and vice-versa.)
435
500
  */
436
- #syncHandles(): void {
437
- for (const handle of this.handles) {
438
- const [prev] = this.#neighborsOf(handle);
501
+ #syncHandles(members: Members): void {
502
+ const { panels, handles } = members;
503
+ const ariaOrientation = this.#isHorizontal ? 'vertical' : 'horizontal';
504
+
505
+ let index = 0;
439
506
 
440
- setAttribute(handle, 'aria-orientation', this.#isHorizontal ? 'vertical' : 'horizontal');
507
+ for (const handle of handles) {
508
+ let following = panels[index];
509
+
510
+ while (following && precedes(following, handle)) {
511
+ index++;
512
+ following = panels[index];
513
+ }
514
+
515
+ const prev = panels[index - 1];
516
+
517
+ setAttribute(handle, 'aria-orientation', ariaOrientation);
441
518
 
442
519
  if (!prev) continue;
443
520
 
@@ -450,36 +527,19 @@ export class GroupState {
450
527
  }
451
528
  }
452
529
 
453
- #notify(): void {
454
- this.#options.onLayoutChange()?.(this.sizes);
455
- }
456
-
457
- /**
458
- * The `data-collapsed` attribute is the source of truth for collapse
459
- * state (it is also the styling hook consumers use).
460
- */
461
- #isCollapsed(panel: HTMLElement): boolean {
462
- return isCollapsible(panel) && panel.hasAttribute('data-collapsed');
463
- }
464
-
465
- #setCollapsed(panel: HTMLElement, collapsed: boolean): void {
466
- if (collapsed === panel.hasAttribute('data-collapsed')) return;
467
-
468
- if (collapsed) {
469
- panel.setAttribute('data-collapsed', '');
470
- } else {
471
- panel.removeAttribute('data-collapsed');
472
- }
530
+ #notify(panels: HTMLElement[]): void {
531
+ this.#options.onLayoutChange()?.(panels.map((panel) => this.#sizes.get(panel) ?? 0));
473
532
  }
474
533
 
475
534
  /**
476
535
  * Re-derive percentage sizes from actual rendered pixels.
477
536
  * Corrects any drift (e.g. from CSS min-sizes) before an interaction.
478
537
  */
479
- #syncSizesFromDOM(): void {
480
- const panels = this.panels;
538
+ #syncSizesFromDOM(panels: HTMLElement[], measured?: number[]): void {
481
539
  // collapsed panels are 0 even though their borders/padding measure larger
482
- const px = panels.map((panel) => (this.#isCollapsed(panel) ? 0 : this.#pixelSizeOf(panel)));
540
+ const px = panels.map((panel, index) =>
541
+ isCollapsed(panel) ? 0 : (measured?.[index] ?? this.#pixelSizeOf(panel))
542
+ );
483
543
  const total = px.reduce((sum, value) => sum + value, 0);
484
544
 
485
545
  if (total <= 0) return;
@@ -500,29 +560,6 @@ export class GroupState {
500
560
  return this.#isHorizontal ? box.width : box.height;
501
561
  }
502
562
 
503
- /**
504
- * The panels immediately before and after the given handle element,
505
- * in document order.
506
- */
507
- #neighborsOf(handleElement: HTMLElement): [HTMLElement | null, HTMLElement | null] {
508
- let prev: HTMLElement | null = null;
509
- let next: HTMLElement | null = null;
510
-
511
- for (const panel of this.panels) {
512
- const position = handleElement.compareDocumentPosition(panel);
513
-
514
- if (position & Node.DOCUMENT_POSITION_PRECEDING) {
515
- prev = panel;
516
- } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
517
- next = panel;
518
-
519
- break;
520
- }
521
- }
522
-
523
- return [prev, next];
524
- }
525
-
526
563
  /**
527
564
  * Moves the boundary between the two panels by `requestedDelta` (%),
528
565
  * respecting both panels' min/max constraints.
@@ -532,22 +569,26 @@ export class GroupState {
532
569
  next: HTMLElement,
533
570
  basePrevSize: number,
534
571
  baseNextSize: number,
535
- requestedDelta: number
572
+ requestedDelta: number,
573
+ members: Members
536
574
  ): void {
537
575
  const total = basePrevSize + baseNextSize;
576
+ const prevMin = minSizeOf(prev);
577
+ const prevMax = maxSizeOf(prev);
578
+ const prevCollapsible = isCollapsible(prev);
538
579
 
539
580
  let target = basePrevSize + requestedDelta;
540
581
 
541
- if (isCollapsible(prev) && target < minSizeOf(prev)) {
582
+ if (prevCollapsible && target < prevMin) {
542
583
  /**
543
584
  * Collapsible panels snap: below half the minimum they close
544
585
  * entirely; between half and the minimum they hold at the minimum.
545
586
  * (This also keeps a collapsed panel closed when its handle is
546
587
  * dragged further in the closing direction.)
547
588
  */
548
- target = target < minSizeOf(prev) / 2 ? 0 : minSizeOf(prev);
589
+ target = target < prevMin / 2 ? 0 : prevMin;
549
590
  } else {
550
- target = clamp(target, minSizeOf(prev), maxSizeOf(prev));
591
+ target = clamp(target, prevMin, prevMax);
551
592
  }
552
593
 
553
594
  /**
@@ -562,7 +603,7 @@ export class GroupState {
562
603
  target = clamp(target, nextMin, nextMax);
563
604
 
564
605
  // both panels' constraints cannot be satisfied at once
565
- if (!isCollapsible(prev) && (target < minSizeOf(prev) || target > maxSizeOf(prev))) return;
606
+ if (!prevCollapsible && (target < prevMin || target > prevMax)) return;
566
607
 
567
608
  /**
568
609
  * Nothing to do when the clamped result matches the current sizes
@@ -575,30 +616,33 @@ export class GroupState {
575
616
  return;
576
617
  }
577
618
 
578
- if (isCollapsible(prev)) {
579
- if (target === 0 && !this.#isCollapsed(prev)) {
619
+ if (prevCollapsible) {
620
+ if (target === 0 && !isCollapsed(prev)) {
580
621
  this.#previousSizes.set(prev, basePrevSize);
581
622
  }
582
623
 
583
- this.#setCollapsed(prev, target === 0);
624
+ setCollapsed(prev, target === 0);
584
625
  }
585
626
 
586
627
  this.#sizes.set(prev, target);
587
628
  this.#sizes.set(next, total - target);
588
629
 
589
- this.#apply([prev, next]);
590
- this.#notify();
630
+ this.#apply([prev, next], members);
631
+ this.#notify(members.panels);
591
632
  }
592
633
 
593
634
  startDrag(handleElement: HTMLElement, event: PointerEvent): void {
594
635
  if (event.button !== 0) return;
595
636
  if (this.#drag) return;
596
637
 
597
- const [prev, next] = this.#neighborsOf(handleElement);
638
+ const members = this.#members();
639
+ const [prev, next] = neighborsOf(handleElement, members.panels);
598
640
 
599
641
  if (!prev || !next) return;
600
642
 
601
- this.#syncSizesFromDOM();
643
+ const measured = members.panels.map((panel) => this.#pixelSizeOf(panel));
644
+
645
+ this.#syncSizesFromDOM(members.panels, measured);
602
646
 
603
647
  const move = (moveEvent: PointerEvent) => this.#dragMove(moveEvent);
604
648
  const end = (endEvent: PointerEvent) => this.#endDrag(handleElement, endEvent);
@@ -609,7 +653,8 @@ export class GroupState {
609
653
  startPrevSize: this.#sizes.get(prev) ?? 0,
610
654
  startNextSize: this.#sizes.get(next) ?? 0,
611
655
  startCoordinate: this.#isHorizontal ? event.clientX : event.clientY,
612
- totalPx: this.panels.reduce((sum, panel) => sum + this.#pixelSizeOf(panel), 0),
656
+ totalPx: measured.reduce((sum, value) => sum + value, 0),
657
+ members,
613
658
  move,
614
659
  end,
615
660
  };
@@ -624,9 +669,9 @@ export class GroupState {
624
669
  // synthetic events (tests) may not have an active pointer
625
670
  }
626
671
 
627
- handleElement.addEventListener('pointermove', this.#drag.move);
628
- handleElement.addEventListener('pointerup', this.#drag.end);
629
- handleElement.addEventListener('pointercancel', this.#drag.end);
672
+ handleElement.addEventListener('pointermove', move);
673
+ handleElement.addEventListener('pointerup', end);
674
+ handleElement.addEventListener('pointercancel', end);
630
675
  handleElement.setAttribute('data-resizing', '');
631
676
 
632
677
  document.body.style.cursor = this.#isHorizontal ? 'col-resize' : 'row-resize';
@@ -642,7 +687,14 @@ export class GroupState {
642
687
  const coordinate = this.#isHorizontal ? event.clientX : event.clientY;
643
688
  const deltaPercent = ((coordinate - drag.startCoordinate) / drag.totalPx) * 100;
644
689
 
645
- this.#applyDelta(drag.prev, drag.next, drag.startPrevSize, drag.startNextSize, deltaPercent);
690
+ this.#applyDelta(
691
+ drag.prev,
692
+ drag.next,
693
+ drag.startPrevSize,
694
+ drag.startNextSize,
695
+ deltaPercent,
696
+ drag.members
697
+ );
646
698
  }
647
699
 
648
700
  #endDrag(handleElement: HTMLElement, event: PointerEvent): void {
@@ -671,12 +723,13 @@ export class GroupState {
671
723
  * Keyboard support for the WAI-ARIA window-splitter pattern.
672
724
  */
673
725
  handleKeyDown(handleElement: HTMLElement, event: KeyboardEvent): void {
674
- const [prev, next] = this.#neighborsOf(handleElement);
726
+ const members = this.#members();
727
+ const [prev, next] = neighborsOf(handleElement, members.panels);
675
728
 
676
729
  if (!prev || !next) return;
677
730
 
678
731
  if (event.key === 'Enter') {
679
- this.#toggleCollapse(prev, next);
732
+ this.#toggleCollapse(prev, next, members);
680
733
 
681
734
  return;
682
735
  }
@@ -684,43 +737,44 @@ export class GroupState {
684
737
  const step = event.shiftKey ? KEYBOARD_STEP_COARSE : KEYBOARD_STEP;
685
738
  const isHorizontal = this.#isHorizontal;
686
739
 
687
- let delta: number | null = null;
740
+ let toDelta: ((prevSize: number) => number) | null = null;
688
741
 
689
742
  switch (event.key) {
690
743
  case 'ArrowLeft':
691
- if (isHorizontal) delta = -step;
744
+ if (isHorizontal) toDelta = () => -step;
692
745
 
693
746
  break;
694
747
  case 'ArrowRight':
695
- if (isHorizontal) delta = step;
748
+ if (isHorizontal) toDelta = () => step;
696
749
 
697
750
  break;
698
751
  case 'ArrowUp':
699
- if (!isHorizontal) delta = -step;
752
+ if (!isHorizontal) toDelta = () => -step;
700
753
 
701
754
  break;
702
755
  case 'ArrowDown':
703
- if (!isHorizontal) delta = step;
756
+ if (!isHorizontal) toDelta = () => step;
704
757
 
705
758
  break;
706
759
  case 'Home':
707
- this.#syncSizesFromDOM();
708
- delta = minSizeOf(prev) - (this.#sizes.get(prev) ?? 0);
760
+ toDelta = (prevSize) => minSizeOf(prev) - prevSize;
709
761
 
710
762
  break;
711
763
  case 'End':
712
- this.#syncSizesFromDOM();
713
- delta = maxSizeOf(prev) - (this.#sizes.get(prev) ?? 0);
764
+ toDelta = (prevSize) => maxSizeOf(prev) - prevSize;
714
765
 
715
766
  break;
716
767
  }
717
768
 
718
- if (delta === null) return;
769
+ if (!toDelta) return;
719
770
 
720
771
  event.preventDefault();
721
772
 
722
- this.#syncSizesFromDOM();
723
- this.#applyDelta(prev, next, this.#sizes.get(prev) ?? 0, this.#sizes.get(next) ?? 0, delta);
773
+ this.#syncSizesFromDOM(members.panels);
774
+
775
+ const prevSize = this.#sizes.get(prev) ?? 0;
776
+
777
+ this.#applyDelta(prev, next, prevSize, this.#sizes.get(next) ?? 0, toDelta(prevSize), members);
724
778
  }
725
779
 
726
780
  /**
@@ -729,15 +783,15 @@ export class GroupState {
729
783
  *
730
784
  * Only does anything when the preceding panel is `@collapsible`.
731
785
  */
732
- #toggleCollapse(prev: HTMLElement, next: HTMLElement): void {
786
+ #toggleCollapse(prev: HTMLElement, next: HTMLElement, members: Members): void {
733
787
  if (!isCollapsible(prev)) return;
734
788
 
735
- this.#syncSizesFromDOM();
789
+ this.#syncSizesFromDOM(members.panels);
736
790
 
737
791
  const prevSize = this.#sizes.get(prev) ?? 0;
738
792
  const nextSize = this.#sizes.get(next) ?? 0;
739
793
 
740
- if (this.#isCollapsed(prev)) {
794
+ if (isCollapsed(prev)) {
741
795
  const preferred =
742
796
  this.#previousSizes.get(prev) ?? requestedSizeOf(prev) ?? Math.max(minSizeOf(prev), 10);
743
797
  const available = nextSize - minSizeOf(next);
@@ -745,17 +799,17 @@ export class GroupState {
745
799
 
746
800
  if (restored <= 0) return;
747
801
 
748
- this.#setCollapsed(prev, false);
802
+ setCollapsed(prev, false);
749
803
  this.#sizes.set(prev, restored);
750
804
  this.#sizes.set(next, nextSize - restored);
751
805
  } else {
752
806
  this.#previousSizes.set(prev, prevSize);
753
- this.#setCollapsed(prev, true);
807
+ setCollapsed(prev, true);
754
808
  this.#sizes.set(prev, 0);
755
809
  this.#sizes.set(next, nextSize + prevSize);
756
810
  }
757
811
 
758
- this.#apply([prev, next]);
759
- this.#notify();
812
+ this.#apply([prev, next], members);
813
+ this.#notify(members.panels);
760
814
  }
761
815
  }