react-resizable-panels 0.0.55 → 0.0.57

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 (95) hide show
  1. package/.eslintrc.cjs +26 -0
  2. package/CHANGELOG.md +238 -90
  3. package/README.md +55 -49
  4. package/dist/declarations/src/Panel.d.ts +75 -20
  5. package/dist/declarations/src/PanelGroup.d.ts +29 -25
  6. package/dist/declarations/src/PanelResizeHandle.d.ts +1 -1
  7. package/dist/declarations/src/index.d.ts +5 -6
  8. package/dist/declarations/src/types.d.ts +3 -26
  9. package/dist/declarations/src/vendor/react.d.ts +4 -4
  10. package/dist/react-resizable-panels.browser.cjs.js +1276 -1043
  11. package/dist/react-resizable-panels.browser.cjs.mjs +1 -2
  12. package/dist/react-resizable-panels.browser.development.cjs.js +1410 -1097
  13. package/dist/react-resizable-panels.browser.development.cjs.mjs +1 -2
  14. package/dist/react-resizable-panels.browser.development.esm.js +1411 -1097
  15. package/dist/react-resizable-panels.browser.esm.js +1277 -1043
  16. package/dist/react-resizable-panels.cjs.js +1276 -1043
  17. package/dist/react-resizable-panels.cjs.js.map +1 -1
  18. package/dist/react-resizable-panels.cjs.mjs +1 -2
  19. package/dist/react-resizable-panels.development.cjs.js +1415 -1102
  20. package/dist/react-resizable-panels.development.cjs.mjs +1 -2
  21. package/dist/react-resizable-panels.development.esm.js +1416 -1102
  22. package/dist/react-resizable-panels.development.node.cjs.js +1179 -947
  23. package/dist/react-resizable-panels.development.node.cjs.mjs +1 -2
  24. package/dist/react-resizable-panels.development.node.esm.js +1180 -947
  25. package/dist/react-resizable-panels.esm.js +1277 -1043
  26. package/dist/react-resizable-panels.esm.js.map +1 -1
  27. package/dist/react-resizable-panels.node.cjs.js +1068 -910
  28. package/dist/react-resizable-panels.node.cjs.mjs +1 -2
  29. package/dist/react-resizable-panels.node.esm.js +1069 -910
  30. package/jest.config.js +10 -0
  31. package/package.json +5 -1
  32. package/src/Panel.test.tsx +308 -0
  33. package/src/Panel.ts +175 -123
  34. package/src/PanelGroup.test.tsx +210 -0
  35. package/src/PanelGroup.ts +730 -667
  36. package/src/PanelGroupContext.ts +33 -0
  37. package/src/PanelResizeHandle.ts +21 -17
  38. package/src/hooks/useUniqueId.ts +1 -1
  39. package/src/hooks/useWindowSplitterBehavior.ts +9 -164
  40. package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +185 -0
  41. package/src/index.ts +19 -14
  42. package/src/types.ts +3 -30
  43. package/src/utils/adjustLayoutByDelta.test.ts +1808 -0
  44. package/src/utils/adjustLayoutByDelta.ts +211 -0
  45. package/src/utils/calculateAriaValues.test.ts +111 -0
  46. package/src/utils/calculateAriaValues.ts +67 -0
  47. package/src/utils/calculateDeltaPercentage.ts +68 -0
  48. package/src/utils/calculateDragOffsetPercentage.ts +30 -0
  49. package/src/utils/calculateUnsafeDefaultLayout.test.ts +92 -0
  50. package/src/utils/calculateUnsafeDefaultLayout.ts +55 -0
  51. package/src/utils/callPanelCallbacks.ts +81 -0
  52. package/src/utils/compareLayouts.test.ts +9 -0
  53. package/src/utils/compareLayouts.ts +12 -0
  54. package/src/utils/computePanelFlexBoxStyle.ts +44 -0
  55. package/src/utils/computePercentagePanelConstraints.test.ts +98 -0
  56. package/src/utils/computePercentagePanelConstraints.ts +56 -0
  57. package/src/utils/convertPercentageToPixels.test.ts +9 -0
  58. package/src/utils/convertPercentageToPixels.ts +6 -0
  59. package/src/utils/convertPixelConstraintsToPercentages.test.ts +47 -0
  60. package/src/utils/convertPixelConstraintsToPercentages.ts +72 -0
  61. package/src/utils/convertPixelsToPercentage.test.ts +9 -0
  62. package/src/utils/convertPixelsToPercentage.ts +6 -0
  63. package/src/utils/determinePivotIndices.ts +10 -0
  64. package/src/utils/dom/calculateAvailablePanelSizeInPixels.ts +29 -0
  65. package/src/utils/dom/getAvailableGroupSizePixels.ts +29 -0
  66. package/src/utils/dom/getPanelElement.ts +7 -0
  67. package/src/utils/dom/getPanelGroupElement.ts +9 -0
  68. package/src/utils/dom/getResizeHandleElement.ts +9 -0
  69. package/src/utils/dom/getResizeHandleElementIndex.ts +12 -0
  70. package/src/utils/dom/getResizeHandleElementsForGroup.ts +9 -0
  71. package/src/utils/dom/getResizeHandlePanelIds.ts +18 -0
  72. package/src/utils/events.ts +13 -0
  73. package/src/utils/getPercentageSizeFromMixedSizes.test.ts +47 -0
  74. package/src/utils/getPercentageSizeFromMixedSizes.ts +15 -0
  75. package/src/utils/getResizeEventCursorPosition.ts +19 -0
  76. package/src/utils/initializeDefaultStorage.ts +26 -0
  77. package/src/utils/numbers/fuzzyCompareNumbers.test.ts +16 -0
  78. package/src/utils/numbers/fuzzyCompareNumbers.ts +17 -0
  79. package/src/utils/numbers/fuzzyNumbersEqual.ts +9 -0
  80. package/src/utils/resizePanel.test.ts +45 -0
  81. package/src/utils/resizePanel.ts +60 -0
  82. package/src/utils/serialization.ts +9 -4
  83. package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +23 -0
  84. package/src/utils/shouldMonitorPixelBasedConstraints.ts +13 -0
  85. package/src/utils/test-utils.ts +136 -0
  86. package/src/utils/validatePanelConstraints.test.ts +151 -0
  87. package/src/utils/validatePanelConstraints.ts +103 -0
  88. package/src/utils/validatePanelGroupLayout.test.ts +233 -0
  89. package/src/utils/validatePanelGroupLayout.ts +88 -0
  90. package/src/vendor/react.ts +4 -0
  91. package/.eslintrc.json +0 -22
  92. package/dist/declarations/src/utils/group.d.ts +0 -29
  93. package/src/PanelContexts.ts +0 -22
  94. package/src/utils/coordinates.ts +0 -149
  95. package/src/utils/group.ts +0 -614
