@window-splitter/state 0.4.0 → 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.
@@ -1,6 +1,86 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`utils > prepareSnapshot 1`] = `
4
+ {
5
+ "children": {},
6
+ "context": {
7
+ "dragOvershoot": "0",
8
+ "groupId": "group",
9
+ "items": [
10
+ {
11
+ "collapseIsControlled": false,
12
+ "collapsedSize": {
13
+ "type": "pixel",
14
+ "value": "0",
15
+ },
16
+ "currentValue": {
17
+ "type": "pixel",
18
+ "value": "-1",
19
+ },
20
+ "id": "panel-1",
21
+ "lastKnownSize": {
22
+ "height": 200,
23
+ "width": 190,
24
+ },
25
+ "max": "1fr",
26
+ "min": {
27
+ "type": "pixel",
28
+ "value": "100",
29
+ },
30
+ "onResize": {},
31
+ "type": "panel",
32
+ },
33
+ {
34
+ "id": "resizer-1",
35
+ "size": {
36
+ "type": "pixel",
37
+ "value": "10",
38
+ },
39
+ "type": "handle",
40
+ },
41
+ {
42
+ "collapseIsControlled": false,
43
+ "collapsed": false,
44
+ "collapsedSize": {
45
+ "type": "pixel",
46
+ "value": "50",
47
+ },
48
+ "collapsible": true,
49
+ "currentValue": {
50
+ "type": "pixel",
51
+ "value": "-1",
52
+ },
53
+ "id": "panel-2",
54
+ "lastKnownSize": {
55
+ "height": 200,
56
+ "width": 300,
57
+ },
58
+ "max": {
59
+ "type": "pixel",
60
+ "value": "300",
61
+ },
62
+ "min": {
63
+ "type": "pixel",
64
+ "value": "0",
65
+ },
66
+ "onResize": {},
67
+ "type": "panel",
68
+ },
69
+ ],
70
+ "orientation": "horizontal",
71
+ "size": {
72
+ "height": 200,
73
+ "width": 500,
74
+ },
75
+ },
76
+ "historyValue": {},
77
+ "status": "active",
78
+ "tags": [],
79
+ "value": "idle",
80
+ }
81
+ `;
82
+
83
+ exports[`utils > prepareSnapshot 2`] = `
4
84
  {
5
85
  "children": {},
6
86
  "context": {
@@ -15,7 +95,7 @@ exports[`utils > prepareSnapshot 1`] = `
15
95
  },
16
96
  "currentValue": {
17
97
  "type": "percent",
18
- "value": "0.38775510204081632653",
98
+ "value": "0.59183673469387755102",
19
99
  },
20
100
  "id": "panel-1",
21
101
  "max": "1fr",
