@window-splitter/state 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);
@@ -1072,7 +1164,7 @@ function updateLayout(
1072
1164
  )
1073
1165
  );
1074
1166
 
1075
- if (leftoverSpace.gt(0)) {
1167
+ if (!leftoverSpace.eq(0)) {
1076
1168
  panelBefore.currentValue.value =
1077
1169
  panelBefore.currentValue.value.add(leftoverSpace);
1078
1170
  }
@@ -1081,7 +1173,7 @@ function updateLayout(
1081
1173
  }
1082
1174
 
1083
1175
  /** Converts the items to percentages */
1084
- export function commitLayout(context: GroupMachineContextValue) {
1176
+ function commitLayout(context: GroupMachineContextValue) {
1085
1177
  const newItems = [...context.items];
1086
1178
 
1087
1179
  // First set all the static width
@@ -1327,7 +1419,13 @@ export const groupMachine = createMachine(
1327
1419
  setActualItemsSize: { actions: ["recordActualItemSize"] },
1328
1420
  dragHandleStart: { target: "dragging" },
1329
1421
  setPanelPixelSize: {
1330
- actions: ["prepare", "onSetPanelSize", "commit"],
1422
+ actions: [
1423
+ "prepare",
1424
+ "onSetPanelSize",
1425
+ "commit",
1426
+ "onResize",
1427
+ "onAutosave",
1428
+ ],
1331
1429
  },
1332
1430
  collapsePanel: [
1333
1431
  {
@@ -1348,7 +1446,7 @@ export const groupMachine = createMachine(
1348
1446
  dragging: {
1349
1447
  entry: ["prepare"],
1350
1448
  on: {
1351
- dragHandle: { actions: ["onDragHandle"] },
1449
+ dragHandle: { actions: ["onDragHandle", "onResize"] },
1352
1450
  dragHandleEnd: { target: "idle" },
1353
1451
  collapsePanel: {
1354
1452
  guard: "shouldCollapseToggle",
@@ -1372,24 +1470,30 @@ export const groupMachine = createMachine(
1372
1470
  },
1373
1471
  },
1374
1472
  on: {
1375
- applyDelta: { actions: ["onApplyDelta"] },
1473
+ applyDelta: { actions: ["onApplyDelta", "onResize"] },
1376
1474
  },
1377
1475
  },
1378
1476
  },
1379
1477
  on: {
1380
1478
  registerPanel: { actions: ["assignPanelData"] },
1381
1479
  registerDynamicPanel: {
1382
- actions: ["prepare", "onRegisterDynamicPanel", "commit", "onAutosave"],
1480
+ actions: [
1481
+ "prepare",
1482
+ "onRegisterDynamicPanel",
1483
+ "commit",
1484
+ "onResize",
1485
+ "onAutosave",
1486
+ ],
1383
1487
  },
1384
1488
  unregisterPanel: {
1385
- actions: ["prepare", "removeItem", "commit", "onAutosave"],
1489
+ actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1386
1490
  },
1387
1491
  registerPanelHandle: { actions: ["assignPanelHandleData"] },
1388
1492
  unregisterPanelHandle: {
1389
- actions: ["prepare", "removeItem", "commit", "onAutosave"],
1493
+ actions: ["prepare", "removeItem", "commit", "onResize", "onAutosave"],
1390
1494
  },
1391
- setSize: { actions: ["updateSize"] },
1392
- setOrientation: { actions: ["updateOrientation"] },
1495
+ setSize: { actions: ["updateSize", "onResize"] },
1496
+ setOrientation: { actions: ["updateOrientation", "onResize"] },
1393
1497
  },
1394
1498
  },
1395
1499
  {
@@ -1629,6 +1733,19 @@ export const groupMachine = createMachine(
1629
1733
  })
1630
1734
  );
1631
1735
  }),
1736
+ onResize: ({ context }) => {
1737
+ for (const item of context.items) {
1738
+ if (isPanelData(item)) {
1739
+ item.onResize?.current?.({
1740
+ pixel: getUnitPixelValue(context, item.currentValue).toNumber(),
1741
+ percentage: getUnitPercentageValue(
1742
+ getGroupSize(context),
1743
+ item.currentValue
1744
+ ),
1745
+ });
1746
+ }
1747
+ }
1748
+ },
1632
1749
  },
1633
1750
  }
1634
1751
  );