@@ -0,0 +1,233 @@
1
+ import { verifyExpectedWarnings } from "./test-utils";
2
+ import { validatePanelGroupLayout } from "./validatePanelGroupLayout";
3
+
4
+ describe("validatePanelGroupLayout", () => {
5
+ it("should accept requested layout if there are no constraints provided", () => {
6
+ expect(
7
+ validatePanelGroupLayout({
8
+ groupSizePixels: NaN,
9
+ layout: [10, 60, 30],
10
+ panelConstraints: [{}, {}, {}],
11
+ })
12
+ ).toEqual([10, 60, 30]);
13
+ });
14
+
15
+ it("should reject layouts that do not total 100%", () => {
16
+ verifyExpectedWarnings(
17
+ () =>
18
+ validatePanelGroupLayout({
19
+ groupSizePixels: NaN,
20
+ layout: [10, 20, 30],
21
+ panelConstraints: [{}, {}, {}],
22
+ }),
23
+ "Invalid layout total size"
24
+ );
25
+
26
+ verifyExpectedWarnings(
27
+ () =>
28
+ validatePanelGroupLayout({
29
+ groupSizePixels: NaN,
30
+ layout: [50, 100, 150],
31
+ panelConstraints: [{}, {}, {}],
32
+ }),
33
+ "Invalid layout total size"
34
+ );
35
+ });
36
+
37
+ it("should reject layouts that do not match the number of panels", () => {
38
+ expect(() =>
39
+ validatePanelGroupLayout({
40
+ groupSizePixels: NaN,
41
+ layout: [10, 20, 30],
42
+ panelConstraints: [{}, {}],
43
+ })
44
+ ).toThrow("Invalid 2 panel layout");
45
+
46
+ expect(() =>
47
+ validatePanelGroupLayout({
48
+ groupSizePixels: NaN,
49
+ layout: [50, 50],
50
+ panelConstraints: [{}, {}, {}],
51
+ })
52
+ ).toThrow("Invalid 3 panel layout");
53
+ });
54
+
55
+ describe("minimum size constraints", () => {
56
+ it("should adjust the layout to account for minimum percentage sizes", () => {
57
+ expect(
58
+ validatePanelGroupLayout({
59
+ groupSizePixels: NaN,
60
+ layout: [25, 75],
61
+ panelConstraints: [
62
+ {
63
+ minSizePercentage: 35,
64
+ },
65
+ {},
66
+ ],
67
+ })
68
+ ).toEqual([35, 65]);
69
+ });
70
+
71
+ it("should adjust the layout to account for minimum pixel sizes", () => {
72
+ expect(
73
+ validatePanelGroupLayout({
74
+ groupSizePixels: 400,
75
+ layout: [20, 80],
76
+ panelConstraints: [
77
+ {
78
+ minSizePixels: 100,
79
+ },
80
+ {},
81
+ ],
82
+ })
83
+ ).toEqual([25, 75]);
84
+ });
85
+
86
+ it("should account for multiple panels with minimum size constraints", () => {
87
+ expect(
88
+ validatePanelGroupLayout({
89
+ groupSizePixels: NaN,
90
+ layout: [20, 60, 20],
91
+ panelConstraints: [
92
+ {
93
+ minSizePercentage: 25,
94
+ },
95
+ {},
96
+ {
97
+ minSizePercentage: 25,
98
+ },
99
+ ],
100
+ })
101
+ ).toEqual([25, 50, 25]);
102
+ });
103
+ });
104
+
105
+ describe("maximum size constraints", () => {
106
+ it("should adjust the layout to account for maximum percentage sizes", () => {
107
+ expect(
108
+ validatePanelGroupLayout({
109
+ groupSizePixels: NaN,
110
+ layout: [25, 75],
111
+ panelConstraints: [{}, { maxSizePercentage: 65 }],
112
+ })
113
+ ).toEqual([35, 65]);
114
+ });
115
+
116
+ it("should adjust the layout to account for maximum pixel sizes", () => {
117
+ expect(
118
+ validatePanelGroupLayout({
119
+ groupSizePixels: 400,
120
+ layout: [20, 80],
121
+ panelConstraints: [
122
+ {},
123
+ {
124
+ maxSizePixels: 100,
125
+ },
126
+ ],
127
+ })
128
+ ).toEqual([75, 25]);
129
+ });
130
+
131
+ it("should account for multiple panels with maximum size constraints", () => {
132
+ expect(
133
+ validatePanelGroupLayout({
134
+ groupSizePixels: NaN,
135
+ layout: [20, 60, 20],
136
+ panelConstraints: [
137
+ {
138
+ maxSizePercentage: 15,
139
+ },
140
+ { maxSizePercentage: 50 },
141
+ {},
142
+ ],
143
+ })
144
+ ).toEqual([15, 50, 35]);
145
+ });
146
+ });
147
+
148
+ describe("collapsible panels", () => {
149
+ it("should not collapse a panel that's at or above the minimum size", () => {
150
+ expect(
151
+ validatePanelGroupLayout({
152
+ groupSizePixels: NaN,
153
+ layout: [25, 75],
154
+ panelConstraints: [{ collapsible: true, minSizePercentage: 25 }, {}],
155
+ })
156
+ ).toEqual([25, 75]);
157
+ });
158
+
159
+ it("should collapse a panel that's below the minimum percentage size", () => {
160
+ expect(
161
+ validatePanelGroupLayout({
162
+ groupSizePixels: NaN,
163
+ layout: [20, 80],
164
+ panelConstraints: [
165
+ {
166
+ collapsible: true,
167
+ collapsedSizePercentage: 10,
168
+ minSizePercentage: 25,
169
+ },
170
+ {},
171
+ ],
172
+ })
173
+ ).toEqual([10, 90]);
174
+ });
175
+
176
+ it("should collapse a panel that's below the minimum pixel size", () => {
177
+ expect(
178
+ validatePanelGroupLayout({
179
+ groupSizePixels: 400,
180
+ layout: [20, 80],
181
+ panelConstraints: [
182
+ {
183
+ collapsible: true,
184
+ collapsedSizePixels: 40,
185
+ minSizePixels: 100,
186
+ },
187
+ {},
188
+ ],
189
+ })
190
+ ).toEqual([10, 90]);
191
+ });
192
+ });
193
+
194
+ describe("combination of minimum and maximum size constraints", () => {
195
+ it("three panel min/max configuration", () => {
196
+ expect(
197
+ validatePanelGroupLayout({
198
+ groupSizePixels: NaN,
199
+ layout: [25, 50, 25],
200
+ panelConstraints: [
201
+ { minSizePercentage: 10, maxSizePercentage: 25 },
202
+ { maxSizePercentage: 75 },
203
+ { minSizePercentage: 10, maxSizePercentage: 50 },
204
+ ],
205
+ })
206
+ ).toEqual([25, 50, 25]);
207
+
208
+ expect(
209
+ validatePanelGroupLayout({
210
+ groupSizePixels: NaN,
211
+ layout: [5, 80, 15],
212
+ panelConstraints: [
213
+ { minSizePercentage: 10, maxSizePercentage: 25 },
214
+ { maxSizePercentage: 75 },
215
+ { minSizePercentage: 10, maxSizePercentage: 50 },
216
+ ],
217
+ })
218
+ ).toEqual([10, 75, 15]);
219
+
220
+ expect(
221
+ validatePanelGroupLayout({
222
+ groupSizePixels: NaN,
223
+ layout: [30, 10, 60],
224
+ panelConstraints: [
225
+ { minSizePercentage: 10, maxSizePercentage: 25 },
226
+ { maxSizePercentage: 75 },
227
+ { minSizePercentage: 10, maxSizePercentage: 50 },
228
+ ],
229
+ })
230
+ ).toEqual([25, 25, 50]);
231
+ });
232
+ });
233
+ });
@@ -0,0 +1,88 @@
1
+ import { isDevelopment } from "#is-development";
2
+ import { PanelConstraints } from "../Panel";
3
+ import { fuzzyNumbersEqual } from "./numbers/fuzzyNumbersEqual";
4
+ import { resizePanel } from "./resizePanel";
5
+
6
+ // All units must be in percentages; pixel values should be pre-converted
7
+ export function validatePanelGroupLayout({
8
+ groupSizePixels,
9
+ layout: prevLayout,
10
+ panelConstraints,
11
+ }: {
12
+ groupSizePixels: number;
13
+ layout: number[];
14
+ panelConstraints: PanelConstraints[];
15
+ }): number[] {
16
+ const nextLayout = [...prevLayout];
17
+
18
+ // Validate layout expectations
19
+ if (nextLayout.length !== panelConstraints.length) {
20
+ throw Error(
21
+ `Invalid ${panelConstraints.length} panel layout: ${nextLayout
22
+ .map((size) => `${size}%`)
23
+ .join(", ")}`
24
+ );
25
+ } else if (
26
+ !fuzzyNumbersEqual(
27
+ nextLayout.reduce((accumulated, current) => accumulated + current, 0),
28
+ 100
29
+ )
30
+ ) {
31
+ // This is not ideal so we should warn about it, but it may be recoverable in some cases
32
+ // (especially if the amount is small)
33
+ if (isDevelopment) {
34
+ console.warn(
35
+ `WARNING: Invalid layout total size: ${nextLayout
36
+ .map((size) => `${size}%`)
37
+ .join(", ")}`
38
+ );
39
+ }
40
+ }
41
+
42
+ let remainingSize = 0;
43
+
44
+ // First pass: Validate the proposed layout given each panel's constraints
45
+ for (let index = 0; index < panelConstraints.length; index++) {
46
+ const unsafeSize = nextLayout[index]!;
47
+
48
+ const safeSize = resizePanel({
49
+ groupSizePixels,
50
+ panelConstraints,
51
+ panelIndex: index,
52
+ size: unsafeSize,
53
+ });
54
+
55
+ if (unsafeSize != safeSize) {
56
+ remainingSize += unsafeSize - safeSize;
57
+
58
+ nextLayout[index] = safeSize;
59
+ }
60
+ }
61
+
62
+ // If there is additional, left over space, assign it to any panel(s) that permits it
63
+ // (It's not worth taking multiple additional passes to evenly distribute)
64
+ if (!fuzzyNumbersEqual(remainingSize, 0)) {
65
+ for (let index = 0; index < panelConstraints.length; index++) {
66
+ const prevSize = nextLayout[index]!;
67
+ const unsafeSize = prevSize + remainingSize;
68
+ const safeSize = resizePanel({
69
+ groupSizePixels,
70
+ panelConstraints,
71
+ panelIndex: index,
72
+ size: unsafeSize,
73
+ });
74
+
75
+ if (prevSize !== safeSize) {
76
+ remainingSize -= safeSize - prevSize;
77
+ nextLayout[index] = safeSize;
78
+
79
+ // Once we've used up the remainder, bail
80
+ if (fuzzyNumbersEqual(remainingSize, 0)) {
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ return nextLayout;
88
+ }
@@ -13,6 +13,7 @@ import type {
13
13
  ElementType,
14
14
  ForwardedRef,
15
15
  MouseEvent,
16
+ PropsWithChildren,
16
17
  ReactNode,
17
18
  RefObject,
18
19
  TouchEvent,
@@ -21,6 +22,7 @@ import type {
21
22
  const {
22
23
  createElement,
23
24
  createContext,
25
+ createRef,
24
26
  forwardRef,
25
27
  useCallback,
26
28
  useContext,
@@ -38,6 +40,7 @@ const useId = (React as any)["useId".toString()] as () => string;
38
40
  export {
39
41
  createElement,
40
42
  createContext,
43
+ createRef,
41
44
  forwardRef,
42
45
  useCallback,
43
46
  useContext,
@@ -55,6 +58,7 @@ export type {
55
58
  ElementType,
56
59
  ForwardedRef,
57
60
  MouseEvent,
61
+ PropsWithChildren,
58
62
  ReactNode,
59
63
  RefObject,
60
64
  TouchEvent,
package/.eslintrc.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "ignorePatterns": [".parcel-cache", "dist", "node_modules"],
3
- "parser": "@typescript-eslint/parser",
4
- "parserOptions": { "project": ["../../tsconfig.json"] },
5
- "plugins": ["@typescript-eslint", "no-restricted-imports", "react-hooks"],
6
- "root": true,
7
- "rules": {
8
- "no-restricted-imports": [
9
- "error",
10
- {
11
- "paths": ["react"]
12
- }
13
- ],
14
- "react-hooks/rules-of-hooks": "error",
15
- "react-hooks/exhaustive-deps": [
16
- "warn",
17
- {
18
- "additionalHooks": "(useIsomorphicLayoutEffect)"
19
- }
20
- ]
21
- }
22
- }
@@ -1,29 +0,0 @@
1
- import { CommittedValues, InitialDragState } from "../PanelGroup.js";
2
- import { PanelData, ResizeEvent, Units } from "../types.js";
3
- export declare function adjustByDelta(event: ResizeEvent | null, committedValues: CommittedValues, idBefore: string, idAfter: string, deltaPixels: number, prevSizes: number[], panelSizeBeforeCollapse: Map<string, number>, initialDragState: InitialDragState | null): number[];
4
- export declare function callPanelCallbacks(panelsArray: PanelData[], sizes: number[], panelIdToLastNotifiedSizeMap: Record<string, number>): void;
5
- export declare function calculateDefaultLayout({ groupId, panels, units, }: {
6
- groupId: string;
7
- panels: Map<string, PanelData>;
8
- units: Units;
9
- }): number[];
10
- export declare function getBeforeAndAfterIds(id: string, panelsArray: PanelData[]): [idBefore: string | null, idAFter: string | null];
11
- export declare function getAvailableGroupSizePixels(groupId: string): number;
12
- export declare function getFlexGrow(panels: Map<string, PanelData>, id: string, sizes: number[]): string;
13
- export declare function getPanel(id: string): HTMLDivElement | null;
14
- export declare function getPanelGroup(id: string): HTMLDivElement | null;
15
- export declare function getResizeHandle(id: string): HTMLDivElement | null;
16
- export declare function getResizeHandleIndex(id: string): number | null;
17
- export declare function getResizeHandles(): HTMLDivElement[];
18
- export declare function getResizeHandlesForGroup(groupId: string): HTMLDivElement[];
19
- export declare function getResizeHandlePanelIds(groupId: string, handleId: string, panelsArray: PanelData[]): [idBefore: string | null, idAfter: string | null];
20
- export declare function panelsMapToSortedArray(panels: Map<string, PanelData>): PanelData[];
21
- export declare function safeResizePanel(units: Units, groupSizePixels: number, panel: PanelData, prevSize: number, nextSize: number, event?: ResizeEvent | null): number;
22
- export declare function validatePanelProps(units: Units, panelData: PanelData): void;
23
- export declare function validatePanelGroupLayout({ groupId, panels, nextSizes, prevSizes, units, }: {
24
- groupId: string;
25
- panels: Map<string, PanelData>;
26
- nextSizes: number[];
27
- prevSizes: number[];
28
- units: Units;
29
- }): number[];
@@ -1,22 +0,0 @@
1
- import { CSSProperties, createContext } from "./vendor/react";
2
-
3
- import { PanelData, ResizeEvent, ResizeHandler, Units } from "./types";
4
-
5
- export const PanelGroupContext = createContext<{
6
- activeHandleId: string | null;
7
- collapsePanel: (id: string) => void;
8
- direction: "horizontal" | "vertical";
9
- expandPanel: (id: string) => void;
10
- getPanelSize: (id: string, units?: Units) => number;
11
- getPanelStyle: (id: string, defaultSize: number | null) => CSSProperties;
12
- groupId: string;
13
- registerPanel: (id: string, panel: PanelData) => void;
14
- registerResizeHandle: (id: string) => ResizeHandler;
15
- resizePanel: (id: string, percentage: number, units?: Units) => void;
16
- startDragging: (id: string, event: ResizeEvent) => void;
17
- stopDragging: () => void;
18
- unregisterPanel: (id: string) => void;
19
- units: Units;
20
- } | null>(null);
21
-
22
- PanelGroupContext.displayName = "PanelGroupContext";
@@ -1,149 +0,0 @@
1
- import { PRECISION } from "../constants";
2
- import { InitialDragState } from "../PanelGroup";
3
- import { Direction, PanelData, ResizeEvent } from "../types";
4
- import {
5
- getPanelGroup,
6
- getResizeHandle,
7
- getResizeHandlePanelIds,
8
- } from "./group";
9
-
10
- export type Coordinates = {
11
- movement: number;
12
- offset: number;
13
- };
14
-
15
- export type Size = {
16
- height: number;
17
- width: number;
18
- };
19
-
20
- export function getDragOffset(
21
- event: ResizeEvent,
22
- handleId: string,
23
- direction: Direction,
24
- initialOffset: number = 0,
25
- initialHandleElementRect: DOMRect | null = null
26
- ): number {
27
- const isHorizontal = direction === "horizontal";
28
-
29
- let pointerOffset = 0;
30
- if (isMouseEvent(event)) {
31
- pointerOffset = isHorizontal ? event.clientX : event.clientY;
32
- } else if (isTouchEvent(event)) {
33
- const firstTouch = event.touches[0];
34
- pointerOffset = isHorizontal ? firstTouch.screenX : firstTouch.screenY;
35
- } else {
36
- return 0;
37
- }
38
-
39
- const handleElement = getResizeHandle(handleId)!;
40
- const rect =
41
- initialHandleElementRect || handleElement.getBoundingClientRect();
42
- const elementOffset = isHorizontal ? rect.left : rect.top;
43
-
44
- return pointerOffset - elementOffset - initialOffset;
45
- }
46
-
47
- // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
48
- export function getMovement(
49
- event: ResizeEvent,
50
- groupId: string,
51
- handleId: string,
52
- panelsArray: PanelData[],
53
- direction: Direction,
54
- prevSizes: number[],
55
- initialDragState: InitialDragState | null
56
- ): number {
57
- const {
58
- dragOffset = 0,
59
- dragHandleRect,
60
- sizes: initialSizes,
61
- } = initialDragState || {};
62
-
63
- // If we're resizing by mouse or touch, use the initial sizes as a base.
64
- // This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
65
- const baseSizes = initialSizes || prevSizes;
66
-
67
- if (isKeyDown(event)) {
68
- const isHorizontal = direction === "horizontal";
69
-
70
- const groupElement = getPanelGroup(groupId)!;
71
- const rect = groupElement.getBoundingClientRect();
72
- const groupSizeInPixels = isHorizontal ? rect.width : rect.height;
73
-
74
- const denominator = event.shiftKey ? 10 : 100;
75
- const delta = groupSizeInPixels / denominator;
76
-
77
- let movement = 0;
78
- switch (event.key) {
79
- case "ArrowDown":
80
- movement = isHorizontal ? 0 : delta;
81
- break;
82
- case "ArrowLeft":
83
- movement = isHorizontal ? -delta : 0;
84
- break;
85
- case "ArrowRight":
86
- movement = isHorizontal ? delta : 0;
87
- break;
88
- case "ArrowUp":
89
- movement = isHorizontal ? 0 : -delta;
90
- break;
91
- case "End":
92
- movement = groupSizeInPixels;
93
- break;
94
- case "Home":
95
- movement = -groupSizeInPixels;
96
- break;
97
- }
98
-
99
- // If the Panel being resized is collapsible,
100
- // we need to special case resizing around the minSize boundary.
101
- // If contracting, Panels should shrink to their minSize and then snap to fully collapsed.
102
- // If expanding from collapsed, they should snap back to their minSize.
103
- const [idBefore, idAfter] = getResizeHandlePanelIds(
104
- groupId,
105
- handleId,
106
- panelsArray
107
- );
108
- const targetPanelId = movement < 0 ? idBefore : idAfter;
109
- const targetPanelIndex = panelsArray.findIndex(
110
- (panel) => panel.current.id === targetPanelId
111
- );
112
- const targetPanel = panelsArray[targetPanelIndex];
113
- if (targetPanel.current.collapsible) {
114
- const baseSize = baseSizes[targetPanelIndex];
115
- if (
116
- baseSize === 0 ||
117
- baseSize.toPrecision(PRECISION) ===
118
- targetPanel.current.minSize.toPrecision(PRECISION)
119
- ) {
120
- movement =
121
- movement < 0
122
- ? -targetPanel.current.minSize * groupSizeInPixels
123
- : targetPanel.current.minSize * groupSizeInPixels;
124
- }
125
- }
126
-
127
- return movement;
128
- } else {
129
- return getDragOffset(
130
- event,
131
- handleId,
132
- direction,
133
- dragOffset,
134
- dragHandleRect
135
- );
136
- }
137
- }
138
-
139
- export function isKeyDown(event: ResizeEvent): event is KeyboardEvent {
140
- return event.type === "keydown";
141
- }
142
-
143
- export function isMouseEvent(event: ResizeEvent): event is MouseEvent {
144
- return event.type.startsWith("mouse");
145
- }
146
-
147
- export function isTouchEvent(event: ResizeEvent): event is TouchEvent {
148
- return event.type.startsWith("touch");
149
- }