@window-splitter/interface 0.7.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.
Files changed (57) hide show
  1. package/.tshy/build.json +8 -0
  2. package/.tshy/commonjs.json +18 -0
  3. package/.tshy/esm.json +17 -0
  4. package/.turbo/turbo-build.log +5 -0
  5. package/.turbo/turbo-lint.log +5 -0
  6. package/CHANGELOG.md +44 -0
  7. package/README.md +3 -0
  8. package/dist/commonjs/index.d.ts +4 -0
  9. package/dist/commonjs/index.d.ts.map +1 -0
  10. package/dist/commonjs/index.js +20 -0
  11. package/dist/commonjs/index.js.map +1 -0
  12. package/dist/commonjs/interface.d.ts +128 -0
  13. package/dist/commonjs/interface.d.ts.map +1 -0
  14. package/dist/commonjs/interface.js +67 -0
  15. package/dist/commonjs/interface.js.map +1 -0
  16. package/dist/commonjs/mergeAttributes.d.ts +19 -0
  17. package/dist/commonjs/mergeAttributes.d.ts.map +1 -0
  18. package/dist/commonjs/mergeAttributes.js +63 -0
  19. package/dist/commonjs/mergeAttributes.js.map +1 -0
  20. package/dist/commonjs/move.d.ts +52 -0
  21. package/dist/commonjs/move.d.ts.map +1 -0
  22. package/dist/commonjs/move.js +124 -0
  23. package/dist/commonjs/move.js.map +1 -0
  24. package/dist/commonjs/package.json +3 -0
  25. package/dist/commonjs/test.d.ts +18 -0
  26. package/dist/commonjs/test.d.ts.map +1 -0
  27. package/dist/commonjs/test.js +85 -0
  28. package/dist/commonjs/test.js.map +1 -0
  29. package/dist/esm/index.d.ts +4 -0
  30. package/dist/esm/index.d.ts.map +1 -0
  31. package/dist/esm/index.js +4 -0
  32. package/dist/esm/index.js.map +1 -0
  33. package/dist/esm/interface.d.ts +128 -0
  34. package/dist/esm/interface.d.ts.map +1 -0
  35. package/dist/esm/interface.js +62 -0
  36. package/dist/esm/interface.js.map +1 -0
  37. package/dist/esm/mergeAttributes.d.ts +19 -0
  38. package/dist/esm/mergeAttributes.d.ts.map +1 -0
  39. package/dist/esm/mergeAttributes.js +60 -0
  40. package/dist/esm/mergeAttributes.js.map +1 -0
  41. package/dist/esm/move.d.ts +52 -0
  42. package/dist/esm/move.d.ts.map +1 -0
  43. package/dist/esm/move.js +121 -0
  44. package/dist/esm/move.js.map +1 -0
  45. package/dist/esm/package.json +3 -0
  46. package/dist/esm/test.d.ts +18 -0
  47. package/dist/esm/test.d.ts.map +1 -0
  48. package/dist/esm/test.js +81 -0
  49. package/dist/esm/test.js.map +1 -0
  50. package/eslint.config.js +3 -0
  51. package/package.json +83 -0
  52. package/src/index.ts +3 -0
  53. package/src/interface.ts +214 -0
  54. package/src/mergeAttributes.ts +84 -0
  55. package/src/move.ts +210 -0
  56. package/src/test.ts +133 -0
  57. package/tsconfig.json +6 -0
