@accelint/design-toolkit 9.13.0 → 10.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 (292) hide show
  1. package/catalog-info.yaml +1 -1
  2. package/dist/components/accordion/context.d.ts +2 -2
  3. package/dist/components/accordion/group.d.ts +2 -2
  4. package/dist/components/accordion/header.d.ts +2 -2
  5. package/dist/components/accordion/index.d.ts +2 -2
  6. package/dist/components/accordion/panel.d.ts +2 -2
  7. package/dist/components/accordion/trigger.d.ts +2 -2
  8. package/dist/components/action-bar/index.d.ts +2 -2
  9. package/dist/components/audio/index.d.ts +2 -2
  10. package/dist/components/avatar/context.d.ts +4 -4
  11. package/dist/components/avatar/index.d.ts +2 -2
  12. package/dist/components/badge/context.d.ts +4 -4
  13. package/dist/components/badge/index.d.ts +2 -2
  14. package/dist/components/breadcrumbs/index.d.ts +2 -2
  15. package/dist/components/breadcrumbs/item.d.ts +2 -2
  16. package/dist/components/button/context.d.ts +8 -8
  17. package/dist/components/button/index.d.ts +2 -2
  18. package/dist/components/button/link.d.ts +2 -2
  19. package/dist/components/button/toggle.d.ts +2 -2
  20. package/dist/components/carousel/context.d.ts +4 -4
  21. package/dist/components/carousel/gallery.d.ts +2 -2
  22. package/dist/components/carousel/index.d.ts +2 -2
  23. package/dist/components/carousel/navigation.d.ts +3 -3
  24. package/dist/components/carousel/position.d.ts +2 -2
  25. package/dist/components/carousel/select.d.ts +2 -2
  26. package/dist/components/carousel/viewer.d.ts +2 -2
  27. package/dist/components/checkbox/context.d.ts +3 -3
  28. package/dist/components/checkbox/group.d.ts +2 -2
  29. package/dist/components/checkbox/index.d.ts +2 -2
  30. package/dist/components/chip/context.d.ts +4 -4
  31. package/dist/components/chip/deletable.d.ts +2 -2
  32. package/dist/components/chip/index.d.ts +2 -2
  33. package/dist/components/chip/list.d.ts +4 -4
  34. package/dist/components/chip/selectable.d.ts +2 -2
  35. package/dist/components/classification-badge/context.d.ts +4 -4
  36. package/dist/components/classification-badge/index.d.ts +2 -2
  37. package/dist/components/classification-banner/context.d.ts +4 -4
  38. package/dist/components/classification-banner/index.d.ts +2 -2
  39. package/dist/components/clock/index.d.ts +2 -2
  40. package/dist/components/color-picker/index.d.ts +2 -2
  41. package/dist/components/combobox-field/context.d.ts +4 -4
  42. package/dist/components/combobox-field/index.d.ts +2 -2
  43. package/dist/components/coordinate-field/context.d.ts +6 -6
  44. package/dist/components/coordinate-field/index.d.ts +2 -2
  45. package/dist/components/coordinate-field/segment.d.ts +2 -2
  46. package/dist/components/date-field/index.d.ts +2 -2
  47. package/dist/components/deferred-collection/index.d.ts +2 -2
  48. package/dist/components/details-list/context.d.ts +4 -4
  49. package/dist/components/details-list/index.d.ts +2 -2
  50. package/dist/components/details-list/label.d.ts +2 -2
  51. package/dist/components/details-list/value.d.ts +2 -2
  52. package/dist/components/dialog/content.d.ts +2 -2
  53. package/dist/components/dialog/context.d.ts +2 -2
  54. package/dist/components/dialog/footer.d.ts +2 -2
  55. package/dist/components/dialog/index.d.ts +2 -2
  56. package/dist/components/dialog/title.d.ts +2 -2
  57. package/dist/components/divider/context.d.ts +4 -4
  58. package/dist/components/divider/index.d.ts +2 -2
  59. package/dist/components/drawer/back.d.ts +2 -2
  60. package/dist/components/drawer/close.d.ts +2 -2
  61. package/dist/components/drawer/content.d.ts +2 -2
  62. package/dist/components/drawer/context.d.ts +2 -2
  63. package/dist/components/drawer/footer.d.ts +2 -2
  64. package/dist/components/drawer/header-title.d.ts +2 -2
  65. package/dist/components/drawer/index.d.ts +2 -2
  66. package/dist/components/drawer/layout-main.d.ts +2 -2
  67. package/dist/components/drawer/layout.d.ts +2 -2
  68. package/dist/components/drawer/menu-item.d.ts +2 -2
  69. package/dist/components/drawer/menu.d.ts +2 -2
  70. package/dist/components/drawer/panel.d.ts +2 -2
  71. package/dist/components/drawer/trigger.d.ts +2 -2
  72. package/dist/components/drawer/view.d.ts +2 -2
  73. package/dist/components/flashcard/index.d.ts +9 -9
  74. package/dist/components/floating-card/constants.d.ts +26 -0
  75. package/dist/components/floating-card/constants.js +40 -0
  76. package/dist/components/floating-card/constants.js.map +1 -0
  77. package/dist/components/floating-card/context.d.ts +38 -6
  78. package/dist/components/floating-card/context.js +24 -3
  79. package/dist/components/floating-card/context.js.map +1 -1
  80. package/dist/components/floating-card/hooks/use-card-layout.d.ts +36 -0
  81. package/dist/components/floating-card/hooks/use-card-layout.js +106 -0
  82. package/dist/components/floating-card/hooks/use-card-layout.js.map +1 -0
  83. package/dist/components/floating-card/hooks/use-drag.d.ts +62 -0
  84. package/dist/components/floating-card/hooks/use-drag.js +100 -0
  85. package/dist/components/floating-card/hooks/use-drag.js.map +1 -0
  86. package/dist/components/floating-card/hooks/use-mouse-interaction.d.ts +58 -0
  87. package/dist/components/floating-card/hooks/use-mouse-interaction.js +91 -0
  88. package/dist/components/floating-card/hooks/use-mouse-interaction.js.map +1 -0
  89. package/dist/components/floating-card/hooks/use-resize.d.ts +56 -0
  90. package/dist/components/floating-card/hooks/use-resize.js +98 -0
  91. package/dist/components/floating-card/hooks/use-resize.js.map +1 -0
  92. package/dist/components/floating-card/index.d.ts +6 -2
  93. package/dist/components/floating-card/index.js +24 -32
  94. package/dist/components/floating-card/index.js.map +1 -1
  95. package/dist/components/floating-card/panel.d.ts +69 -0
  96. package/dist/components/floating-card/panel.js +111 -0
  97. package/dist/components/floating-card/panel.js.map +1 -0
  98. package/dist/components/floating-card/provider.d.ts +10 -6
  99. package/dist/components/floating-card/provider.js +159 -153
  100. package/dist/components/floating-card/provider.js.map +1 -1
  101. package/dist/components/floating-card/styles.module.css +93 -39
  102. package/dist/components/floating-card/types.d.ts +51 -10
  103. package/dist/components/floating-card/utils.d.ts +8 -85
  104. package/dist/components/floating-card/utils.js +12 -38
  105. package/dist/components/floating-card/utils.js.map +1 -1
  106. package/dist/components/gantt/components/base-elements/point.d.ts +2 -2
  107. package/dist/components/gantt/components/base-elements/range.d.ts +2 -2
  108. package/dist/components/gantt/components/containers/external/gantt-content-container/index.d.ts +2 -2
  109. package/dist/components/gantt/components/containers/external/gantt-panel-container/index.d.ts +2 -2
  110. package/dist/components/gantt/components/containers/internal/index.d.ts +2 -2
  111. package/dist/components/gantt/components/containers/internal/layout-container/index.d.ts +2 -2
  112. package/dist/components/gantt/components/containers/internal/virtualized-content-height-container/index.d.ts +2 -2
  113. package/dist/components/gantt/components/content-row/block.d.ts +2 -2
  114. package/dist/components/gantt/components/content-row/bracket.d.ts +3 -3
  115. package/dist/components/gantt/components/content-row/icon-marker.d.ts +2 -2
  116. package/dist/components/gantt/components/content-row/index.d.ts +2 -2
  117. package/dist/components/gantt/components/content-row/marker.d.ts +2 -2
  118. package/dist/components/gantt/components/content-row/spacer.d.ts +2 -2
  119. package/dist/components/gantt/components/current-time/index.d.ts +2 -2
  120. package/dist/components/gantt/components/header/index.d.ts +3 -3
  121. package/dist/components/gantt/components/panel-row/index.d.ts +2 -2
  122. package/dist/components/gantt/components/rows-virtualizer/index.d.ts +3 -3
  123. package/dist/components/gantt/components/timeline/index.d.ts +2 -2
  124. package/dist/components/gantt/components/timeline-chunk/index.d.ts +3 -3
  125. package/dist/components/gantt/context/index.d.ts +4 -4
  126. package/dist/components/gantt/context/store/index.d.ts +4 -4
  127. package/dist/components/gantt/context/temporal-data/index.d.ts +4 -4
  128. package/dist/components/gantt/hooks/use-layout-subscription/index.js +8 -8
  129. package/dist/components/gantt/hooks/use-layout-subscription/index.js.map +1 -1
  130. package/dist/components/hero/context.d.ts +2 -2
  131. package/dist/components/hero/index.d.ts +2 -2
  132. package/dist/components/hero/subtitle.d.ts +3 -3
  133. package/dist/components/hero/title.d.ts +2 -2
  134. package/dist/components/hotkey/context.d.ts +4 -4
  135. package/dist/components/hotkey/index.d.ts +2 -2
  136. package/dist/components/hotkey/set.d.ts +2 -2
  137. package/dist/components/icon/context.d.ts +4 -4
  138. package/dist/components/icon/index.d.ts +2 -2
  139. package/dist/components/input/context.d.ts +2 -2
  140. package/dist/components/input/index.d.ts +2 -2
  141. package/dist/components/kanban/card-body.d.ts +2 -2
  142. package/dist/components/kanban/card-header-actions.d.ts +2 -2
  143. package/dist/components/kanban/card-header-title.d.ts +2 -2
  144. package/dist/components/kanban/card-header.d.ts +2 -2
  145. package/dist/components/kanban/card.d.ts +2 -2
  146. package/dist/components/kanban/column-actions.d.ts +2 -2
  147. package/dist/components/kanban/column-container.d.ts +2 -2
  148. package/dist/components/kanban/column-content.d.ts +2 -2
  149. package/dist/components/kanban/column-header-actions.d.ts +2 -2
  150. package/dist/components/kanban/column-header-drag-handle.d.ts +2 -2
  151. package/dist/components/kanban/column-header-title.d.ts +2 -2
  152. package/dist/components/kanban/column-header.d.ts +2 -2
  153. package/dist/components/kanban/column.d.ts +2 -2
  154. package/dist/components/kanban/context.d.ts +2 -2
  155. package/dist/components/kanban/header-actions.d.ts +2 -2
  156. package/dist/components/kanban/header-search.d.ts +2 -2
  157. package/dist/components/kanban/header-title.d.ts +2 -2
  158. package/dist/components/kanban/header.d.ts +2 -2
  159. package/dist/components/kanban/kanban.d.ts +4 -4
  160. package/dist/components/label/context.d.ts +4 -4
  161. package/dist/components/label/index.d.ts +2 -2
  162. package/dist/components/lines/index.d.ts +2 -2
  163. package/dist/components/link/context.d.ts +2 -2
  164. package/dist/components/link/index.d.ts +2 -2
  165. package/dist/components/list/context.d.ts +2 -2
  166. package/dist/components/list/index.d.ts +2 -2
  167. package/dist/components/list/item-content.d.ts +2 -2
  168. package/dist/components/list/item-description.d.ts +2 -2
  169. package/dist/components/list/item-title.d.ts +2 -2
  170. package/dist/components/list/item.d.ts +2 -2
  171. package/dist/components/media-controls/context.d.ts +4 -4
  172. package/dist/components/media-controls/fullscreen-button.d.ts +2 -2
  173. package/dist/components/media-controls/index.d.ts +2 -2
  174. package/dist/components/media-controls/mute-button.d.ts +2 -2
  175. package/dist/components/media-controls/play-button.d.ts +2 -2
  176. package/dist/components/media-controls/playback-rate.d.ts +2 -2
  177. package/dist/components/media-controls/seek-button.d.ts +2 -2
  178. package/dist/components/media-controls/time-display.d.ts +2 -2
  179. package/dist/components/media-controls/time-range.d.ts +2 -2
  180. package/dist/components/media-controls/volume-slider.d.ts +2 -2
  181. package/dist/components/menu/context.d.ts +2 -2
  182. package/dist/components/menu/index.d.ts +2 -2
  183. package/dist/components/menu/item-description.d.ts +2 -2
  184. package/dist/components/menu/item-label.d.ts +2 -2
  185. package/dist/components/menu/item.d.ts +2 -2
  186. package/dist/components/menu/section.d.ts +2 -2
  187. package/dist/components/menu/separator.d.ts +2 -2
  188. package/dist/components/menu/submenu.d.ts +2 -2
  189. package/dist/components/notice/index.d.ts +2 -2
  190. package/dist/components/notice/list.d.ts +2 -2
  191. package/dist/components/notice/notice-icon.d.ts +2 -2
  192. package/dist/components/options/context.d.ts +2 -2
  193. package/dist/components/options/index.d.ts +2 -2
  194. package/dist/components/options/item-content.d.ts +2 -2
  195. package/dist/components/options/item-description.d.ts +2 -2
  196. package/dist/components/options/item-label.d.ts +2 -2
  197. package/dist/components/options/item.d.ts +2 -2
  198. package/dist/components/options/section.d.ts +2 -2
  199. package/dist/components/pagination/context.d.ts +2 -2
  200. package/dist/components/pagination/index.d.ts +2 -2
  201. package/dist/components/pagination/next.d.ts +2 -2
  202. package/dist/components/pagination/pages.d.ts +2 -2
  203. package/dist/components/pagination/prev.d.ts +2 -2
  204. package/dist/components/popover/content.d.ts +2 -2
  205. package/dist/components/popover/footer.d.ts +2 -2
  206. package/dist/components/popover/index.d.ts +2 -2
  207. package/dist/components/popover/title.d.ts +2 -2
  208. package/dist/components/popover/trigger.d.ts +2 -2
  209. package/dist/components/query-builder/action-element.d.ts +2 -2
  210. package/dist/components/query-builder/actions.d.ts +4 -4
  211. package/dist/components/query-builder/combinator-selector.d.ts +2 -2
  212. package/dist/components/query-builder/index.d.ts +2 -2
  213. package/dist/components/query-builder/rule-group.d.ts +4 -4
  214. package/dist/components/query-builder/rule.d.ts +2 -2
  215. package/dist/components/query-builder/value-editor.d.ts +2 -2
  216. package/dist/components/query-builder/value-selector.d.ts +2 -2
  217. package/dist/components/radio/context.d.ts +3 -3
  218. package/dist/components/radio/group.d.ts +2 -2
  219. package/dist/components/radio/index.d.ts +2 -2
  220. package/dist/components/search-field/context.d.ts +4 -4
  221. package/dist/components/search-field/index.d.ts +2 -2
  222. package/dist/components/select-field/context.d.ts +4 -4
  223. package/dist/components/select-field/index.d.ts +2 -2
  224. package/dist/components/sidenav/avatar.d.ts +2 -2
  225. package/dist/components/sidenav/content.d.ts +2 -2
  226. package/dist/components/sidenav/context.d.ts +2 -2
  227. package/dist/components/sidenav/footer.d.ts +2 -2
  228. package/dist/components/sidenav/header.d.ts +2 -2
  229. package/dist/components/sidenav/index.d.ts +2 -2
  230. package/dist/components/sidenav/item.d.ts +2 -2
  231. package/dist/components/sidenav/link.d.ts +2 -2
  232. package/dist/components/sidenav/menu-item.d.ts +2 -2
  233. package/dist/components/sidenav/menu.d.ts +2 -2
  234. package/dist/components/sidenav/trigger.d.ts +2 -2
  235. package/dist/components/skeleton/index.d.ts +2 -2
  236. package/dist/components/slider/index.d.ts +2 -2
  237. package/dist/components/status-indicator/index.d.ts +2 -2
  238. package/dist/components/switch/context.d.ts +4 -4
  239. package/dist/components/switch/index.d.ts +2 -2
  240. package/dist/components/table/body.d.ts +4 -3
  241. package/dist/components/table/body.js.map +1 -1
  242. package/dist/components/table/cell.d.ts +4 -3
  243. package/dist/components/table/cell.js.map +1 -1
  244. package/dist/components/table/context.d.ts +2 -2
  245. package/dist/components/table/features.d.ts +80 -0
  246. package/dist/components/table/features.js +61 -0
  247. package/dist/components/table/features.js.map +1 -0
  248. package/dist/components/table/header-cell.d.ts +4 -3
  249. package/dist/components/table/header-cell.js.map +1 -1
  250. package/dist/components/table/header.d.ts +4 -3
  251. package/dist/components/table/header.js.map +1 -1
  252. package/dist/components/table/index.d.ts +2 -2
  253. package/dist/components/table/index.js +40 -49
  254. package/dist/components/table/index.js.map +1 -1
  255. package/dist/components/table/row-ordering-feature.d.ts +88 -0
  256. package/dist/components/table/row-ordering-feature.js +115 -0
  257. package/dist/components/table/row-ordering-feature.js.map +1 -0
  258. package/dist/components/table/row.d.ts +4 -3
  259. package/dist/components/table/row.js.map +1 -1
  260. package/dist/components/table/types.d.ts +15 -13
  261. package/dist/components/tabs/context.d.ts +3 -3
  262. package/dist/components/tabs/index.d.ts +2 -2
  263. package/dist/components/tabs/list.d.ts +2 -2
  264. package/dist/components/tabs/panel.d.ts +2 -2
  265. package/dist/components/tabs/tab.d.ts +2 -2
  266. package/dist/components/text-area-field/context.d.ts +4 -4
  267. package/dist/components/text-area-field/index.d.ts +2 -2
  268. package/dist/components/text-field/context.d.ts +4 -4
  269. package/dist/components/text-field/index.d.ts +2 -2
  270. package/dist/components/time-field/index.d.ts +2 -2
  271. package/dist/components/tooltip/context.d.ts +2 -2
  272. package/dist/components/tooltip/index.d.ts +2 -2
  273. package/dist/components/tooltip/trigger.d.ts +2 -2
  274. package/dist/components/tree/context.d.ts +3 -3
  275. package/dist/components/tree/index.d.ts +2 -2
  276. package/dist/components/tree/item-actions.d.ts +2 -2
  277. package/dist/components/tree/item-content.d.ts +2 -2
  278. package/dist/components/tree/item-description.d.ts +2 -2
  279. package/dist/components/tree/item-label.d.ts +2 -2
  280. package/dist/components/tree/item-prefix-icon.d.ts +2 -2
  281. package/dist/components/tree/item.d.ts +2 -2
  282. package/dist/components/tree/lines.d.ts +2 -2
  283. package/dist/components/video/index.d.ts +2 -2
  284. package/dist/components/view-stack/context.d.ts +2 -2
  285. package/dist/components/view-stack/index.d.ts +2 -2
  286. package/dist/components/view-stack/trigger.d.ts +2 -2
  287. package/dist/components/view-stack/view.d.ts +2 -2
  288. package/dist/index.d.ts +4 -2
  289. package/dist/index.js +3 -1
  290. package/dist/providers/portal.d.ts +2 -2
  291. package/dist/providers/theme-provider.d.ts +2 -2
  292. package/package.json +20 -14
