xiod-ui 1.0.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 (224) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +167 -0
  3. package/dist/components/accordion.d.ts +9 -0
  4. package/dist/components/accordion.js +46 -0
  5. package/dist/components/agent-steps.d.ts +47 -0
  6. package/dist/components/agent-steps.js +223 -0
  7. package/dist/components/alert-dialog.d.ts +21 -0
  8. package/dist/components/alert-dialog.js +74 -0
  9. package/dist/components/alert.d.ts +12 -0
  10. package/dist/components/alert.js +45 -0
  11. package/dist/components/aspect-ratio.d.ts +9 -0
  12. package/dist/components/aspect-ratio.js +22 -0
  13. package/dist/components/autocomplete.d.ts +35 -0
  14. package/dist/components/autocomplete.js +160 -0
  15. package/dist/components/avatar.d.ts +17 -0
  16. package/dist/components/avatar.js +65 -0
  17. package/dist/components/badge.d.ts +15 -0
  18. package/dist/components/badge.js +46 -0
  19. package/dist/components/breadcrumb.d.ts +12 -0
  20. package/dist/components/breadcrumb.js +75 -0
  21. package/dist/components/button-group.d.ts +14 -0
  22. package/dist/components/button-group.js +45 -0
  23. package/dist/components/button-split.d.ts +19 -0
  24. package/dist/components/button-split.js +73 -0
  25. package/dist/components/button.d.ts +15 -0
  26. package/dist/components/button.js +54 -0
  27. package/dist/components/calendar.d.ts +63 -0
  28. package/dist/components/calendar.js +425 -0
  29. package/dist/components/card.d.ts +17 -0
  30. package/dist/components/card.js +139 -0
  31. package/dist/components/carousel.d.ts +59 -0
  32. package/dist/components/carousel.js +503 -0
  33. package/dist/components/checkbox.d.ts +16 -0
  34. package/dist/components/checkbox.js +86 -0
  35. package/dist/components/circular-progress.d.ts +28 -0
  36. package/dist/components/circular-progress.js +127 -0
  37. package/dist/components/collapsible.d.ts +8 -0
  38. package/dist/components/collapsible.js +27 -0
  39. package/dist/components/color-picker.d.ts +159 -0
  40. package/dist/components/color-picker.js +1589 -0
  41. package/dist/components/combobox.d.ts +46 -0
  42. package/dist/components/combobox.js +237 -0
  43. package/dist/components/command.d.ts +22 -0
  44. package/dist/components/command.js +129 -0
  45. package/dist/components/context-menu.d.ts +38 -0
  46. package/dist/components/context-menu.js +164 -0
  47. package/dist/components/copy-to-clipboard.d.ts +32 -0
  48. package/dist/components/copy-to-clipboard.js +83 -0
  49. package/dist/components/corner-badge.d.ts +22 -0
  50. package/dist/components/corner-badge.js +84 -0
  51. package/dist/components/dashboard-grid.d.ts +83 -0
  52. package/dist/components/dashboard-grid.js +486 -0
  53. package/dist/components/date-picker.d.ts +29 -0
  54. package/dist/components/date-picker.js +261 -0
  55. package/dist/components/dialog.d.ts +26 -0
  56. package/dist/components/dialog.js +97 -0
  57. package/dist/components/dot-matrix.d.ts +32 -0
  58. package/dist/components/dot-matrix.js +707 -0
  59. package/dist/components/draggable.d.ts +42 -0
  60. package/dist/components/draggable.js +346 -0
  61. package/dist/components/drawer.d.ts +66 -0
  62. package/dist/components/drawer.js +304 -0
  63. package/dist/components/empty.d.ts +14 -0
  64. package/dist/components/empty.js +75 -0
  65. package/dist/components/field.d.ts +12 -0
  66. package/dist/components/field.js +44 -0
  67. package/dist/components/fieldset.d.ts +7 -0
  68. package/dist/components/fieldset.js +21 -0
  69. package/dist/components/file-upload.d.ts +61 -0
  70. package/dist/components/file-upload.js +482 -0
  71. package/dist/components/form.d.ts +6 -0
  72. package/dist/components/form.js +14 -0
  73. package/dist/components/frame.d.ts +10 -0
  74. package/dist/components/frame.js +47 -0
  75. package/dist/components/gauge.d.ts +27 -0
  76. package/dist/components/gauge.js +74 -0
  77. package/dist/components/grid.d.ts +26 -0
  78. package/dist/components/grid.js +204 -0
  79. package/dist/components/group.d.ts +19 -0
  80. package/dist/components/group.js +45 -0
  81. package/dist/components/input-group.d.ts +15 -0
  82. package/dist/components/input-group.js +61 -0
  83. package/dist/components/input-otp.d.ts +24 -0
  84. package/dist/components/input-otp.js +50 -0
  85. package/dist/components/input-payment.d.ts +131 -0
  86. package/dist/components/input-payment.js +1140 -0
  87. package/dist/components/input-phone.d.ts +70 -0
  88. package/dist/components/input-phone.js +657 -0
  89. package/dist/components/input-sensitive.d.ts +12 -0
  90. package/dist/components/input-sensitive.js +169 -0
  91. package/dist/components/input.d.ts +13 -0
  92. package/dist/components/input.js +26 -0
  93. package/dist/components/kbd.d.ts +6 -0
  94. package/dist/components/kbd.js +19 -0
  95. package/dist/components/kinetic-click.d.ts +48 -0
  96. package/dist/components/kinetic-click.js +1184 -0
  97. package/dist/components/label.d.ts +6 -0
  98. package/dist/components/label.js +18 -0
  99. package/dist/components/list-box.d.ts +20 -0
  100. package/dist/components/list-box.js +148 -0
  101. package/dist/components/loader.d.ts +13 -0
  102. package/dist/components/loader.js +430 -0
  103. package/dist/components/marker.d.ts +15 -0
  104. package/dist/components/marker.js +59 -0
  105. package/dist/components/menu.d.ts +42 -0
  106. package/dist/components/menu.js +186 -0
  107. package/dist/components/menubar.d.ts +40 -0
  108. package/dist/components/menubar.js +107 -0
  109. package/dist/components/message.d.ts +33 -0
  110. package/dist/components/message.js +112 -0
  111. package/dist/components/meter.d.ts +10 -0
  112. package/dist/components/meter.js +42 -0
  113. package/dist/components/morphic-toast.d.ts +61 -0
  114. package/dist/components/morphic-toast.js +916 -0
  115. package/dist/components/navigation-menu.d.ts +26 -0
  116. package/dist/components/navigation-menu.js +116 -0
  117. package/dist/components/number-field.d.ts +15 -0
  118. package/dist/components/number-field.js +86 -0
  119. package/dist/components/option-picker.d.ts +18 -0
  120. package/dist/components/option-picker.js +89 -0
  121. package/dist/components/orb.d.ts +38 -0
  122. package/dist/components/orb.js +1413 -0
  123. package/dist/components/pagination.d.ts +25 -0
  124. package/dist/components/pagination.js +147 -0
  125. package/dist/components/popover.d.ts +22 -0
  126. package/dist/components/popover.js +79 -0
  127. package/dist/components/preview-card.d.ts +16 -0
  128. package/dist/components/preview-card.js +60 -0
  129. package/dist/components/progress.d.ts +21 -0
  130. package/dist/components/progress.js +139 -0
  131. package/dist/components/radio.d.ts +16 -0
  132. package/dist/components/radio.js +68 -0
  133. package/dist/components/resizable.d.ts +58 -0
  134. package/dist/components/resizable.js +964 -0
  135. package/dist/components/ruler-picker.d.ts +27 -0
  136. package/dist/components/ruler-picker.js +253 -0
  137. package/dist/components/scroll-area.d.ts +13 -0
  138. package/dist/components/scroll-area.js +34 -0
  139. package/dist/components/scroll-bar.d.ts +13 -0
  140. package/dist/components/scroll-bar.js +47 -0
  141. package/dist/components/select.d.ts +29 -0
  142. package/dist/components/select.js +140 -0
  143. package/dist/components/separator.d.ts +6 -0
  144. package/dist/components/separator.js +15 -0
  145. package/dist/components/sidebar.d.ts +65 -0
  146. package/dist/components/sidebar.js +408 -0
  147. package/dist/components/skeleton.d.ts +5 -0
  148. package/dist/components/skeleton.js +12 -0
  149. package/dist/components/slider.d.ts +12 -0
  150. package/dist/components/slider.js +96 -0
  151. package/dist/components/sortable.d.ts +44 -0
  152. package/dist/components/sortable.js +327 -0
  153. package/dist/components/switch.d.ts +15 -0
  154. package/dist/components/switch.js +63 -0
  155. package/dist/components/table.d.ts +12 -0
  156. package/dist/components/table.js +65 -0
  157. package/dist/components/tabs.d.ts +12 -0
  158. package/dist/components/tabs.js +39 -0
  159. package/dist/components/text.d.ts +14 -0
  160. package/dist/components/text.js +69 -0
  161. package/dist/components/textarea.d.ts +9 -0
  162. package/dist/components/textarea.js +20 -0
  163. package/dist/components/theme-provider.d.ts +52 -0
  164. package/dist/components/theme-provider.js +148 -0
  165. package/dist/components/timeline.d.ts +34 -0
  166. package/dist/components/timeline.js +147 -0
  167. package/dist/components/toast.d.ts +17 -0
  168. package/dist/components/toast.js +161 -0
  169. package/dist/components/toggle-group.d.ts +14 -0
  170. package/dist/components/toggle-group.js +53 -0
  171. package/dist/components/toggle.d.ts +11 -0
  172. package/dist/components/toggle.js +36 -0
  173. package/dist/components/toolbar.d.ts +11 -0
  174. package/dist/components/toolbar.js +49 -0
  175. package/dist/components/tooltip.d.ts +17 -0
  176. package/dist/components/tooltip.js +56 -0
  177. package/dist/components/waveform.d.ts +61 -0
  178. package/dist/components/waveform.js +500 -0
  179. package/dist/components/wheel-picker.d.ts +44 -0
  180. package/dist/components/wheel-picker.js +771 -0
  181. package/dist/hooks/use-copy-to-clipboard.d.ts +9 -0
  182. package/dist/hooks/use-copy-to-clipboard.js +36 -0
  183. package/dist/hooks/use-media-query.d.ts +21 -0
  184. package/dist/hooks/use-media-query.js +58 -0
  185. package/dist/styles.css +202 -0
  186. package/dist/themes/afterglow.css +89 -0
  187. package/dist/themes/afterglow.scoped.css +90 -0
  188. package/dist/themes/blacklight.css +89 -0
  189. package/dist/themes/blacklight.scoped.css +90 -0
  190. package/dist/themes/cathode.css +89 -0
  191. package/dist/themes/cathode.scoped.css +90 -0
  192. package/dist/themes/cel.css +89 -0
  193. package/dist/themes/cel.scoped.css +90 -0
  194. package/dist/themes/cinder.css +89 -0
  195. package/dist/themes/cinder.scoped.css +90 -0
  196. package/dist/themes/clay.css +89 -0
  197. package/dist/themes/clay.scoped.css +90 -0
  198. package/dist/themes/cobalt.css +89 -0
  199. package/dist/themes/cobalt.scoped.css +90 -0
  200. package/dist/themes/crimson.css +89 -0
  201. package/dist/themes/crimson.scoped.css +90 -0
  202. package/dist/themes/ion.css +89 -0
  203. package/dist/themes/ion.scoped.css +90 -0
  204. package/dist/themes/iris.css +89 -0
  205. package/dist/themes/iris.scoped.css +90 -0
  206. package/dist/themes/lagoon.css +89 -0
  207. package/dist/themes/lagoon.scoped.css +90 -0
  208. package/dist/themes/mochi.css +89 -0
  209. package/dist/themes/mochi.scoped.css +90 -0
  210. package/dist/themes/riso.css +89 -0
  211. package/dist/themes/riso.scoped.css +90 -0
  212. package/dist/themes/roast.css +89 -0
  213. package/dist/themes/roast.scoped.css +90 -0
  214. package/dist/themes/sage.css +89 -0
  215. package/dist/themes/sage.scoped.css +90 -0
  216. package/dist/themes/sepia.css +89 -0
  217. package/dist/themes/sepia.scoped.css +90 -0
  218. package/dist/themes/sorbet.css +89 -0
  219. package/dist/themes/sorbet.scoped.css +90 -0
  220. package/dist/themes/taffy.css +89 -0
  221. package/dist/themes/taffy.scoped.css +90 -0
  222. package/dist/themes/toxin.css +89 -0
  223. package/dist/themes/toxin.scoped.css +90 -0
  224. package/package.json +140 -0
