@window-splitter/state 0.2.5 → 0.3.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
@@ -23,12 +23,12 @@ export type PercentUnit = `${number}%`;
23
23
  export type Unit = PixelUnit | PercentUnit;
24
24
  type Orientation = "horizontal" | "vertical";
25
25
 
26
- interface ParsedPercentUnit {
26
+ export interface ParsedPercentUnit {
27
27
  type: "percent";
28
28
  value: Big.Big;
29
29
  }
30
30
 
31
- interface ParsedPixelUnit {
31
+ export interface ParsedPixelUnit {
32
32
  type: "pixel";
33
33
  value: Big.Big;
34
34
  }
@@ -88,6 +88,10 @@ export interface PanelData
88
88
  onCollapseChange?: {
89
89
  current: ((isCollapsed: boolean) => void) | null | undefined;
90
90
  };
91
+ /** A ref to the latest "onResize" function provided by the user */
92
+ onResize?: {
93
+ current: OnResizeCallback | null | undefined;
94
+ };
91
95
  /**
92
96
  * The current value for the item in the grid
93
97
  */
@@ -113,8 +117,8 @@ function getCollapseAnimation(panel: PanelData) {
113
117
  if (panel.collapseAnimation) {
114
118
  if (typeof panel.collapseAnimation === "string") {
115
119
  easeFn = collapseAnimations[panel.collapseAnimation];
116
- } else if ("duration" in panel.collapseAnimation) {
117
- duration = panel.collapseAnimation.duration ?? duration;
120
+ } else {
121
+ duration = panel.collapseAnimation.duration;
118
122
  easeFn =
119
123
  typeof panel.collapseAnimation.easing === "function"
120
124
  ? panel.collapseAnimation.easing
@@ -318,6 +322,28 @@ type EventForType<T extends GroupMachineEvent["type"]> = Extract<
318
322
 
319
323
  // #region Helpers
320
324
 
325
+ export function getCursor(
326
+ context: Pick<GroupMachineContextValue, "dragOvershoot" | "orientation">
327
+ ) {
328
+ if (context.orientation === "horizontal") {
329
+ if (context.dragOvershoot.gt(0)) {
330
+ return "w-resize";
331
+ } else if (context.dragOvershoot.lt(0)) {
332
+ return "e-resize";
333
+ } else {
334
+ return "ew-resize";
335
+ }
336
+ } else {
337
+ if (context.dragOvershoot.gt(0)) {
338
+ return "n-resize";
339
+ } else if (context.dragOvershoot.lt(0)) {
340
+ return "s-resize";
341
+ } else {
342
+ return "ns-resize";
343
+ }
344
+ }
345
+ }
346
+
321
347
  export function prepareSnapshot(snapshot: Snapshot<unknown>) {
322
348
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
323
349
  const snapshotContext = (snapshot as any)
@@ -328,14 +354,8 @@ export function prepareSnapshot(snapshot: Snapshot<unknown>) {
328
354
  for (const item of snapshotContext.items) {
329
355
  if (isPanelData(item)) {
330
356
  item.currentValue.value = new Big(item.currentValue.value);
331
-
332
- if (item.collapsedSize) {
333
- item.collapsedSize.value = new Big(item.collapsedSize.value);
334
- }
335
-
336
- if (item.min) {
337
- item.min.value = new Big(item.min.value);
338
- }
357
+ item.collapsedSize.value = new Big(item.collapsedSize.value);
358
+ item.min.value = new Big(item.min.value);
339
359
 
340
360
  if (item.max && item.max !== "1fr") {
341
361
  item.max.value = new Big(item.max.value);
@@ -379,6 +399,13 @@ export function isPanelHandle(value: unknown): value is PanelHandleData {
379
399
  );
380
400
  }
381
401
 
402
+ type OnResizeSize = {
403
+ pixel: number;
404
+ percentage: number;
405
+ };
406
+
407
+ export type OnResizeCallback = (size: OnResizeSize) => void;
408
+
382
409
  interface InitializePanelOptions {
383
410
  min?: Unit;
384
411
  max?: Unit;
@@ -389,6 +416,9 @@ interface InitializePanelOptions {
389
416
  onCollapseChange?: {
390
417
  current: ((isCollapsed: boolean) => void) | null | undefined;
391
418
  };
419
+ onResize?: {
420
+ current: OnResizeCallback | null | undefined;
421
+ };
392
422
  collapseAnimation?: PanelData["collapseAnimation"];
393
423
  defaultCollapsed?: boolean;
394
424
  id?: string;
@@ -403,6 +433,25 @@ export function initializePanel(
403
433
  export function initializePanel(
404
434
  item: InitializePanelOptions | InitializePanelOptionsWithId
405
435
  ): PanelData | Omit<PanelData, "id"> {
436
+ const onResize = () => {
437
+ let lastCall: OnResizeSize | null = null;
438
+
439
+ // Memo-ize so we only call the callback once per size
440
+ return ((size) => {
441
+ if (
442
+ !lastCall ||
443
+ (lastCall.pixel === size.pixel &&
444
+ lastCall.percentage === size.percentage)
445
+ ) {
446
+ lastCall = size;
447
+ return;
448
+ }
449
+
450
+ lastCall = size;
451
+ item.onResize?.current?.(size);
452
+ }) satisfies OnResizeCallback;
453
+ };
454
+
406
455
  const data = {
407
456
  type: "panel" as const,
408
457
  min: parseUnit(item.min || "0px"),
@@ -413,6 +462,7 @@ export function initializePanel(
413
462
  collapsible: item.collapsible,
414
463
  collapsedSize: parseUnit(item.collapsedSize ?? "0px"),
415
464
  onCollapseChange: item.onCollapseChange,
465
+ onResize: { current: onResize() },
416
466
  collapseIsControlled: typeof item.collapsed !== "undefined",
417
467
  sizeBeforeCollapse: undefined,
418
468
  id: item.id,
@@ -470,7 +520,7 @@ export function getGroupSize(context: GroupMachineContextValue) {
470
520
  }
471
521
 
472
522
  /** Get the size of a panel in pixels */
473
- export function getUnitPixelValue(
523
+ function getUnitPixelValue(
474
524
  context: GroupMachineContextValue,
475
525
  unit: ParsedUnit | "1fr"
476
526
  ) {
@@ -696,6 +746,52 @@ function formatUnit(unit: ParsedUnit): Unit {
696
746
  return `${unit.value.toNumber()}%`;
697
747
  }
698
748
 
749
+ export function getPanelGroupPixelSizes(context: GroupMachineContextValue) {
750
+ return prepareItems(context).map((i) =>
751
+ isPanelData(i)
752
+ ? i.currentValue.value.toNumber()
753
+ : getUnitPixelValue(context, i.size).toNumber()
754
+ );
755
+ }
756
+
757
+ export function getPanelPixelSize(
758
+ context: GroupMachineContextValue,
759
+ panelId: string
760
+ ) {
761
+ const p = getPanelWithId(
762
+ { ...context, items: prepareItems(context) },
763
+ panelId
764
+ );
765
+
766
+ return p.currentValue.value.toNumber();
767
+ }
768
+
769
+ export function getPanelGroupPercentageSizes(
770
+ context: GroupMachineContextValue
771
+ ) {
772
+ const clamped = commitLayout({
773
+ ...context,
774
+ items: prepareItems(context),
775
+ });
776
+
777
+ return clamped.map((i) => {
778
+ if (isPanelHandle(i)) {
779
+ return getUnitPercentageValue(getGroupSize(context), i.size);
780
+ }
781
+
782
+ return getUnitPercentageValue(getGroupSize(context), i.currentValue);
783
+ });
784
+ }
785
+
786
+ export function getPanelPercentageSize(
787
+ context: GroupMachineContextValue,
788
+ panelId: string
789
+ ) {
790
+ const items = prepareItems(context);
791
+ const p = getPanelWithId({ ...context, items }, panelId);
792
+ return getUnitPercentageValue(getGroupSize(context), p.currentValue);
793
+ }
794
+
699
795
  /** Build the grid template from the item values. */
700
796
  export function buildTemplate(context: GroupMachineContextValue) {
701
797
  const staticWidth = getStaticWidth(context);
@@ -709,10 +805,6 @@ export function buildTemplate(context: GroupMachineContextValue) {
709
805
  item.currentValue.type === "pixel" &&
710
806
  item.currentValue.value.toNumber() !== -1
711
807
  ) {
712
- if (item.currentValue.value.toNumber() < 0) {
713
- return "0px";
714
- }
715
-
716
808
  return formatUnit(item.currentValue);
717
809
  } else if (item.currentValue.type === "percent") {
718
810
  const max = item.max === "1fr" ? "100%" : formatUnit(item.max);
@@ -811,15 +903,17 @@ function createUnrestrainedPanel(_: GroupMachineContextValue, data: PanelData) {
811
903
 
812
904
  /** Converts the items to pixels */
813
905
  export function prepareItems(context: GroupMachineContextValue) {
814
- const newItems = [...context.items];
815
906
  const staticWidth = getStaticWidth(context);
907
+ const newItems = [];
816
908
 
817
- for (const item of newItems) {
909
+ for (const item of context.items) {
818
910
  if (!item || !isPanelData(item)) {
911
+ newItems.push(item);
819
912
  continue;
820
913
  }
821
914
 
822
915
  if (item.currentValue.type === "pixel") {
916
+ newItems.push(item);
823
917
  continue;
824
918
  }
825
919
 
@@ -827,7 +921,10 @@ export function prepareItems(context: GroupMachineContextValue) {
827
921
  .minus(staticWidth)
828
922
  .mul(item.currentValue.value);
829
923
 
830
- item.currentValue = makePixelUnit(pixel.toNumber());
924
+ newItems.push({
925
+ ...item,
926
+ currentValue: makePixelUnit(pixel.toNumber()),
927
+ });
831
928
  }
832
929
 
833
930
  return newItems;
@@ -1072,7 +1169,7 @@ function updateLayout(
1072
1169
  )
1073
1170
  );
1074
1171
 
1075
- if (leftoverSpace.gt(0)) {
1172
+ if (!leftoverSpace.eq(0)) {
1076
1173
  panelBefore.currentValue.value =
1077
1174
  panelBefore.currentValue.value.add(leftoverSpace);
1078
1175
  }
@@ -1081,7 +1178,7 @@ function updateLayout(
1081
1178
  }
1082
1179
 
1083
1180
  /** Converts the items to percentages */
1084
- export function commitLayout(context: GroupMachineContextValue) {
1181
+ function commitLayout(context: GroupMachineContextValue) {
1085
1182
  const newItems = [...context.items];
1086
1183
 
1087
1184
  // First set all the static width
@@ -1327,7 +1424,13 @@ export const groupMachine = createMachine(
1327
1424
  setActualItemsSize: { actions: ["recordActualItemSize"] },
1328
1425
  dragHandleStart: { target: "dragging" },
1329
1426
  setPanelPixelSize: {
1330
- actions: ["prepare", "onSetPanelSize", "commit"],
1427
+ actions: [
1428
+ "prepare",
1429
+ "onSetPanelSize",
1430
+ "commit",
1431
+ "onResize",
1432
+ "onAutosave",
1433
+ ],
1331
1434
  },
1332
1435
  collapsePanel: [
1333
1436
  {
@@ -1348,7 +1451,7 @@ export const groupMachine = createMachine(
1348
1451
  dragging: {
1349
1452
  entry: ["prepare"],
1350
1453
  on: {
1351
- dragHandle: { actions: ["onDragHandle"] },
1454
+ dragHandle: { actions: ["onDragHandle", "onResize"] },
1352
1455
  dragHandleEnd: { target: "idle" },
1353
1456
  collapsePanel: {
1354
1457
  guard: "shouldCollapseToggle",
@@ -1372,24 +1475,30 @@ export const groupMachine = createMachine(
1372
1475
  },
1373
1476
  },
1374
1477
  on: {
1375
- applyDelta: { actions: ["onApplyDelta"] },
1478
+ applyDelta: { actions: ["onApplyDelta", "onResize"] },
1376
1479
  },
1377
1480
  },
1378
1481
  },
1379
1482
  on: {
1380
1483
  registerPanel: { actions: ["assignPanelData"] },
1381
1484
  registerDynamicPanel: {
1382
- actions: ["prepare", "onRegisterDynamicPanel", "commit", "onAutosave"],
1485
+ actions: [
1486
+ "prepare",
1487
+ "onRegisterDynamicPanel",
1488
+ "commit",
1489
+ "onResize",
1490
+ "onAutosave",
1491
+ ],
1383
1492
  },
1384
1493
  unregisterPanel: {
1385
- actions: ["prepare", "removeItem", "commit", "onAutosave"],
1494
+ actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1386
1495
  },
1387
1496
  registerPanelHandle: { actions: ["assignPanelHandleData"] },
1388
1497
  unregisterPanelHandle: {
1389
- actions: ["prepare", "removeItem", "commit", "onAutosave"],
1498
+ actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1390
1499
  },
1391
- setSize: { actions: ["updateSize"] },
1392
- setOrientation: { actions: ["updateOrientation"] },
1500
+ setSize: { actions: ["updateSize", "onResize"] },
1501
+ setOrientation: { actions: ["updateOrientation", "onResize"] },
1393
1502
  },
1394
1503
  },
1395
1504
  {
@@ -1629,6 +1738,19 @@ export const groupMachine = createMachine(
1629
1738
  })
1630
1739
  );
1631
1740
  }),
1741
+ onResize: ({ context }) => {
1742
+ for (const item of context.items) {
1743
+ if (isPanelData(item)) {
1744
+ item.onResize?.current?.({
1745
+ pixel: getUnitPixelValue(context, item.currentValue).toNumber(),
1746
+ percentage: getUnitPercentageValue(
1747
+ getGroupSize(context),
1748
+ item.currentValue
1749
+ ),
1750
+ });
1751
+ }
1752
+ }
1753
+ },
1632
1754
  },
1633
1755
  }
1634
1756
  );