@zvk/ui 0.1.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 (278) hide show
  1. package/LICENSE.md +26 -0
  2. package/README.md +31 -0
  3. package/dist/components/accordion/accordion.d.ts +43 -0
  4. package/dist/components/accordion/accordion.js +207 -0
  5. package/dist/components/accordion/index.d.ts +2 -0
  6. package/dist/components/accordion/index.js +2 -0
  7. package/dist/components/alert/alert.d.ts +24 -0
  8. package/dist/components/alert/alert.js +17 -0
  9. package/dist/components/alert/index.d.ts +2 -0
  10. package/dist/components/alert/index.js +1 -0
  11. package/dist/components/alert-dialog/alert-dialog.d.ts +46 -0
  12. package/dist/components/alert-dialog/alert-dialog.js +112 -0
  13. package/dist/components/alert-dialog/index.d.ts +2 -0
  14. package/dist/components/alert-dialog/index.js +2 -0
  15. package/dist/components/avatar/avatar.d.ts +14 -0
  16. package/dist/components/avatar/avatar.js +22 -0
  17. package/dist/components/avatar/index.d.ts +2 -0
  18. package/dist/components/avatar/index.js +2 -0
  19. package/dist/components/badge/badge.d.ts +11 -0
  20. package/dist/components/badge/badge.js +6 -0
  21. package/dist/components/badge/index.d.ts +2 -0
  22. package/dist/components/badge/index.js +1 -0
  23. package/dist/components/breadcrumbs/breadcrumbs.d.ts +24 -0
  24. package/dist/components/breadcrumbs/breadcrumbs.js +18 -0
  25. package/dist/components/breadcrumbs/index.d.ts +2 -0
  26. package/dist/components/breadcrumbs/index.js +1 -0
  27. package/dist/components/button/button.d.ts +13 -0
  28. package/dist/components/button/button.js +8 -0
  29. package/dist/components/button/index.d.ts +2 -0
  30. package/dist/components/button/index.js +1 -0
  31. package/dist/components/card/card.d.ts +31 -0
  32. package/dist/components/card/card.js +28 -0
  33. package/dist/components/card/index.d.ts +2 -0
  34. package/dist/components/card/index.js +1 -0
  35. package/dist/components/checkbox/checkbox.d.ts +11 -0
  36. package/dist/components/checkbox/checkbox.js +30 -0
  37. package/dist/components/checkbox/index.d.ts +2 -0
  38. package/dist/components/checkbox/index.js +2 -0
  39. package/dist/components/code-block/code-block.d.ts +10 -0
  40. package/dist/components/code-block/code-block.js +16 -0
  41. package/dist/components/code-block/index.d.ts +2 -0
  42. package/dist/components/code-block/index.js +1 -0
  43. package/dist/components/collapsible/collapsible.d.ts +23 -0
  44. package/dist/components/collapsible/collapsible.js +52 -0
  45. package/dist/components/collapsible/index.d.ts +2 -0
  46. package/dist/components/collapsible/index.js +2 -0
  47. package/dist/components/combobox/combobox.d.ts +20 -0
  48. package/dist/components/combobox/combobox.js +121 -0
  49. package/dist/components/combobox/index.d.ts +2 -0
  50. package/dist/components/combobox/index.js +2 -0
  51. package/dist/components/command/command-dialog.d.ts +2 -0
  52. package/dist/components/command/command-dialog.js +1 -0
  53. package/dist/components/command/command-filter.d.ts +7 -0
  54. package/dist/components/command/command-filter.js +14 -0
  55. package/dist/components/command/command.d.ts +55 -0
  56. package/dist/components/command/command.js +200 -0
  57. package/dist/components/command/index.d.ts +2 -0
  58. package/dist/components/command/index.js +2 -0
  59. package/dist/components/context-menu/context-menu.d.ts +34 -0
  60. package/dist/components/context-menu/context-menu.js +154 -0
  61. package/dist/components/context-menu/index.d.ts +2 -0
  62. package/dist/components/context-menu/index.js +2 -0
  63. package/dist/components/conversation/conversation.d.ts +60 -0
  64. package/dist/components/conversation/conversation.js +49 -0
  65. package/dist/components/conversation/index.d.ts +2 -0
  66. package/dist/components/conversation/index.js +1 -0
  67. package/dist/components/copy-button/copy-button.d.ts +23 -0
  68. package/dist/components/copy-button/copy-button.js +50 -0
  69. package/dist/components/copy-button/index.d.ts +2 -0
  70. package/dist/components/copy-button/index.js +2 -0
  71. package/dist/components/dialog/dialog.d.ts +62 -0
  72. package/dist/components/dialog/dialog.js +141 -0
  73. package/dist/components/dialog/index.d.ts +2 -0
  74. package/dist/components/dialog/index.js +2 -0
  75. package/dist/components/dropdown-menu/dropdown-menu.d.ts +43 -0
  76. package/dist/components/dropdown-menu/dropdown-menu.js +286 -0
  77. package/dist/components/dropdown-menu/index.d.ts +2 -0
  78. package/dist/components/dropdown-menu/index.js +2 -0
  79. package/dist/components/empty-state/empty-state.d.ts +13 -0
  80. package/dist/components/empty-state/empty-state.js +34 -0
  81. package/dist/components/empty-state/index.d.ts +2 -0
  82. package/dist/components/empty-state/index.js +1 -0
  83. package/dist/components/error-boundary/error-boundary.d.ts +29 -0
  84. package/dist/components/error-boundary/error-boundary.js +43 -0
  85. package/dist/components/error-boundary/index.d.ts +2 -0
  86. package/dist/components/error-boundary/index.js +2 -0
  87. package/dist/components/field/field.d.ts +23 -0
  88. package/dist/components/field/field.js +20 -0
  89. package/dist/components/field/index.d.ts +2 -0
  90. package/dist/components/field/index.js +1 -0
  91. package/dist/components/file-upload-input/file-upload-input.d.ts +13 -0
  92. package/dist/components/file-upload-input/file-upload-input.js +41 -0
  93. package/dist/components/file-upload-input/index.d.ts +2 -0
  94. package/dist/components/file-upload-input/index.js +2 -0
  95. package/dist/components/form/form.d.ts +30 -0
  96. package/dist/components/form/form.js +88 -0
  97. package/dist/components/form/index.d.ts +2 -0
  98. package/dist/components/form/index.js +2 -0
  99. package/dist/components/icon-button/icon-button.d.ts +10 -0
  100. package/dist/components/icon-button/icon-button.js +8 -0
  101. package/dist/components/icon-button/index.d.ts +2 -0
  102. package/dist/components/icon-button/index.js +1 -0
  103. package/dist/components/index.d.ts +102 -0
  104. package/dist/components/index.js +51 -0
  105. package/dist/components/input/index.d.ts +2 -0
  106. package/dist/components/input/index.js +1 -0
  107. package/dist/components/input/input.d.ts +11 -0
  108. package/dist/components/input/input.js +27 -0
  109. package/dist/components/label/index.d.ts +2 -0
  110. package/dist/components/label/index.js +1 -0
  111. package/dist/components/label/label.d.ts +9 -0
  112. package/dist/components/label/label.js +6 -0
  113. package/dist/components/menubar/index.d.ts +2 -0
  114. package/dist/components/menubar/index.js +2 -0
  115. package/dist/components/menubar/menubar.d.ts +39 -0
  116. package/dist/components/menubar/menubar.js +214 -0
  117. package/dist/components/pagination/index.d.ts +2 -0
  118. package/dist/components/pagination/index.js +1 -0
  119. package/dist/components/pagination/pagination.d.ts +21 -0
  120. package/dist/components/pagination/pagination.js +92 -0
  121. package/dist/components/popover/index.d.ts +2 -0
  122. package/dist/components/popover/index.js +2 -0
  123. package/dist/components/popover/popover.d.ts +28 -0
  124. package/dist/components/popover/popover.js +164 -0
  125. package/dist/components/progress/index.d.ts +2 -0
  126. package/dist/components/progress/index.js +1 -0
  127. package/dist/components/progress/progress.d.ts +24 -0
  128. package/dist/components/progress/progress.js +29 -0
  129. package/dist/components/radio-group/index.d.ts +2 -0
  130. package/dist/components/radio-group/index.js +2 -0
  131. package/dist/components/radio-group/radio-group.d.ts +42 -0
  132. package/dist/components/radio-group/radio-group.js +69 -0
  133. package/dist/components/responsive-container/index.d.ts +2 -0
  134. package/dist/components/responsive-container/index.js +1 -0
  135. package/dist/components/responsive-container/responsive-container.d.ts +10 -0
  136. package/dist/components/responsive-container/responsive-container.js +6 -0
  137. package/dist/components/scroll-area/index.d.ts +2 -0
  138. package/dist/components/scroll-area/index.js +2 -0
  139. package/dist/components/scroll-area/scroll-area.d.ts +21 -0
  140. package/dist/components/scroll-area/scroll-area.js +23 -0
  141. package/dist/components/sectioned-sidebar-nav/index.d.ts +2 -0
  142. package/dist/components/sectioned-sidebar-nav/index.js +1 -0
  143. package/dist/components/sectioned-sidebar-nav/sectioned-sidebar-nav.d.ts +39 -0
  144. package/dist/components/sectioned-sidebar-nav/sectioned-sidebar-nav.js +37 -0
  145. package/dist/components/select/index.d.ts +2 -0
  146. package/dist/components/select/index.js +2 -0
  147. package/dist/components/select/select.d.ts +46 -0
  148. package/dist/components/select/select.js +239 -0
  149. package/dist/components/separator/index.d.ts +2 -0
  150. package/dist/components/separator/index.js +1 -0
  151. package/dist/components/separator/separator.d.ts +8 -0
  152. package/dist/components/separator/separator.js +6 -0
  153. package/dist/components/sheet/index.d.ts +2 -0
  154. package/dist/components/sheet/index.js +2 -0
  155. package/dist/components/sheet/sheet.d.ts +49 -0
  156. package/dist/components/sheet/sheet.js +116 -0
  157. package/dist/components/sidebar-shell/index.d.ts +2 -0
  158. package/dist/components/sidebar-shell/index.js +1 -0
  159. package/dist/components/sidebar-shell/sidebar-shell.d.ts +35 -0
  160. package/dist/components/sidebar-shell/sidebar-shell.js +28 -0
  161. package/dist/components/skeleton/index.d.ts +2 -0
  162. package/dist/components/skeleton/index.js +1 -0
  163. package/dist/components/skeleton/skeleton.d.ts +10 -0
  164. package/dist/components/skeleton/skeleton.js +16 -0
  165. package/dist/components/slider/index.d.ts +2 -0
  166. package/dist/components/slider/index.js +2 -0
  167. package/dist/components/slider/slider.d.ts +12 -0
  168. package/dist/components/slider/slider.js +30 -0
  169. package/dist/components/spinner/index.d.ts +2 -0
  170. package/dist/components/spinner/index.js +1 -0
  171. package/dist/components/spinner/spinner.d.ts +10 -0
  172. package/dist/components/spinner/spinner.js +7 -0
  173. package/dist/components/stat/index.d.ts +2 -0
  174. package/dist/components/stat/index.js +1 -0
  175. package/dist/components/stat/stat.d.ts +13 -0
  176. package/dist/components/stat/stat.js +8 -0
  177. package/dist/components/switch/index.d.ts +2 -0
  178. package/dist/components/switch/index.js +2 -0
  179. package/dist/components/switch/switch.d.ts +11 -0
  180. package/dist/components/switch/switch.js +27 -0
  181. package/dist/components/table/index.d.ts +2 -0
  182. package/dist/components/table/index.js +1 -0
  183. package/dist/components/table/table.d.ts +45 -0
  184. package/dist/components/table/table.js +36 -0
  185. package/dist/components/tabs/index.d.ts +2 -0
  186. package/dist/components/tabs/index.js +2 -0
  187. package/dist/components/tabs/tabs.d.ts +34 -0
  188. package/dist/components/tabs/tabs.js +233 -0
  189. package/dist/components/tabs-with-sidebar/index.d.ts +2 -0
  190. package/dist/components/tabs-with-sidebar/index.js +2 -0
  191. package/dist/components/tabs-with-sidebar/tabs-with-sidebar.d.ts +21 -0
  192. package/dist/components/tabs-with-sidebar/tabs-with-sidebar.js +18 -0
  193. package/dist/components/textarea/index.d.ts +2 -0
  194. package/dist/components/textarea/index.js +2 -0
  195. package/dist/components/textarea/textarea.d.ts +11 -0
  196. package/dist/components/textarea/textarea.js +28 -0
  197. package/dist/components/toast/index.d.ts +2 -0
  198. package/dist/components/toast/index.js +1 -0
  199. package/dist/components/toast/toast.d.ts +33 -0
  200. package/dist/components/toast/toast.js +27 -0
  201. package/dist/components/toggle/index.d.ts +2 -0
  202. package/dist/components/toggle/index.js +2 -0
  203. package/dist/components/toggle/toggle.d.ts +12 -0
  204. package/dist/components/toggle/toggle.js +18 -0
  205. package/dist/components/toggle-group/index.d.ts +2 -0
  206. package/dist/components/toggle-group/index.js +2 -0
  207. package/dist/components/toggle-group/toggle-group.d.ts +28 -0
  208. package/dist/components/toggle-group/toggle-group.js +67 -0
  209. package/dist/components/tooltip/index.d.ts +2 -0
  210. package/dist/components/tooltip/index.js +2 -0
  211. package/dist/components/tooltip/tooltip.d.ts +10 -0
  212. package/dist/components/tooltip/tooltip.js +100 -0
  213. package/dist/hooks/index.d.ts +7 -0
  214. package/dist/hooks/index.js +5 -0
  215. package/dist/hooks/use-composed-refs.d.ts +3 -0
  216. package/dist/hooks/use-composed-refs.js +18 -0
  217. package/dist/hooks/use-controllable-state.d.ts +7 -0
  218. package/dist/hooks/use-controllable-state.js +30 -0
  219. package/dist/hooks/use-disclosure.d.ts +13 -0
  220. package/dist/hooks/use-disclosure.js +20 -0
  221. package/dist/hooks/use-event.d.ts +1 -0
  222. package/dist/hooks/use-event.js +11 -0
  223. package/dist/index.d.ts +3 -0
  224. package/dist/index.js +3 -0
  225. package/dist/internal/collection/collection.d.ts +18 -0
  226. package/dist/internal/collection/collection.js +54 -0
  227. package/dist/internal/collection/index.d.ts +2 -0
  228. package/dist/internal/collection/index.js +1 -0
  229. package/dist/internal/dismissable-layer/dismissable-layer.d.ts +13 -0
  230. package/dist/internal/dismissable-layer/dismissable-layer.js +73 -0
  231. package/dist/internal/dismissable-layer/index.d.ts +2 -0
  232. package/dist/internal/dismissable-layer/index.js +1 -0
  233. package/dist/internal/floating/auto-update.d.ts +9 -0
  234. package/dist/internal/floating/auto-update.js +48 -0
  235. package/dist/internal/floating/compute-position.d.ts +2 -0
  236. package/dist/internal/floating/compute-position.js +96 -0
  237. package/dist/internal/floating/detect-overflow.d.ts +13 -0
  238. package/dist/internal/floating/detect-overflow.js +13 -0
  239. package/dist/internal/floating/floating-types.d.ts +42 -0
  240. package/dist/internal/floating/floating-types.js +1 -0
  241. package/dist/internal/floating/index.d.ts +27 -0
  242. package/dist/internal/floating/index.js +5 -0
  243. package/dist/internal/floating/middleware.d.ts +11 -0
  244. package/dist/internal/floating/middleware.js +42 -0
  245. package/dist/internal/floating/use-floating-position.d.ts +2 -0
  246. package/dist/internal/floating/use-floating-position.js +113 -0
  247. package/dist/internal/focus/focus-scope.d.ts +10 -0
  248. package/dist/internal/focus/focus-scope.js +68 -0
  249. package/dist/internal/focus/focus-utils.d.ts +9 -0
  250. package/dist/internal/focus/focus-utils.js +94 -0
  251. package/dist/internal/focus/index.d.ts +3 -0
  252. package/dist/internal/focus/index.js +2 -0
  253. package/dist/internal/overlay-stack/index.d.ts +1 -0
  254. package/dist/internal/overlay-stack/index.js +1 -0
  255. package/dist/internal/overlay-stack/overlay-stack.d.ts +12 -0
  256. package/dist/internal/overlay-stack/overlay-stack.js +41 -0
  257. package/dist/internal/portal/index.d.ts +2 -0
  258. package/dist/internal/portal/index.js +1 -0
  259. package/dist/internal/portal/portal.d.ts +7 -0
  260. package/dist/internal/portal/portal.js +19 -0
  261. package/dist/internal/scroll-lock/index.d.ts +1 -0
  262. package/dist/internal/scroll-lock/index.js +1 -0
  263. package/dist/internal/scroll-lock/scroll-lock.d.ts +4 -0
  264. package/dist/internal/scroll-lock/scroll-lock.js +69 -0
  265. package/dist/styles.css +3852 -0
  266. package/dist/tokens/index.d.ts +2 -0
  267. package/dist/tokens/index.js +1 -0
  268. package/dist/tokens/token-types.d.ts +23 -0
  269. package/dist/tokens/token-types.js +1 -0
  270. package/dist/tokens/tokens.d.ts +139 -0
  271. package/dist/tokens/tokens.js +139 -0
  272. package/dist/utils/cn.d.ts +2 -0
  273. package/dist/utils/cn.js +3 -0
  274. package/dist/utils/compose-event-handlers.d.ts +6 -0
  275. package/dist/utils/compose-event-handlers.js +8 -0
  276. package/dist/utils/index.d.ts +4 -0
  277. package/dist/utils/index.js +2 -0
  278. package/package.json +282 -0