@@ -44,7 +124,7 @@ exports[`utils > prepareSnapshot 1`] = `
44
124
  "collapsible": true,
45
125
  "currentValue": {
46
126
  "type": "percent",
47
- "value": "0.61224489795918367347",
127
+ "value": "0.40816326530612244898",
48
128
  },
49
129
  "id": "panel-2",
50
130
  "max": {
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,
@@ -115,6 +116,7 @@ export interface PanelData
115
116
  collapseAnimation?:
116
117
  | CollapseAnimation
117
118
  | { duration: number; easing: CollapseAnimation | ((t: number) => number) };
119
+ lastKnownSize?: Rect;
118
120
  }
119
121
 
120
122
  function getCollapseAnimation(panel: PanelData) {
@@ -235,7 +237,6 @@ interface SetSizeEvent {
235
237
  /** Set the size of the whole group */
236
238
  type: "setSize";
237
239
  size: Rect;
238
- handleOverflow?: boolean;
239
240
  }
240
241
 
241
242
  interface SetActualItemsSizeEvent {
@@ -302,8 +303,17 @@ export interface GroupMachineContextValue {
302
303
  /** How much the drag has overshot the handle */
303
304
  dragOvershoot: Big.Big;
304
305
  groupId: string;
306
+ /**
307
+ * How to save the persisted state
308
+ */
309
+ autosaveStrategy?: "localStorage" | "cookie";
305
310
  }
306
311
 
312
+ export type GroupMachineSnapshot = Snapshot<unknown> & {
313
+ context: GroupMachineContextValue;
314
+ value: string;
315
+ };
316
+
307
317
  export type GroupMachineEvent =
308
318
  | RegisterPanelEvent
309
319
  | RegisterDynamicPanelEvent
@@ -352,10 +362,8 @@ export function getCursor(
352
362
  }
353
363
  }
354
364
 
355
- export function prepareSnapshot(snapshot: Snapshot<unknown>) {
356
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
357
- const snapshotContext = (snapshot as any)
358
- .context as unknown as GroupMachineContextValue;
365
+ export function prepareSnapshot(snapshot: GroupMachineSnapshot) {
366
+ const snapshotContext = snapshot.context;
359
367
 
360
368
  snapshotContext.dragOvershoot = new Big(snapshotContext.dragOvershoot);
361
369
 
@@ -800,6 +808,7 @@ export function getPanelPercentageSize(
800
808
  /** Build the grid template from the item values. */
801
809
  export function buildTemplate(context: GroupMachineContextValue) {
802
810
  const staticWidth = getStaticWidth(context);
811
+ let hasSeenFillPanel = false;
803
812
 
804
813
  return context.items
805
814
  .map((item) => {
@@ -817,6 +826,15 @@ export function buildTemplate(context: GroupMachineContextValue) {
817
826
 
818
827
  return formatUnit(item.currentValue);
819
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
+
820
838
  const max = item.max === "1fr" ? "100%" : formatUnit(item.max);
821
839
  return `minmax(${min}, min(calc(${item.currentValue.value} * (100% - ${staticWidth}px)), ${max}))`;
822
840
  } else if (item.collapsible && item.collapsed) {
@@ -939,6 +957,16 @@ export function prepareItems(context: GroupMachineContextValue): Item[] {
939
957
  continue;
940
958
  }
941
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 });
967
+ continue;
968
+ }
969
+
942
970
  if (item.currentValue.type === "pixel") {
943
971
  newItems.push({ ...item });
944
972
  continue;
@@ -1433,6 +1461,10 @@ function handleOverflow(context: GroupMachineContextValue) {
1433
1461
  return { ...newContext, items: commitLayout(newContext) };
1434
1462
  }
1435
1463
 
1464
+ function clearLastKnownSize(items: Item[]) {
1465
+ return items.map((i) => ({ ...i, lastKnownSize: undefined }));
1466
+ }
1467
+
1436
1468
  // #endregion
1437
1469
 
1438
1470
  // #region Machine
@@ -1534,6 +1566,7 @@ export const groupMachine = createMachine(
1534
1566
  orientation?: Orientation;
1535
1567
  groupId: string;
1536
1568
  initialItems?: Item[];
1569
+ autosaveStrategy?: "localStorage" | "cookie";
1537
1570
  },
1538
1571
  },
1539
1572
  context: ({ input }) => ({
@@ -1542,15 +1575,17 @@ export const groupMachine = createMachine(
1542
1575
  orientation: input.orientation || "horizontal",
1543
1576
  dragOvershoot: new Big(0),
1544
1577
  groupId: input.groupId,
1578
+ autosaveStrategy: input.autosaveStrategy,
1545
1579
  }),
1546
1580
  states: {
1547
1581
  idle: {
1582
+ entry: ["onAutosave"],
1548
1583
  on: {
1549
- setActualItemsSize: { actions: ["recordActualItemSize", "onResize"] },
1550
1584
  dragHandleStart: { target: "dragging" },
1551
1585
  setPanelPixelSize: {
1552
1586
  actions: [
1553
1587
  "prepare",
1588
+ "onClearLastKnownSize",
1554
1589
  "onSetPanelSize",
1555
1590
  "commit",
1556
1591
  "onResize",
@@ -1578,7 +1613,9 @@ export const groupMachine = createMachine(
1578
1613
  dragging: {
1579
1614
  entry: ["prepare"],
1580
1615
  on: {
1581
- dragHandle: { actions: ["onDragHandle", "onResize"] },
1616
+ dragHandle: {
1617
+ actions: ["onClearLastKnownSize", "onDragHandle", "onResize"],
1618
+ },
1582
1619
  dragHandleEnd: { target: "idle" },
1583
1620
  collapsePanel: {
1584
1621
  guard: "shouldCollapseToggle",
@@ -1589,16 +1626,16 @@ export const groupMachine = createMachine(
1589
1626
  actions: "runCollapseToggle",
1590
1627
  },
1591
1628
  },
1592
- exit: ["commit", "onAutosave"],
1629
+ exit: ["commit"],
1593
1630
  },
1594
1631
  togglingCollapse: {
1595
- entry: ["prepare"],
1632
+ entry: ["prepare", "onClearLastKnownSize"],
1596
1633
  invoke: {
1597
1634
  src: "animation",
1598
1635
  input: (i) => ({ ...i, send: i.self.send }),
1599
1636
  onDone: {
1600
1637
  target: "idle",
1601
- actions: ["onToggleCollapseComplete", "commit", "onAutosave"],
1638
+ actions: ["onToggleCollapseComplete", "commit"],
1602
1639
  },
1603
1640
  },
1604
1641
  on: {
@@ -1607,25 +1644,43 @@ export const groupMachine = createMachine(
1607
1644
  },
1608
1645
  },
1609
1646
  on: {
1647
+ setActualItemsSize: { actions: ["recordActualItemSize", "onResize"] },
1610
1648
  registerPanel: { actions: ["assignPanelData"] },
1611
1649
  registerDynamicPanel: {
1612
1650
  actions: [
1613
1651
  "prepare",
1614
1652
  "onRegisterDynamicPanel",
1653
+ "onClearLastKnownSize",
1615
1654
  "commit",
1616
1655
  "onResize",
1617
1656
  "onAutosave",
1618
1657
  ],
1619
1658
  },
1620
1659
  unregisterPanel: {
1621
- actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1660
+ actions: [
1661
+ "prepare",
1662
+ "removeItem",
1663
+ "onClearLastKnownSize",
1664
+ "commit",
1665
+ "onResize",
1666
+ "onAutosave",
1667
+ ],
1622
1668
  },
1623
1669
  registerPanelHandle: { actions: ["assignPanelHandleData"] },
1624
1670
  unregisterPanelHandle: {
1625
- actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1671
+ actions: [
1672
+ "prepare",
1673
+ "removeItem",
1674
+ "onClearLastKnownSize",
1675
+ "commit",
1676
+ "onResize",
1677
+ "onAutosave",
1678
+ ],
1626
1679
  },
1627
1680
  setSize: { actions: ["updateSize", "onResize"] },
1628
- setOrientation: { actions: ["updateOrientation", "onResize"] },
1681
+ setOrientation: {
1682
+ actions: ["updateOrientation", "onClearLastKnownSize", "onResize"],
1683
+ },
1629
1684
  },
1630
1685
  },
1631
1686
  {
@@ -1677,6 +1732,26 @@ export const groupMachine = createMachine(
1677
1732
  animation: animationActor,
1678
1733
  },
1679
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
+ },
1680
1755
  notifyCollapseToggle: ({ context, event }) => {
1681
1756
  isEvent(event, ["collapsePanel", "expandPanel"]);
1682
1757
  const panel = getPanelWithId(context, event.panelId);
@@ -1703,8 +1778,7 @@ export const groupMachine = createMachine(
1703
1778
  }),
1704
1779
  onToggleCollapseComplete: assign({
1705
1780
  items: ({ context, event: e }) => {
1706
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1707
- const output = (e as any).output as AnimationActorOutput;
1781
+ const { output } = e as unknown as { output: AnimationActorOutput };
1708
1782
  invariant(output, "Expected output from animation actor");
1709
1783
 
1710
1784
  const panel = getPanelWithId(context, output.panelId);
@@ -1717,34 +1791,50 @@ export const groupMachine = createMachine(
1717
1791
  return context.items;
1718
1792
  },
1719
1793
  }),
1720
- updateSize: enqueueActions(({ context, event, enqueue }) => {
1721
- isEvent(event, ["setSize"]);
1722
-
1723
- if (event.handleOverflow) {
1724
- enqueue.assign(handleOverflow({ ...context, size: event.size }));
1725
- } else {
1726
- enqueue.assign({ size: event.size });
1727
- }
1794
+ updateSize: assign({
1795
+ size: ({ event }) => {
1796
+ isEvent(event, ["setSize"]);
1797
+ return event.size;
1798
+ },
1728
1799
  }),
1729
1800
  recordActualItemSize: assign({
1730
1801
  items: ({ context, event }) => {
1731
1802
  isEvent(event, ["setActualItemsSize"]);
1732
1803
 
1733
- 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;
1811
+
1812
+ for (const item of withLastKnownSize) {
1813
+ if (isPanelData(item)) {
1814
+ const size =
1815
+ item.lastKnownSize?.[
1816
+ context.orientation === "horizontal" ? "width" : "height"
1817
+ ];
1734
1818
 
1735
- for (const [id, size] of Object.entries(event.childrenSizes)) {
1736
- const item = context.items.find((i) => i.id === id);
1819
+ // If any size is 0 don't handle overflow
1820
+ if (!size) {
1821
+ return withLastKnownSize;
1822
+ }
1737
1823
 
1738
- if (!isPanelData(item)) {
1739
- continue;
1824
+ totalSize += size;
1825
+ } else {
1826
+ totalSize += item.size.value.toNumber();
1740
1827
  }
1828
+ }
1741
1829
 
1742
- item.currentValue = makePixelUnit(
1743
- orientation === "horizontal" ? size.width : size.height
1744
- );
1830
+ if (totalSize > getGroupSize(context)) {
1831
+ return handleOverflow({
1832
+ ...context,
1833
+ items: prepareItems({ ...context, items: withLastKnownSize }),
1834
+ }).items;
1745
1835
  }
1746
1836
 
1747
- return commitLayout(context);
1837
+ return withLastKnownSize;
1748
1838
  },
1749
1839
  }),
1750
1840
  updateOrientation: assign({
@@ -1753,6 +1843,9 @@ export const groupMachine = createMachine(
1753
1843
  return event.orientation;
1754
1844
  },
1755
1845
  }),
1846
+ onClearLastKnownSize: assign({
1847
+ items: ({ context }) => clearLastKnownSize(context.items),
1848
+ }),
1756
1849
  assignPanelData: assign({
1757
1850
  items: ({ context, event }) => {
1758
1851
  isEvent(event, ["registerPanel"]);
@@ -1903,11 +1996,17 @@ export const groupMachine = createMachine(
1903
1996
  onResize: ({ context }) => {
1904
1997
  for (const item of context.items) {
1905
1998
  if (isPanelData(item)) {
1906
- const pixel = clampUnit(
1907
- context,
1908
- item,
1909
- getUnitPixelValue(context, item.currentValue)
1910
- );
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
+ );
1911
2010
  const groupSize = getGroupSize(context);
1912
2011
 
1913
2012
  item.onResize?.current?.({