@@ -0,0 +1,121 @@
1
+ // import {disableTextSelection, restoreTextSelection} from './textSelection';
2
+ /**
3
+ * Handles move interactions across mouse, touch, and keyboard, including dragging with
4
+ * the mouse or touch, and using the arrow keys. Normalizes behavior across browsers and
5
+ * platforms, and ignores emulated mouse events on touch devices.
6
+ */
7
+ export function move(props) {
8
+ const { onMoveStart, onMove: onMoveProp, onMoveEnd } = props;
9
+ const state = { didMove: false, lastPosition: null, id: null };
10
+ const onMove = (originalEvent, pointerType, deltaX, deltaY) => {
11
+ if (deltaX === 0 && deltaY === 0) {
12
+ return;
13
+ }
14
+ if (!state.didMove) {
15
+ state.didMove = true;
16
+ onMoveStart?.({
17
+ type: "movestart",
18
+ pointerType,
19
+ shiftKey: originalEvent.shiftKey,
20
+ metaKey: originalEvent.metaKey,
21
+ ctrlKey: originalEvent.ctrlKey,
22
+ altKey: originalEvent.altKey,
23
+ });
24
+ }
25
+ onMoveProp?.({
26
+ type: "move",
27
+ pointerType,
28
+ deltaX: deltaX,
29
+ deltaY: deltaY,
30
+ shiftKey: originalEvent.shiftKey,
31
+ metaKey: originalEvent.metaKey,
32
+ ctrlKey: originalEvent.ctrlKey,
33
+ altKey: originalEvent.altKey,
34
+ });
35
+ };
36
+ const end = (originalEvent, pointerType) => {
37
+ // restoreTextSelection();
38
+ if (state.didMove) {
39
+ onMoveEnd?.({
40
+ type: "moveend",
41
+ pointerType,
42
+ shiftKey: originalEvent.shiftKey,
43
+ metaKey: originalEvent.metaKey,
44
+ ctrlKey: originalEvent.ctrlKey,
45
+ altKey: originalEvent.altKey,
46
+ });
47
+ }
48
+ };
49
+ const moveProps = {};
50
+ const start = () => {
51
+ // disableTextSelection();
52
+ state.didMove = false;
53
+ };
54
+ const onPointerMove = (e) => {
55
+ if (e.pointerId === state.id) {
56
+ const pointerType = (e.pointerType || "mouse");
57
+ // Problems with PointerEvent#movementX/movementY:
58
+ // 1. it is always 0 on macOS Safari.
59
+ // 2. On Chrome Android, it's scaled by devicePixelRatio, but not on Chrome macOS
60
+ onMove(e, pointerType, e.pageX - (state.lastPosition?.pageX ?? 0), e.pageY - (state.lastPosition?.pageY ?? 0));
61
+ state.lastPosition = { pageX: e.pageX, pageY: e.pageY };
62
+ }
63
+ };
64
+ const onPointerUp = (e) => {
65
+ if (e.pointerId === state.id) {
66
+ const pointerType = (e.pointerType || "mouse");
67
+ end(e, pointerType);
68
+ state.id = null;
69
+ window.removeEventListener("pointermove", onPointerMove, false);
70
+ window.removeEventListener("pointerup", onPointerUp, false);
71
+ window.removeEventListener("pointercancel", onPointerUp, false);
72
+ }
73
+ };
74
+ moveProps.onPointerDown = (e) => {
75
+ if (e.button === 0 && state.id == null) {
76
+ start();
77
+ e.stopPropagation();
78
+ e.preventDefault();
79
+ state.lastPosition = { pageX: e.pageX, pageY: e.pageY };
80
+ state.id = e.pointerId;
81
+ window.addEventListener("pointermove", onPointerMove, false);
82
+ window.addEventListener("pointerup", onPointerUp, false);
83
+ window.addEventListener("pointercancel", onPointerUp, false);
84
+ }
85
+ };
86
+ const triggerKeyboardMove = (e, deltaX, deltaY) => {
87
+ start();
88
+ onMove(e, "keyboard", deltaX, deltaY);
89
+ end(e, "keyboard");
90
+ };
91
+ moveProps.onKeyDown = (e) => {
92
+ switch (e.key) {
93
+ case "Left":
94
+ case "ArrowLeft":
95
+ e.preventDefault();
96
+ e.stopPropagation();
97
+ triggerKeyboardMove(e, -1, 0);
98
+ break;
99
+ case "Right":
100
+ case "ArrowRight":
101
+ e.preventDefault();
102
+ e.stopPropagation();
103
+ triggerKeyboardMove(e, 1, 0);
104
+ break;
105
+ case "Up":
106
+ case "ArrowUp":
107
+ e.preventDefault();
108
+ e.stopPropagation();
109
+ triggerKeyboardMove(e, 0, -1);
110
+ break;
111
+ case "Down":
112
+ case "ArrowDown":
113
+ e.preventDefault();
114
+ e.stopPropagation();
115
+ triggerKeyboardMove(e, 0, 1);
116
+ break;
117
+ }
118
+ };
119
+ return { moveProps: moveProps };
120
+ }
121
+ //# sourceMappingURL=move.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move.js","sourceRoot":"","sources":["../../src/move.ts"],"names":[],"mappings":"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","sourcesContent":["// import {disableTextSelection, restoreTextSelection} from './textSelection';\n\nexport interface MoveResult {\n /** Props to spread on the target element. */\n moveProps: {\n onPointerDown: (e: PointerEvent) => void;\n onKeyDown: (e: KeyboardEvent) => void;\n };\n}\n\ninterface EventBase {\n shiftKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n altKey: boolean;\n}\n\ntype PointerType = \"mouse\" | \"pen\" | \"touch\" | \"keyboard\" | \"virtual\";\n\ninterface BaseMoveEvent {\n /** The pointer type that triggered the move event. */\n pointerType: PointerType;\n /** Whether the shift keyboard modifier was held during the move event. */\n shiftKey: boolean;\n /** Whether the ctrl keyboard modifier was held during the move event. */\n ctrlKey: boolean;\n /** Whether the meta keyboard modifier was held during the move event. */\n metaKey: boolean;\n /** Whether the alt keyboard modifier was held during the move event. */\n altKey: boolean;\n}\n\ninterface MoveStartEvent extends BaseMoveEvent {\n /** The type of move event being fired. */\n type: \"movestart\";\n}\n\ninterface MoveMoveEvent extends BaseMoveEvent {\n /** The type of move event being fired. */\n type: \"move\";\n /** The amount moved in the X direction since the last event. */\n deltaX: number;\n /** The amount moved in the Y direction since the last event. */\n deltaY: number;\n}\n\ninterface MoveEndEvent extends BaseMoveEvent {\n /** The type of move event being fired. */\n type: \"moveend\";\n}\n\nexport interface MoveEvents {\n /** Handler that is called when a move interaction starts. */\n onMoveStart?: (e: MoveStartEvent) => void;\n /** Handler that is called when the element is moved. */\n onMove?: (e: MoveMoveEvent) => void;\n /** Handler that is called when a move interaction ends. */\n onMoveEnd?: (e: MoveEndEvent) => void;\n}\n\n/**\n * Handles move interactions across mouse, touch, and keyboard, including dragging with\n * the mouse or touch, and using the arrow keys. Normalizes behavior across browsers and\n * platforms, and ignores emulated mouse events on touch devices.\n */\nexport function move(props: MoveEvents): MoveResult {\n const { onMoveStart, onMove: onMoveProp, onMoveEnd } = props;\n\n const state = { didMove: false, lastPosition: null, id: null } as {\n didMove: boolean;\n lastPosition: { pageX: number; pageY: number } | null;\n id: number | null;\n };\n\n const onMove = (\n originalEvent: EventBase,\n pointerType: PointerType,\n deltaX: number,\n deltaY: number\n ) => {\n if (deltaX === 0 && deltaY === 0) {\n return;\n }\n\n if (!state.didMove) {\n state.didMove = true;\n onMoveStart?.({\n type: \"movestart\",\n pointerType,\n shiftKey: originalEvent.shiftKey,\n metaKey: originalEvent.metaKey,\n ctrlKey: originalEvent.ctrlKey,\n altKey: originalEvent.altKey,\n });\n }\n onMoveProp?.({\n type: \"move\",\n pointerType,\n deltaX: deltaX,\n deltaY: deltaY,\n shiftKey: originalEvent.shiftKey,\n metaKey: originalEvent.metaKey,\n ctrlKey: originalEvent.ctrlKey,\n altKey: originalEvent.altKey,\n });\n };\n\n const end = (originalEvent: EventBase, pointerType: PointerType) => {\n // restoreTextSelection();\n if (state.didMove) {\n onMoveEnd?.({\n type: \"moveend\",\n pointerType,\n shiftKey: originalEvent.shiftKey,\n metaKey: originalEvent.metaKey,\n ctrlKey: originalEvent.ctrlKey,\n altKey: originalEvent.altKey,\n });\n }\n };\n\n const moveProps: Partial<MoveResult[\"moveProps\"]> = {};\n\n const start = () => {\n // disableTextSelection();\n state.didMove = false;\n };\n\n const onPointerMove = (e: PointerEvent) => {\n if (e.pointerId === state.id) {\n const pointerType = (e.pointerType || \"mouse\") as PointerType;\n\n // Problems with PointerEvent#movementX/movementY:\n // 1. it is always 0 on macOS Safari.\n // 2. On Chrome Android, it's scaled by devicePixelRatio, but not on Chrome macOS\n onMove(\n e,\n pointerType,\n e.pageX - (state.lastPosition?.pageX ?? 0),\n e.pageY - (state.lastPosition?.pageY ?? 0)\n );\n state.lastPosition = { pageX: e.pageX, pageY: e.pageY };\n }\n };\n\n const onPointerUp = (e: PointerEvent) => {\n if (e.pointerId === state.id) {\n const pointerType = (e.pointerType || \"mouse\") as PointerType;\n end(e, pointerType);\n state.id = null;\n window.removeEventListener(\"pointermove\", onPointerMove, false);\n window.removeEventListener(\"pointerup\", onPointerUp, false);\n window.removeEventListener(\"pointercancel\", onPointerUp, false);\n }\n };\n\n moveProps.onPointerDown = (e) => {\n if (e.button === 0 && state.id == null) {\n start();\n e.stopPropagation();\n e.preventDefault();\n state.lastPosition = { pageX: e.pageX, pageY: e.pageY };\n state.id = e.pointerId;\n window.addEventListener(\"pointermove\", onPointerMove, false);\n window.addEventListener(\"pointerup\", onPointerUp, false);\n window.addEventListener(\"pointercancel\", onPointerUp, false);\n }\n };\n\n const triggerKeyboardMove = (\n e: EventBase,\n deltaX: number,\n deltaY: number\n ) => {\n start();\n onMove(e, \"keyboard\", deltaX, deltaY);\n end(e, \"keyboard\");\n };\n\n moveProps.onKeyDown = (e) => {\n switch (e.key) {\n case \"Left\":\n case \"ArrowLeft\":\n e.preventDefault();\n e.stopPropagation();\n triggerKeyboardMove(e, -1, 0);\n break;\n case \"Right\":\n case \"ArrowRight\":\n e.preventDefault();\n e.stopPropagation();\n triggerKeyboardMove(e, 1, 0);\n break;\n case \"Up\":\n case \"ArrowUp\":\n e.preventDefault();\n e.stopPropagation();\n triggerKeyboardMove(e, 0, -1);\n break;\n case \"Down\":\n case \"ArrowDown\":\n e.preventDefault();\n e.stopPropagation();\n triggerKeyboardMove(e, 0, 1);\n break;\n }\n };\n\n return { moveProps: moveProps as MoveResult[\"moveProps\"] };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,18 @@
1
+ import { PanelGroupHandle } from "./interface.js";
2
+ export declare function dragHandle(options: {
3
+ handleId?: string;
4
+ delta: number;
5
+ orientation?: "horizontal" | "vertical";
6
+ }): Promise<void>;
7
+ type WaitForFn = <T>(callback: () => T | Promise<T>, options?: {
8
+ timeout?: number;
9
+ }) => Promise<T>;
10
+ export declare function createTestUtils(options: {
11
+ waitFor: WaitForFn;
12
+ }): {
13
+ waitForCondition: (condition: () => boolean) => Promise<void>;
14
+ waitForMeasurement: (handle: PanelGroupHandle) => Promise<void>;
15
+ expectTemplate: (handle: PanelGroupHandle, resolvedTemplate: string) => Promise<void>;
16
+ };
17
+ export {};
18
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,wBAAsB,UAAU,CAAC,OAAO,EAAE;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;CACzC,iBAgDA;AAED,KAAK,SAAS,GAAG,CAAC,CAAC,EACjB,QAAQ,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KACE,OAAO,CAAC,CAAC,CAAC,CAAC;AAgEhB,wBAAgB,eAAe,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE;wCA9DA,OAAO;;;EAoErE"}
@@ -0,0 +1,81 @@
1
+ import { expect } from "vitest";
2
+ export async function dragHandle(options) {
3
+ const orientation = options.orientation || "horizontal";
4
+ const handle = document.querySelector(options.handleId
5
+ ? `[data-splitter-id="${options.handleId}"]`
6
+ : '[data-splitter-type="handle"]');
7
+ if (!handle) {
8
+ throw new Error(`Handle not found: ${options.handleId}`);
9
+ }
10
+ const rect = handle.getBoundingClientRect();
11
+ const x = rect.x + rect.width / 2;
12
+ const y = rect.y + rect.height / 2;
13
+ const step = options.delta > 0 ? 1 : -1;
14
+ const pointerId = 1;
15
+ handle.dispatchEvent(new PointerEvent("pointerdown", {
16
+ bubbles: true,
17
+ clientX: x,
18
+ clientY: y,
19
+ pointerId,
20
+ button: 0,
21
+ }));
22
+ for (let i = 0; i < Math.abs(options.delta - 1); i++) {
23
+ handle.dispatchEvent(new PointerEvent("pointermove", {
24
+ bubbles: true,
25
+ pointerId,
26
+ clientX: orientation === "horizontal" ? x + i * step : x,
27
+ clientY: orientation === "vertical" ? y + i * step : y,
28
+ }));
29
+ await new Promise((r) => setTimeout(r, 10));
30
+ }
31
+ handle.dispatchEvent(new PointerEvent("pointerup", {
32
+ bubbles: true,
33
+ pointerId,
34
+ clientX: orientation === "horizontal" ? x + options.delta : x,
35
+ clientY: orientation === "vertical" ? y + options.delta : y,
36
+ }));
37
+ }
38
+ function waitForCondition(waitFor, condition) {
39
+ const stack = new Error().stack;
40
+ return waitFor(() => {
41
+ if (!condition()) {
42
+ const error = new Error("Not ready");
43
+ error.stack = stack;
44
+ throw error;
45
+ }
46
+ }, {
47
+ timeout: 10_000,
48
+ });
49
+ }
50
+ async function waitForMeasurement(waitFor, handle) {
51
+ await waitForCondition(waitFor, () => !handle.getTemplate().includes("minmax"));
52
+ await new Promise((resolve) => setTimeout(resolve, 100));
53
+ }
54
+ async function expectTemplate(waitFor, handle, resolvedTemplate) {
55
+ const stack = new Error().stack;
56
+ let template;
57
+ await waitFor(() => {
58
+ template = handle.getTemplate();
59
+ if (!template.includes(resolvedTemplate)) {
60
+ const e = new Error(`\nExpected: ${resolvedTemplate}\nGot : ${template}`);
61
+ e.stack = stack;
62
+ throw e;
63
+ }
64
+ if (handle.getState() !== "idle") {
65
+ const e = new Error(`\nExpected: idle\nGot : ${handle.getState()}`);
66
+ e.stack = stack;
67
+ throw e;
68
+ }
69
+ }, {
70
+ timeout: 2_000,
71
+ });
72
+ expect(template).toBe(resolvedTemplate);
73
+ }
74
+ export function createTestUtils(options) {
75
+ return {
76
+ waitForCondition: waitForCondition.bind(null, options.waitFor),
77
+ waitForMeasurement: waitForMeasurement.bind(null, options.waitFor),
78
+ expectTemplate: expectTemplate.bind(null, options.waitFor),
79
+ };
80
+ }
81
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from \"vitest\";\nimport { PanelGroupHandle } from \"./interface.js\";\n\nexport async function dragHandle(options: {\n handleId?: string;\n delta: number;\n orientation?: \"horizontal\" | \"vertical\";\n}) {\n const orientation = options.orientation || \"horizontal\";\n const handle = document.querySelector(\n options.handleId\n ? `[data-splitter-id=\"${options.handleId}\"]`\n : '[data-splitter-type=\"handle\"]'\n );\n\n if (!handle) {\n throw new Error(`Handle not found: ${options.handleId}`);\n }\n\n const rect = handle.getBoundingClientRect();\n const x = rect.x + rect.width / 2;\n const y = rect.y + rect.height / 2;\n const step = options.delta > 0 ? 1 : -1;\n const pointerId = 1;\n\n handle.dispatchEvent(\n new PointerEvent(\"pointerdown\", {\n bubbles: true,\n clientX: x,\n clientY: y,\n pointerId,\n button: 0,\n })\n );\n\n for (let i = 0; i < Math.abs(options.delta - 1); i++) {\n handle.dispatchEvent(\n new PointerEvent(\"pointermove\", {\n bubbles: true,\n pointerId,\n clientX: orientation === \"horizontal\" ? x + i * step : x,\n clientY: orientation === \"vertical\" ? y + i * step : y,\n })\n );\n await new Promise((r) => setTimeout(r, 10));\n }\n\n handle.dispatchEvent(\n new PointerEvent(\"pointerup\", {\n bubbles: true,\n pointerId,\n clientX: orientation === \"horizontal\" ? x + options.delta : x,\n clientY: orientation === \"vertical\" ? y + options.delta : y,\n })\n );\n}\n\ntype WaitForFn = <T>(\n callback: () => T | Promise<T>,\n options?: {\n timeout?: number;\n }\n) => Promise<T>;\n\nfunction waitForCondition(waitFor: WaitForFn, condition: () => boolean) {\n const stack = new Error().stack;\n\n return waitFor(\n () => {\n if (!condition()) {\n const error = new Error(\"Not ready\");\n error.stack = stack;\n throw error;\n }\n },\n {\n timeout: 10_000,\n }\n );\n}\n\nasync function waitForMeasurement(\n waitFor: WaitForFn,\n handle: PanelGroupHandle\n) {\n await waitForCondition(\n waitFor,\n () => !handle.getTemplate().includes(\"minmax\")\n );\n await new Promise((resolve) => setTimeout(resolve, 100));\n}\n\nasync function expectTemplate(\n waitFor: WaitForFn,\n handle: PanelGroupHandle,\n resolvedTemplate: string\n) {\n const stack = new Error().stack;\n let template;\n\n await waitFor(\n () => {\n template = handle.getTemplate();\n\n if (!template.includes(resolvedTemplate)) {\n const e = new Error(\n `\\nExpected: ${resolvedTemplate}\\nGot : ${template}`\n );\n e.stack = stack;\n throw e;\n }\n\n if (handle.getState() !== \"idle\") {\n const e = new Error(`\\nExpected: idle\\nGot : ${handle.getState()}`);\n e.stack = stack;\n throw e;\n }\n },\n {\n timeout: 2_000,\n }\n );\n\n expect(template).toBe(resolvedTemplate);\n}\n\nexport function createTestUtils(options: { waitFor: WaitForFn }) {\n return {\n waitForCondition: waitForCondition.bind(null, options.waitFor),\n waitForMeasurement: waitForMeasurement.bind(null, options.waitFor),\n expectTemplate: expectTemplate.bind(null, options.waitFor),\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import base from "@internal/eslint-config/base.js";
2
+
3
+ export default base;
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/package.json",
3
+ "name": "@window-splitter/interface",
4
+ "sideEffects": false,
5
+ "version": "0.7.0",
6
+ "description": "Shared component interface for window splitter components",
7
+ "homepage": "https://react-window-splitter-six.vercel.app",
8
+ "repository": {
9
+ "url": "https://github.com/hipstersmoothie/react-splitter",
10
+ "directory": "packages/interface"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "author": {
16
+ "name": "Andrew Lisowski",
17
+ "email": "lisowski54@gmail.com"
18
+ },
19
+ "engines": {
20
+ "node": ">=18.0.0"
21
+ },
22
+ "scripts": {
23
+ "build": "tshy",
24
+ "dev": "tshy -w",
25
+ "lint": "eslint .",
26
+ "clean": "rm -rf dist .turbo .tshy .tshy-build"
27
+ },
28
+ "license": "MIT",
29
+ "devDependencies": {
30
+ "@internal/eslint-config": "0.7.0",
31
+ "@testing-library/jest-dom": "^6.4.8",
32
+ "eslint": "^9.9.0",
33
+ "tshy": "^3.0.2",
34
+ "typescript": "^5.5.4",
35
+ "vitest": "^3.1.2"
36
+ },
37
+ "dependencies": {
38
+ "@window-splitter/state": "0.7.0"
39
+ },
40
+ "tshy": {
41
+ "exclude": [
42
+ "src/**/*.test.ts",
43
+ "node_modules"
44
+ ],
45
+ "exports": {
46
+ ".": "./src/index.ts",
47
+ "./test": "./src/test.ts"
48
+ }
49
+ },
50
+ "type": "module",
51
+ "exports": {
52
+ ".": {
53
+ "import": {
54
+ "types": "./dist/esm/index.d.ts",
55
+ "default": "./dist/esm/index.js"
56
+ },
57
+ "require": {
58
+ "types": "./dist/commonjs/index.d.ts",
59
+ "default": "./dist/commonjs/index.js"
60
+ }
61
+ },
62
+ "./test": {
63
+ "import": {
64
+ "types": "./dist/esm/test.d.ts",
65
+ "default": "./dist/esm/test.js"
66
+ },
67
+ "require": {
68
+ "types": "./dist/commonjs/test.d.ts",
69
+ "default": "./dist/commonjs/test.js"
70
+ }
71
+ }
72
+ },
73
+ "main": "./dist/commonjs/index.js",
74
+ "module": "./dist/esm/index.js",
75
+ "keywords": [
76
+ "panel",
77
+ "splitter",
78
+ "resizable",
79
+ "window"
80
+ ],
81
+ "types": "./dist/commonjs/index.d.ts",
82
+ "gitHead": "cf734f23404e11dbc51119898b2c78d166500b15"
83
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./interface.js";
2
+ export * from "./move.js";
3
+ export * from "./mergeAttributes.js";
@@ -0,0 +1,214 @@
1
+ import {
2
+ Constraints,
3
+ getUnitPercentageValue,
4
+ GroupMachineContextValue,
5
+ OnResizeCallback,
6
+ PanelData,
7
+ ParsedUnit,
8
+ PixelUnit,
9
+ Rect,
10
+ Unit,
11
+ } from "@window-splitter/state";
12
+
13
+ export interface PanelGroupHandle {
14
+ /** The id of the group */
15
+ getId: () => string;
16
+ /** Get the sizes of all the items in the layout as pixels */
17
+ getPixelSizes: () => Array<number>;
18
+ /** Get the sizes of all the items in the layout as percentages of the group size */
19
+ getPercentageSizes: () => Array<number>;
20
+ /**
21
+ * Set the size of all the items in the layout.
22
+ * This just calls `setSize` on each item. It is up to
23
+ * you to make sure the sizes make sense.
24
+ *
25
+ * NOTE: Setting handle sizes will do nothing.
26
+ */
27
+ setSizes: (items: Array<Unit>) => void;
28
+ /** Get the template for the group in pixels. Useful for testing */
29
+ getTemplate: () => string;
30
+ getState: () => "idle" | "dragging";
31
+ }
32
+
33
+ export interface SharedPanelGroupProps
34
+ extends Partial<
35
+ Pick<GroupMachineContextValue, "orientation" | "autosaveStrategy">
36
+ > {
37
+ /** Persisted state to initialized the machine with */
38
+ snapshot?: GroupMachineContextValue;
39
+ /** An id to use for autosaving the layout */
40
+ autosaveId?: string;
41
+ }
42
+
43
+ export interface PanelHandle {
44
+ /** Collapse the panel */
45
+ collapse: () => void;
46
+ /** Returns true if the panel is collapsed */
47
+ isCollapsed: () => boolean;
48
+ /** Expand the panel */
49
+ expand: () => void;
50
+ /** Returns true if the panel is expanded */
51
+ isExpanded: () => boolean;
52
+ /** The id of the panel */
53
+ getId: () => string;
54
+ /** Get the size of the panel in pixels */
55
+ getPixelSize: () => number;
56
+ /** Get percentage of the panel relative to the group */
57
+ getPercentageSize: () => number;
58
+ /**
59
+ * Set the size of the panel in pixels.
60
+ *
61
+ * This will be clamped to the min/max values of the panel.
62
+ * If you want the panel to collapse/expand you should use the
63
+ * expand/collapse methods.
64
+ */
65
+ setSize: (size: Unit) => void;
66
+ }
67
+ export interface SharedPanelProps<CollapsValue>
68
+ extends Constraints<Unit>,
69
+ Pick<PanelData, "collapseAnimation"> {
70
+ /** Callback called when the panel is resized */
71
+ onResize?: OnResizeCallback;
72
+ /**
73
+ * __CONTROLLED COMPONENT__
74
+ *
75
+ * If this prop is used it will be used as the source of truth for the collapsed state.
76
+ * It should be used in conjunction with the `onCollapseChange` prop.
77
+ *
78
+ * Use this if you want full control over the collapsed state. When trying to
79
+ * collapse a panel it will defer to onCollapseChange to determine if it should
80
+ * be collapsed.
81
+ */
82
+ collapsed?: CollapsValue;
83
+ /**
84
+ * __CONTROLLED COMPONENT__
85
+ *
86
+ * A callback called with the new desired collapsed state. If paired w
87
+ * with the `collapsed` prop this will be used to control the collapsed state.
88
+ *
89
+ * Otherwise this will just be called with the new collapsed state so you can
90
+ * use it to update your own state.
91
+ */
92
+ onCollapseChange?: (isCollapsed: boolean) => void;
93
+ }
94
+
95
+ export function getPanelDomAttributes({
96
+ groupId,
97
+ id,
98
+ collapsible,
99
+ collapsed,
100
+ }: {
101
+ groupId: string | undefined;
102
+ id: string;
103
+ collapsible: boolean | undefined;
104
+ collapsed: boolean | undefined;
105
+ }) {
106
+ return {
107
+ id: id,
108
+ "data-splitter-group-id": groupId,
109
+ "data-splitter-type": "panel",
110
+ "data-splitter-id": id,
111
+ "data-collapsed": collapsible ? collapsed : undefined,
112
+ };
113
+ }
114
+
115
+ export interface SharedPanelResizerProps
116
+ extends Partial<Pick<PanelHandle, "setSize">> {
117
+ /** If the handle is disabled */
118
+ disabled?: boolean;
119
+ /** The size of the handle */
120
+ size?: PixelUnit;
121
+ /** Called when the user starts dragging the handle */
122
+ onDragStart?: () => void;
123
+ /** Called when the user drags the handle */
124
+ onDrag?: () => void;
125
+ /** Called when the user stops dragging the handle */
126
+ onDragEnd?: () => void;
127
+ }
128
+
129
+ export function getPanelResizerDomAttributes({
130
+ groupId,
131
+ id,
132
+ orientation,
133
+ isDragging,
134
+ activeDragHandleId,
135
+ disabled,
136
+ controlsId,
137
+ min,
138
+ max,
139
+ currentValue,
140
+ groupSize,
141
+ }: {
142
+ groupId: string | undefined;
143
+ id: string;
144
+ orientation: "horizontal" | "vertical";
145
+ isDragging: boolean;
146
+ activeDragHandleId: string | undefined;
147
+ disabled: boolean | undefined;
148
+ controlsId: string | undefined;
149
+ min: ParsedUnit | undefined;
150
+ max: ParsedUnit | "1fr" | undefined;
151
+ currentValue: ParsedUnit | undefined;
152
+ groupSize: number;
153
+ }) {
154
+ return {
155
+ id: id,
156
+ role: "separator" as const,
157
+ "data-splitter-type": "handle",
158
+ "data-splitter-id": id,
159
+ "data-splitter-group-id": groupId,
160
+ "data-handle-orientation": orientation,
161
+ "data-state": isDragging
162
+ ? "dragging"
163
+ : activeDragHandleId
164
+ ? "inactive"
165
+ : "idle",
166
+ "aria-label": "Resize Handle",
167
+ "aria-disabled": disabled,
168
+ "aria-controls": controlsId,
169
+ "aria-valuemin": min ? getUnitPercentageValue(groupSize, min) : undefined,
170
+ "aria-valuemax":
171
+ max === "1fr"
172
+ ? 100
173
+ : max
174
+ ? getUnitPercentageValue(groupSize, max)
175
+ : undefined,
176
+ "aria-valuenow": currentValue
177
+ ? getUnitPercentageValue(groupSize, currentValue)
178
+ : undefined,
179
+ };
180
+ }
181
+
182
+ export function measureGroupChildren(
183
+ groupId: string,
184
+ cb: (childrenSizes: Record<string, Rect>) => void
185
+ ) {
186
+ const childrenObserver = new ResizeObserver((childrenEntries) => {
187
+ const childrenSizes: Record<string, { width: number; height: number }> = {};
188
+
189
+ for (const childEntry of childrenEntries) {
190
+ const child = childEntry.target as HTMLElement;
191
+ const childId = child.getAttribute("data-splitter-id");
192
+ const childSize = childEntry.borderBoxSize[0];
193
+
194
+ if (childId && childSize) {
195
+ childrenSizes[childId] = {
196
+ width: childSize.inlineSize,
197
+ height: childSize.blockSize,
198
+ };
199
+ }
200
+ }
201
+
202
+ cb(childrenSizes);
203
+ });
204
+
205
+ const c = document.querySelectorAll(`[data-splitter-group-id="${groupId}"]`);
206
+
207
+ for (const child of c) {
208
+ childrenObserver.observe(child);
209
+ }
210
+
211
+ return () => {
212
+ childrenObserver.disconnect();
213
+ };
214
+ }
@@ -0,0 +1,84 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ /*
4
+ * Copyright 2020 Adobe. All rights reserved.
5
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License. You may obtain a copy
7
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software distributed under
10
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
11
+ * OF ANY KIND, either express or implied. See the License for the specific language
12
+ * governing permissions and limitations under the License.
13
+ */
14
+
15
+ function chain(...callbacks: any[]): (...args: any[]) => void {
16
+ return (...args: any[]) => {
17
+ for (const callback of callbacks) {
18
+ if (typeof callback === "function") {
19
+ callback(...args);
20
+ }
21
+ }
22
+ };
23
+ }
24
+
25
+ type Props = Record<string, any>;
26
+
27
+ type PropsArg = Props | null | undefined;
28
+
29
+ // taken from: https://stackoverflow.com/questions/51603250/typescript-3-parameter-list-intersection-type/51604379#51604379
30
+ type TupleTypes<T> = { [P in keyof T]: T[P] } extends { [key: number]: infer V }
31
+ ? NullToObject<V>
32
+ : never;
33
+ type NullToObject<T> = T extends null | undefined ? object : T;
34
+
35
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
36
+ k: infer I
37
+ ) => void
38
+ ? I
39
+ : never;
40
+
41
+ /**
42
+ * Merges multiple props objects together. Event handlers are chained,
43
+ * classNames are combined, and ids are deduplicated - different ids
44
+ * will trigger a side-effect and re-render components hooked up with `useId`.
45
+ * For all other props, the last prop object overrides all previous ones.
46
+ * @param args - Multiple sets of props to merge together.
47
+ */
48
+ export function mergeAttributes<T extends PropsArg[]>(
49
+ ...args: T
50
+ ): UnionToIntersection<TupleTypes<T>> {
51
+ // Start with a base clone of the first argument. This is a lot faster than starting
52
+ // with an empty object and adding properties as we go.
53
+ const result: Props = { ...args[0] };
54
+ for (let i = 1; i < args.length; i++) {
55
+ const props = args[i];
56
+ for (const key in props) {
57
+ const a = result[key];
58
+ const b = props[key];
59
+
60
+ // Chain events
61
+ if (
62
+ typeof a === "function" &&
63
+ typeof b === "function" &&
64
+ // This is a lot faster than a regex.
65
+ key[0] === "o" &&
66
+ key[1] === "n" &&
67
+ key.charCodeAt(2) >= /* 'A' */ 65 &&
68
+ key.charCodeAt(2) <= /* 'Z' */ 90
69
+ ) {
70
+ result[key] = chain(a, b);
71
+ } else if (
72
+ key === "style" &&
73
+ typeof a === "object" &&
74
+ typeof b === "object"
75
+ ) {
76
+ result[key] = { ...b, ...a };
77
+ } else {
78
+ result[key] = b !== undefined ? b : a;
79
+ }
80
+ }
81
+ }
82
+
83
+ return result as UnionToIntersection<TupleTypes<T>>;
84
+ }