@@ -0,0 +1,62 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { Bounds, Dimensions, Position } from "../types.js";
14
+
15
+ //#region src/components/floating-card/hooks/use-drag.d.ts
16
+ /**
17
+ * Clamps a position so the card stays fully inside its bounds.
18
+ *
19
+ * @param position - Desired top-left position.
20
+ * @param dimensions - Card size, used to keep the far edges inside.
21
+ * @param bounds - Box the card must remain within.
22
+ * @returns The clamped position.
23
+ */
24
+ declare function constrainPosition(position: Position, dimensions: Dimensions, bounds: Bounds): Position;
25
+ type UseDragProps = {
26
+ /** Whether dragging is disabled, e.g. because the card is pinned. */
27
+ disabled: boolean;
28
+ /** Current card position. */
29
+ position: Position;
30
+ /** Current card dimensions. */
31
+ dimensions: Dimensions;
32
+ /** Reads the bounding box once when the gesture starts. */
33
+ getBounds: () => Bounds;
34
+ /** Called with each new position during the drag. */
35
+ onPositionChange: (position: Position) => void;
36
+ /** Called once when the drag threshold is first crossed. */
37
+ onDragStart?: () => void;
38
+ };
39
+ /**
40
+ * Drags a card by a pointer gesture, keeping it inside its container.
41
+ *
42
+ * @param props - {@link UseDragProps}
43
+ * @returns A `handleStart` handler to attach to the card's drag surface.
44
+ *
45
+ * @remarks
46
+ * A drag only begins once the pointer moves past {@link DRAG_THRESHOLD}, so a
47
+ * click on the header still reads as a click. Bounds are read once per gesture
48
+ * rather than per move to keep the drag off the layout path.
49
+ */
50
+ declare function useDrag({
51
+ disabled,
52
+ position,
53
+ dimensions,
54
+ getBounds,
55
+ onPositionChange,
56
+ onDragStart
57
+ }: UseDragProps): {
58
+ handleStart: (event: PointerEvent, payload: void) => void;
59
+ };
60
+ //#endregion
61
+ export { UseDragProps, constrainPosition, useDrag };
62
+ //# sourceMappingURL=use-drag.d.ts.map
@@ -0,0 +1,100 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import { DRAG_THRESHOLD } from "../constants.js";
15
+ import { useMouseInteraction } from "./use-mouse-interaction.js";
16
+ import { useRef } from "react";
17
+ import { clamp } from "radashi";
18
+
19
+ //#region src/components/floating-card/hooks/use-drag.ts
20
+ /** Elements that own their own pointer behavior and must never begin a drag. */
21
+ const INTERACTIVE_SELECTORS = [
22
+ "button",
23
+ "input",
24
+ "select",
25
+ "textarea",
26
+ "a",
27
+ "[role=\"button\"]",
28
+ "[role=\"link\"]",
29
+ "[contenteditable]"
30
+ ].join(", ");
31
+ function isInteractiveElement(target) {
32
+ return target instanceof Element && target.closest(INTERACTIVE_SELECTORS) ? true : false;
33
+ }
34
+ /**
35
+ * Clamps a position so the card stays fully inside its bounds.
36
+ *
37
+ * @param position - Desired top-left position.
38
+ * @param dimensions - Card size, used to keep the far edges inside.
39
+ * @param bounds - Box the card must remain within.
40
+ * @returns The clamped position.
41
+ */
42
+ function constrainPosition(position, dimensions, bounds) {
43
+ const maxX = Math.max(bounds.left, bounds.right - dimensions.width);
44
+ const maxY = Math.max(bounds.top, bounds.bottom - dimensions.height);
45
+ return {
46
+ x: clamp(position.x, bounds.left, maxX),
47
+ y: clamp(position.y, bounds.top, maxY)
48
+ };
49
+ }
50
+ /**
51
+ * Drags a card by a pointer gesture, keeping it inside its container.
52
+ *
53
+ * @param props - {@link UseDragProps}
54
+ * @returns A `handleStart` handler to attach to the card's drag surface.
55
+ *
56
+ * @remarks
57
+ * A drag only begins once the pointer moves past {@link DRAG_THRESHOLD}, so a
58
+ * click on the header still reads as a click. Bounds are read once per gesture
59
+ * rather than per move to keep the drag off the layout path.
60
+ */
61
+ function useDrag({ disabled, position, dimensions, getBounds, onPositionChange, onDragStart }) {
62
+ const latest = useRef({
63
+ position,
64
+ dimensions,
65
+ disabled
66
+ });
67
+ latest.current = {
68
+ position,
69
+ dimensions,
70
+ disabled
71
+ };
72
+ const { handleStart } = useMouseInteraction({
73
+ shouldStart: (event) => !latest.current.disabled && event.button === 0 && !isInteractiveElement(event.target),
74
+ onStart: (event) => ({
75
+ isDragging: false,
76
+ pointerX: event.clientX,
77
+ pointerY: event.clientY,
78
+ origin: latest.current.position,
79
+ bounds: getBounds()
80
+ }),
81
+ onMove: (event, session) => {
82
+ const deltaX = event.clientX - session.pointerX;
83
+ const deltaY = event.clientY - session.pointerY;
84
+ if (!session.isDragging && Math.hypot(deltaX, deltaY) < DRAG_THRESHOLD) return;
85
+ if (!session.isDragging) {
86
+ session.isDragging = true;
87
+ onDragStart?.();
88
+ }
89
+ onPositionChange(constrainPosition({
90
+ x: session.origin.x + deltaX,
91
+ y: session.origin.y + deltaY
92
+ }, latest.current.dimensions, session.bounds));
93
+ }
94
+ });
95
+ return { handleStart };
96
+ }
97
+
98
+ //#endregion
99
+ export { constrainPosition, useDrag };
100
+ //# sourceMappingURL=use-drag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-drag.js","names":[],"sources":["../../../../src/components/floating-card/hooks/use-drag.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { clamp } from 'radashi';\nimport { useRef } from 'react';\nimport { DRAG_THRESHOLD } from '../constants';\nimport { useMouseInteraction } from './use-mouse-interaction';\nimport type { Bounds, Dimensions, Position } from '../types';\n\n/** Elements that own their own pointer behavior and must never begin a drag. */\nconst INTERACTIVE_SELECTORS = [\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'a',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[contenteditable]',\n].join(', ');\n\nfunction isInteractiveElement(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest(INTERACTIVE_SELECTORS)\n ? true\n : false;\n}\n\n/**\n * Clamps a position so the card stays fully inside its bounds.\n *\n * @param position - Desired top-left position.\n * @param dimensions - Card size, used to keep the far edges inside.\n * @param bounds - Box the card must remain within.\n * @returns The clamped position.\n */\nexport function constrainPosition(\n position: Position,\n dimensions: Dimensions,\n bounds: Bounds,\n): Position {\n // A card wider than its bounds has no valid range, so the far edge is pinned\n // to the near one and the card rests against the top-left corner.\n const maxX = Math.max(bounds.left, bounds.right - dimensions.width);\n const maxY = Math.max(bounds.top, bounds.bottom - dimensions.height);\n\n return {\n x: clamp(position.x, bounds.left, maxX),\n y: clamp(position.y, bounds.top, maxY),\n };\n}\n\ntype DragSession = {\n isDragging: boolean;\n pointerX: number;\n pointerY: number;\n origin: Position;\n bounds: Bounds;\n};\n\nexport type UseDragProps = {\n /** Whether dragging is disabled, e.g. because the card is pinned. */\n disabled: boolean;\n /** Current card position. */\n position: Position;\n /** Current card dimensions. */\n dimensions: Dimensions;\n /** Reads the bounding box once when the gesture starts. */\n getBounds: () => Bounds;\n /** Called with each new position during the drag. */\n onPositionChange: (position: Position) => void;\n /** Called once when the drag threshold is first crossed. */\n onDragStart?: () => void;\n};\n\n/**\n * Drags a card by a pointer gesture, keeping it inside its container.\n *\n * @param props - {@link UseDragProps}\n * @returns A `handleStart` handler to attach to the card's drag surface.\n *\n * @remarks\n * A drag only begins once the pointer moves past {@link DRAG_THRESHOLD}, so a\n * click on the header still reads as a click. Bounds are read once per gesture\n * rather than per move to keep the drag off the layout path.\n */\nexport function useDrag({\n disabled,\n position,\n dimensions,\n getBounds,\n onPositionChange,\n onDragStart,\n}: UseDragProps) {\n // Read inside the session so a drag in progress always sees current values.\n const latest = useRef({ position, dimensions, disabled });\n latest.current = { position, dimensions, disabled };\n\n const { handleStart } = useMouseInteraction<DragSession>({\n shouldStart: (event) =>\n !latest.current.disabled &&\n event.button === 0 &&\n !isInteractiveElement(event.target),\n onStart: (event) => ({\n isDragging: false,\n pointerX: event.clientX,\n pointerY: event.clientY,\n origin: latest.current.position,\n bounds: getBounds(),\n }),\n onMove: (event, session) => {\n const deltaX = event.clientX - session.pointerX;\n const deltaY = event.clientY - session.pointerY;\n\n if (!session.isDragging && Math.hypot(deltaX, deltaY) < DRAG_THRESHOLD) {\n return;\n }\n\n if (!session.isDragging) {\n session.isDragging = true;\n onDragStart?.();\n }\n\n onPositionChange(\n constrainPosition(\n {\n x: session.origin.x + deltaX,\n y: session.origin.y + deltaY,\n },\n latest.current.dimensions,\n session.bounds,\n ),\n );\n },\n });\n\n return { handleStart };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,KAAK,KAAK;AAEZ,SAAS,qBAAqB,QAAqC;AACjE,QAAO,kBAAkB,WAAW,OAAO,QAAQ,sBAAsB,GACrE,OACA;;;;;;;;;;AAWN,SAAgB,kBACd,UACA,YACA,QACU;CAGV,MAAM,OAAO,KAAK,IAAI,OAAO,MAAM,OAAO,QAAQ,WAAW,MAAM;CACnE,MAAM,OAAO,KAAK,IAAI,OAAO,KAAK,OAAO,SAAS,WAAW,OAAO;AAEpE,QAAO;EACL,GAAG,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK;EACvC,GAAG,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK;EACvC;;;;;;;;;;;;;AAqCH,SAAgB,QAAQ,EACtB,UACA,UACA,YACA,WACA,kBACA,eACe;CAEf,MAAM,SAAS,OAAO;EAAE;EAAU;EAAY;EAAU,CAAC;AACzD,QAAO,UAAU;EAAE;EAAU;EAAY;EAAU;CAEnD,MAAM,EAAE,gBAAgB,oBAAiC;EACvD,cAAc,UACZ,CAAC,OAAO,QAAQ,YAChB,MAAM,WAAW,KACjB,CAAC,qBAAqB,MAAM,OAAO;EACrC,UAAU,WAAW;GACnB,YAAY;GACZ,UAAU,MAAM;GAChB,UAAU,MAAM;GAChB,QAAQ,OAAO,QAAQ;GACvB,QAAQ,WAAW;GACpB;EACD,SAAS,OAAO,YAAY;GAC1B,MAAM,SAAS,MAAM,UAAU,QAAQ;GACvC,MAAM,SAAS,MAAM,UAAU,QAAQ;AAEvC,OAAI,CAAC,QAAQ,cAAc,KAAK,MAAM,QAAQ,OAAO,GAAG,eACtD;AAGF,OAAI,CAAC,QAAQ,YAAY;AACvB,YAAQ,aAAa;AACrB,mBAAe;;AAGjB,oBACE,kBACE;IACE,GAAG,QAAQ,OAAO,IAAI;IACtB,GAAG,QAAQ,OAAO,IAAI;IACvB,EACD,OAAO,QAAQ,YACf,QAAQ,OACT,CACF;;EAEJ,CAAC;AAEF,QAAO,EAAE,aAAa"}
@@ -0,0 +1,58 @@
1
+ //#region src/components/floating-card/hooks/use-mouse-interaction.d.ts
2
+ /**
3
+ * Configuration for a pointer-driven interaction session.
4
+ *
5
+ * @template Session - Mutable state carried through a single interaction.
6
+ */
7
+ type MouseInteractionConfig<Session, Payload = void> = {
8
+ /**
9
+ * Called on pointerdown. Return the session state, or null to abort.
10
+ *
11
+ * @remarks `payload` carries whatever the caller passed to `handleStart`,
12
+ * which lets one element's handler describe what it started -- a resize
13
+ * handle naming its direction, for instance.
14
+ */
15
+ onStart: (event: PointerEvent, payload: Payload) => Session | null;
16
+ /**
17
+ * Called on each pointermove while a session is active.
18
+ *
19
+ * @remarks The session object persists across the whole gesture and may be
20
+ * mutated in place to carry state between moves.
21
+ */
22
+ onMove: (event: PointerEvent, session: Session) => void;
23
+ /** Optional. Called on pointerup or pointercancel, ending the session. */
24
+ onEnd?: (event: PointerEvent, session: Session) => void;
25
+ /** Optional guard run before onStart; return false to ignore the event. */
26
+ shouldStart?: (event: PointerEvent) => boolean;
27
+ };
28
+ /**
29
+ * Runs a pointer-driven interaction (drag, resize) against document-level
30
+ * listeners so the gesture keeps tracking when the pointer leaves the element.
31
+ *
32
+ * @param config - Session lifecycle callbacks.
33
+ * @returns A `handleStart` handler to attach to the element that begins the gesture.
34
+ *
35
+ * @remarks
36
+ * Listeners are registered only for the duration of a session and torn down
37
+ * with an AbortController, which also covers unmounting mid-gesture.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const { handleStart } = useMouseInteraction({
42
+ * onStart: (event) => ({ startX: event.clientX }),
43
+ * onMove: (event, session) => move(event.clientX - session.startX),
44
+ * onEnd: () => commit(),
45
+ * });
46
+ * ```
47
+ */
48
+ declare function useMouseInteraction<Session, Payload = void>({
49
+ onStart,
50
+ onMove,
51
+ onEnd,
52
+ shouldStart
53
+ }: MouseInteractionConfig<Session, Payload>): {
54
+ handleStart: (event: PointerEvent, payload: Payload) => void;
55
+ };
56
+ //#endregion
57
+ export { MouseInteractionConfig, useMouseInteraction };
58
+ //# sourceMappingURL=use-mouse-interaction.d.ts.map
@@ -0,0 +1,91 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import { useCallback, useEffect, useRef } from "react";
15
+
16
+ //#region src/components/floating-card/hooks/use-mouse-interaction.ts
17
+ /**
18
+ * Runs a pointer-driven interaction (drag, resize) against document-level
19
+ * listeners so the gesture keeps tracking when the pointer leaves the element.
20
+ *
21
+ * @param config - Session lifecycle callbacks.
22
+ * @returns A `handleStart` handler to attach to the element that begins the gesture.
23
+ *
24
+ * @remarks
25
+ * Listeners are registered only for the duration of a session and torn down
26
+ * with an AbortController, which also covers unmounting mid-gesture.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const { handleStart } = useMouseInteraction({
31
+ * onStart: (event) => ({ startX: event.clientX }),
32
+ * onMove: (event, session) => move(event.clientX - session.startX),
33
+ * onEnd: () => commit(),
34
+ * });
35
+ * ```
36
+ */
37
+ function useMouseInteraction({ onStart, onMove, onEnd, shouldStart }) {
38
+ const sessionRef = useRef(null);
39
+ const abortRef = useRef(null);
40
+ const handlers = useRef({
41
+ onStart,
42
+ onMove,
43
+ onEnd,
44
+ shouldStart
45
+ });
46
+ handlers.current = {
47
+ onStart,
48
+ onMove,
49
+ onEnd,
50
+ shouldStart
51
+ };
52
+ const endSession = useCallback(() => {
53
+ sessionRef.current = null;
54
+ abortRef.current?.abort();
55
+ abortRef.current = null;
56
+ }, []);
57
+ const handleStart = useCallback((event, payload) => {
58
+ if (handlers.current.shouldStart?.(event) === false) return;
59
+ const session = handlers.current.onStart(event, payload);
60
+ if (session === null) return;
61
+ abortRef.current?.abort();
62
+ sessionRef.current = session;
63
+ event.preventDefault();
64
+ const controller = new AbortController();
65
+ abortRef.current = controller;
66
+ const handleMove = (moveEvent) => {
67
+ if (sessionRef.current === null) return;
68
+ handlers.current.onMove(moveEvent, sessionRef.current);
69
+ };
70
+ const handleEnd = (endEvent) => {
71
+ if (sessionRef.current === null) return;
72
+ handlers.current.onEnd?.(endEvent, sessionRef.current);
73
+ endSession();
74
+ };
75
+ const options = { signal: controller.signal };
76
+ document.addEventListener("pointermove", handleMove, options);
77
+ document.addEventListener("pointerup", handleEnd, options);
78
+ document.addEventListener("pointercancel", handleEnd, options);
79
+ }, [endSession]);
80
+ useEffect(() => {
81
+ return () => {
82
+ abortRef.current?.abort();
83
+ abortRef.current = null;
84
+ };
85
+ }, []);
86
+ return { handleStart };
87
+ }
88
+
89
+ //#endregion
90
+ export { useMouseInteraction };
91
+ //# sourceMappingURL=use-mouse-interaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mouse-interaction.js","names":[],"sources":["../../../../src/components/floating-card/hooks/use-mouse-interaction.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\n/**\n * Configuration for a pointer-driven interaction session.\n *\n * @template Session - Mutable state carried through a single interaction.\n */\nexport type MouseInteractionConfig<Session, Payload = void> = {\n /**\n * Called on pointerdown. Return the session state, or null to abort.\n *\n * @remarks `payload` carries whatever the caller passed to `handleStart`,\n * which lets one element's handler describe what it started -- a resize\n * handle naming its direction, for instance.\n */\n onStart: (event: PointerEvent, payload: Payload) => Session | null;\n /**\n * Called on each pointermove while a session is active.\n *\n * @remarks The session object persists across the whole gesture and may be\n * mutated in place to carry state between moves.\n */\n onMove: (event: PointerEvent, session: Session) => void;\n /** Optional. Called on pointerup or pointercancel, ending the session. */\n onEnd?: (event: PointerEvent, session: Session) => void;\n /** Optional guard run before onStart; return false to ignore the event. */\n shouldStart?: (event: PointerEvent) => boolean;\n};\n\n/**\n * Runs a pointer-driven interaction (drag, resize) against document-level\n * listeners so the gesture keeps tracking when the pointer leaves the element.\n *\n * @param config - Session lifecycle callbacks.\n * @returns A `handleStart` handler to attach to the element that begins the gesture.\n *\n * @remarks\n * Listeners are registered only for the duration of a session and torn down\n * with an AbortController, which also covers unmounting mid-gesture.\n *\n * @example\n * ```ts\n * const { handleStart } = useMouseInteraction({\n * onStart: (event) => ({ startX: event.clientX }),\n * onMove: (event, session) => move(event.clientX - session.startX),\n * onEnd: () => commit(),\n * });\n * ```\n */\nexport function useMouseInteraction<Session, Payload = void>({\n onStart,\n onMove,\n onEnd,\n shouldStart,\n}: MouseInteractionConfig<Session, Payload>) {\n const sessionRef = useRef<Session | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n // Callbacks are read from refs so a session started with one render's\n // handlers keeps working after a re-render without re-binding listeners.\n const handlers = useRef({ onStart, onMove, onEnd, shouldStart });\n handlers.current = { onStart, onMove, onEnd, shouldStart };\n\n const endSession = useCallback(() => {\n sessionRef.current = null;\n abortRef.current?.abort();\n abortRef.current = null;\n }, []);\n\n const handleStart = useCallback(\n (event: PointerEvent, payload: Payload) => {\n if (handlers.current.shouldStart?.(event) === false) {\n return;\n }\n\n const session = handlers.current.onStart(event, payload);\n\n if (session === null) {\n return;\n }\n\n // A second press before the first releases -- a lost pointerup, or a\n // resize handle pressed mid-drag -- would otherwise strand the previous\n // controller's listeners, leaving two sessions driving the same card.\n abortRef.current?.abort();\n\n sessionRef.current = session;\n event.preventDefault();\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n const handleMove = (moveEvent: PointerEvent) => {\n if (sessionRef.current === null) {\n return;\n }\n\n handlers.current.onMove(moveEvent, sessionRef.current);\n };\n\n const handleEnd = (endEvent: PointerEvent) => {\n if (sessionRef.current === null) {\n return;\n }\n\n handlers.current.onEnd?.(endEvent, sessionRef.current);\n endSession();\n };\n\n const options = { signal: controller.signal };\n\n document.addEventListener('pointermove', handleMove, options);\n document.addEventListener('pointerup', handleEnd, options);\n document.addEventListener('pointercancel', handleEnd, options);\n },\n [endSession],\n );\n\n useEffect(() => {\n return () => {\n abortRef.current?.abort();\n abortRef.current = null;\n };\n }, []);\n\n return { handleStart };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DA,SAAgB,oBAA6C,EAC3D,SACA,QACA,OACA,eAC2C;CAC3C,MAAM,aAAa,OAAuB,KAAK;CAC/C,MAAM,WAAW,OAA+B,KAAK;CAIrD,MAAM,WAAW,OAAO;EAAE;EAAS;EAAQ;EAAO;EAAa,CAAC;AAChE,UAAS,UAAU;EAAE;EAAS;EAAQ;EAAO;EAAa;CAE1D,MAAM,aAAa,kBAAkB;AACnC,aAAW,UAAU;AACrB,WAAS,SAAS,OAAO;AACzB,WAAS,UAAU;IAClB,EAAE,CAAC;CAEN,MAAM,cAAc,aACjB,OAAqB,YAAqB;AACzC,MAAI,SAAS,QAAQ,cAAc,MAAM,KAAK,MAC5C;EAGF,MAAM,UAAU,SAAS,QAAQ,QAAQ,OAAO,QAAQ;AAExD,MAAI,YAAY,KACd;AAMF,WAAS,SAAS,OAAO;AAEzB,aAAW,UAAU;AACrB,QAAM,gBAAgB;EAEtB,MAAM,aAAa,IAAI,iBAAiB;AACxC,WAAS,UAAU;EAEnB,MAAM,cAAc,cAA4B;AAC9C,OAAI,WAAW,YAAY,KACzB;AAGF,YAAS,QAAQ,OAAO,WAAW,WAAW,QAAQ;;EAGxD,MAAM,aAAa,aAA2B;AAC5C,OAAI,WAAW,YAAY,KACzB;AAGF,YAAS,QAAQ,QAAQ,UAAU,WAAW,QAAQ;AACtD,eAAY;;EAGd,MAAM,UAAU,EAAE,QAAQ,WAAW,QAAQ;AAE7C,WAAS,iBAAiB,eAAe,YAAY,QAAQ;AAC7D,WAAS,iBAAiB,aAAa,WAAW,QAAQ;AAC1D,WAAS,iBAAiB,iBAAiB,WAAW,QAAQ;IAEhE,CAAC,WAAW,CACb;AAED,iBAAgB;AACd,eAAa;AACX,YAAS,SAAS,OAAO;AACzB,YAAS,UAAU;;IAEpB,EAAE,CAAC;AAEN,QAAO,EAAE,aAAa"}
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { Bounds, Dimensions, Position, ResizeHandle } from "../types.js";
14
+
15
+ //#region src/components/floating-card/hooks/use-resize.d.ts
16
+ type UseResizeProps = {
17
+ /** Whether resizing is disabled, e.g. because the card is pinned. */
18
+ disabled: boolean;
19
+ /** Current card position. */
20
+ position: Position;
21
+ /** Current card dimensions. */
22
+ dimensions: Dimensions;
23
+ /** Reads the bounding box once when the gesture starts. */
24
+ getBounds: () => Bounds;
25
+ /** Called with the new geometry during the resize. */
26
+ onResize: (dimensions: Dimensions, position: Position) => void;
27
+ /** Called once when the gesture begins. */
28
+ onResizeStart?: () => void;
29
+ };
30
+ /**
31
+ * Resizes a card from any of its eight edges and corners.
32
+ *
33
+ * @param props - {@link UseResizeProps}
34
+ * @returns `getHandleProps`, which builds the pointer handler for one handle.
35
+ *
36
+ * @remarks
37
+ * North and west handles move the card's origin as well as its size so the
38
+ * opposite edge stays put. Every result is clamped to {@link MIN_DIMENSIONS}
39
+ * and to the container, so a card can never be resized outside its bounds or
40
+ * collapsed to nothing.
41
+ */
42
+ declare function useResize({
43
+ disabled,
44
+ position,
45
+ dimensions,
46
+ getBounds,
47
+ onResize,
48
+ onResizeStart
49
+ }: UseResizeProps): {
50
+ getHandleProps: (handle: ResizeHandle) => {
51
+ onPointerDown: (event: React.PointerEvent) => void;
52
+ };
53
+ };
54
+ //#endregion
55
+ export { UseResizeProps, useResize };
56
+ //# sourceMappingURL=use-resize.d.ts.map
@@ -0,0 +1,98 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import { MIN_DIMENSIONS } from "../constants.js";
15
+ import { useMouseInteraction } from "./use-mouse-interaction.js";
16
+ import { useCallback, useRef } from "react";
17
+ import { clamp } from "radashi";
18
+
19
+ //#region src/components/floating-card/hooks/use-resize.ts
20
+ /**
21
+ * Resizes a card from any of its eight edges and corners.
22
+ *
23
+ * @param props - {@link UseResizeProps}
24
+ * @returns `getHandleProps`, which builds the pointer handler for one handle.
25
+ *
26
+ * @remarks
27
+ * North and west handles move the card's origin as well as its size so the
28
+ * opposite edge stays put. Every result is clamped to {@link MIN_DIMENSIONS}
29
+ * and to the container, so a card can never be resized outside its bounds or
30
+ * collapsed to nothing.
31
+ */
32
+ function useResize({ disabled, position, dimensions, getBounds, onResize, onResizeStart }) {
33
+ const latest = useRef({
34
+ position,
35
+ dimensions,
36
+ disabled
37
+ });
38
+ latest.current = {
39
+ position,
40
+ dimensions,
41
+ disabled
42
+ };
43
+ const { handleStart } = useMouseInteraction({
44
+ shouldStart: (event) => !latest.current.disabled && event.button === 0,
45
+ onStart: (event, handle) => {
46
+ onResizeStart?.();
47
+ return {
48
+ pointerX: event.clientX,
49
+ pointerY: event.clientY,
50
+ origin: latest.current.position,
51
+ size: latest.current.dimensions,
52
+ handle,
53
+ bounds: getBounds()
54
+ };
55
+ },
56
+ onMove: (event, session) => {
57
+ const deltaX = event.clientX - session.pointerX;
58
+ const deltaY = event.clientY - session.pointerY;
59
+ const { handle, origin, size, bounds } = session;
60
+ let { x, y } = origin;
61
+ let { width, height } = size;
62
+ if (handle.includes("e")) {
63
+ const limit = Math.max(bounds.right - origin.x, size.width);
64
+ width = Math.min(size.width + deltaX, limit);
65
+ }
66
+ if (handle.includes("s")) {
67
+ const limit = Math.max(bounds.bottom - origin.y, size.height);
68
+ height = Math.min(size.height + deltaY, limit);
69
+ }
70
+ if (handle.includes("w")) {
71
+ const right = origin.x + size.width;
72
+ const limit = Math.min(bounds.left, origin.x);
73
+ x = clamp(origin.x + deltaX, limit, right - MIN_DIMENSIONS.width);
74
+ width = right - x;
75
+ }
76
+ if (handle.includes("n")) {
77
+ const bottom = origin.y + size.height;
78
+ const limit = Math.min(bounds.top, origin.y);
79
+ y = clamp(origin.y + deltaY, limit, bottom - MIN_DIMENSIONS.height);
80
+ height = bottom - y;
81
+ }
82
+ onResize({
83
+ width: Math.max(width, MIN_DIMENSIONS.width),
84
+ height: Math.max(height, MIN_DIMENSIONS.height)
85
+ }, {
86
+ x,
87
+ y
88
+ });
89
+ }
90
+ });
91
+ return { getHandleProps: useCallback((handle) => ({ onPointerDown: (event) => {
92
+ handleStart(event.nativeEvent, handle);
93
+ } }), [handleStart]) };
94
+ }
95
+
96
+ //#endregion
97
+ export { useResize };
98
+ //# sourceMappingURL=use-resize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-resize.js","names":[],"sources":["../../../../src/components/floating-card/hooks/use-resize.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { clamp } from 'radashi';\nimport { useCallback, useRef } from 'react';\nimport { MIN_DIMENSIONS } from '../constants';\nimport { useMouseInteraction } from './use-mouse-interaction';\nimport type { Bounds, Dimensions, Position, ResizeHandle } from '../types';\n\ntype ResizeSession = {\n pointerX: number;\n pointerY: number;\n origin: Position;\n size: Dimensions;\n handle: ResizeHandle;\n bounds: Bounds;\n};\n\nexport type UseResizeProps = {\n /** Whether resizing is disabled, e.g. because the card is pinned. */\n disabled: boolean;\n /** Current card position. */\n position: Position;\n /** Current card dimensions. */\n dimensions: Dimensions;\n /** Reads the bounding box once when the gesture starts. */\n getBounds: () => Bounds;\n /** Called with the new geometry during the resize. */\n onResize: (dimensions: Dimensions, position: Position) => void;\n /** Called once when the gesture begins. */\n onResizeStart?: () => void;\n};\n\n/**\n * Resizes a card from any of its eight edges and corners.\n *\n * @param props - {@link UseResizeProps}\n * @returns `getHandleProps`, which builds the pointer handler for one handle.\n *\n * @remarks\n * North and west handles move the card's origin as well as its size so the\n * opposite edge stays put. Every result is clamped to {@link MIN_DIMENSIONS}\n * and to the container, so a card can never be resized outside its bounds or\n * collapsed to nothing.\n */\nexport function useResize({\n disabled,\n position,\n dimensions,\n getBounds,\n onResize,\n onResizeStart,\n}: UseResizeProps) {\n const latest = useRef({ position, dimensions, disabled });\n latest.current = { position, dimensions, disabled };\n\n const { handleStart } = useMouseInteraction<ResizeSession, ResizeHandle>({\n shouldStart: (event) => !latest.current.disabled && event.button === 0,\n onStart: (event, handle) => {\n onResizeStart?.();\n\n return {\n pointerX: event.clientX,\n pointerY: event.clientY,\n origin: latest.current.position,\n size: latest.current.dimensions,\n handle,\n bounds: getBounds(),\n };\n },\n onMove: (event, session) => {\n const deltaX = event.clientX - session.pointerX;\n const deltaY = event.clientY - session.pointerY;\n const { handle, origin, size, bounds } = session;\n\n let { x, y } = origin;\n let { width, height } = size;\n\n // A card that already extends past its bounds must still be resizable, so\n // the limit never falls below the size the gesture started at -- otherwise\n // the first pointermove would snap it inward.\n if (handle.includes('e')) {\n const limit = Math.max(bounds.right - origin.x, size.width);\n\n width = Math.min(size.width + deltaX, limit);\n }\n\n if (handle.includes('s')) {\n const limit = Math.max(bounds.bottom - origin.y, size.height);\n\n height = Math.min(size.height + deltaY, limit);\n }\n\n if (handle.includes('w')) {\n // Clamping x first keeps the right edge fixed while honouring bounds.\n const right = origin.x + size.width;\n const limit = Math.min(bounds.left, origin.x);\n\n x = clamp(origin.x + deltaX, limit, right - MIN_DIMENSIONS.width);\n width = right - x;\n }\n\n if (handle.includes('n')) {\n const bottom = origin.y + size.height;\n const limit = Math.min(bounds.top, origin.y);\n\n y = clamp(origin.y + deltaY, limit, bottom - MIN_DIMENSIONS.height);\n height = bottom - y;\n }\n\n onResize(\n {\n width: Math.max(width, MIN_DIMENSIONS.width),\n height: Math.max(height, MIN_DIMENSIONS.height),\n },\n { x, y },\n );\n },\n });\n\n const getHandleProps = useCallback(\n (handle: ResizeHandle) => ({\n onPointerDown: (event: React.PointerEvent) => {\n handleStart(event.nativeEvent, handle);\n },\n }),\n [handleStart],\n );\n\n return { getHandleProps };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,UAAU,EACxB,UACA,UACA,YACA,WACA,UACA,iBACiB;CACjB,MAAM,SAAS,OAAO;EAAE;EAAU;EAAY;EAAU,CAAC;AACzD,QAAO,UAAU;EAAE;EAAU;EAAY;EAAU;CAEnD,MAAM,EAAE,gBAAgB,oBAAiD;EACvE,cAAc,UAAU,CAAC,OAAO,QAAQ,YAAY,MAAM,WAAW;EACrE,UAAU,OAAO,WAAW;AAC1B,oBAAiB;AAEjB,UAAO;IACL,UAAU,MAAM;IAChB,UAAU,MAAM;IAChB,QAAQ,OAAO,QAAQ;IACvB,MAAM,OAAO,QAAQ;IACrB;IACA,QAAQ,WAAW;IACpB;;EAEH,SAAS,OAAO,YAAY;GAC1B,MAAM,SAAS,MAAM,UAAU,QAAQ;GACvC,MAAM,SAAS,MAAM,UAAU,QAAQ;GACvC,MAAM,EAAE,QAAQ,QAAQ,MAAM,WAAW;GAEzC,IAAI,EAAE,GAAG,MAAM;GACf,IAAI,EAAE,OAAO,WAAW;AAKxB,OAAI,OAAO,SAAS,IAAI,EAAE;IACxB,MAAM,QAAQ,KAAK,IAAI,OAAO,QAAQ,OAAO,GAAG,KAAK,MAAM;AAE3D,YAAQ,KAAK,IAAI,KAAK,QAAQ,QAAQ,MAAM;;AAG9C,OAAI,OAAO,SAAS,IAAI,EAAE;IACxB,MAAM,QAAQ,KAAK,IAAI,OAAO,SAAS,OAAO,GAAG,KAAK,OAAO;AAE7D,aAAS,KAAK,IAAI,KAAK,SAAS,QAAQ,MAAM;;AAGhD,OAAI,OAAO,SAAS,IAAI,EAAE;IAExB,MAAM,QAAQ,OAAO,IAAI,KAAK;IAC9B,MAAM,QAAQ,KAAK,IAAI,OAAO,MAAM,OAAO,EAAE;AAE7C,QAAI,MAAM,OAAO,IAAI,QAAQ,OAAO,QAAQ,eAAe,MAAM;AACjE,YAAQ,QAAQ;;AAGlB,OAAI,OAAO,SAAS,IAAI,EAAE;IACxB,MAAM,SAAS,OAAO,IAAI,KAAK;IAC/B,MAAM,QAAQ,KAAK,IAAI,OAAO,KAAK,OAAO,EAAE;AAE5C,QAAI,MAAM,OAAO,IAAI,QAAQ,OAAO,SAAS,eAAe,OAAO;AACnE,aAAS,SAAS;;AAGpB,YACE;IACE,OAAO,KAAK,IAAI,OAAO,eAAe,MAAM;IAC5C,QAAQ,KAAK,IAAI,QAAQ,eAAe,OAAO;IAChD,EACD;IAAE;IAAG;IAAG,CACT;;EAEJ,CAAC;AAWF,QAAO,EAAE,gBATc,aACpB,YAA0B,EACzB,gBAAgB,UAA8B;AAC5C,cAAY,MAAM,aAAa,OAAO;IAEzC,GACD,CAAC,YAAY,CACd,EAEwB"}
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import { FloatingCardProps } from "./types.js";
14
- import * as react20 from "react";
14
+ import * as react18 from "react";
15
15
  import { PropsWithChildren } from "react";