@@ -0,0 +1,964 @@
1
+ "use client";
2
+ import { cn } from "cn";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import * as React$1 from "react";
5
+ import { GripVertical } from "xiod-icons/icons/GripVertical";
6
+ import { GripHorizontal } from "xiod-icons/icons/GripHorizontal";
7
+ //#region src/components/resizable.tsx
8
+ const activeGroups = /* @__PURE__ */ new Map();
9
+ const ResizableGroupContext = React$1.createContext(null);
10
+ function useResizableGroup() {
11
+ const context = React$1.useContext(ResizableGroupContext);
12
+ if (!context) throw new Error("useResizableGroup must be used within a ResizablePanelGroup");
13
+ return context;
14
+ }
15
+ function parseSizeAndUnit(size) {
16
+ if (size === void 0) return [0, "%"];
17
+ if (typeof size === "number") return [size, "px"];
18
+ const numeric = parseFloat(size);
19
+ if (Number.isNaN(numeric)) return [0, "%"];
20
+ if (size.endsWith("%")) return [numeric, "%"];
21
+ if (size.endsWith("px")) return [numeric, "px"];
22
+ if (size.endsWith("rem")) return [numeric, "rem"];
23
+ if (size.endsWith("em")) return [numeric, "em"];
24
+ if (size.endsWith("vh")) return [numeric, "vh"];
25
+ if (size.endsWith("vw")) return [numeric, "vw"];
26
+ return [numeric, "%"];
27
+ }
28
+ function convertSizeToPixels(size, element, groupSize) {
29
+ if (size === void 0) return 0;
30
+ const [val, unit] = parseSizeAndUnit(size);
31
+ switch (unit) {
32
+ case "%": return val / 100 * groupSize;
33
+ case "px": return val;
34
+ case "rem": {
35
+ if (typeof window === "undefined" || !element) return val * 16;
36
+ const style = window.getComputedStyle(element.ownerDocument.documentElement);
37
+ return val * (parseFloat(style.fontSize) || 16);
38
+ }
39
+ case "em": {
40
+ if (typeof window === "undefined" || !element) return val * 16;
41
+ const style = window.getComputedStyle(element);
42
+ return val * (parseFloat(style.fontSize) || 16);
43
+ }
44
+ case "vh":
45
+ if (typeof window === "undefined") return val * 800;
46
+ return val / 100 * window.innerHeight;
47
+ case "vw":
48
+ if (typeof window === "undefined") return val * 1200;
49
+ return val / 100 * window.innerWidth;
50
+ default: return 0;
51
+ }
52
+ }
53
+ function getResolvedConstraints(panel, groupSizeInPixels) {
54
+ const element = panel.ref.current;
55
+ const config = panel.config;
56
+ return {
57
+ collapsedSize: config.collapsedSize !== void 0 ? parseFloat((convertSizeToPixels(config.collapsedSize, element, groupSizeInPixels) / groupSizeInPixels * 100).toFixed(3)) : 0,
58
+ minSize: config.minSize !== void 0 ? parseFloat((convertSizeToPixels(config.minSize, element, groupSizeInPixels) / groupSizeInPixels * 100).toFixed(3)) : 0,
59
+ maxSize: config.maxSize !== void 0 ? parseFloat((convertSizeToPixels(config.maxSize, element, groupSizeInPixels) / groupSizeInPixels * 100).toFixed(3)) : 100,
60
+ defaultSize: config.defaultSize !== void 0 ? parseFloat((convertSizeToPixels(config.defaultSize, element, groupSizeInPixels) / groupSizeInPixels * 100).toFixed(3)) : void 0,
61
+ collapsible: !!config.collapsible,
62
+ disabled: !!config.disabled
63
+ };
64
+ }
65
+ function validatePanelSize({ size, prevSize, constraints, overrideDisabledPanels }) {
66
+ const { collapsedSize, minSize, maxSize, collapsible, disabled } = constraints;
67
+ if (disabled && !overrideDisabledPanels) return prevSize;
68
+ let finalSize = size;
69
+ if (finalSize < minSize) {
70
+ if (collapsible) {
71
+ const halfway = (collapsedSize + minSize) / 2;
72
+ if (finalSize < halfway) finalSize = collapsedSize;
73
+ else finalSize = minSize;
74
+ } else finalSize = minSize;
75
+ }
76
+ finalSize = Math.min(maxSize, finalSize);
77
+ return parseFloat(finalSize.toFixed(3));
78
+ }
79
+ function validateLayoutUnderConstraints(layout, groupSize, panels) {
80
+ if (groupSize <= 0 || layout.length === 0) return layout;
81
+ const constraints = panels.map((p) => getResolvedConstraints(p, groupSize));
82
+ const nextLayout = [...layout];
83
+ let remainingSize = 0;
84
+ for (let i = 0; i < nextLayout.length; i++) {
85
+ const prevSize = layout[i];
86
+ const unsafeSize = nextLayout[i];
87
+ const safeSize = validatePanelSize({
88
+ size: unsafeSize,
89
+ prevSize,
90
+ constraints: constraints[i],
91
+ overrideDisabledPanels: true
92
+ });
93
+ if (Math.abs(unsafeSize - safeSize) > .001) {
94
+ remainingSize += unsafeSize - safeSize;
95
+ nextLayout[i] = safeSize;
96
+ }
97
+ }
98
+ if (Math.abs(remainingSize) > .001) for (let i = 0; i < nextLayout.length; i++) {
99
+ const prevSize = nextLayout[i];
100
+ const safeSize = validatePanelSize({
101
+ size: prevSize + remainingSize,
102
+ prevSize,
103
+ constraints: constraints[i],
104
+ overrideDisabledPanels: true
105
+ });
106
+ if (Math.abs(prevSize - safeSize) > .001) {
107
+ remainingSize -= safeSize - prevSize;
108
+ nextLayout[i] = safeSize;
109
+ if (Math.abs(remainingSize) <= .001) break;
110
+ }
111
+ }
112
+ const finalTotal = nextLayout.reduce((a, b) => a + b, 0);
113
+ if (Math.abs(finalTotal - 100) > .01) return nextLayout.map((val) => parseFloat((val / finalTotal * 100).toFixed(3)));
114
+ return nextLayout;
115
+ }
116
+ function adjustLayout({ delta, layout: initialLayout, panels, handleIndex, groupSize, overrideDisabledPanels = false }) {
117
+ if (Math.abs(delta) < .001) return initialLayout;
118
+ const nextLayout = [...initialLayout];
119
+ const totalPanels = panels.length;
120
+ const isLeftGrowing = delta > 0;
121
+ const absDelta = Math.abs(delta);
122
+ const constraints = panels.map((p) => getResolvedConstraints(p, groupSize));
123
+ let deltaToShrink = absDelta;
124
+ let shrinkDeltaApplied = 0;
125
+ if (isLeftGrowing) for (let i = handleIndex + 1; i < totalPanels; i++) {
126
+ const prevSize = nextLayout[i];
127
+ const newSize = validatePanelSize({
128
+ size: prevSize - deltaToShrink,
129
+ prevSize,
130
+ constraints: constraints[i],
131
+ overrideDisabledPanels
132
+ });
133
+ const applied = prevSize - newSize;
134
+ shrinkDeltaApplied += applied;
135
+ nextLayout[i] = parseFloat(newSize.toFixed(3));
136
+ deltaToShrink -= applied;
137
+ if (deltaToShrink <= .001) break;
138
+ }
139
+ else for (let i = handleIndex; i >= 0; i--) {
140
+ const prevSize = nextLayout[i];
141
+ const newSize = validatePanelSize({
142
+ size: prevSize - deltaToShrink,
143
+ prevSize,
144
+ constraints: constraints[i],
145
+ overrideDisabledPanels
146
+ });
147
+ const applied = prevSize - newSize;
148
+ shrinkDeltaApplied += applied;
149
+ nextLayout[i] = parseFloat(newSize.toFixed(3));
150
+ deltaToShrink -= applied;
151
+ if (deltaToShrink <= .001) break;
152
+ }
153
+ let deltaToGrow = shrinkDeltaApplied;
154
+ if (isLeftGrowing) for (let i = handleIndex; i >= 0; i--) {
155
+ const prevSize = nextLayout[i];
156
+ const newSize = validatePanelSize({
157
+ size: prevSize + deltaToGrow,
158
+ prevSize,
159
+ constraints: constraints[i],
160
+ overrideDisabledPanels
161
+ });
162
+ const applied = newSize - prevSize;
163
+ nextLayout[i] = parseFloat(newSize.toFixed(3));
164
+ deltaToGrow -= applied;
165
+ if (deltaToGrow <= .001) break;
166
+ }
167
+ else for (let i = handleIndex + 1; i < totalPanels; i++) {
168
+ const prevSize = nextLayout[i];
169
+ const newSize = validatePanelSize({
170
+ size: prevSize + deltaToGrow,
171
+ prevSize,
172
+ constraints: constraints[i],
173
+ overrideDisabledPanels
174
+ });
175
+ const applied = newSize - prevSize;
176
+ nextLayout[i] = parseFloat(newSize.toFixed(3));
177
+ deltaToGrow -= applied;
178
+ if (deltaToGrow <= .001) break;
179
+ }
180
+ const total = nextLayout.reduce((sum, size) => sum + size, 0);
181
+ if (Math.abs(total - 100) > .01) return nextLayout.map((val) => parseFloat((val / total * 100).toFixed(3)));
182
+ return nextLayout;
183
+ }
184
+ function ResizablePanelGroup({ children, className, direction = "horizontal", onLayoutChange, onLayoutChanged, defaultLayout, storageKey, storage, groupRef, disabled = false, ...props }) {
185
+ const id = React$1.useId();
186
+ const panelsRef = React$1.useRef([]);
187
+ const handlesRef = React$1.useRef([]);
188
+ const containerRef = React$1.useRef(null);
189
+ const [layout, setLayout] = React$1.useState([]);
190
+ const [panelsList, setPanelsList] = React$1.useState([]);
191
+ const [activeHandleId, setActiveHandleId] = React$1.useState(null);
192
+ const [groupSize, setGroupSize] = React$1.useState(0);
193
+ const layoutRef = React$1.useRef(layout);
194
+ React$1.useEffect(() => {
195
+ layoutRef.current = layout;
196
+ }, [layout]);
197
+ const directionRef = React$1.useRef(direction);
198
+ React$1.useEffect(() => {
199
+ directionRef.current = direction;
200
+ }, [direction]);
201
+ const sortPanels = React$1.useCallback(() => {
202
+ panelsRef.current.sort((a, b) => {
203
+ const elA = a.ref.current;
204
+ const elB = b.ref.current;
205
+ if (!elA || !elB) return 0;
206
+ return elA.compareDocumentPosition(elB) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
207
+ });
208
+ setPanelsList([...panelsRef.current]);
209
+ }, []);
210
+ const sortHandles = React$1.useCallback(() => {
211
+ handlesRef.current.sort((a, b) => {
212
+ const elA = a.ref.current;
213
+ const elB = b.ref.current;
214
+ if (!elA || !elB) return 0;
215
+ return elA.compareDocumentPosition(elB) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
216
+ });
217
+ }, []);
218
+ const registerPanel = React$1.useCallback((panelId, ref, config) => {
219
+ panelsRef.current.push({
220
+ id: panelId,
221
+ ref,
222
+ config
223
+ });
224
+ sortPanels();
225
+ return () => {
226
+ panelsRef.current = panelsRef.current.filter((p) => p.id !== panelId);
227
+ sortPanels();
228
+ };
229
+ }, [sortPanels]);
230
+ const registerHandle = React$1.useCallback((handleId, ref, config) => {
231
+ handlesRef.current.push({
232
+ id: handleId,
233
+ ref,
234
+ config
235
+ });
236
+ sortHandles();
237
+ return () => {
238
+ handlesRef.current = handlesRef.current.filter((handle) => handle.id !== handleId);
239
+ sortHandles();
240
+ };
241
+ }, [sortHandles]);
242
+ React$1.useEffect(() => {
243
+ const container = containerRef.current;
244
+ if (!container) return;
245
+ const observer = new ResizeObserver((entries) => {
246
+ for (const entry of entries) if (entry.target === container) {
247
+ const isHorizontal = directionRef.current === "horizontal";
248
+ const newSize = panelsRef.current.reduce((total, panel) => {
249
+ const el = panel.ref.current;
250
+ if (!el) return total;
251
+ return total + (isHorizontal ? el.offsetWidth : el.offsetHeight);
252
+ }, 0);
253
+ if (newSize > 0) setGroupSize((prevSize) => {
254
+ if (prevSize === newSize) return prevSize;
255
+ setLayout((prevLayout) => {
256
+ if (prevLayout.length === 0 || prevSize <= 0) return prevLayout;
257
+ let fixedPanelsTotalPercent = 0;
258
+ let flexiblePanelsTotalPrevPercent = 0;
259
+ let hasPreservePixelSize = false;
260
+ const fixedPercentMap = /* @__PURE__ */ new Map();
261
+ const flexibleIndices = [];
262
+ panelsRef.current.forEach((panel, i) => {
263
+ const prevVal = prevLayout[i] ?? 0;
264
+ if (panel.config.groupResizeBehavior === "preserve-pixel-size") {
265
+ hasPreservePixelSize = true;
266
+ const prevSizeInPixels = prevVal / 100 * prevSize;
267
+ const nextPercent = parseFloat((prevSizeInPixels / newSize * 100).toFixed(3));
268
+ fixedPercentMap.set(i, nextPercent);
269
+ fixedPanelsTotalPercent += nextPercent;
270
+ } else {
271
+ flexibleIndices.push(i);
272
+ flexiblePanelsTotalPrevPercent += prevVal;
273
+ }
274
+ });
275
+ if (!hasPreservePixelSize || flexibleIndices.length === 0) return prevLayout;
276
+ const remainingPercent = 100 - fixedPanelsTotalPercent;
277
+ const nextLayout = [...prevLayout];
278
+ fixedPercentMap.forEach((pct, i) => {
279
+ nextLayout[i] = pct;
280
+ });
281
+ if (flexiblePanelsTotalPrevPercent > 0) flexibleIndices.forEach((i) => {
282
+ const prevVal = prevLayout[i] ?? 0;
283
+ nextLayout[i] = parseFloat((prevVal / flexiblePanelsTotalPrevPercent * remainingPercent).toFixed(3));
284
+ });
285
+ else {
286
+ const share = remainingPercent / flexibleIndices.length;
287
+ flexibleIndices.forEach((i) => {
288
+ nextLayout[i] = parseFloat(share.toFixed(3));
289
+ });
290
+ }
291
+ return validateLayoutUnderConstraints(nextLayout, newSize, panelsRef.current);
292
+ });
293
+ return newSize;
294
+ });
295
+ }
296
+ });
297
+ observer.observe(container);
298
+ return () => {
299
+ observer.disconnect();
300
+ };
301
+ }, []);
302
+ React$1.useEffect(() => {
303
+ if (panelsList.length === 0) return;
304
+ setLayout((prev) => {
305
+ if (prev.length === panelsList.length) return prev;
306
+ const newLayout = Array.from({ length: panelsList.length }).fill(0);
307
+ let totalSpecified = 0;
308
+ let unspecifiedCount = 0;
309
+ panelsList.forEach((panel, i) => {
310
+ const def = defaultLayout?.[i] ?? panel.config.defaultSize;
311
+ if (def !== void 0) {
312
+ const [val, unit] = parseSizeAndUnit(def);
313
+ let pct = val;
314
+ if (unit !== "%") {
315
+ if (groupSize > 0) pct = convertSizeToPixels(def, panel.ref.current, groupSize) / groupSize * 100;
316
+ else pct = unit === "px" ? 0 : val;
317
+ }
318
+ newLayout[i] = parseFloat(pct.toFixed(3));
319
+ totalSpecified += pct;
320
+ } else unspecifiedCount++;
321
+ });
322
+ if (unspecifiedCount > 0) {
323
+ const share = Math.max(0, 100 - totalSpecified) / unspecifiedCount;
324
+ panelsList.forEach((panel, i) => {
325
+ if (defaultLayout?.[i] === void 0 && panel.config.defaultSize === void 0) newLayout[i] = parseFloat(share.toFixed(3));
326
+ });
327
+ } else if (Math.abs(totalSpecified - 100) > .05 && totalSpecified > 0) panelsList.forEach((_, i) => {
328
+ newLayout[i] = parseFloat((newLayout[i] / totalSpecified * 100).toFixed(3));
329
+ });
330
+ return validateLayoutUnderConstraints(newLayout, groupSize, panelsList);
331
+ });
332
+ }, [
333
+ panelsList,
334
+ groupSize,
335
+ defaultLayout
336
+ ]);
337
+ const onLayoutChangedRef = React$1.useRef(onLayoutChanged);
338
+ React$1.useEffect(() => {
339
+ onLayoutChangedRef.current = onLayoutChanged;
340
+ }, [onLayoutChanged]);
341
+ const triggerLayoutChanged = React$1.useCallback(() => {
342
+ onLayoutChangedRef.current?.(layoutRef.current);
343
+ }, []);
344
+ React$1.useEffect(() => {
345
+ if (!storageKey || panelsList.length === 0) return;
346
+ try {
347
+ const finalKey = `${storageKey}:${panelsRef.current.map((p) => p.id).join(":")}`;
348
+ const saved = (storage || window.localStorage).getItem(finalKey);
349
+ if (saved) {
350
+ const parsed = JSON.parse(saved);
351
+ if (Array.isArray(parsed) && parsed.length === panelsRef.current.length) {
352
+ const validated = validateLayoutUnderConstraints(parsed, groupSize, panelsList);
353
+ setLayout(validated);
354
+ }
355
+ }
356
+ } catch (e) {
357
+ console.warn("Resizable: Failed to load layout from storage", e);
358
+ }
359
+ }, [
360
+ storageKey,
361
+ storage,
362
+ panelsList,
363
+ groupSize
364
+ ]);
365
+ const prevLayoutStringRef = React$1.useRef("");
366
+ React$1.useEffect(() => {
367
+ if (layout.length === 0) return;
368
+ const layoutStr = JSON.stringify(layout);
369
+ if (prevLayoutStringRef.current !== layoutStr) {
370
+ prevLayoutStringRef.current = layoutStr;
371
+ onLayoutChange?.(layout);
372
+ if (storageKey && panelsRef.current.length > 0) try {
373
+ const finalKey = `${storageKey}:${panelsRef.current.map((p) => p.id).join(":")}`;
374
+ (storage || window.localStorage).setItem(finalKey, layoutStr);
375
+ } catch (e) {
376
+ console.warn("Resizable: Failed to save layout to storage", e);
377
+ }
378
+ }
379
+ }, [
380
+ layout,
381
+ onLayoutChange,
382
+ storageKey,
383
+ storage
384
+ ]);
385
+ const prevCollapsedRef = React$1.useRef({});
386
+ React$1.useEffect(() => {
387
+ if (layout.length === 0 || panelsList.length !== layout.length || groupSize === 0) return;
388
+ const nextCollapsed = {};
389
+ panelsList.forEach((panel, i) => {
390
+ const size = layout[i];
391
+ if (size === void 0) return;
392
+ const pc = getResolvedConstraints(panel, groupSize);
393
+ const isCollapsed = pc.collapsible && Math.abs(size - pc.collapsedSize) < .01;
394
+ nextCollapsed[panel.id] = isCollapsed;
395
+ const wasCollapsed = prevCollapsedRef.current[panel.id];
396
+ if (wasCollapsed !== void 0 && wasCollapsed !== isCollapsed) {
397
+ if (isCollapsed) panel.config.onCollapse?.();
398
+ else panel.config.onExpand?.();
399
+ }
400
+ });
401
+ prevCollapsedRef.current = nextCollapsed;
402
+ }, [
403
+ layout,
404
+ panelsList,
405
+ groupSize
406
+ ]);
407
+ React$1.useEffect(() => {
408
+ activeGroups.set(id, {
409
+ groupId: id,
410
+ direction,
411
+ element: containerRef.current,
412
+ groupSize,
413
+ panels: panelsRef.current,
414
+ handles: handlesRef.current,
415
+ layout,
416
+ setLayout: (nextLayout) => {
417
+ setLayout(nextLayout);
418
+ },
419
+ setActiveHandleId,
420
+ triggerLayoutChanged
421
+ });
422
+ return () => {
423
+ activeGroups.delete(id);
424
+ };
425
+ }, [
426
+ id,
427
+ direction,
428
+ groupSize,
429
+ layout,
430
+ triggerLayoutChanged
431
+ ]);
432
+ React$1.useImperativeHandle(groupRef, () => ({
433
+ getLayout: () => layoutRef.current,
434
+ setLayout: (newLayout) => {
435
+ if (newLayout.length !== panelsRef.current.length) return;
436
+ const validated = validateLayoutUnderConstraints(newLayout, groupSize, panelsRef.current);
437
+ setLayout(validated);
438
+ }
439
+ }));
440
+ const startDragging = React$1.useCallback((handleId, event) => {
441
+ if (disabled) return;
442
+ event.preventDefault();
443
+ if (!containerRef.current || groupSize === 0) return;
444
+ const startX = event.clientX;
445
+ const startY = event.clientY;
446
+ const activeDragHandles = [];
447
+ activeGroups.forEach((group) => {
448
+ group.handles.forEach((h) => {
449
+ const handleEl = h.ref.current;
450
+ if (!handleEl || h.config?.disabled) return;
451
+ const rect = handleEl.getBoundingClientRect();
452
+ const threshold = 12;
453
+ if (startX >= rect.left - threshold && startX <= rect.right + threshold && startY >= rect.top - threshold && startY <= rect.bottom + threshold) {
454
+ const handleIndex = group.handles.findIndex((item) => item.id === h.id);
455
+ if (handleIndex !== -1 && handleIndex < group.panels.length - 1) activeDragHandles.push({
456
+ groupId: group.groupId,
457
+ handleId: h.id,
458
+ handleIndex,
459
+ direction: group.direction,
460
+ initialLayout: [...group.layout],
461
+ groupSize: group.groupSize,
462
+ handleEl
463
+ });
464
+ }
465
+ });
466
+ });
467
+ if (activeDragHandles.length === 0) return;
468
+ activeDragHandles.forEach((adh) => {
469
+ const group = activeGroups.get(adh.groupId);
470
+ if (group) group.setActiveHandleId(adh.handleId);
471
+ });
472
+ const hasHorizontal = activeDragHandles.some((h) => h.direction === "horizontal");
473
+ const hasVertical = activeDragHandles.some((h) => h.direction === "vertical");
474
+ let cursorStyle = "col-resize";
475
+ if (hasHorizontal && hasVertical) cursorStyle = "move";
476
+ else if (hasVertical) cursorStyle = "row-resize";
477
+ const style = document.createElement("style");
478
+ style.id = `resizable-style-${handleId}`;
479
+ style.innerHTML = `* { cursor: ${cursorStyle} !important; user-select: none !important; }`;
480
+ document.head.appendChild(style);
481
+ const handlePointerMove = (moveEvent) => {
482
+ const clickedAdh = activeDragHandles.find((adh) => adh.handleId === handleId);
483
+ if (clickedAdh?.handleEl && !clickedAdh.handleEl.hasPointerCapture(moveEvent.pointerId)) clickedAdh.handleEl.setPointerCapture(moveEvent.pointerId);
484
+ activeDragHandles.forEach((adh) => {
485
+ const { direction: activeDirection, initialLayout, handleIndex, groupSize: activeGroupSize, groupId } = adh;
486
+ const group = activeGroups.get(groupId);
487
+ if (!group || activeGroupSize === 0) return;
488
+ const next = adjustLayout({
489
+ delta: ((activeDirection === "horizontal" ? moveEvent.clientX : moveEvent.clientY) - (activeDirection === "horizontal" ? startX : startY)) / activeGroupSize * 100,
490
+ layout: initialLayout,
491
+ panels: group.panels,
492
+ handleIndex,
493
+ groupSize: activeGroupSize,
494
+ overrideDisabledPanels: false
495
+ });
496
+ group.setLayout(next);
497
+ });
498
+ };
499
+ const handlePointerUp = () => {
500
+ activeDragHandles.forEach((adh) => {
501
+ const group = activeGroups.get(adh.groupId);
502
+ if (group) {
503
+ group.setActiveHandleId(null);
504
+ group.triggerLayoutChanged();
505
+ }
506
+ });
507
+ document.getElementById(`resizable-style-${handleId}`)?.remove();
508
+ window.removeEventListener("pointermove", handlePointerMove);
509
+ window.removeEventListener("pointerup", handlePointerUp);
510
+ };
511
+ window.addEventListener("pointermove", handlePointerMove);
512
+ window.addEventListener("pointerup", handlePointerUp);
513
+ }, [disabled, groupSize]);
514
+ const handleKeyDown = React$1.useCallback((handleId, event) => {
515
+ if (disabled || groupSize <= 0) return;
516
+ const handleIndex = handlesRef.current.findIndex((h) => h.id === handleId);
517
+ if (handleIndex === -1 || handleIndex >= panelsRef.current.length - 1) return;
518
+ if (handlesRef.current[handleIndex].config?.disabled) return;
519
+ const isHorizontal = directionRef.current === "horizontal";
520
+ const currentLayout = [...layoutRef.current];
521
+ const panelA = panelsRef.current[handleIndex];
522
+ const panelB = panelsRef.current[handleIndex + 1];
523
+ let deltaPercent = 0;
524
+ const step = event.shiftKey ? 10 : 5;
525
+ switch (event.key) {
526
+ case "ArrowLeft":
527
+ if (isHorizontal) deltaPercent = -step;
528
+ break;
529
+ case "ArrowUp":
530
+ if (!isHorizontal) deltaPercent = -step;
531
+ break;
532
+ case "ArrowRight":
533
+ if (isHorizontal) deltaPercent = step;
534
+ break;
535
+ case "ArrowDown":
536
+ if (!isHorizontal) deltaPercent = step;
537
+ break;
538
+ case "Home": {
539
+ const pc = getResolvedConstraints(panelA, groupSize);
540
+ deltaPercent = -currentLayout[handleIndex] + (pc.collapsible ? pc.collapsedSize : pc.minSize);
541
+ break;
542
+ }
543
+ case "End": {
544
+ const pc = getResolvedConstraints(panelB, groupSize);
545
+ deltaPercent = currentLayout[handleIndex + 1] - (pc.collapsible ? pc.collapsedSize : pc.minSize);
546
+ break;
547
+ }
548
+ case "Enter": {
549
+ event.preventDefault();
550
+ const pc = getResolvedConstraints(panelA, groupSize);
551
+ if (pc.collapsible) {
552
+ const sizeA = currentLayout[handleIndex];
553
+ const isCollapsed = Math.abs(sizeA - pc.collapsedSize) < .01;
554
+ let targetSize = sizeA;
555
+ if (isCollapsed) {
556
+ targetSize = panelA.expandToSize ?? pc.minSize;
557
+ if (targetSize === pc.collapsedSize) targetSize = pc.minSize > pc.collapsedSize ? pc.minSize : pc.collapsedSize + 1;
558
+ } else {
559
+ panelA.expandToSize = sizeA;
560
+ targetSize = pc.collapsedSize;
561
+ }
562
+ deltaPercent = targetSize - sizeA;
563
+ }
564
+ break;
565
+ }
566
+ case "F6": {
567
+ event.preventDefault();
568
+ const separatorElements = handlesRef.current.map((h) => h.ref.current).filter(Boolean);
569
+ const currentIndex = separatorElements.indexOf(event.currentTarget);
570
+ if (currentIndex !== -1) separatorElements[event.shiftKey ? currentIndex > 0 ? currentIndex - 1 : separatorElements.length - 1 : currentIndex + 1 < separatorElements.length ? currentIndex + 1 : 0]?.focus({ preventScroll: true });
571
+ return;
572
+ }
573
+ default: return;
574
+ }
575
+ event.preventDefault();
576
+ if (Math.abs(deltaPercent) < .001) return;
577
+ const next = adjustLayout({
578
+ delta: deltaPercent,
579
+ layout: currentLayout,
580
+ panels: panelsRef.current,
581
+ handleIndex,
582
+ groupSize,
583
+ overrideDisabledPanels: false
584
+ });
585
+ setLayout(next);
586
+ onLayoutChanged?.(next);
587
+ }, [
588
+ groupSize,
589
+ disabled,
590
+ onLayoutChanged
591
+ ]);
592
+ const handleDoubleClick = React$1.useCallback((handleId) => {
593
+ if (disabled) return;
594
+ const handleIndex = handlesRef.current.findIndex((h) => h.id === handleId);
595
+ if (handleIndex === -1 || handleIndex >= panelsRef.current.length - 1) return;
596
+ const handle = handlesRef.current[handleIndex];
597
+ if (handle?.config?.disabled || handle?.config?.disableDoubleClick) return;
598
+ const currentLayout = [...layoutRef.current];
599
+ const panelA = panelsRef.current[handleIndex];
600
+ const sizeA = currentLayout[handleIndex];
601
+ const pc = getResolvedConstraints(panelA, groupSize);
602
+ if (!pc.collapsible) return;
603
+ const isCollapsed = Math.abs(sizeA - pc.collapsedSize) < .01;
604
+ let targetSize = sizeA;
605
+ if (isCollapsed) {
606
+ targetSize = panelA.expandToSize ?? pc.minSize;
607
+ if (targetSize === pc.collapsedSize) targetSize = pc.minSize > pc.collapsedSize ? pc.minSize : pc.collapsedSize + 1;
608
+ } else {
609
+ panelA.expandToSize = sizeA;
610
+ targetSize = pc.collapsedSize;
611
+ }
612
+ if (Math.abs(targetSize - sizeA) > .01) {
613
+ const next = adjustLayout({
614
+ delta: targetSize - sizeA,
615
+ layout: currentLayout,
616
+ panels: panelsRef.current,
617
+ handleIndex,
618
+ groupSize,
619
+ overrideDisabledPanels: false
620
+ });
621
+ setLayout(next);
622
+ onLayoutChanged?.(next);
623
+ }
624
+ }, [
625
+ groupSize,
626
+ disabled,
627
+ onLayoutChanged
628
+ ]);
629
+ const resizePanel = React$1.useCallback((panelId, targetSize) => {
630
+ const panelIndex = panelsRef.current.findIndex((p) => p.id === panelId);
631
+ if (panelIndex === -1 || groupSize === 0) return;
632
+ const prev = layoutRef.current;
633
+ const currentSize = prev[panelIndex];
634
+ if (currentSize === void 0) return;
635
+ const delta = targetSize - currentSize;
636
+ if (Math.abs(delta) < .001) return;
637
+ const handleIndex = panelIndex === prev.length - 1 ? panelIndex - 1 : panelIndex;
638
+ const next = adjustLayout({
639
+ delta: panelIndex === handleIndex ? delta : -delta,
640
+ layout: prev,
641
+ panels: panelsRef.current,
642
+ handleIndex,
643
+ groupSize,
644
+ overrideDisabledPanels: true
645
+ });
646
+ if (JSON.stringify(prev) !== JSON.stringify(next)) setLayout(next);
647
+ }, [groupSize]);
648
+ const contextValue = React$1.useMemo(() => ({
649
+ direction,
650
+ registerPanel,
651
+ registerHandle,
652
+ startDragging,
653
+ handleKeyDown,
654
+ handleDoubleClick,
655
+ activeHandleId,
656
+ layout,
657
+ panels: panelsList,
658
+ handles: handlesRef.current,
659
+ groupSize,
660
+ resizePanel
661
+ }), [
662
+ direction,
663
+ registerPanel,
664
+ registerHandle,
665
+ startDragging,
666
+ handleKeyDown,
667
+ handleDoubleClick,
668
+ activeHandleId,
669
+ layout,
670
+ panelsList,
671
+ groupSize,
672
+ resizePanel
673
+ ]);
674
+ return /* @__PURE__ */ jsx(ResizableGroupContext.Provider, {
675
+ value: contextValue,
676
+ children: /* @__PURE__ */ jsx("div", {
677
+ ref: (node) => {
678
+ containerRef.current = node;
679
+ },
680
+ className: cn("flex size-full data-[panel-group-direction=vertical]:flex-col", className),
681
+ "data-panel-group": true,
682
+ "data-panel-group-direction": direction,
683
+ "data-slot": "resizable-group",
684
+ style: { touchAction: direction === "horizontal" ? "pan-y" : "pan-x" },
685
+ ...props,
686
+ children
687
+ })
688
+ });
689
+ }
690
+ function ResizablePanel({ id: idProp, children, className, defaultSize, minSize = "0%", maxSize = "100%", collapsible = false, collapsedSize = "0%", disabled = false, groupResizeBehavior = "preserve-relative-size", onResize, onCollapse, onExpand, panelRef, style, ...props }) {
691
+ const reactId = React$1.useId();
692
+ const id = idProp || reactId;
693
+ const ref = React$1.useRef(null);
694
+ const { registerPanel, layout, panels, resizePanel, groupSize, direction } = useResizableGroup();
695
+ const expandToSizeRef = React$1.useRef(void 0);
696
+ React$1.useEffect(() => {
697
+ return registerPanel(id, ref, {
698
+ defaultSize,
699
+ minSize,
700
+ maxSize,
701
+ collapsible,
702
+ collapsedSize,
703
+ disabled,
704
+ groupResizeBehavior,
705
+ onResize,
706
+ onCollapse,
707
+ onExpand
708
+ });
709
+ }, [
710
+ id,
711
+ registerPanel,
712
+ defaultSize,
713
+ minSize,
714
+ maxSize,
715
+ collapsible,
716
+ collapsedSize,
717
+ disabled,
718
+ groupResizeBehavior,
719
+ onResize,
720
+ onCollapse,
721
+ onExpand
722
+ ]);
723
+ const index = panels.findIndex((p) => p.id === id);
724
+ const size = index !== -1 ? layout[index] : void 0;
725
+ const pc = index !== -1 && groupSize > 0 ? getResolvedConstraints(panels[index], groupSize) : {
726
+ collapsedSize: 0,
727
+ minSize: 0,
728
+ maxSize: 100,
729
+ collapsible: false,
730
+ disabled: false
731
+ };
732
+ const isCollapsed = size !== void 0 && pc.collapsible && Math.abs(size - pc.collapsedSize) < .01;
733
+ const prevSizeRef = React$1.useRef(void 0);
734
+ React$1.useEffect(() => {
735
+ if (size === void 0) return;
736
+ const currentPixels = ref.current ? direction === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight : 0;
737
+ const currentSizeObj = {
738
+ asPercentage: size,
739
+ inPixels: currentPixels
740
+ };
741
+ if (!prevSizeRef.current || Math.abs(prevSizeRef.current.asPercentage - currentSizeObj.asPercentage) > .01 || Math.abs(prevSizeRef.current.inPixels - currentSizeObj.inPixels) > 1) {
742
+ onResize?.(currentSizeObj);
743
+ prevSizeRef.current = currentSizeObj;
744
+ }
745
+ }, [
746
+ size,
747
+ direction,
748
+ onResize
749
+ ]);
750
+ React$1.useEffect(() => {
751
+ if (index !== -1 && size !== void 0) {
752
+ const activePanel = panels[index];
753
+ if (activePanel) {
754
+ if (!isCollapsed) {
755
+ activePanel.expandToSize = size;
756
+ expandToSizeRef.current = size;
757
+ } else activePanel.expandToSize = expandToSizeRef.current;
758
+ }
759
+ }
760
+ }, [
761
+ size,
762
+ isCollapsed,
763
+ index,
764
+ panels
765
+ ]);
766
+ React$1.useImperativeHandle(panelRef, () => ({
767
+ collapse: () => {
768
+ const idx = panels.findIndex((p) => p.id === id);
769
+ if (idx === -1) return;
770
+ const constraints = getResolvedConstraints(panels[idx], groupSize);
771
+ if (constraints.collapsible && size !== constraints.collapsedSize) {
772
+ expandToSizeRef.current = size;
773
+ panels[idx].expandToSize = size;
774
+ resizePanel(id, constraints.collapsedSize);
775
+ }
776
+ },
777
+ expand: () => {
778
+ const idx = panels.findIndex((p) => p.id === id);
779
+ if (idx === -1) return;
780
+ const constraints = getResolvedConstraints(panels[idx], groupSize);
781
+ const panelIsCollapsed = size === constraints.collapsedSize;
782
+ if (constraints.collapsible && panelIsCollapsed) {
783
+ let target = expandToSizeRef.current ?? constraints.minSize;
784
+ if (target === constraints.collapsedSize) target = constraints.minSize > constraints.collapsedSize ? constraints.minSize : constraints.collapsedSize + 1;
785
+ resizePanel(id, target);
786
+ }
787
+ },
788
+ resize: (newSize) => {
789
+ const pixels = convertSizeToPixels(newSize, ref.current, groupSize);
790
+ const pct = parseFloat((pixels / groupSize * 100).toFixed(3));
791
+ resizePanel(id, pct);
792
+ },
793
+ isCollapsed: () => {
794
+ const idx = panels.findIndex((p) => p.id === id);
795
+ if (idx === -1) return false;
796
+ const constraints = getResolvedConstraints(panels[idx], groupSize);
797
+ return constraints.collapsible && Math.abs((size ?? 0) - constraints.collapsedSize) < .01;
798
+ },
799
+ isExpanded: () => {
800
+ const idx = panels.findIndex((p) => p.id === id);
801
+ if (idx === -1) return true;
802
+ const constraints = getResolvedConstraints(panels[idx], groupSize);
803
+ return !constraints.collapsible || Math.abs((size ?? 0) - constraints.collapsedSize) >= .01;
804
+ },
805
+ getSize: () => {
806
+ return {
807
+ asPercentage: size ?? 0,
808
+ inPixels: ref.current ? direction === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight : 0
809
+ };
810
+ }
811
+ }));
812
+ const outerStyle = {
813
+ ...size !== void 0 ? {
814
+ flexGrow: size,
815
+ flexShrink: 1,
816
+ flexBasis: "0px"
817
+ } : {
818
+ flexGrow: 1,
819
+ flexShrink: 1,
820
+ flexBasis: "0px"
821
+ },
822
+ display: "flex",
823
+ flexBasis: "0px",
824
+ flexShrink: 1,
825
+ overflow: "hidden",
826
+ minHeight: 0,
827
+ minWidth: 0
828
+ };
829
+ const innerStyle = {
830
+ maxHeight: "100%",
831
+ maxWidth: "100%",
832
+ flexGrow: 1,
833
+ overflow: "auto",
834
+ touchAction: direction === "horizontal" ? "pan-y" : "pan-x",
835
+ ...style
836
+ };
837
+ return /* @__PURE__ */ jsx("div", {
838
+ ref: (node) => {
839
+ ref.current = node;
840
+ },
841
+ style: outerStyle,
842
+ "data-panel": true,
843
+ "data-disabled": disabled || void 0,
844
+ "data-state": isCollapsed ? "collapsed" : "expanded",
845
+ "data-slot": "resizable-panel-outer",
846
+ ...props,
847
+ children: /* @__PURE__ */ jsx("div", {
848
+ className: cn("size-full select-none relative", isCollapsed && "pointer-events-none", className),
849
+ style: innerStyle,
850
+ "data-slot": "resizable-panel",
851
+ children
852
+ })
853
+ });
854
+ }
855
+ function ResizableHandle({ className, style, withHandle = false, disabled = false, disableDoubleClick = false, ...props }) {
856
+ const id = React$1.useId();
857
+ const ref = React$1.useRef(null);
858
+ const { direction, registerHandle, startDragging, handleKeyDown, handleDoubleClick, activeHandleId, layout, panels, handles, groupSize } = useResizableGroup();
859
+ const [isFocused, setIsFocused] = React$1.useState(false);
860
+ React$1.useEffect(() => {
861
+ return registerHandle(id, ref, {
862
+ disabled,
863
+ disableDoubleClick
864
+ });
865
+ }, [
866
+ id,
867
+ registerHandle,
868
+ disabled,
869
+ disableDoubleClick
870
+ ]);
871
+ const isHorizontal = direction === "horizontal";
872
+ const isDragging = activeHandleId === id;
873
+ const handleClasses = cn("relative flex items-center justify-center transition-colors select-none focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 z-10 bg-border", isHorizontal ? "w-px h-full cursor-col-resize before:absolute before:inset-y-0 before:inset-x-0 before:bg-gradient-to-b before:from-transparent before:via-ring/80 before:to-transparent before:opacity-0 before:transition-opacity before:duration-300 hover:before:opacity-100 data-[state=dragging]:before:opacity-100 after:absolute after:-inset-x-2 after:inset-y-0 pointer-coarse:after:-inset-x-5" : "h-px w-full cursor-row-resize before:absolute before:inset-x-0 before:inset-y-0 before:bg-gradient-to-r before:from-transparent before:via-ring/80 before:to-transparent before:opacity-0 before:transition-opacity before:duration-300 hover:before:opacity-100 data-[state=dragging]:before:opacity-100 after:absolute after:-inset-y-2 after:inset-x-0 pointer-coarse:after:-inset-y-5", isDragging && "before:opacity-100", disabled && "pointer-events-none opacity-64", className);
874
+ const handlePointerDown = React$1.useCallback((event) => {
875
+ if (disabled) return;
876
+ startDragging(id, event);
877
+ }, [
878
+ id,
879
+ disabled,
880
+ startDragging
881
+ ]);
882
+ const onKeyDown = React$1.useCallback((event) => {
883
+ if (disabled) return;
884
+ handleKeyDown(id, event);
885
+ }, [
886
+ id,
887
+ disabled,
888
+ handleKeyDown
889
+ ]);
890
+ const onDoubleClick = React$1.useCallback((event) => {
891
+ if (disabled) return;
892
+ event.preventDefault();
893
+ handleDoubleClick(id);
894
+ }, [
895
+ id,
896
+ disabled,
897
+ handleDoubleClick
898
+ ]);
899
+ const handleIndex = handles.findIndex((h) => h.id === id);
900
+ let ariaValueNow;
901
+ let ariaValueMin;
902
+ let ariaValueMax;
903
+ let controlledPanelId;
904
+ if (handleIndex !== -1 && handleIndex < panels.length - 1 && layout.length > handleIndex && groupSize > 0) {
905
+ controlledPanelId = panels[handleIndex].id;
906
+ ariaValueNow = Math.round(layout[handleIndex]);
907
+ const minLayout = adjustLayout({
908
+ delta: -100,
909
+ layout,
910
+ panels,
911
+ handleIndex,
912
+ groupSize,
913
+ overrideDisabledPanels: false
914
+ });
915
+ ariaValueMin = Math.round(minLayout[handleIndex]);
916
+ const maxLayout = adjustLayout({
917
+ delta: 100,
918
+ layout,
919
+ panels,
920
+ handleIndex,
921
+ groupSize,
922
+ overrideDisabledPanels: false
923
+ });
924
+ ariaValueMax = Math.round(maxLayout[handleIndex]);
925
+ }
926
+ let dataSeparator = "idle";
927
+ if (disabled) dataSeparator = "disabled";
928
+ else if (isDragging) dataSeparator = "active";
929
+ else if (isFocused) dataSeparator = "focus";
930
+ return /* @__PURE__ */ jsx("button", {
931
+ ref: (node) => {
932
+ ref.current = node;
933
+ },
934
+ type: "button",
935
+ className: handleClasses,
936
+ onPointerDown: handlePointerDown,
937
+ onKeyDown,
938
+ onDoubleClick,
939
+ onFocus: () => setIsFocused(true),
940
+ onBlur: () => setIsFocused(false),
941
+ role: "separator",
942
+ tabIndex: disabled ? -1 : 0,
943
+ "aria-orientation": isHorizontal ? "vertical" : "horizontal",
944
+ "aria-valuenow": ariaValueNow,
945
+ "aria-valuemin": ariaValueMin,
946
+ "aria-valuemax": ariaValueMax,
947
+ "aria-controls": controlledPanelId,
948
+ "aria-disabled": disabled || void 0,
949
+ "data-separator": dataSeparator,
950
+ "data-slot": "resizable-handle",
951
+ "data-state": isDragging ? "dragging" : "idle",
952
+ style: {
953
+ touchAction: "none",
954
+ ...style
955
+ },
956
+ ...props,
957
+ children: withHandle && /* @__PURE__ */ jsx("div", {
958
+ className: cn("absolute rounded-md bg-background border shadow-xs/5 flex items-center justify-center pointer-events-none z-20 hover:scale-105 transition-transform [&_svg:not([class*='size-'])]:size-2 [&_svg]:pointer-events-none [&_svg]:shrink-0", isHorizontal ? "h-6 w-3.5 left-1/2 -translate-x-1/2" : "h-3.5 w-6 top-1/2 -translate-y-1/2"),
959
+ children: isHorizontal ? /* @__PURE__ */ jsx(GripVertical, { className: "size-2 text-muted-foreground/64" }) : /* @__PURE__ */ jsx(GripHorizontal, { className: "size-2 text-muted-foreground/64" })
960
+ })
961
+ });
962
+ }
963
+ //#endregion
964
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup };