@window-splitter/state 0.3.2 → 0.4.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/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import Cookies from "universal-cookie";
1
2
  import { raf } from "@react-spring/rafz";
2
3
  import {
3
4
  createMachine,
@@ -65,6 +66,13 @@ export interface Constraints<T extends ParsedUnit | Unit = ParsedUnit> {
65
66
  defaultCollapsed?: boolean;
66
67
  /** The size of the panel once collapsed */
67
68
  collapsedSize?: T;
69
+ /**
70
+ * By default the layout will be stored in percentage values while at rest.
71
+ * This makes scaling the layout easier when the container is resized.
72
+ * However you might have a panel you want to stay at a static size when
73
+ * the container is resized.
74
+ */
75
+ isStaticAtRest?: boolean;
68
76
  }
69
77
 
70
78
  interface Order {
@@ -108,6 +116,7 @@ export interface PanelData
108
116
  collapseAnimation?:
109
117
  | CollapseAnimation
110
118
  | { duration: number; easing: CollapseAnimation | ((t: number) => number) };
119
+ lastKnownSize?: Rect;
111
120
  }
112
121
 
113
122
  function getCollapseAnimation(panel: PanelData) {
@@ -294,8 +303,17 @@ export interface GroupMachineContextValue {
294
303
  /** How much the drag has overshot the handle */
295
304
  dragOvershoot: Big.Big;
296
305
  groupId: string;
306
+ /**
307
+ * How to save the persisted state
308
+ */
309
+ autosaveStrategy?: "localStorage" | "cookie";
297
310
  }
298
311
 
312
+ export type GroupMachineSnapshot = Snapshot<unknown> & {
313
+ context: GroupMachineContextValue;
314
+ value: string;
315
+ };
316
+
299
317
  export type GroupMachineEvent =
300
318
  | RegisterPanelEvent
301
319
  | RegisterDynamicPanelEvent
@@ -344,10 +362,8 @@ export function getCursor(
344
362
  }
345
363
  }
346
364
 
347
- export function prepareSnapshot(snapshot: Snapshot<unknown>) {
348
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
349
- const snapshotContext = (snapshot as any)
350
- .context as unknown as GroupMachineContextValue;
365
+ export function prepareSnapshot(snapshot: GroupMachineSnapshot) {
366
+ const snapshotContext = snapshot.context;
351
367
 
352
368
  snapshotContext.dragOvershoot = new Big(snapshotContext.dragOvershoot);
353
369
 
@@ -406,23 +422,24 @@ type OnResizeSize = {
406
422
 
407
423
  export type OnResizeCallback = (size: OnResizeSize) => void;
408
424
 
409
- interface InitializePanelOptions {
425
+ type InitializePanelOptions = {
410
426
  min?: Unit;
411
427
  max?: Unit;
412
428
  default?: Unit;
413
- collapsible?: boolean;
414
- collapsed?: boolean;
415
429
  collapsedSize?: Unit;
416
- onCollapseChange?: {
417
- current: ((isCollapsed: boolean) => void) | null | undefined;
418
- };
419
- onResize?: {
420
- current: OnResizeCallback | null | undefined;
421
- };
422
- collapseAnimation?: PanelData["collapseAnimation"];
423
- defaultCollapsed?: boolean;
424
430
  id?: string;
425
- }
431
+ } & Partial<
432
+ Pick<
433
+ PanelData,
434
+ | "isStaticAtRest"
435
+ | "collapseAnimation"
436
+ | "defaultCollapsed"
437
+ | "onResize"
438
+ | "collapsible"
439
+ | "collapsed"
440
+ | "onCollapseChange"
441
+ >
442
+ >;
426
443
 
427
444
  type InitializePanelOptionsWithId = InitializePanelOptions & { id: string };
428
445
 
@@ -468,6 +485,7 @@ export function initializePanel(
468
485
  id: item.id,
469
486
  collapseAnimation: item.collapseAnimation,
470
487
  default: item.default ? parseUnit(item.default) : undefined,
488
+ isStaticAtRest: item.isStaticAtRest,
471
489
  } satisfies Omit<PanelData, "id" | "currentValue"> & { id?: string };
472
490
 
473
491
  return { ...data, currentValue: makePixelUnit(-1) } satisfies Omit<
@@ -686,10 +704,7 @@ function panelHasSpace(
686
704
  );
687
705
  }
688
706
 
689
- return (
690
- item.currentValue.value.gt(getUnitPixelValue(context, item.min)) &&
691
- item.currentValue.value.lte(getUnitPixelValue(context, item.max))
692
- );
707
+ return item.currentValue.value.gt(getUnitPixelValue(context, item.min));
693
708
  }
694
709
 
695
710
  /** Search in a `direction` for a panel that still has space to expand. */
@@ -726,11 +741,9 @@ function getStaticWidth(context: GroupMachineContextValue) {
726
741
  for (const item of context.items) {
727
742
  if (isPanelHandle(item)) {
728
743
  width = width.add(item.size.value);
729
- } else if (
730
- isPanelData(item) &&
731
- item.collapsed &&
732
- item.currentValue.type === "pixel"
733
- ) {
744
+ } else if (item.collapsed && item.currentValue.type === "pixel") {
745
+ width = width.add(item.currentValue.value);
746
+ } else if (item.isStaticAtRest) {
734
747
  width = width.add(item.currentValue.value);
735
748
  }
736
749
  }
@@ -795,6 +808,7 @@ export function getPanelPercentageSize(
795
808
  /** Build the grid template from the item values. */
796
809
  export function buildTemplate(context: GroupMachineContextValue) {
797
810
  const staticWidth = getStaticWidth(context);
811
+ let hasSeenFillPanel = false;
798
812
 
799
813
  return context.items
800
814
  .map((item) => {
@@ -805,8 +819,22 @@ export function buildTemplate(context: GroupMachineContextValue) {
805
819
  item.currentValue.type === "pixel" &&
806
820
  item.currentValue.value.toNumber() !== -1
807
821
  ) {
822
+ if (item.isStaticAtRest) {
823
+ const max = item.max === "1fr" ? "100%" : formatUnit(item.max);
824
+ return `clamp(${min}, ${formatUnit(item.currentValue)}, ${max})`;
825
+ }
826
+
808
827
  return formatUnit(item.currentValue);
809
828
  } else if (item.currentValue.type === "percent") {
829
+ if (
830
+ !hasSeenFillPanel &&
831
+ (item.max === "1fr" ||
832
+ (item.max.type === "percent" && item.max.value.eq(100)))
833
+ ) {
834
+ hasSeenFillPanel = true;
835
+ return `minmax(${min}, 1fr)`;
836
+ }
837
+
810
838
  const max = item.max === "1fr" ? "100%" : formatUnit(item.max);
811
839
  return `minmax(${min}, min(calc(${item.currentValue.value} * (100% - ${staticWidth}px)), ${max}))`;
812
840
  } else if (item.collapsible && item.collapsed) {
@@ -919,18 +947,28 @@ function createUnrestrainedPanel(_: GroupMachineContextValue, data: PanelData) {
919
947
  */
920
948
 
921
949
  /** Converts the items to pixels */
922
- export function prepareItems(context: GroupMachineContextValue) {
950
+ export function prepareItems(context: GroupMachineContextValue): Item[] {
923
951
  const staticWidth = getStaticWidth(context);
924
952
  const newItems = [];
925
953
 
926
954
  for (const item of context.items) {
927
955
  if (!item || !isPanelData(item)) {
928
- newItems.push(item);
956
+ newItems.push({ ...item });
957
+ continue;
958
+ }
959
+
960
+ if (item.lastKnownSize) {
961
+ const lastSize = makePixelUnit(
962
+ context.orientation === "horizontal"
963
+ ? item.lastKnownSize.width
964
+ : item.lastKnownSize.height
965
+ );
966
+ newItems.push({ ...item, currentValue: lastSize });
929
967
  continue;
930
968
  }
931
969
 
932
970
  if (item.currentValue.type === "pixel") {
933
- newItems.push(item);
971
+ newItems.push({ ...item });
934
972
  continue;
935
973
  }
936
974
 
@@ -1031,6 +1069,10 @@ function updateLayout(
1031
1069
 
1032
1070
  const isInDragBugger =
1033
1071
  newDragOvershoot.abs().lt(COLLAPSE_THRESHOLD) &&
1072
+ // Let the panel expand at it's min size
1073
+ !panelAfter.currentValue.value
1074
+ .add(newDragOvershoot.abs())
1075
+ .gte(panelAfter.min.value) &&
1034
1076
  panelAfter.collapsible &&
1035
1077
  panelAfter.collapsed &&
1036
1078
  (isInLeftOvershoot || isInRightOvershoot);
@@ -1048,9 +1090,11 @@ function updateLayout(
1048
1090
 
1049
1091
  // Don't let the panel collapse until the threshold is reached
1050
1092
  if (
1093
+ !dragEvent.disregardCollapseBuffer &&
1051
1094
  panelBefore.collapsible &&
1052
- panelBefore.currentValue.value ===
1095
+ panelBefore.currentValue.value.eq(
1053
1096
  getUnitPixelValue(context, panelBefore.min)
1097
+ )
1054
1098
  ) {
1055
1099
  const potentialNewValue = panelBefore.currentValue.value.sub(
1056
1100
  newDragOvershoot.abs()
@@ -1116,8 +1160,6 @@ function updateLayout(
1116
1160
  .add(Math.abs(moveAmount))
1117
1161
  );
1118
1162
 
1119
- panelAfter.collapsed = false;
1120
-
1121
1163
  if (extra.gt(0)) {
1122
1164
  panelAfterNewValue = panelAfterNewValue.add(extra);
1123
1165
  }
@@ -1131,6 +1173,13 @@ function updateLayout(
1131
1173
  .minus(Math.abs(moveAmount))
1132
1174
  );
1133
1175
 
1176
+ if (panelBeforeNewValue.lt(panelBefore.min.value)) {
1177
+ // TODO this should probably distribute the space between the panels?
1178
+ return { dragOvershoot: newDragOvershoot };
1179
+ }
1180
+
1181
+ panelAfter.collapsed = false;
1182
+
1134
1183
  if (
1135
1184
  panelAfter.onCollapseChange?.current &&
1136
1185
  !panelAfter.collapseIsControlled &&
@@ -1140,9 +1189,9 @@ function updateLayout(
1140
1189
  }
1141
1190
  }
1142
1191
 
1143
- const panelBeforeIsAboutToCollapse =
1144
- panelBefore.currentValue.value ===
1145
- getUnitPixelValue(context, panelBefore.min);
1192
+ const panelBeforeIsAboutToCollapse = panelBefore.currentValue.value.eq(
1193
+ getUnitPixelValue(context, panelBefore.min)
1194
+ );
1146
1195
 
1147
1196
  // If the panel was expanded and now is at it's min size, collapse it
1148
1197
  if (
@@ -1187,8 +1236,11 @@ function updateLayout(
1187
1236
  );
1188
1237
 
1189
1238
  if (!leftoverSpace.eq(0)) {
1190
- panelBefore.currentValue.value =
1191
- panelBefore.currentValue.value.add(leftoverSpace);
1239
+ panelBefore.currentValue.value = clampUnit(
1240
+ context,
1241
+ panelBefore,
1242
+ panelBefore.currentValue.value.add(leftoverSpace)
1243
+ );
1192
1244
  }
1193
1245
 
1194
1246
  return { items: newItems };
@@ -1215,7 +1267,7 @@ function commitLayout(context: GroupMachineContextValue) {
1215
1267
  const staticWidth = getStaticWidth({ ...context, items: newItems });
1216
1268
 
1217
1269
  newItems.forEach((item, index) => {
1218
- if (item.type !== "panel" || item.collapsed) {
1270
+ if (item.type !== "panel" || item.collapsed || item.isStaticAtRest) {
1219
1271
  return;
1220
1272
  }
1221
1273
 
@@ -1334,6 +1386,85 @@ function applyDeltaInBothDirections(
1334
1386
  }
1335
1387
  }
1336
1388
 
1389
+ /**
1390
+ * A layout might overflow at small screen sizes.
1391
+ * This function tries to fix that by:
1392
+ *
1393
+ * 1. It will try to collapse a panel if it can.
1394
+ */
1395
+ function handleOverflow(context: GroupMachineContextValue) {
1396
+ // If we haven't measured yet we can't do anything
1397
+ if (
1398
+ context.items.some((i) => isPanelData(i) && i.currentValue.value.eq(-1))
1399
+ ) {
1400
+ return context;
1401
+ }
1402
+
1403
+ const groupSize = new Big(getGroupSize(context));
1404
+ const nonStaticWidth = groupSize.sub(getStaticWidth(context).toNumber());
1405
+ const pixelItems = context.items.map((i) => {
1406
+ if (isPanelHandle(i)) return i.size.value;
1407
+ if (i.collapsed) return getUnitPixelValue(context, i.currentValue);
1408
+
1409
+ const pixel =
1410
+ (i.currentValue.type === "pixel" && i.currentValue.value) ||
1411
+ i.currentValue.value.mul(nonStaticWidth);
1412
+
1413
+ return clampUnit(context, i, pixel);
1414
+ });
1415
+ const totalSize = pixelItems.reduce((acc, i) => acc.add(i), new Big(0));
1416
+ const overflow = totalSize.abs().sub(groupSize);
1417
+
1418
+ if (overflow.eq(0) || groupSize.eq(0)) {
1419
+ return context;
1420
+ }
1421
+
1422
+ let newContext = { ...context, items: prepareItems(context) };
1423
+
1424
+ const collapsiblePanel = newContext.items.find((i): i is PanelData =>
1425
+ Boolean(isPanelData(i) && i.collapsible)
1426
+ );
1427
+
1428
+ if (collapsiblePanel) {
1429
+ const collapsiblePanelIndex = newContext.items.findIndex(
1430
+ (i) => i.id === collapsiblePanel.id
1431
+ );
1432
+ const handleId = getHandleForPanelId(newContext, collapsiblePanel.id);
1433
+ const sizeChange = collapsiblePanel.currentValue.value.sub(
1434
+ getUnitPixelValue(newContext, collapsiblePanel.collapsedSize)
1435
+ );
1436
+
1437
+ // Try to collapse the panel
1438
+ newContext = {
1439
+ ...newContext,
1440
+ ...iterativelyUpdateLayout({
1441
+ handleId: handleId.item.id,
1442
+ delta: sizeChange,
1443
+ direction: (handleId.direction * -1) as -1 | 1,
1444
+ context: {
1445
+ ...newContext,
1446
+ // act like its the old size so the space is distributed correctly
1447
+ size: { width: totalSize.toNumber(), height: totalSize.toNumber() },
1448
+ },
1449
+ }),
1450
+ };
1451
+
1452
+ // Then remove all the overflow
1453
+ applyDeltaInBothDirections(
1454
+ newContext,
1455
+ newContext.items,
1456
+ collapsiblePanelIndex,
1457
+ overflow.neg()
1458
+ );
1459
+ }
1460
+
1461
+ return { ...newContext, items: commitLayout(newContext) };
1462
+ }
1463
+
1464
+ function clearLastKnownSize(items: Item[]) {
1465
+ return items.map((i) => ({ ...i, lastKnownSize: undefined }));
1466
+ }
1467
+
1337
1468
  // #endregion
1338
1469
 
1339
1470
  // #region Machine
@@ -1349,6 +1480,22 @@ interface AnimationActorOutput {
1349
1480
  action: "expand" | "collapse";
1350
1481
  }
1351
1482
 
1483
+ function getDeltaForEvent(
1484
+ context: GroupMachineContextValue,
1485
+ event: CollapsePanelEvent | ExpandPanelEvent
1486
+ ) {
1487
+ const panel = getPanelWithId(context, event.panelId);
1488
+
1489
+ if (event.type === "expandPanel") {
1490
+ return new Big(
1491
+ panel.sizeBeforeCollapse ?? getUnitPixelValue(context, panel.min)
1492
+ ).minus(panel.currentValue.value);
1493
+ }
1494
+
1495
+ const collapsedSize = getUnitPixelValue(context, panel.collapsedSize);
1496
+ return panel.currentValue.value.minus(collapsedSize);
1497
+ }
1498
+
1352
1499
  const animationActor = fromPromise<
1353
1500
  AnimationActorOutput | undefined,
1354
1501
  AnimationActorInput
@@ -1359,18 +1506,11 @@ const animationActor = fromPromise<
1359
1506
  const handle = getHandleForPanelId(context, event.panelId);
1360
1507
 
1361
1508
  let direction = new Big(handle.direction);
1362
- let fullDelta = new Big(0);
1363
-
1364
- if (event.type === "expandPanel") {
1365
- fullDelta = new Big(
1366
- panel.sizeBeforeCollapse ?? getUnitPixelValue(context, panel.min)
1367
- ).minus(panel.currentValue.value);
1368
- } else {
1369
- const collapsedSize = getUnitPixelValue(context, panel.collapsedSize);
1509
+ const fullDelta = getDeltaForEvent(context, event);
1370
1510
 
1511
+ if (event.type === "collapsePanel") {
1371
1512
  panel.sizeBeforeCollapse = panel.currentValue.value.toNumber();
1372
1513
  direction = direction.mul(new Big(-1));
1373
- fullDelta = panel.currentValue.value.minus(collapsedSize);
1374
1514
  }
1375
1515
 
1376
1516
  const fps = 60;
@@ -1426,6 +1566,7 @@ export const groupMachine = createMachine(
1426
1566
  orientation?: Orientation;
1427
1567
  groupId: string;
1428
1568
  initialItems?: Item[];
1569
+ autosaveStrategy?: "localStorage" | "cookie";
1429
1570
  },
1430
1571
  },
1431
1572
  context: ({ input }) => ({
@@ -1434,15 +1575,17 @@ export const groupMachine = createMachine(
1434
1575
  orientation: input.orientation || "horizontal",
1435
1576
  dragOvershoot: new Big(0),
1436
1577
  groupId: input.groupId,
1578
+ autosaveStrategy: input.autosaveStrategy,
1437
1579
  }),
1438
1580
  states: {
1439
1581
  idle: {
1582
+ entry: ["onAutosave"],
1440
1583
  on: {
1441
- setActualItemsSize: { actions: ["recordActualItemSize", "onResize"] },
1442
1584
  dragHandleStart: { target: "dragging" },
1443
1585
  setPanelPixelSize: {
1444
1586
  actions: [
1445
1587
  "prepare",
1588
+ "onClearLastKnownSize",
1446
1589
  "onSetPanelSize",
1447
1590
  "commit",
1448
1591
  "onResize",
@@ -1457,6 +1600,8 @@ export const groupMachine = createMachine(
1457
1600
  { target: "togglingCollapse" },
1458
1601
  ],
1459
1602
  expandPanel: [
1603
+ // This will match if we can't expand and the expansion won't happen
1604
+ { guard: "cannotExpandPanel" },
1460
1605
  {
1461
1606
  actions: "notifyCollapseToggle",
1462
1607
  guard: "shouldNotifyCollapseToggle",
@@ -1468,7 +1613,9 @@ export const groupMachine = createMachine(
1468
1613
  dragging: {
1469
1614
  entry: ["prepare"],
1470
1615
  on: {
1471
- dragHandle: { actions: ["onDragHandle", "onResize"] },
1616
+ dragHandle: {
1617
+ actions: ["onClearLastKnownSize", "onDragHandle", "onResize"],
1618
+ },
1472
1619
  dragHandleEnd: { target: "idle" },
1473
1620
  collapsePanel: {
1474
1621
  guard: "shouldCollapseToggle",
@@ -1479,16 +1626,16 @@ export const groupMachine = createMachine(
1479
1626
  actions: "runCollapseToggle",
1480
1627
  },
1481
1628
  },
1482
- exit: ["commit", "onAutosave"],
1629
+ exit: ["commit"],
1483
1630
  },
1484
1631
  togglingCollapse: {
1485
- entry: ["prepare"],
1632
+ entry: ["prepare", "onClearLastKnownSize"],
1486
1633
  invoke: {
1487
1634
  src: "animation",
1488
1635
  input: (i) => ({ ...i, send: i.self.send }),
1489
1636
  onDone: {
1490
1637
  target: "idle",
1491
- actions: ["onToggleCollapseComplete", "commit", "onAutosave"],
1638
+ actions: ["onToggleCollapseComplete", "commit"],
1492
1639
  },
1493
1640
  },
1494
1641
  on: {
@@ -1497,25 +1644,43 @@ export const groupMachine = createMachine(
1497
1644
  },
1498
1645
  },
1499
1646
  on: {
1647
+ setActualItemsSize: { actions: ["recordActualItemSize", "onResize"] },
1500
1648
  registerPanel: { actions: ["assignPanelData"] },
1501
1649
  registerDynamicPanel: {
1502
1650
  actions: [
1503
1651
  "prepare",
1504
1652
  "onRegisterDynamicPanel",
1653
+ "onClearLastKnownSize",
1505
1654
  "commit",
1506
1655
  "onResize",
1507
1656
  "onAutosave",
1508
1657
  ],
1509
1658
  },
1510
1659
  unregisterPanel: {
1511
- actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1660
+ actions: [
1661
+ "prepare",
1662
+ "removeItem",
1663
+ "onClearLastKnownSize",
1664
+ "commit",
1665
+ "onResize",
1666
+ "onAutosave",
1667
+ ],
1512
1668
  },
1513
1669
  registerPanelHandle: { actions: ["assignPanelHandleData"] },
1514
1670
  unregisterPanelHandle: {
1515
- actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1671
+ actions: [
1672
+ "prepare",
1673
+ "removeItem",
1674
+ "onClearLastKnownSize",
1675
+ "commit",
1676
+ "onResize",
1677
+ "onAutosave",
1678
+ ],
1516
1679
  },
1517
1680
  setSize: { actions: ["updateSize", "onResize"] },
1518
- setOrientation: { actions: ["updateOrientation", "onResize"] },
1681
+ setOrientation: {
1682
+ actions: ["updateOrientation", "onClearLastKnownSize", "onResize"],
1683
+ },
1519
1684
  },
1520
1685
  },
1521
1686
  {
@@ -1530,11 +1695,63 @@ export const groupMachine = createMachine(
1530
1695
  const panel = getPanelWithId(context, event.panelId);
1531
1696
  return panel.collapseIsControlled === true;
1532
1697
  },
1698
+ cannotExpandPanel: ({ context, event }) => {
1699
+ isEvent(event, ["expandPanel"]);
1700
+ const delta = getDeltaForEvent(context, event);
1701
+ const handle = getHandleForPanelId(context, event.panelId);
1702
+ const pixelItems = prepareItems(context);
1703
+
1704
+ let interimContext = { ...context, items: pixelItems };
1705
+ interimContext = {
1706
+ ...interimContext,
1707
+ ...iterativelyUpdateLayout({
1708
+ context: interimContext,
1709
+ handleId: handle.item.id,
1710
+ controlled: event.controlled,
1711
+ delta: delta,
1712
+ direction: handle.direction,
1713
+ }),
1714
+ };
1715
+ const updatedPanel = interimContext.items.find(
1716
+ (i) => i.id === event.panelId
1717
+ );
1718
+ const totalSize = interimContext.items.reduce(
1719
+ (acc, i) =>
1720
+ acc.add(isPanelData(i) ? i.currentValue.value : i.size.value),
1721
+ new Big(0)
1722
+ );
1723
+ const didExpand =
1724
+ updatedPanel &&
1725
+ isPanelData(updatedPanel) &&
1726
+ !updatedPanel.currentValue.value.eq(updatedPanel.collapsedSize.value);
1727
+
1728
+ return totalSize.gt(getGroupSize(context)) || !didExpand;
1729
+ },
1533
1730
  },
1534
1731
  actors: {
1535
1732
  animation: animationActor,
1536
1733
  },
1537
1734
  actions: {
1735
+ onAutosave: ({ context, self }) => {
1736
+ if (!context.autosaveStrategy || typeof window === "undefined") {
1737
+ return;
1738
+ }
1739
+
1740
+ const snapshot = self.getPersistedSnapshot() as GroupMachineSnapshot;
1741
+ snapshot.context.items = clearLastKnownSize(context.items);
1742
+ snapshot.value = "idle";
1743
+ const data = JSON.stringify(snapshot);
1744
+
1745
+ if (context.autosaveStrategy === "localStorage") {
1746
+ localStorage.setItem(context.groupId, data);
1747
+ } else {
1748
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1749
+ const ActualClass = (Cookies as any).default || Cookies;
1750
+ const cookies = new ActualClass(null, { path: "/" });
1751
+
1752
+ cookies.set(context.groupId, data, { path: "/", maxAge: 31536000 });
1753
+ }
1754
+ },
1538
1755
  notifyCollapseToggle: ({ context, event }) => {
1539
1756
  isEvent(event, ["collapsePanel", "expandPanel"]);
1540
1757
  const panel = getPanelWithId(context, event.panelId);
@@ -1561,8 +1778,7 @@ export const groupMachine = createMachine(
1561
1778
  }),
1562
1779
  onToggleCollapseComplete: assign({
1563
1780
  items: ({ context, event: e }) => {
1564
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1565
- const output = (e as any).output as AnimationActorOutput;
1781
+ const { output } = e as unknown as { output: AnimationActorOutput };
1566
1782
  invariant(output, "Expected output from animation actor");
1567
1783
 
1568
1784
  const panel = getPanelWithId(context, output.panelId);
@@ -1585,21 +1801,40 @@ export const groupMachine = createMachine(
1585
1801
  items: ({ context, event }) => {
1586
1802
  isEvent(event, ["setActualItemsSize"]);
1587
1803
 
1588
- const orientation = context.orientation;
1804
+ const withLastKnownSize = context.items.map((i) => {
1805
+ if (!isPanelData(i)) return i;
1806
+ const lastKnownSize = event.childrenSizes[i.id] || i.lastKnownSize;
1807
+ return { ...i, lastKnownSize };
1808
+ });
1809
+
1810
+ let totalSize = 0;
1589
1811
 
1590
- for (const [id, size] of Object.entries(event.childrenSizes)) {
1591
- const item = context.items.find((i) => i.id === id);
1812
+ for (const item of withLastKnownSize) {
1813
+ if (isPanelData(item)) {
1814
+ const size =
1815
+ item.lastKnownSize?.[
1816
+ context.orientation === "horizontal" ? "width" : "height"
1817
+ ];
1592
1818
 
1593
- if (!isPanelData(item)) {
1594
- continue;
1819
+ // If any size is 0 don't handle overflow
1820
+ if (!size) {
1821
+ return withLastKnownSize;
1822
+ }
1823
+
1824
+ totalSize += size;
1825
+ } else {
1826
+ totalSize += item.size.value.toNumber();
1595
1827
  }
1828
+ }
1596
1829
 
1597
- item.currentValue = makePixelUnit(
1598
- orientation === "horizontal" ? size.width : size.height
1599
- );
1830
+ if (totalSize > getGroupSize(context)) {
1831
+ return handleOverflow({
1832
+ ...context,
1833
+ items: prepareItems({ ...context, items: withLastKnownSize }),
1834
+ }).items;
1600
1835
  }
1601
1836
 
1602
- return commitLayout(context);
1837
+ return withLastKnownSize;
1603
1838
  },
1604
1839
  }),
1605
1840
  updateOrientation: assign({
@@ -1608,6 +1843,9 @@ export const groupMachine = createMachine(
1608
1843
  return event.orientation;
1609
1844
  },
1610
1845
  }),
1846
+ onClearLastKnownSize: assign({
1847
+ items: ({ context }) => clearLastKnownSize(context.items),
1848
+ }),
1611
1849
  assignPanelData: assign({
1612
1850
  items: ({ context, event }) => {
1613
1851
  isEvent(event, ["registerPanel"]);
@@ -1758,15 +1996,25 @@ export const groupMachine = createMachine(
1758
1996
  onResize: ({ context }) => {
1759
1997
  for (const item of context.items) {
1760
1998
  if (isPanelData(item)) {
1761
- const pixel = clampUnit(
1762
- context,
1763
- item,
1764
- getUnitPixelValue(context, item.currentValue)
1765
- );
1999
+ const pixel = item.lastKnownSize
2000
+ ? new Big(
2001
+ context.orientation === "horizontal"
2002
+ ? item.lastKnownSize.width
2003
+ : item.lastKnownSize.height
2004
+ )
2005
+ : clampUnit(
2006
+ context,
2007
+ item,
2008
+ getUnitPixelValue(context, item.currentValue)
2009
+ );
2010
+ const groupSize = getGroupSize(context);
1766
2011
 
1767
2012
  item.onResize?.current?.({
1768
2013
  pixel: pixel.toNumber(),
1769
- percentage: pixel.div(getGroupSize(context)).toNumber(),
2014
+ percentage:
2015
+ groupSize > 0
2016
+ ? pixel.div(getGroupSize(context)).toNumber()
2017
+ : -1,
1770
2018
  });
1771
2019
  }
1772
2020
  }