16
16
 
17
17
  //#region src/components/floating-card/index.d.ts
@@ -33,6 +33,10 @@ import { PropsWithChildren } from "react";
33
33
  * @remarks
34
34
  * - Requires `FloatingCardProvider` as an ancestor.
35
35
  * - The floating card is only rendered if a valid DOM reference exists for the given `id`.
36
+ * - `initialDimensions` and `initialPosition` are applied each time the card
37
+ * opens. While it stays open, later changes to them are ignored so a user's
38
+ * own drag or resize is never overridden; closing and reopening starts the
39
+ * card from those values again.
36
40
  *
37
41
  * @example
38
42
  * ```tsx
@@ -64,7 +68,7 @@ declare function FloatingCard({
64
68
  isOpen,
65
69
  initialDimensions,
66
70
  initialPosition
67
- }: PropsWithChildren<FloatingCardProps>): react20.ReactPortal | null;
71
+ }: PropsWithChildren<FloatingCardProps>): react18.ReactPortal | null;
68
72
  //#endregion
69
73
  export { FloatingCard };
70
74
  //# sourceMappingURL=index.d.ts.map
@@ -11,15 +11,12 @@
11
11
  */
12
12
 
13
13
 
14
- import { useFloatingCard } from "./context.js";
14
+ import { DEFAULT_DIMENSIONS, DEFAULT_POSITION } from "./constants.js";
15
+ import { useFloatingCard, useFloatingCardRegistry } from "./context.js";
15
16
  import { useEffect } from "react";
16
17
  import { createPortal } from "react-dom";
17
18
 
18
19
  //#region src/components/floating-card/index.tsx
19
- const defaultDimensions = {
20
- width: 300,
21
- height: 400
22
- };
23
20
  /**
24
21
  * Renders its children into a floating card using React portals.
25
22
  *
@@ -37,6 +34,10 @@ const defaultDimensions = {
37
34
  * @remarks
38
35
  * - Requires `FloatingCardProvider` as an ancestor.
39
36
  * - The floating card is only rendered if a valid DOM reference exists for the given `id`.
37
+ * - `initialDimensions` and `initialPosition` are applied each time the card
38
+ * opens. While it stays open, later changes to them are ignored so a user's
39
+ * own drag or resize is never overridden; closing and reopening starts the
40
+ * card from those values again.
40
41
  *
41
42
  * @example
42
43
  * ```tsx