@@ -0,0 +1,100 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Portal } from "../../internal/portal/index.js";
5
+ import { useFloatingPosition } from "../../internal/floating/index.js";
6
+ import { composeEventHandlers } from "../../utils/compose-event-handlers.js";
7
+ function composeRefs(...refs) {
8
+ return (node) => {
9
+ for (const ref of refs) {
10
+ if (typeof ref === "function") {
11
+ ref(node);
12
+ }
13
+ else if (ref !== undefined) {
14
+ ref.current = node;
15
+ }
16
+ }
17
+ };
18
+ }
19
+ function joinIds(...ids) {
20
+ const value = ids.filter((id) => id !== undefined && id !== "").join(" ");
21
+ return value.length > 0 ? value : undefined;
22
+ }
23
+ function getPlacementParts(placement) {
24
+ const [side, align = "center"] = placement.split("-");
25
+ return { side, align };
26
+ }
27
+ export function Tooltip({ children, content, delay = 0, disabled = false, placement = "bottom" }) {
28
+ const tooltipId = React.useId();
29
+ const tooltipElementId = `${tooltipId}-content`;
30
+ const [open, setOpen] = React.useState(false);
31
+ const openTimeoutRef = React.useRef(null);
32
+ const { floatingRef, floatingStyle, placement: resolvedPlacement, referenceRef, updatePosition } = useFloatingPosition({
33
+ open,
34
+ placement,
35
+ offset: 8,
36
+ flip: true,
37
+ shift: true
38
+ });
39
+ const clearOpenTimeout = React.useCallback(() => {
40
+ if (openTimeoutRef.current === null) {
41
+ return;
42
+ }
43
+ window.clearTimeout(openTimeoutRef.current);
44
+ openTimeoutRef.current = null;
45
+ }, []);
46
+ const openWithDelay = React.useCallback(() => {
47
+ if (disabled) {
48
+ return;
49
+ }
50
+ clearOpenTimeout();
51
+ if (delay > 0) {
52
+ openTimeoutRef.current = window.setTimeout(() => {
53
+ setOpen(true);
54
+ }, delay);
55
+ return;
56
+ }
57
+ setOpen(true);
58
+ }, [clearOpenTimeout, delay, disabled]);
59
+ const closeTooltip = React.useCallback(() => {
60
+ clearOpenTimeout();
61
+ setOpen(false);
62
+ }, [clearOpenTimeout]);
63
+ React.useEffect(() => {
64
+ if (!open) {
65
+ return;
66
+ }
67
+ updatePosition();
68
+ }, [open, content, updatePosition]);
69
+ React.useEffect(() => {
70
+ if (disabled) {
71
+ closeTooltip();
72
+ }
73
+ }, [closeTooltip, disabled]);
74
+ React.useEffect(() => () => clearOpenTimeout(), [clearOpenTimeout]);
75
+ if (!React.isValidElement(children) || disabled) {
76
+ return children;
77
+ }
78
+ const trigger = children;
79
+ const childProps = trigger.props;
80
+ const childAriaDescribedBy = childProps["aria-describedby"];
81
+ const triggerAriaDescribedBy = joinIds(typeof childAriaDescribedBy === "string" ? childAriaDescribedBy : undefined, open ? tooltipElementId : undefined);
82
+ const mergedRef = composeRefs(childProps.ref, referenceRef);
83
+ const placementParts = getPlacementParts(resolvedPlacement);
84
+ return (_jsxs(_Fragment, { children: [React.cloneElement(trigger, {
85
+ ...childProps,
86
+ ref: mergedRef,
87
+ "aria-describedby": triggerAriaDescribedBy,
88
+ onMouseEnter: composeEventHandlers(childProps.onMouseEnter, openWithDelay),
89
+ onPointerEnter: composeEventHandlers(childProps.onPointerEnter, openWithDelay),
90
+ onMouseLeave: composeEventHandlers(childProps.onMouseLeave, closeTooltip),
91
+ onPointerLeave: composeEventHandlers(childProps.onPointerLeave, closeTooltip),
92
+ onFocus: composeEventHandlers(childProps.onFocus, openWithDelay),
93
+ onBlur: composeEventHandlers(childProps.onBlur, closeTooltip),
94
+ onKeyDown: composeEventHandlers(childProps.onKeyDown, (event) => {
95
+ if (event.key === "Escape") {
96
+ closeTooltip();
97
+ }
98
+ }, { checkDefaultPrevented: false })
99
+ }), open ? (_jsx(Portal, { children: _jsx("span", { id: tooltipElementId, className: "liano-tooltip", "data-align": placementParts.align, "data-side": placementParts.side, role: "tooltip", ref: floatingRef, style: floatingStyle, children: content }) })) : null] }));
100
+ }
@@ -0,0 +1,7 @@
1
+ export { useComposedRefs } from "./use-composed-refs.js";
2
+ export type { LianoPossibleRef } from "./use-composed-refs.js";
3
+ export { useControllableState } from "./use-controllable-state.js";
4
+ export type { LianoSetStateAction, UseControllableStateOptions } from "./use-controllable-state.js";
5
+ export { useDisclosure } from "./use-disclosure.js";
6
+ export type { UseDisclosureOptions, UseDisclosureReturn } from "./use-disclosure.js";
7
+ export { useEvent } from "./use-event.js";
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ export { useComposedRefs } from "./use-composed-refs.js";
3
+ export { useControllableState } from "./use-controllable-state.js";
4
+ export { useDisclosure } from "./use-disclosure.js";
5
+ export { useEvent } from "./use-event.js";
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ export type LianoPossibleRef<Value> = React.Ref<Value> | undefined;
3
+ export declare function useComposedRefs<Value>(...refs: LianoPossibleRef<Value>[]): React.RefCallback<Value>;
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ function setRef(ref, value) {
4
+ if (typeof ref === "function") {
5
+ ref(value);
6
+ return;
7
+ }
8
+ if (ref) {
9
+ ref.current = value;
10
+ }
11
+ }
12
+ export function useComposedRefs(...refs) {
13
+ return React.useCallback((value) => {
14
+ for (const ref of refs) {
15
+ setRef(ref, value);
16
+ }
17
+ }, refs);
18
+ }
@@ -0,0 +1,7 @@
1
+ export type LianoSetStateAction<Value> = Value | ((previous: Value) => Value);
2
+ export interface UseControllableStateOptions<Value> {
3
+ value?: Value;
4
+ defaultValue: Value;
5
+ onChange?: (value: Value) => void;
6
+ }
7
+ export declare function useControllableState<Value>({ value, defaultValue, onChange }: UseControllableStateOptions<Value>): readonly [Value, (next: LianoSetStateAction<Value>) => void];
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { useEvent } from "./use-event.js";
4
+ export function useControllableState({ value, defaultValue, onChange }) {
5
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
6
+ const handleChange = useEvent((nextValue) => {
7
+ onChange?.(nextValue);
8
+ });
9
+ const isControlled = value !== undefined;
10
+ const currentValue = isControlled ? value : internalValue;
11
+ const currentValueRef = React.useRef(currentValue);
12
+ React.useLayoutEffect(() => {
13
+ currentValueRef.current = currentValue;
14
+ }, [currentValue]);
15
+ const setValue = React.useCallback((next) => {
16
+ const previousValue = isControlled ? currentValue : currentValueRef.current;
17
+ const nextValue = typeof next === "function" ? next(previousValue) : next;
18
+ if (Object.is(nextValue, previousValue)) {
19
+ return;
20
+ }
21
+ if (isControlled) {
22
+ handleChange(nextValue);
23
+ return;
24
+ }
25
+ currentValueRef.current = nextValue;
26
+ setInternalValue(nextValue);
27
+ handleChange(nextValue);
28
+ }, [currentValue, handleChange, isControlled]);
29
+ return [currentValue, setValue];
30
+ }
@@ -0,0 +1,13 @@
1
+ export interface UseDisclosureOptions {
2
+ open?: boolean;
3
+ defaultOpen?: boolean;
4
+ onOpenChange?: (open: boolean) => void;
5
+ }
6
+ export interface UseDisclosureReturn {
7
+ open: boolean;
8
+ setOpen: (open: boolean | ((previous: boolean) => boolean)) => void;
9
+ openDisclosure: () => void;
10
+ closeDisclosure: () => void;
11
+ toggleDisclosure: () => void;
12
+ }
13
+ export declare function useDisclosure({ open, defaultOpen, onOpenChange }?: UseDisclosureOptions): UseDisclosureReturn;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { useControllableState } from "./use-controllable-state.js";
4
+ export function useDisclosure({ open, defaultOpen = false, onOpenChange } = {}) {
5
+ const [currentOpen, setOpen] = useControllableState({
6
+ ...(open !== undefined ? { value: open } : {}),
7
+ ...(onOpenChange ? { onChange: onOpenChange } : {}),
8
+ defaultValue: defaultOpen
9
+ });
10
+ const openDisclosure = React.useCallback(() => setOpen(true), [setOpen]);
11
+ const closeDisclosure = React.useCallback(() => setOpen(false), [setOpen]);
12
+ const toggleDisclosure = React.useCallback(() => setOpen((previous) => !previous), [setOpen]);
13
+ return {
14
+ open: currentOpen,
15
+ setOpen,
16
+ openDisclosure,
17
+ closeDisclosure,
18
+ toggleDisclosure
19
+ };
20
+ }
@@ -0,0 +1 @@
1
+ export declare function useEvent<Callback extends (...args: never[]) => unknown>(callback: Callback): Callback;
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ export function useEvent(callback) {
4
+ const callbackRef = React.useRef(callback);
5
+ React.useLayoutEffect(() => {
6
+ callbackRef.current = callback;
7
+ });
8
+ return React.useCallback(((...args) => {
9
+ return callbackRef.current(...args);
10
+ }), []);
11
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./components/index.js";
2
+ export * from "./tokens/index.js";
3
+ export * from "./utils/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./components/index.js";
2
+ export * from "./tokens/index.js";
3
+ export * from "./utils/index.js";
@@ -0,0 +1,18 @@
1
+ export interface CollectionItem<ItemData> {
2
+ id: string;
3
+ data: ItemData;
4
+ }
5
+ export interface Collection<ItemData extends {
6
+ disabled?: boolean | undefined;
7
+ }> {
8
+ firstEnabled: () => CollectionItem<ItemData> | undefined;
9
+ items: () => Array<CollectionItem<ItemData>>;
10
+ lastEnabled: () => CollectionItem<ItemData> | undefined;
11
+ nextEnabled: (id: string | undefined) => CollectionItem<ItemData> | undefined;
12
+ previousEnabled: (id: string | undefined) => CollectionItem<ItemData> | undefined;
13
+ register: (id: string, data: ItemData) => void;
14
+ unregister: (id: string) => void;
15
+ }
16
+ export declare function createCollection<ItemData extends {
17
+ disabled?: boolean | undefined;
18
+ }>(): Collection<ItemData>;
@@ -0,0 +1,54 @@
1
+ function enabledItems(items) {
2
+ return items.filter((item) => item.data.disabled !== true);
3
+ }
4
+ function wrapIndex(index, length) {
5
+ return ((index % length) + length) % length;
6
+ }
7
+ export function createCollection() {
8
+ const order = [];
9
+ const records = new Map();
10
+ const items = () => order
11
+ .map((id) => {
12
+ const data = records.get(id);
13
+ return data === undefined ? undefined : { id, data };
14
+ })
15
+ .filter((item) => item !== undefined);
16
+ const firstEnabled = () => enabledItems(items())[0];
17
+ const lastEnabled = () => enabledItems(items()).at(-1);
18
+ const nextEnabled = (id) => {
19
+ const enabled = enabledItems(items());
20
+ if (enabled.length === 0) {
21
+ return undefined;
22
+ }
23
+ const currentIndex = id === undefined ? -1 : enabled.findIndex((item) => item.id === id);
24
+ return enabled[wrapIndex(currentIndex + 1, enabled.length)];
25
+ };
26
+ const previousEnabled = (id) => {
27
+ const enabled = enabledItems(items());
28
+ if (enabled.length === 0) {
29
+ return undefined;
30
+ }
31
+ const currentIndex = id === undefined ? 0 : enabled.findIndex((item) => item.id === id);
32
+ return enabled[wrapIndex(currentIndex - 1, enabled.length)];
33
+ };
34
+ return {
35
+ firstEnabled,
36
+ items,
37
+ lastEnabled,
38
+ nextEnabled,
39
+ previousEnabled,
40
+ register: (id, data) => {
41
+ if (!order.includes(id)) {
42
+ order.push(id);
43
+ }
44
+ records.set(id, data);
45
+ },
46
+ unregister: (id) => {
47
+ records.delete(id);
48
+ const index = order.indexOf(id);
49
+ if (index >= 0) {
50
+ order.splice(index, 1);
51
+ }
52
+ }
53
+ };
54
+ }
@@ -0,0 +1,2 @@
1
+ export { createCollection } from "./collection.js";
2
+ export type { Collection, CollectionItem } from "./collection.js";
@@ -0,0 +1 @@
1
+ export { createCollection } from "./collection.js";
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ export interface DismissableLayerProps {
3
+ children: React.ReactNode;
4
+ open?: boolean;
5
+ modal?: boolean;
6
+ disableOutsidePointerDown?: boolean;
7
+ disableEscapeKeyDown?: boolean;
8
+ onDismiss?: (event: Event) => void;
9
+ onEscapeKeyDown?: (event: Event) => void;
10
+ onPointerDownOutside?: (event: Event) => void;
11
+ }
12
+ export declare function DismissableLayer({ children, open, disableOutsidePointerDown, disableEscapeKeyDown, onDismiss, onEscapeKeyDown, onPointerDownOutside }: DismissableLayerProps): React.ReactElement | null;
13
+ export default DismissableLayer;
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { isTopOverlay, popOverlay, pushOverlay } from "../overlay-stack/overlay-stack.js";
5
+ export function DismissableLayer({ children, open = true, disableOutsidePointerDown = false, disableEscapeKeyDown = false, onDismiss, onEscapeKeyDown, onPointerDownOutside }) {
6
+ const layerRef = React.useRef(null);
7
+ const idRef = React.useRef("");
8
+ React.useEffect(() => {
9
+ if (!open || layerRef.current === null) {
10
+ return;
11
+ }
12
+ const id = pushOverlay(layerRef.current);
13
+ idRef.current = id;
14
+ return () => {
15
+ popOverlay(id);
16
+ idRef.current = "";
17
+ };
18
+ }, [open]);
19
+ React.useEffect(() => {
20
+ if (!open || layerRef.current === null) {
21
+ return;
22
+ }
23
+ const handlePointerDown = (event) => {
24
+ if (disableOutsidePointerDown) {
25
+ return;
26
+ }
27
+ if (!isTopOverlay(idRef.current)) {
28
+ return;
29
+ }
30
+ const target = event.target;
31
+ if (target && layerRef.current?.contains(target)) {
32
+ return;
33
+ }
34
+ const insideEvent = new CustomEvent("pointerdownoutside", {
35
+ bubbles: false,
36
+ cancelable: true,
37
+ detail: event
38
+ });
39
+ onPointerDownOutside?.(insideEvent);
40
+ if (!insideEvent.defaultPrevented) {
41
+ onDismiss?.(insideEvent);
42
+ }
43
+ };
44
+ const handleKeyDown = (event) => {
45
+ if (event.key !== "Escape" || disableEscapeKeyDown) {
46
+ return;
47
+ }
48
+ if (!isTopOverlay(idRef.current)) {
49
+ return;
50
+ }
51
+ const escapeEvent = new CustomEvent("escape", {
52
+ bubbles: false,
53
+ cancelable: true,
54
+ detail: event
55
+ });
56
+ onEscapeKeyDown?.(escapeEvent);
57
+ if (!escapeEvent.defaultPrevented) {
58
+ onDismiss?.(escapeEvent);
59
+ }
60
+ };
61
+ document.addEventListener("pointerdown", handlePointerDown, true);
62
+ document.addEventListener("keydown", handleKeyDown, true);
63
+ return () => {
64
+ document.removeEventListener("pointerdown", handlePointerDown, true);
65
+ document.removeEventListener("keydown", handleKeyDown, true);
66
+ };
67
+ }, [disableEscapeKeyDown, disableOutsidePointerDown, onDismiss, onEscapeKeyDown, onPointerDownOutside, open]);
68
+ if (!open) {
69
+ return null;
70
+ }
71
+ return _jsx("div", { ref: layerRef, children: children });
72
+ }
73
+ export default DismissableLayer;
@@ -0,0 +1,2 @@
1
+ export { DismissableLayer } from "./dismissable-layer.js";
2
+ export type { DismissableLayerProps } from "./dismissable-layer.js";
@@ -0,0 +1 @@
1
+ export { DismissableLayer } from "./dismissable-layer.js";
@@ -0,0 +1,9 @@
1
+ export type AutoUpdateStopListening = () => void;
2
+ interface AutoUpdateParams {
3
+ enabled: boolean;
4
+ reference: HTMLElement | null;
5
+ floating: HTMLElement | null;
6
+ update: () => void;
7
+ }
8
+ export declare function autoUpdateFloating(params: AutoUpdateParams): AutoUpdateStopListening;
9
+ export {};
@@ -0,0 +1,48 @@
1
+ function hasBrowserApis() {
2
+ return typeof window !== "undefined" && typeof document !== "undefined";
3
+ }
4
+ export function autoUpdateFloating(params) {
5
+ const { enabled, reference, floating, update } = params;
6
+ if (!hasBrowserApis() || !enabled || reference === null || floating === null) {
7
+ return () => { };
8
+ }
9
+ let frameRequest = null;
10
+ const scheduleUpdate = () => {
11
+ if (frameRequest !== null) {
12
+ cancelAnimationFrame(frameRequest);
13
+ }
14
+ frameRequest = window.requestAnimationFrame(() => {
15
+ frameRequest = null;
16
+ update();
17
+ });
18
+ };
19
+ const cleanupFns = [];
20
+ const handleScroll = () => {
21
+ scheduleUpdate();
22
+ };
23
+ const handleResize = () => {
24
+ scheduleUpdate();
25
+ };
26
+ const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(scheduleUpdate) : null;
27
+ window.addEventListener("scroll", handleScroll, { passive: true });
28
+ window.addEventListener("resize", handleResize);
29
+ cleanupFns.push(() => {
30
+ window.removeEventListener("scroll", handleScroll);
31
+ window.removeEventListener("resize", handleResize);
32
+ });
33
+ observer?.observe(reference);
34
+ observer?.observe(floating);
35
+ cleanupFns.push(() => {
36
+ observer?.disconnect();
37
+ });
38
+ scheduleUpdate();
39
+ return () => {
40
+ for (const cleanup of cleanupFns) {
41
+ cleanup();
42
+ }
43
+ if (frameRequest !== null) {
44
+ cancelAnimationFrame(frameRequest);
45
+ frameRequest = null;
46
+ }
47
+ };
48
+ }
@@ -0,0 +1,2 @@
1
+ import type { FloatingPositionInput, FloatingPositionResult } from "./floating-types.js";
2
+ export declare function computeFloatingPosition(options: FloatingPositionInput): FloatingPositionResult;
@@ -0,0 +1,96 @@
1
+ import { clamp, getOppositeSide, parsePlacement, buildPlacement } from "./middleware.js";
2
+ import { detectOverflow } from "./detect-overflow.js";
3
+ function getCenteredOffset(referenceSize, floatingSize) {
4
+ return (referenceSize - floatingSize) / 2;
5
+ }
6
+ function getPlacementCoords(placement, reference, floating, offset) {
7
+ const { side, align } = parsePlacement(placement);
8
+ if (side === "top" || side === "bottom") {
9
+ const baseY = side === "top" ? reference.y - floating.height - offset : reference.y + reference.height + offset;
10
+ let x = reference.x;
11
+ if (align === "start") {
12
+ x = reference.x;
13
+ }
14
+ else if (align === "end") {
15
+ x = reference.x + reference.width - floating.width;
16
+ }
17
+ else {
18
+ x = reference.x + getCenteredOffset(reference.width, floating.width);
19
+ }
20
+ return { x, y: baseY };
21
+ }
22
+ const baseX = side === "left" ? reference.x - floating.width - offset : reference.x + reference.width + offset;
23
+ let y = reference.y;
24
+ if (align === "start") {
25
+ y = reference.y;
26
+ }
27
+ else if (align === "end") {
28
+ y = reference.y + reference.height - floating.height;
29
+ }
30
+ else {
31
+ y = reference.y + getCenteredOffset(reference.height, floating.height);
32
+ }
33
+ return { x: baseX, y };
34
+ }
35
+ function getOverflowForPlacement(placement, reference, floating, boundary, offset, collisionPadding) {
36
+ const { x, y } = getPlacementCoords(placement, reference, floating, offset);
37
+ return detectOverflow({
38
+ boundary,
39
+ collisionPadding,
40
+ floatingRect: {
41
+ x,
42
+ y,
43
+ width: floating.width,
44
+ height: floating.height
45
+ }
46
+ });
47
+ }
48
+ export function computeFloatingPosition(options) {
49
+ const { reference, floating, boundary, placement: rawPlacement = "bottom", strategy = "absolute", offset = 0, collisionPadding = 0, matchReferenceWidth = false, maxHeight, flip = true, shift = true } = options;
50
+ const parsed = parsePlacement(rawPlacement);
51
+ const defaultPlacement = buildPlacement(parsed.side, parsed.align);
52
+ let currentPlacement = defaultPlacement;
53
+ let basePlacement = getPlacementCoords(currentPlacement, reference, floating, offset);
54
+ if (flip) {
55
+ const overflow = getOverflowForPlacement(currentPlacement, reference, floating, boundary, offset, collisionPadding);
56
+ const { side: currentSide } = parsePlacement(currentPlacement);
57
+ const overflowSide = overflow[currentSide];
58
+ if (overflowSide > 0) {
59
+ const oppositeSide = getOppositeSide(currentSide);
60
+ const oppositePlacement = buildPlacement(oppositeSide, parsed.align);
61
+ const oppositeOverflow = getOverflowForPlacement(oppositePlacement, reference, floating, boundary, offset, collisionPadding);
62
+ if (oppositeOverflow[oppositeSide] < overflowSide) {
63
+ currentPlacement = oppositePlacement;
64
+ basePlacement = getPlacementCoords(currentPlacement, reference, floating, offset);
65
+ }
66
+ }
67
+ }
68
+ let x = basePlacement.x;
69
+ let y = basePlacement.y;
70
+ if (shift) {
71
+ const { side } = parsePlacement(currentPlacement);
72
+ if (side === "top" || side === "bottom") {
73
+ x = clamp(x, boundary.x + collisionPadding, boundary.x + boundary.width - collisionPadding - floating.width);
74
+ }
75
+ else {
76
+ y = clamp(y, boundary.y + collisionPadding, boundary.y + boundary.height - collisionPadding - floating.height);
77
+ }
78
+ }
79
+ const rawAvailableWidth = Math.max(0, boundary.width - collisionPadding * 2);
80
+ const rawAvailableHeight = Math.max(0, boundary.height - collisionPadding * 2);
81
+ const availableWidth = matchReferenceWidth
82
+ ? Math.min(rawAvailableWidth, reference.width)
83
+ : rawAvailableWidth;
84
+ const constrainedHeight = Math.max(0, rawAvailableHeight);
85
+ const availableHeight = Math.min(constrainedHeight, maxHeight === undefined ? constrainedHeight : maxHeight);
86
+ return {
87
+ x,
88
+ y,
89
+ placement: currentPlacement,
90
+ strategy,
91
+ availableWidth,
92
+ availableHeight,
93
+ referenceWidth: reference.width,
94
+ referenceHeight: reference.height
95
+ };
96
+ }
@@ -0,0 +1,13 @@
1
+ import type { FloatingBoundary, FloatingRect } from "./floating-types.js";
2
+ export interface FloatingOverflow {
3
+ top: number;
4
+ right: number;
5
+ bottom: number;
6
+ left: number;
7
+ }
8
+ export interface OverflowInput {
9
+ boundary: FloatingBoundary;
10
+ floatingRect: FloatingRect;
11
+ collisionPadding: number;
12
+ }
13
+ export declare function detectOverflow(input: OverflowInput): FloatingOverflow;
@@ -0,0 +1,13 @@
1
+ export function detectOverflow(input) {
2
+ const { boundary, floatingRect, collisionPadding } = input;
3
+ const minX = boundary.x + collisionPadding;
4
+ const maxX = boundary.x + boundary.width - collisionPadding;
5
+ const minY = boundary.y + collisionPadding;
6
+ const maxY = boundary.y + boundary.height - collisionPadding;
7
+ return {
8
+ top: Math.max(0, minY - floatingRect.y),
9
+ left: Math.max(0, minX - floatingRect.x),
10
+ right: Math.max(0, floatingRect.x + floatingRect.width - maxX),
11
+ bottom: Math.max(0, floatingRect.y + floatingRect.height - maxY)
12
+ };
13
+ }
@@ -0,0 +1,42 @@
1
+ export type FloatingSide = "top" | "right" | "bottom" | "left";
2
+ export type FloatingAlign = "start" | "center" | "end";
3
+ export type FloatingPlacement = FloatingSide | `${FloatingSide}-${Exclude<FloatingAlign, "center">}`;
4
+ export type FloatingStrategy = "absolute" | "fixed";
5
+ export interface FloatingRect {
6
+ x: number;
7
+ y: number;
8
+ width: number;
9
+ height: number;
10
+ }
11
+ export interface FloatingBoundary {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ }
17
+ export interface ComputeFloatingPositionOptions {
18
+ placement?: FloatingPlacement;
19
+ strategy?: FloatingStrategy;
20
+ offset?: number;
21
+ collisionPadding?: number;
22
+ matchReferenceWidth?: boolean;
23
+ maxHeight?: number;
24
+ flip?: boolean;
25
+ shift?: boolean;
26
+ boundary?: FloatingBoundary;
27
+ }
28
+ export interface FloatingPositionInput extends ComputeFloatingPositionOptions {
29
+ reference: FloatingRect;
30
+ floating: FloatingRect;
31
+ boundary: FloatingBoundary;
32
+ }
33
+ export interface FloatingPositionResult {
34
+ x: number;
35
+ y: number;
36
+ placement: FloatingPlacement;
37
+ strategy: FloatingStrategy;
38
+ availableWidth: number;
39
+ availableHeight: number;
40
+ referenceWidth: number;
41
+ referenceHeight: number;
42
+ }
@@ -0,0 +1 @@
1
+ export {};