@@ -62,29 +63,22 @@ const defaultDimensions = {
62
63
  * ```
63
64
  */
64
65
  function FloatingCard({ id, children, title, isOpen = true, initialDimensions, initialPosition }) {
65
- const { cards, api: floatingCardApi } = useFloatingCard();
66
- const { width, height } = initialDimensions ?? defaultDimensions;
67
- const { x, y } = initialPosition ?? {};
66
+ const { cards, closeCard } = useFloatingCard();
67
+ const { openCard } = useFloatingCardRegistry();
68
+ const { width, height } = initialDimensions ?? DEFAULT_DIMENSIONS;
69
+ const { x, y } = initialPosition ?? DEFAULT_POSITION;
68
70
  useEffect(() => {
69
- if (!floatingCardApi) return;
70
71
  if (!isOpen) {
71
- floatingCardApi.getPanel(id)?.api.close();
72
+ closeCard(id);
72
73
  return;
73
74
  }
74
- if (!floatingCardApi.getPanel(id)) {
75
- const panel = floatingCardApi.addPanel({
76
- id,
77
- title,
78
- component: "default",
79
- floating: {
80
- width,
81
- height,
82
- x,
83
- y
84
- }
85
- });
86
- panel.group.locked = "no-drop-target";
87
- }
75
+ openCard(id, title, {
76
+ x,
77
+ y
78
+ }, {
79
+ width,
80
+ height
81
+ });
88
82
  }, [
89
83
  id,
90
84
  title,
@@ -93,16 +87,14 @@ function FloatingCard({ id, children, title, isOpen = true, initialDimensions, i
93
87
  height,
94
88
  x,
95
89
  y,
96
- floatingCardApi
90
+ openCard,
91
+ closeCard
97
92
  ]);
98
93
  useEffect(() => {
99
- const panel = floatingCardApi?.getPanel(id);
100
- if (panel) panel.setTitle(title ?? id);
101
- }, [
102
- title,
103
- floatingCardApi,
104
- id
105
- ]);
94
+ return () => {
95
+ closeCard(id);
96
+ };
97
+ }, [id, closeCard]);
106
98
  return isOpen && cards[id] ? createPortal(children, cards[id]) : null;
107
99
  }
108
100
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/floating-card/index.tsx"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { type PropsWithChildren, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useFloatingCard } from './context';\nimport type { FloatingCardProps } from './types';\n\nconst defaultDimensions = { width: 300, height: 400 } as const;\n\n/**\n * Renders its children into a floating card using React portals.\n *\n * The `FloatingCard` component registers itself with the floating card engine on mount\n * and renders its children into the corresponding DOM node via a portal.\n *\n * @param id - Unique identifier for the floating card.\n * @param title - Optional title displayed in the floating card header.\n * @param isOpen - Whether the floating card is rendered. Defaults to `true`.\n * @param initialDimensions - Initial width and height of the floating card. Defaults to `{ width: 300, height: 400 }`.\n * @param initialPosition - Initial x and y coordinates of the floating card.\n * @param children - React children to render inside the floating card.\n * @returns The floating card component (portaled content) or null.\n *\n * @remarks\n * - Requires `FloatingCardProvider` as an ancestor.\n * - The floating card is only rendered if a valid DOM reference exists for the given `id`.\n *\n * @example\n * ```tsx\n * import { uuid } from '@accelint/core/utility/uuid';\n *\n * const cardId = uuid();\n * const [isOpen, setIsOpen] = useState(true);\n *\n * <FloatingCardProvider>\n * <FloatingCard\n * id={cardId}\n * title=\"Settings Panel\"\n * isOpen={isOpen}\n * initialDimensions={{ width: 400, height: 500 }}\n * >\n * <SettingsForm />\n * </FloatingCard>\n *\n * <button onClick={() => setIsOpen(!isOpen)}>\n * Toggle Panel\n * </button>\n * </FloatingCardProvider>\n * ```\n */\nexport function FloatingCard({\n id,\n children,\n title,\n isOpen = true,\n initialDimensions,\n initialPosition,\n}: PropsWithChildren<FloatingCardProps>) {\n const { cards, api: floatingCardApi } = useFloatingCard();\n\n const { width, height } = initialDimensions ?? defaultDimensions;\n const { x, y } = initialPosition ?? {};\n\n // Register card with Dockview API when isOpen changes.\n // Early return if API not ready (Dockview not fully initialized).\n useEffect(() => {\n if (!floatingCardApi) {\n return;\n }\n if (!isOpen) {\n floatingCardApi.getPanel(id)?.api.close();\n return;\n }\n\n if (!floatingCardApi.getPanel(id)) {\n const panel = floatingCardApi.addPanel({\n id,\n title,\n component: 'default',\n floating: { width, height, x, y },\n });\n\n panel.group.locked = 'no-drop-target';\n }\n\n // Cleanup not included here. Cleanup is done at the provider level when the card is removed from the `cards` registry.\n }, [id, title, isOpen, width, height, x, y, floatingCardApi]);\n\n useEffect(() => {\n const panel = floatingCardApi?.getPanel(id);\n if (panel) {\n panel.setTitle(title ?? id);\n }\n }, [title, floatingCardApi, id]);\n\n return isOpen && cards[id] ? createPortal(children, cards[id]) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,MAAM,oBAAoB;CAAE,OAAO;CAAK,QAAQ;CAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CrD,SAAgB,aAAa,EAC3B,IACA,UACA,OACA,SAAS,MACT,mBACA,mBACuC;CACvC,MAAM,EAAE,OAAO,KAAK,oBAAoB,iBAAiB;CAEzD,MAAM,EAAE,OAAO,WAAW,qBAAqB;CAC/C,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE;AAItC,iBAAgB;AACd,MAAI,CAAC,gBACH;AAEF,MAAI,CAAC,QAAQ;AACX,mBAAgB,SAAS,GAAG,EAAE,IAAI,OAAO;AACzC;;AAGF,MAAI,CAAC,gBAAgB,SAAS,GAAG,EAAE;GACjC,MAAM,QAAQ,gBAAgB,SAAS;IACrC;IACA;IACA,WAAW;IACX,UAAU;KAAE;KAAO;KAAQ;KAAG;KAAG;IAClC,CAAC;AAEF,SAAM,MAAM,SAAS;;IAItB;EAAC;EAAI;EAAO;EAAQ;EAAO;EAAQ;EAAG;EAAG;EAAgB,CAAC;AAE7D,iBAAgB;EACd,MAAM,QAAQ,iBAAiB,SAAS,GAAG;AAC3C,MAAI,MACF,OAAM,SAAS,SAAS,GAAG;IAE5B;EAAC;EAAO;EAAiB;EAAG,CAAC;AAEhC,QAAO,UAAU,MAAM,MAAM,aAAa,UAAU,MAAM,IAAI,GAAG"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/floating-card/index.tsx"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { type PropsWithChildren, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { DEFAULT_DIMENSIONS, DEFAULT_POSITION } from './constants';\nimport { useFloatingCard, useFloatingCardRegistry } from './context';\nimport type { FloatingCardProps } from './types';\n\n/**\n * Renders its children into a floating card using React portals.\n *\n * The `FloatingCard` component registers itself with the floating card engine on mount\n * and renders its children into the corresponding DOM node via a portal.\n *\n * @param id - Unique identifier for the floating card.\n * @param title - Optional title displayed in the floating card header.\n * @param isOpen - Whether the floating card is rendered. Defaults to `true`.\n * @param initialDimensions - Initial width and height of the floating card. Defaults to `{ width: 300, height: 400 }`.\n * @param initialPosition - Initial x and y coordinates of the floating card.\n * @param children - React children to render inside the floating card.\n * @returns The floating card component (portaled content) or null.\n *\n * @remarks\n * - Requires `FloatingCardProvider` as an ancestor.\n * - The floating card is only rendered if a valid DOM reference exists for the given `id`.\n * - `initialDimensions` and `initialPosition` are applied each time the card\n * opens. While it stays open, later changes to them are ignored so a user's\n * own drag or resize is never overridden; closing and reopening starts the\n * card from those values again.\n *\n * @example\n * ```tsx\n * import { uuid } from '@accelint/core/utility/uuid';\n *\n * const cardId = uuid();\n * const [isOpen, setIsOpen] = useState(true);\n *\n * <FloatingCardProvider>\n * <FloatingCard\n * id={cardId}\n * title=\"Settings Panel\"\n * isOpen={isOpen}\n * initialDimensions={{ width: 400, height: 500 }}\n * >\n * <SettingsForm />\n * </FloatingCard>\n *\n * <button onClick={() => setIsOpen(!isOpen)}>\n * Toggle Panel\n * </button>\n * </FloatingCardProvider>\n * ```\n */\nexport function FloatingCard({\n id,\n children,\n title,\n isOpen = true,\n initialDimensions,\n initialPosition,\n}: PropsWithChildren<FloatingCardProps>) {\n const { cards, closeCard } = useFloatingCard();\n const { openCard } = useFloatingCardRegistry();\n\n const { width, height } = initialDimensions ?? DEFAULT_DIMENSIONS;\n const { x, y } = initialPosition ?? DEFAULT_POSITION;\n\n useEffect(() => {\n if (!isOpen) {\n closeCard(id);\n\n return;\n }\n\n openCard(id, title, { x, y }, { width, height });\n }, [id, title, isOpen, width, height, x, y, openCard, closeCard]);\n\n // Unregister on unmount so a card removed from the tree leaves no panel behind.\n useEffect(() => {\n return () => {\n closeCard(id);\n };\n }, [id, closeCard]);\n\n return isOpen && cards[id] ? createPortal(children, cards[id]) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,SAAgB,aAAa,EAC3B,IACA,UACA,OACA,SAAS,MACT,mBACA,mBACuC;CACvC,MAAM,EAAE,OAAO,cAAc,iBAAiB;CAC9C,MAAM,EAAE,aAAa,yBAAyB;CAE9C,MAAM,EAAE,OAAO,WAAW,qBAAqB;CAC/C,MAAM,EAAE,GAAG,MAAM,mBAAmB;AAEpC,iBAAgB;AACd,MAAI,CAAC,QAAQ;AACX,aAAU,GAAG;AAEb;;AAGF,WAAS,IAAI,OAAO;GAAE;GAAG;GAAG,EAAE;GAAE;GAAO;GAAQ,CAAC;IAC/C;EAAC;EAAI;EAAO;EAAQ;EAAO;EAAQ;EAAG;EAAG;EAAU;EAAU,CAAC;AAGjE,iBAAgB;AACd,eAAa;AACX,aAAU,GAAG;;IAEd,CAAC,IAAI,UAAU,CAAC;AAEnB,QAAO,UAAU,MAAM,MAAM,aAAa,UAAU,MAAM,IAAI,GAAG"}