@zentauri-ui/zentauri-components 1.1.1 → 1.2.1

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 (290) hide show
  1. package/README.md +62 -21
  2. package/dist/chunk-2VQJ6OIL.js +31 -0
  3. package/dist/chunk-2VQJ6OIL.js.map +1 -0
  4. package/dist/chunk-73VCO5TE.mjs +29 -0
  5. package/dist/chunk-73VCO5TE.mjs.map +1 -0
  6. package/dist/chunk-BSWYZTYK.js +31 -0
  7. package/dist/chunk-BSWYZTYK.js.map +1 -0
  8. package/dist/chunk-CY5BQKRZ.mjs +29 -0
  9. package/dist/chunk-CY5BQKRZ.mjs.map +1 -0
  10. package/dist/chunk-DFEZH7TC.mjs +27 -0
  11. package/dist/chunk-DFEZH7TC.mjs.map +1 -0
  12. package/dist/chunk-FT2LMA66.mjs +25 -0
  13. package/dist/chunk-FT2LMA66.mjs.map +1 -0
  14. package/dist/chunk-JE3PD5ZA.js +107 -0
  15. package/dist/chunk-JE3PD5ZA.js.map +1 -0
  16. package/dist/chunk-JXCTEAXD.js +38 -0
  17. package/dist/chunk-JXCTEAXD.js.map +1 -0
  18. package/dist/chunk-LIJ6BDGP.mjs +36 -0
  19. package/dist/chunk-LIJ6BDGP.mjs.map +1 -0
  20. package/dist/chunk-P6YRSEOY.js +225 -0
  21. package/dist/chunk-P6YRSEOY.js.map +1 -0
  22. package/dist/chunk-PMAF6FBF.mjs +37 -0
  23. package/dist/chunk-PMAF6FBF.mjs.map +1 -0
  24. package/dist/chunk-TZ2JVWTZ.mjs +104 -0
  25. package/dist/chunk-TZ2JVWTZ.mjs.map +1 -0
  26. package/dist/chunk-UIYFEP3I.js +39 -0
  27. package/dist/chunk-UIYFEP3I.js.map +1 -0
  28. package/dist/chunk-UJ3AER3U.mjs +214 -0
  29. package/dist/chunk-UJ3AER3U.mjs.map +1 -0
  30. package/dist/chunk-UOZYPWDZ.js +32 -0
  31. package/dist/chunk-UOZYPWDZ.js.map +1 -0
  32. package/dist/chunk-WL5I7RVS.mjs +54 -0
  33. package/dist/chunk-WL5I7RVS.mjs.map +1 -0
  34. package/dist/chunk-WP7GYBRI.js +27 -0
  35. package/dist/chunk-WP7GYBRI.js.map +1 -0
  36. package/dist/chunk-YPLVTUYL.js +56 -0
  37. package/dist/chunk-YPLVTUYL.js.map +1 -0
  38. package/dist/hooks/useBodyScrollLock.d.mts +14 -0
  39. package/dist/hooks/useBodyScrollLock.d.ts +14 -0
  40. package/dist/hooks/useBodyScrollLock.js +13 -0
  41. package/dist/hooks/useBodyScrollLock.js.map +1 -0
  42. package/dist/hooks/useBodyScrollLock.mjs +4 -0
  43. package/dist/hooks/useBodyScrollLock.mjs.map +1 -0
  44. package/dist/hooks/useClickOutside.d.mts +23 -0
  45. package/dist/hooks/useClickOutside.d.ts +23 -0
  46. package/dist/hooks/useClickOutside.js +13 -0
  47. package/dist/hooks/useClickOutside.js.map +1 -0
  48. package/dist/hooks/useClickOutside.mjs +4 -0
  49. package/dist/hooks/useClickOutside.mjs.map +1 -0
  50. package/dist/hooks/useClipboard.d.mts +22 -0
  51. package/dist/hooks/useClipboard.d.ts +22 -0
  52. package/dist/hooks/useClipboard.js +51 -0
  53. package/dist/hooks/useClipboard.js.map +1 -0
  54. package/dist/hooks/useClipboard.mjs +49 -0
  55. package/dist/hooks/useClipboard.mjs.map +1 -0
  56. package/dist/hooks/useControllableState.d.mts +22 -0
  57. package/dist/hooks/useControllableState.d.ts +22 -0
  58. package/dist/hooks/useControllableState.js +13 -0
  59. package/dist/hooks/useControllableState.js.map +1 -0
  60. package/dist/hooks/useControllableState.mjs +4 -0
  61. package/dist/hooks/useControllableState.mjs.map +1 -0
  62. package/dist/hooks/useDebouncedValue.d.mts +14 -0
  63. package/dist/hooks/useDebouncedValue.d.ts +14 -0
  64. package/dist/hooks/useDebouncedValue.js +22 -0
  65. package/dist/hooks/useDebouncedValue.js.map +1 -0
  66. package/dist/hooks/useDebouncedValue.mjs +20 -0
  67. package/dist/hooks/useDebouncedValue.mjs.map +1 -0
  68. package/dist/hooks/useDisclosure.d.mts +25 -0
  69. package/dist/hooks/useDisclosure.d.ts +25 -0
  70. package/dist/hooks/useDisclosure.js +37 -0
  71. package/dist/hooks/useDisclosure.js.map +1 -0
  72. package/dist/hooks/useDisclosure.mjs +35 -0
  73. package/dist/hooks/useDisclosure.mjs.map +1 -0
  74. package/dist/hooks/useDocumentTitle.d.mts +19 -0
  75. package/dist/hooks/useDocumentTitle.d.ts +19 -0
  76. package/dist/hooks/useDocumentTitle.js +40 -0
  77. package/dist/hooks/useDocumentTitle.js.map +1 -0
  78. package/dist/hooks/useDocumentTitle.mjs +38 -0
  79. package/dist/hooks/useDocumentTitle.mjs.map +1 -0
  80. package/dist/hooks/useFocusManagement.d.mts +24 -0
  81. package/dist/hooks/useFocusManagement.d.ts +24 -0
  82. package/dist/hooks/useFocusManagement.js +14 -0
  83. package/dist/hooks/useFocusManagement.js.map +1 -0
  84. package/dist/hooks/useFocusManagement.mjs +5 -0
  85. package/dist/hooks/useFocusManagement.mjs.map +1 -0
  86. package/dist/hooks/useHover.d.mts +15 -0
  87. package/dist/hooks/useHover.d.ts +15 -0
  88. package/dist/hooks/useHover.js +37 -0
  89. package/dist/hooks/useHover.js.map +1 -0
  90. package/dist/hooks/useHover.mjs +35 -0
  91. package/dist/hooks/useHover.mjs.map +1 -0
  92. package/dist/hooks/useInView.d.mts +19 -0
  93. package/dist/hooks/useInView.d.ts +19 -0
  94. package/dist/hooks/useInView.js +15 -0
  95. package/dist/hooks/useInView.js.map +1 -0
  96. package/dist/hooks/useInView.mjs +13 -0
  97. package/dist/hooks/useInView.mjs.map +1 -0
  98. package/dist/hooks/useIntersectionObserver.d.mts +19 -0
  99. package/dist/hooks/useIntersectionObserver.d.ts +19 -0
  100. package/dist/hooks/useIntersectionObserver.js +13 -0
  101. package/dist/hooks/useIntersectionObserver.js.map +1 -0
  102. package/dist/hooks/useIntersectionObserver.mjs +4 -0
  103. package/dist/hooks/useIntersectionObserver.mjs.map +1 -0
  104. package/dist/hooks/useIsMounted.d.mts +11 -0
  105. package/dist/hooks/useIsMounted.d.ts +11 -0
  106. package/dist/hooks/useIsMounted.js +20 -0
  107. package/dist/hooks/useIsMounted.js.map +1 -0
  108. package/dist/hooks/useIsMounted.mjs +18 -0
  109. package/dist/hooks/useIsMounted.mjs.map +1 -0
  110. package/dist/hooks/useIsomorphicLayoutEffect.d.mts +11 -0
  111. package/dist/hooks/useIsomorphicLayoutEffect.d.ts +11 -0
  112. package/dist/hooks/useIsomorphicLayoutEffect.js +11 -0
  113. package/dist/hooks/useIsomorphicLayoutEffect.js.map +1 -0
  114. package/dist/hooks/useIsomorphicLayoutEffect.mjs +9 -0
  115. package/dist/hooks/useIsomorphicLayoutEffect.mjs.map +1 -0
  116. package/dist/hooks/useLocalStorage.d.mts +22 -0
  117. package/dist/hooks/useLocalStorage.d.ts +22 -0
  118. package/dist/hooks/useLocalStorage.js +84 -0
  119. package/dist/hooks/useLocalStorage.js.map +1 -0
  120. package/dist/hooks/useLocalStorage.mjs +82 -0
  121. package/dist/hooks/useLocalStorage.mjs.map +1 -0
  122. package/dist/hooks/useMediaQuery.d.mts +13 -0
  123. package/dist/hooks/useMediaQuery.d.ts +13 -0
  124. package/dist/hooks/useMediaQuery.js +13 -0
  125. package/dist/hooks/useMediaQuery.js.map +1 -0
  126. package/dist/hooks/useMediaQuery.mjs +4 -0
  127. package/dist/hooks/useMediaQuery.mjs.map +1 -0
  128. package/dist/hooks/useNetworkStatus.d.mts +10 -0
  129. package/dist/hooks/useNetworkStatus.d.ts +10 -0
  130. package/dist/hooks/useNetworkStatus.js +30 -0
  131. package/dist/hooks/useNetworkStatus.js.map +1 -0
  132. package/dist/hooks/useNetworkStatus.mjs +28 -0
  133. package/dist/hooks/useNetworkStatus.mjs.map +1 -0
  134. package/dist/hooks/usePageVisibility.d.mts +10 -0
  135. package/dist/hooks/usePageVisibility.d.ts +10 -0
  136. package/dist/hooks/usePageVisibility.js +28 -0
  137. package/dist/hooks/usePageVisibility.js.map +1 -0
  138. package/dist/hooks/usePageVisibility.mjs +26 -0
  139. package/dist/hooks/usePageVisibility.mjs.map +1 -0
  140. package/dist/hooks/usePagination.d.mts +5 -0
  141. package/dist/hooks/usePagination.d.ts +5 -0
  142. package/dist/hooks/usePagination.js +18 -0
  143. package/dist/hooks/usePagination.js.map +1 -0
  144. package/dist/hooks/usePagination.mjs +5 -0
  145. package/dist/hooks/usePagination.mjs.map +1 -0
  146. package/dist/hooks/usePrefersColorScheme.d.mts +10 -0
  147. package/dist/hooks/usePrefersColorScheme.d.ts +10 -0
  148. package/dist/hooks/usePrefersColorScheme.js +17 -0
  149. package/dist/hooks/usePrefersColorScheme.js.map +1 -0
  150. package/dist/hooks/usePrefersColorScheme.mjs +15 -0
  151. package/dist/hooks/usePrefersColorScheme.mjs.map +1 -0
  152. package/dist/hooks/usePrefersReducedMotion.d.mts +10 -0
  153. package/dist/hooks/usePrefersReducedMotion.d.ts +10 -0
  154. package/dist/hooks/usePrefersReducedMotion.js +13 -0
  155. package/dist/hooks/usePrefersReducedMotion.js.map +1 -0
  156. package/dist/hooks/usePrefersReducedMotion.mjs +11 -0
  157. package/dist/hooks/usePrefersReducedMotion.mjs.map +1 -0
  158. package/dist/hooks/useResizeObserver.d.mts +23 -0
  159. package/dist/hooks/useResizeObserver.d.ts +23 -0
  160. package/dist/hooks/useResizeObserver.js +38 -0
  161. package/dist/hooks/useResizeObserver.js.map +1 -0
  162. package/dist/hooks/useResizeObserver.mjs +36 -0
  163. package/dist/hooks/useResizeObserver.mjs.map +1 -0
  164. package/dist/hooks/useSessionStorage.d.mts +22 -0
  165. package/dist/hooks/useSessionStorage.d.ts +22 -0
  166. package/dist/hooks/useSessionStorage.js +58 -0
  167. package/dist/hooks/useSessionStorage.js.map +1 -0
  168. package/dist/hooks/useSessionStorage.mjs +56 -0
  169. package/dist/hooks/useSessionStorage.mjs.map +1 -0
  170. package/dist/hooks/useThrottledCallback.d.mts +14 -0
  171. package/dist/hooks/useThrottledCallback.d.ts +14 -0
  172. package/dist/hooks/useThrottledCallback.js +27 -0
  173. package/dist/hooks/useThrottledCallback.js.map +1 -0
  174. package/dist/hooks/useThrottledCallback.mjs +25 -0
  175. package/dist/hooks/useThrottledCallback.mjs.map +1 -0
  176. package/dist/hooks/useToggle.d.mts +9 -0
  177. package/dist/hooks/useToggle.d.ts +9 -0
  178. package/dist/hooks/useToggle.js +20 -0
  179. package/dist/hooks/useToggle.js.map +1 -0
  180. package/dist/hooks/useToggle.mjs +18 -0
  181. package/dist/hooks/useToggle.mjs.map +1 -0
  182. package/dist/hooks/useWindowSize.d.mts +14 -0
  183. package/dist/hooks/useWindowSize.d.ts +14 -0
  184. package/dist/hooks/useWindowSize.js +30 -0
  185. package/dist/hooks/useWindowSize.js.map +1 -0
  186. package/dist/hooks/useWindowSize.mjs +28 -0
  187. package/dist/hooks/useWindowSize.mjs.map +1 -0
  188. package/dist/hooks/utils.d.mts +8 -0
  189. package/dist/hooks/utils.d.ts +8 -0
  190. package/dist/hooks/utils.js +24 -0
  191. package/dist/hooks/utils.js.map +1 -0
  192. package/dist/hooks/utils.mjs +3 -0
  193. package/dist/hooks/utils.mjs.map +1 -0
  194. package/dist/index-ClPu5gDp.d.ts +86 -0
  195. package/dist/index-D4p9fn1o.d.mts +86 -0
  196. package/dist/types-BQ2H3yG7.d.mts +34 -0
  197. package/dist/types-BQ2H3yG7.d.ts +34 -0
  198. package/dist/ui/accordion.js +5 -5
  199. package/dist/ui/accordion.mjs +1 -1
  200. package/dist/ui/alert/animated.d.mts +13 -0
  201. package/dist/ui/alert/animated.d.ts +13 -0
  202. package/dist/ui/alert/animated.js +27 -0
  203. package/dist/ui/alert/animated.js.map +1 -0
  204. package/dist/ui/alert/animated.mjs +25 -0
  205. package/dist/ui/alert/animated.mjs.map +1 -0
  206. package/dist/ui/alert.d.mts +11 -36
  207. package/dist/ui/alert.d.ts +11 -36
  208. package/dist/ui/alert.js +40 -218
  209. package/dist/ui/alert.js.map +1 -1
  210. package/dist/ui/alert.mjs +7 -211
  211. package/dist/ui/alert.mjs.map +1 -1
  212. package/dist/ui/avatar.js +6 -6
  213. package/dist/ui/avatar.js.map +1 -1
  214. package/dist/ui/avatar.mjs +1 -1
  215. package/dist/ui/avatar.mjs.map +1 -1
  216. package/dist/ui/badge.js +2 -2
  217. package/dist/ui/badge.mjs +1 -1
  218. package/dist/ui/breadcrumb.js +7 -7
  219. package/dist/ui/breadcrumb.mjs +1 -1
  220. package/dist/ui/buttons.js +3 -3
  221. package/dist/ui/buttons.mjs +1 -1
  222. package/dist/ui/card.js +7 -7
  223. package/dist/ui/card.js.map +1 -1
  224. package/dist/ui/card.mjs +1 -1
  225. package/dist/ui/card.mjs.map +1 -1
  226. package/dist/ui/divider.js +6 -6
  227. package/dist/ui/divider.mjs +1 -1
  228. package/dist/ui/drawer.js +15 -60
  229. package/dist/ui/drawer.js.map +1 -1
  230. package/dist/ui/drawer.mjs +9 -54
  231. package/dist/ui/drawer.mjs.map +1 -1
  232. package/dist/ui/dropdown.js +6 -13
  233. package/dist/ui/dropdown.js.map +1 -1
  234. package/dist/ui/dropdown.mjs +4 -11
  235. package/dist/ui/dropdown.mjs.map +1 -1
  236. package/dist/ui/empty-state.js +6 -6
  237. package/dist/ui/empty-state.js.map +1 -1
  238. package/dist/ui/empty-state.mjs +1 -1
  239. package/dist/ui/empty-state.mjs.map +1 -1
  240. package/dist/ui/file-upload.js +3 -3
  241. package/dist/ui/file-upload.mjs +1 -1
  242. package/dist/ui/inputs.js +3 -3
  243. package/dist/ui/inputs.mjs +1 -1
  244. package/dist/ui/modal.js +16 -61
  245. package/dist/ui/modal.js.map +1 -1
  246. package/dist/ui/modal.mjs +9 -54
  247. package/dist/ui/modal.mjs.map +1 -1
  248. package/dist/ui/pagination.d.mts +3 -81
  249. package/dist/ui/pagination.d.ts +3 -81
  250. package/dist/ui/pagination.js +13 -122
  251. package/dist/ui/pagination.js.map +1 -1
  252. package/dist/ui/pagination.mjs +5 -114
  253. package/dist/ui/pagination.mjs.map +1 -1
  254. package/dist/ui/progress.js +7 -10
  255. package/dist/ui/progress.js.map +1 -1
  256. package/dist/ui/progress.mjs +1 -4
  257. package/dist/ui/progress.mjs.map +1 -1
  258. package/dist/ui/select.js +6 -6
  259. package/dist/ui/select.mjs +1 -1
  260. package/dist/ui/skeleton.js +7 -7
  261. package/dist/ui/skeleton.mjs +1 -1
  262. package/dist/ui/slider.js +9 -9
  263. package/dist/ui/slider.js.map +1 -1
  264. package/dist/ui/slider.mjs +1 -1
  265. package/dist/ui/slider.mjs.map +1 -1
  266. package/dist/ui/spinner.js +24 -10
  267. package/dist/ui/spinner.js.map +1 -1
  268. package/dist/ui/spinner.mjs +17 -3
  269. package/dist/ui/spinner.mjs.map +1 -1
  270. package/dist/ui/stepper.js +6 -6
  271. package/dist/ui/stepper.mjs +1 -1
  272. package/dist/ui/table.js +9 -9
  273. package/dist/ui/table.js.map +1 -1
  274. package/dist/ui/table.mjs +1 -1
  275. package/dist/ui/table.mjs.map +1 -1
  276. package/dist/ui/tabs.js +5 -5
  277. package/dist/ui/tabs.mjs +1 -1
  278. package/dist/ui/toast.js +7 -7
  279. package/dist/ui/toast.js.map +1 -1
  280. package/dist/ui/toast.mjs +1 -1
  281. package/dist/ui/toast.mjs.map +1 -1
  282. package/dist/ui/toggle.js +3 -3
  283. package/dist/ui/toggle.mjs +1 -1
  284. package/dist/ui/tooltip.js +2 -2
  285. package/dist/ui/tooltip.mjs +1 -1
  286. package/package.json +13 -3
  287. package/dist/chunk-B23TPTVG.mjs +0 -11
  288. package/dist/chunk-B23TPTVG.mjs.map +0 -1
  289. package/dist/chunk-WZ2GOU2J.js +0 -13
  290. package/dist/chunk-WZ2GOU2J.js.map +0 -1
package/README.md CHANGED
@@ -6,16 +6,16 @@ A React UI kit for building product interfaces with Tailwind CSS. Components are
6
6
 
7
7
  The library targets **React 18+** apps that use **Tailwind CSS v4** (or an equivalent setup where Tailwind can scan this package via `@source`). Styling uses utility classes; **class-variance-authority** powers variant APIs (size, appearance, and similar props), with **clsx** and **tailwind-merge** for predictable `className` composition. **Framer Motion** backs motion where components animate, and **react-icons** is used for iconography where applicable.
8
8
 
9
- Published artifacts live under `dist/`. You can import either the **UI barrel** (`@zentauri-ui/zentauri-components/ui`) or a **per-area subpath** (`@zentauri-ui/zentauri-components/ui/<name>`) so bundlers only pull in the entry you use. Most apps rely on Tailwind scanning the package sources (see installation); a separate CSS import is not required for that setup.
9
+ Published artifacts live under `dist/`. Imports use **per-entry subpaths**: `@zentauri-ui/zentauri-components/ui/<area>` for components and `@zentauri-ui/zentauri-components/hooks/<entry>` for React hooks (and shared helpers under `hooks/utils`). Each entry resolves to its own ESM (`.mjs`), CJS (`.js`), and types (`.d.ts`) so bundlers pull only what you import. Most apps rely on Tailwind scanning the package sources (see installation); a separate CSS import is not required for that setup.
10
10
 
11
11
  ## Package exports
12
12
 
13
- | Subpath | Description |
14
- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
15
- | `@zentauri-ui/zentauri-components/ui` | Full UI barrel: all components, hooks, and types (ESM `.js`, CJS `.cjs`, `.d.ts`) |
16
- | `@zentauri-ui/zentauri-components/ui/<name>` | Single area entry (same artifacts per file). Use this when you import from one module only to keep the dependency graph smaller. |
13
+ | Subpath | Description |
14
+ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
15
+ | `@zentauri-ui/zentauri-components/ui/<name>` | Single UI area: components (and any re-exports from that area’s `index`, e.g. `usePagination` from `ui/pagination`). |
16
+ | `@zentauri-ui/zentauri-components/hooks/<entry>` | One hook module or `utils` (`cn`, `clampPage`, `range` from `src/lib/utils.ts`). Entries match files under `src/hooks/` (see **React hooks**). |
17
17
 
18
- The `<name>` segment matches the folder under `src/ui/` (for example `accordion`, `select`, `empty-state`, `buttons` for `Button`, `inputs` for `Input`).
18
+ The UI `<name>` segment matches the folder under `src/ui/` (for example `accordion`, `select`, `empty-state`, `buttons` for `Button`, `inputs` for `Input`). The hooks `<entry>` is the file stem (for example `useMediaQuery`, `usePagination`) or `utils`.
19
19
 
20
20
  ## Requirements
21
21
 
@@ -24,7 +24,7 @@ The `<name>` segment matches the folder under `src/ui/` (for example `accordion`
24
24
 
25
25
  ## Components
26
26
 
27
- Each area is available from the barrel and from its own subpath (`…/ui/<subpath>`):
27
+ Each area is available from its own subpath (`…/ui/<subpath>`):
28
28
 
29
29
  | Area | Subpath `…/ui/…` |
30
30
  | -------------- | ---------------- |
@@ -55,9 +55,56 @@ Each area is available from the barrel and from its own subpath (`…/ui/<subpat
55
55
  | Toggle | `toggle` |
56
56
  | Tooltip | `tooltip` |
57
57
 
58
+ ## React hooks
59
+
60
+ Hooks live in `src/hooks/`. Each hook is a separate published entry under `@zentauri-ui/zentauri-components/hooks/<name>` (same pattern as UI areas). Types are exported where the implementation defines them (for example `UseDisclosureResult`, `PaginationPageItem`). For class-name merging and pagination helpers used alongside hooks, import from `@zentauri-ui/zentauri-components/hooks/utils`.
61
+
62
+ | Hook / module | Subpath `…/hooks/…` | Notes (selected exports) |
63
+ | -------------------------- | ----------------------------- | -------------------------- |
64
+ | `useBodyScrollLock` | `useBodyScrollLock` | Locks document scroll while open |
65
+ | `useClickOutside` | `useClickOutside` | `ClickOutsideEventType`, `UseClickOutsideParams` |
66
+ | `useClipboard` | `useClipboard` | `UseClipboardResult` |
67
+ | `useControllableState` | `useControllableState` | `UseControllableStateParams` |
68
+ | `useDebouncedValue` | `useDebouncedValue` | Debounced state from a value |
69
+ | `useDisclosure` | `useDisclosure` | `UseDisclosureParams`, `UseDisclosureResult` |
70
+ | `useDocumentTitle` | `useDocumentTitle` | `UseDocumentTitleParams` |
71
+ | `useFocusManagement` | `useFocusManagement` | Focus trap / focus moves for overlays |
72
+ | `useHover` | `useHover` | Pointer hover state |
73
+ | `useInView` | `useInView` | `UseInViewParams` |
74
+ | `useIntersectionObserver` | `useIntersectionObserver` | `UseIntersectionObserverParams` |
75
+ | `useIsomorphicLayoutEffect`| `useIsomorphicLayoutEffect` | `useLayoutEffect` safe for SSR |
76
+ | `useIsMounted` | `useIsMounted` | Ref / flag after mount |
77
+ | `useLocalStorage` | `useLocalStorage` | `UseLocalStorageResult` |
78
+ | `useMediaQuery` | `useMediaQuery` | Match CSS media queries |
79
+ | `useNetworkStatus` | `useNetworkStatus` | Online / offline |
80
+ | `usePageVisibility` | `usePageVisibility` | Document visibility API |
81
+ | `usePagination` | `usePagination` | `buildPaginationItems`, `BuildPaginationItemsParams`, `PaginationPageItem` |
82
+ | `usePrefersColorScheme` | `usePrefersColorScheme` | `ColorSchemePreference` |
83
+ | `usePrefersReducedMotion` | `usePrefersReducedMotion` | `prefers-reduced-motion` |
84
+ | `useResizeObserver` | `useResizeObserver` | `ElementSize` |
85
+ | `useSessionStorage` | `useSessionStorage` | `UseSessionStorageResult` |
86
+ | `useThrottledCallback` | `useThrottledCallback` | Throttled callback ref |
87
+ | `useToggle` | `useToggle` | Boolean toggle state |
88
+ | `useWindowSize` | `useWindowSize` | `WindowSize` |
89
+ | `cn`, `clampPage`, `range` | `utils` | Shared helpers from `src/lib/utils.ts` |
90
+
91
+ #### Hook import example
92
+
93
+ ```tsx
94
+ import { useDisclosure } from "@zentauri-ui/zentauri-components/hooks/useDisclosure";
95
+ import { useMediaQuery } from "@zentauri-ui/zentauri-components/hooks/useMediaQuery";
96
+ import {
97
+ buildPaginationItems,
98
+ usePagination,
99
+ } from "@zentauri-ui/zentauri-components/hooks/usePagination";
100
+ import { cn } from "@zentauri-ui/zentauri-components/hooks/utils";
101
+ ```
102
+
103
+ Some UI packages re-export the hook that belongs to that component (for example `usePagination` from `@zentauri-ui/zentauri-components/ui/pagination`). Prefer `hooks/<name>` when you only need the hook without the UI primitives.
104
+
58
105
  ## Installation
59
106
 
60
- **Getting started** — Add the package, install peer dependencies so primitives resolve correctly, point Tailwind at the library sources, then import from the UI barrel or from a specific `ui/<name>` subpath.
107
+ **Getting started** — Add the package, install peer dependencies so primitives resolve correctly, point Tailwind at the library sources, then import from `ui/<name>` and/or `hooks/<entry>` subpaths.
61
108
 
62
109
  ### Step 1 — Install the package
63
110
 
@@ -135,11 +182,11 @@ Add an `@source` entry so Tailwind scans class names inside `@zentauri-ui/zentau
135
182
  @source "../node_modules/@zentauri-ui/zentauri-components";
136
183
  ```
137
184
 
138
- ### Step 4 — Import and use components
185
+ ### Step 4 — Import and use components and hooks
139
186
 
140
- Prefer a **subpath** when you only need one area (smaller resolved graph than the full barrel). The barrel remains valid when you use many primitives from different areas.
187
+ Use **one subpath per UI area** and **one subpath per hook module** so the bundler resolves only the entries you use.
141
188
 
142
- #### Imports (subpath recommended for a single area)
189
+ #### Imports (single UI area)
143
190
 
144
191
  ```tsx
145
192
  import {
@@ -150,7 +197,7 @@ import {
150
197
  } from "@zentauri-ui/zentauri-components/ui/accordion";
151
198
  ```
152
199
 
153
- #### Imports (multiple areas — one subpath import per area)
200
+ #### Imports (multiple UI areas)
154
201
 
155
202
  ```tsx
156
203
  import { Button } from "@zentauri-ui/zentauri-components/ui/buttons";
@@ -163,17 +210,11 @@ import {
163
210
  } from "@zentauri-ui/zentauri-components/ui/select";
164
211
  ```
165
212
 
166
- #### Imports (barrel one entry for symbols from several areas)
213
+ #### Imports (hooks alongside UI)
167
214
 
168
215
  ```tsx
169
- import {
170
- Button,
171
- Select,
172
- SelectTrigger,
173
- SelectValue,
174
- SelectContent,
175
- SelectItem,
176
- } from "@zentauri-ui/zentauri-components/ui";
216
+ import { useDisclosure } from "@zentauri-ui/zentauri-components/hooks/useDisclosure";
217
+ import { Button } from "@zentauri-ui/zentauri-components/ui/buttons";
177
218
  ```
178
219
 
179
220
  #### Usage
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useControllableState/useControllableState.ts
6
+ function useControllableState({
7
+ value: valueProp,
8
+ defaultValue,
9
+ onChange
10
+ }) {
11
+ const [uncontrolled, setUncontrolled] = react.useState(defaultValue);
12
+ const isControlled = valueProp !== void 0;
13
+ const value = isControlled ? valueProp : uncontrolled;
14
+ const onChangeRef = react.useRef(onChange);
15
+ onChangeRef.current = onChange;
16
+ const setValue = react.useCallback(
17
+ (next) => {
18
+ const resolved = typeof next === "function" ? next(value) : next;
19
+ if (!isControlled) {
20
+ setUncontrolled(resolved);
21
+ }
22
+ onChangeRef.current?.(resolved);
23
+ },
24
+ [isControlled, value]
25
+ );
26
+ return [value, setValue];
27
+ }
28
+
29
+ exports.useControllableState = useControllableState;
30
+ //# sourceMappingURL=chunk-2VQJ6OIL.js.map
31
+ //# sourceMappingURL=chunk-2VQJ6OIL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useControllableState/useControllableState.ts"],"names":["useState","useRef","useCallback"],"mappings":";;;;;AAwBO,SAAS,oBAAA,CAAwB;AAAA,EACtC,KAAA,EAAO,SAAA;AAAA,EACP,YAAA;AAAA,EACA;AACF,CAAA,EAA6E;AAC3E,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,eAAS,YAAY,CAAA;AAC7D,EAAA,MAAM,eAAe,SAAA,KAAc,MAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,eAAe,SAAA,GAAY,YAAA;AACzC,EAAA,MAAM,WAAA,GAAcC,aAAO,QAAQ,CAAA;AACnC,EAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AAEtB,EAAA,MAAM,QAAA,GAAWC,iBAAA;AAAA,IACf,CAAC,IAAA,KAA+B;AAC9B,MAAA,MAAM,WACJ,OAAO,IAAA,KAAS,UAAA,GAAc,IAAA,CAAwB,KAAK,CAAA,GAAI,IAAA;AACjE,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,eAAA,CAAgB,QAAQ,CAAA;AAAA,MAC1B;AACA,MAAA,WAAA,CAAY,UAAU,QAAQ,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,cAAc,KAAK;AAAA,GACtB;AAEA,EAAA,OAAO,CAAC,OAAO,QAAQ,CAAA;AACzB","file":"chunk-2VQJ6OIL.js","sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nexport type UseControllableStateParams<T> = {\n /** When defined, the hook is controlled and this value is returned as state. */\n value?: T;\n /** Initial / fallback value when uncontrolled (`value` is `undefined`). */\n defaultValue: T;\n /** Notified on every `setValue` with the resolved next value (controlled and uncontrolled). */\n onChange?: (next: T) => void;\n};\n\n/**\n * Implements the React “controlled vs uncontrolled” pattern as a single state tuple.\n *\n * - If `value` is `undefined`, internal state mirrors `defaultValue` and updates on `setValue`.\n * - If `value` is defined, returned state follows `value`; `setValue` still calls `onChange` so the parent can update.\n * - `setValue` accepts either the next value or an updater `(prev) => next` (updater uses the current `value` in controlled mode).\n *\n * @typeParam T - State value type.\n * @param params - `value`, `defaultValue`, and optional `onChange`.\n * @returns `[value, setValue]` compatible with `useState`-style usage.\n */\nexport function useControllableState<T>({\n value: valueProp,\n defaultValue,\n onChange,\n}: UseControllableStateParams<T>): [T, (next: T | ((prev: T) => T)) => void] {\n const [uncontrolled, setUncontrolled] = useState(defaultValue);\n const isControlled = valueProp !== undefined;\n const value = isControlled ? valueProp : uncontrolled;\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const setValue = useCallback(\n (next: T | ((prev: T) => T)) => {\n const resolved =\n typeof next === \"function\" ? (next as (prev: T) => T)(value) : next;\n if (!isControlled) {\n setUncontrolled(resolved);\n }\n onChangeRef.current?.(resolved);\n },\n [isControlled, value],\n );\n\n return [value, setValue];\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import { useState, useRef, useCallback } from 'react';
2
+
3
+ // src/hooks/useControllableState/useControllableState.ts
4
+ function useControllableState({
5
+ value: valueProp,
6
+ defaultValue,
7
+ onChange
8
+ }) {
9
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
10
+ const isControlled = valueProp !== void 0;
11
+ const value = isControlled ? valueProp : uncontrolled;
12
+ const onChangeRef = useRef(onChange);
13
+ onChangeRef.current = onChange;
14
+ const setValue = useCallback(
15
+ (next) => {
16
+ const resolved = typeof next === "function" ? next(value) : next;
17
+ if (!isControlled) {
18
+ setUncontrolled(resolved);
19
+ }
20
+ onChangeRef.current?.(resolved);
21
+ },
22
+ [isControlled, value]
23
+ );
24
+ return [value, setValue];
25
+ }
26
+
27
+ export { useControllableState };
28
+ //# sourceMappingURL=chunk-73VCO5TE.mjs.map
29
+ //# sourceMappingURL=chunk-73VCO5TE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useControllableState/useControllableState.ts"],"names":[],"mappings":";;;AAwBO,SAAS,oBAAA,CAAwB;AAAA,EACtC,KAAA,EAAO,SAAA;AAAA,EACP,YAAA;AAAA,EACA;AACF,CAAA,EAA6E;AAC3E,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,YAAY,CAAA;AAC7D,EAAA,MAAM,eAAe,SAAA,KAAc,MAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,eAAe,SAAA,GAAY,YAAA;AACzC,EAAA,MAAM,WAAA,GAAc,OAAO,QAAQ,CAAA;AACnC,EAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AAEtB,EAAA,MAAM,QAAA,GAAW,WAAA;AAAA,IACf,CAAC,IAAA,KAA+B;AAC9B,MAAA,MAAM,WACJ,OAAO,IAAA,KAAS,UAAA,GAAc,IAAA,CAAwB,KAAK,CAAA,GAAI,IAAA;AACjE,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,eAAA,CAAgB,QAAQ,CAAA;AAAA,MAC1B;AACA,MAAA,WAAA,CAAY,UAAU,QAAQ,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,cAAc,KAAK;AAAA,GACtB;AAEA,EAAA,OAAO,CAAC,OAAO,QAAQ,CAAA;AACzB","file":"chunk-73VCO5TE.mjs","sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nexport type UseControllableStateParams<T> = {\n /** When defined, the hook is controlled and this value is returned as state. */\n value?: T;\n /** Initial / fallback value when uncontrolled (`value` is `undefined`). */\n defaultValue: T;\n /** Notified on every `setValue` with the resolved next value (controlled and uncontrolled). */\n onChange?: (next: T) => void;\n};\n\n/**\n * Implements the React “controlled vs uncontrolled” pattern as a single state tuple.\n *\n * - If `value` is `undefined`, internal state mirrors `defaultValue` and updates on `setValue`.\n * - If `value` is defined, returned state follows `value`; `setValue` still calls `onChange` so the parent can update.\n * - `setValue` accepts either the next value or an updater `(prev) => next` (updater uses the current `value` in controlled mode).\n *\n * @typeParam T - State value type.\n * @param params - `value`, `defaultValue`, and optional `onChange`.\n * @returns `[value, setValue]` compatible with `useState`-style usage.\n */\nexport function useControllableState<T>({\n value: valueProp,\n defaultValue,\n onChange,\n}: UseControllableStateParams<T>): [T, (next: T | ((prev: T) => T)) => void] {\n const [uncontrolled, setUncontrolled] = useState(defaultValue);\n const isControlled = valueProp !== undefined;\n const value = isControlled ? valueProp : uncontrolled;\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const setValue = useCallback(\n (next: T | ((prev: T) => T)) => {\n const resolved =\n typeof next === \"function\" ? (next as (prev: T) => T)(value) : next;\n if (!isControlled) {\n setUncontrolled(resolved);\n }\n onChangeRef.current?.(resolved);\n },\n [isControlled, value],\n );\n\n return [value, setValue];\n}\n"]}
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useClickOutside/useClickOutside.ts
6
+ var useClickOutside = ({
7
+ setOpen,
8
+ ref,
9
+ listenEvents
10
+ }) => {
11
+ react.useEffect(() => {
12
+ const events = listenEvents && listenEvents.length > 0 ? listenEvents : ["mousedown"];
13
+ const handleClickOutside = (event) => {
14
+ if (ref.current && !ref.current.contains(event.target)) {
15
+ setOpen(false);
16
+ }
17
+ };
18
+ for (const eventName of events) {
19
+ document.addEventListener(eventName, handleClickOutside);
20
+ }
21
+ return () => {
22
+ for (const eventName of events) {
23
+ document.removeEventListener(eventName, handleClickOutside);
24
+ }
25
+ };
26
+ }, [listenEvents, ref, setOpen]);
27
+ };
28
+
29
+ exports.useClickOutside = useClickOutside;
30
+ //# sourceMappingURL=chunk-BSWYZTYK.js.map
31
+ //# sourceMappingURL=chunk-BSWYZTYK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useClickOutside/useClickOutside.ts"],"names":["useEffect"],"mappings":";;;;;AA4BO,IAAM,kBAAkB,CAAC;AAAA,EAC9B,OAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA,KAA6B;AAC3B,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,SACJ,YAAA,IAAgB,YAAA,CAAa,SAAS,CAAA,GAAI,YAAA,GAAe,CAAC,WAAW,CAAA;AACvE,IAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAiB;AAC3C,MAAA,IAAI,GAAA,CAAI,WAAW,CAAC,GAAA,CAAI,QAAQ,QAAA,CAAS,KAAA,CAAM,MAAc,CAAA,EAAG;AAC9D,QAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,MACf;AAAA,IACF,CAAA;AAEA,IAAA,KAAA,MAAW,aAAa,MAAA,EAAQ;AAC9B,MAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,kBAAkB,CAAA;AAAA,IACzD;AACA,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,MAAW,aAAa,MAAA,EAAQ;AAC9B,QAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,kBAAkB,CAAA;AAAA,MAC5D;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,EAAc,GAAA,EAAK,OAAO,CAAC,CAAA;AACjC","file":"chunk-BSWYZTYK.js","sourcesContent":["\"use client\";\n\nimport type { RefObject } from \"react\";\nimport { Dispatch, SetStateAction, useEffect } from \"react\";\n\n/** DOM events that can represent an “outside” press for closing overlays. */\nexport type ClickOutsideEventType =\n | \"mousedown\"\n | \"pointerdown\"\n | \"touchstart\";\n\nexport type UseClickOutsideParams = {\n /** Called with `false` when a qualifying event target is outside `ref.current`. */\n setOpen: (open: boolean) => void | Dispatch<SetStateAction<boolean>>;\n /** Root element of the floating UI; clicks inside this node do not close. */\n ref: RefObject<HTMLElement | null>;\n /** Defaults to `[\"mousedown\"]` for backward compatibility */\n listenEvents?: ClickOutsideEventType[];\n};\n\n/**\n * Registers document-level listeners so that when the user activates outside of `ref`, `setOpen(false)`\n * runs. Useful for dropdowns, popovers, and menus paired with `open` state.\n *\n * @param params.setOpen - State setter or callback that closes the surface.\n * @param params.ref - Container ref; outside is determined with `contains()` on the event target.\n * @param params.listenEvents - Which events to listen for; default is `mousedown` only.\n */\nexport const useClickOutside = ({\n setOpen,\n ref,\n listenEvents,\n}: UseClickOutsideParams) => {\n useEffect(() => {\n const events =\n listenEvents && listenEvents.length > 0 ? listenEvents : [\"mousedown\"];\n const handleClickOutside = (event: Event) => {\n if (ref.current && !ref.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n\n for (const eventName of events) {\n document.addEventListener(eventName, handleClickOutside);\n }\n return () => {\n for (const eventName of events) {\n document.removeEventListener(eventName, handleClickOutside);\n }\n };\n }, [listenEvents, ref, setOpen]);\n};\n"]}
@@ -0,0 +1,29 @@
1
+ import { useEffect } from 'react';
2
+
3
+ // src/hooks/useClickOutside/useClickOutside.ts
4
+ var useClickOutside = ({
5
+ setOpen,
6
+ ref,
7
+ listenEvents
8
+ }) => {
9
+ useEffect(() => {
10
+ const events = listenEvents && listenEvents.length > 0 ? listenEvents : ["mousedown"];
11
+ const handleClickOutside = (event) => {
12
+ if (ref.current && !ref.current.contains(event.target)) {
13
+ setOpen(false);
14
+ }
15
+ };
16
+ for (const eventName of events) {
17
+ document.addEventListener(eventName, handleClickOutside);
18
+ }
19
+ return () => {
20
+ for (const eventName of events) {
21
+ document.removeEventListener(eventName, handleClickOutside);
22
+ }
23
+ };
24
+ }, [listenEvents, ref, setOpen]);
25
+ };
26
+
27
+ export { useClickOutside };
28
+ //# sourceMappingURL=chunk-CY5BQKRZ.mjs.map
29
+ //# sourceMappingURL=chunk-CY5BQKRZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useClickOutside/useClickOutside.ts"],"names":[],"mappings":";;;AA4BO,IAAM,kBAAkB,CAAC;AAAA,EAC9B,OAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA,KAA6B;AAC3B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SACJ,YAAA,IAAgB,YAAA,CAAa,SAAS,CAAA,GAAI,YAAA,GAAe,CAAC,WAAW,CAAA;AACvE,IAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAiB;AAC3C,MAAA,IAAI,GAAA,CAAI,WAAW,CAAC,GAAA,CAAI,QAAQ,QAAA,CAAS,KAAA,CAAM,MAAc,CAAA,EAAG;AAC9D,QAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,MACf;AAAA,IACF,CAAA;AAEA,IAAA,KAAA,MAAW,aAAa,MAAA,EAAQ;AAC9B,MAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,kBAAkB,CAAA;AAAA,IACzD;AACA,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,MAAW,aAAa,MAAA,EAAQ;AAC9B,QAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,kBAAkB,CAAA;AAAA,MAC5D;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,EAAc,GAAA,EAAK,OAAO,CAAC,CAAA;AACjC","file":"chunk-CY5BQKRZ.mjs","sourcesContent":["\"use client\";\n\nimport type { RefObject } from \"react\";\nimport { Dispatch, SetStateAction, useEffect } from \"react\";\n\n/** DOM events that can represent an “outside” press for closing overlays. */\nexport type ClickOutsideEventType =\n | \"mousedown\"\n | \"pointerdown\"\n | \"touchstart\";\n\nexport type UseClickOutsideParams = {\n /** Called with `false` when a qualifying event target is outside `ref.current`. */\n setOpen: (open: boolean) => void | Dispatch<SetStateAction<boolean>>;\n /** Root element of the floating UI; clicks inside this node do not close. */\n ref: RefObject<HTMLElement | null>;\n /** Defaults to `[\"mousedown\"]` for backward compatibility */\n listenEvents?: ClickOutsideEventType[];\n};\n\n/**\n * Registers document-level listeners so that when the user activates outside of `ref`, `setOpen(false)`\n * runs. Useful for dropdowns, popovers, and menus paired with `open` state.\n *\n * @param params.setOpen - State setter or callback that closes the surface.\n * @param params.ref - Container ref; outside is determined with `contains()` on the event target.\n * @param params.listenEvents - Which events to listen for; default is `mousedown` only.\n */\nexport const useClickOutside = ({\n setOpen,\n ref,\n listenEvents,\n}: UseClickOutsideParams) => {\n useEffect(() => {\n const events =\n listenEvents && listenEvents.length > 0 ? listenEvents : [\"mousedown\"];\n const handleClickOutside = (event: Event) => {\n if (ref.current && !ref.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n\n for (const eventName of events) {\n document.addEventListener(eventName, handleClickOutside);\n }\n return () => {\n for (const eventName of events) {\n document.removeEventListener(eventName, handleClickOutside);\n }\n };\n }, [listenEvents, ref, setOpen]);\n};\n"]}
@@ -0,0 +1,27 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ // src/lib/utils.ts
5
+ function cn(...inputs) {
6
+ return twMerge(clsx(inputs));
7
+ }
8
+ var clampPage = (page, pageCount) => {
9
+ if (pageCount <= 0) {
10
+ return 1;
11
+ }
12
+ return Math.min(pageCount, Math.max(1, Math.floor(page)));
13
+ };
14
+ var range = (from, to) => {
15
+ const out = [];
16
+ for (let i = from; i <= to; i += 1) {
17
+ out.push(i);
18
+ }
19
+ return out;
20
+ };
21
+ var clamp = (value, min, max) => {
22
+ return Math.min(max, Math.max(min, value));
23
+ };
24
+
25
+ export { clamp, clampPage, cn, range };
26
+ //# sourceMappingURL=chunk-DFEZH7TC.mjs.map
27
+ //# sourceMappingURL=chunk-DFEZH7TC.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/utils.ts"],"names":[],"mappings":";;;;AAGO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;AAEO,IAAM,SAAA,GAAY,CAAC,IAAA,EAAc,SAAA,KAA8B;AACpE,EAAA,IAAI,aAAa,CAAA,EAAG;AAClB,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAC,CAAA;AAC1D;AAEO,IAAM,KAAA,GAAQ,CAAC,IAAA,EAAc,EAAA,KAAyB;AAC3D,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,IAAA,EAAM,CAAA,IAAK,EAAA,EAAI,KAAK,CAAA,EAAG;AAClC,IAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACZ;AACA,EAAA,OAAO,GAAA;AACT;AAEO,IAAM,KAAA,GAAQ,CAAC,KAAA,EAAe,GAAA,EAAa,GAAA,KAAgB;AAChE,EAAA,OAAO,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAA;AAC3C","file":"chunk-DFEZH7TC.mjs","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport const clampPage = (page: number, pageCount: number): number => {\n if (pageCount <= 0) {\n return 1;\n }\n return Math.min(pageCount, Math.max(1, Math.floor(page)));\n}\n\nexport const range = (from: number, to: number): number[] => {\n const out: number[] = [];\n for (let i = from; i <= to; i += 1) {\n out.push(i);\n }\n return out;\n}\n\nexport const clamp = (value: number, min: number, max: number) => {\n return Math.min(max, Math.max(min, value));\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ // src/hooks/useMediaQuery/useMediaQuery.ts
4
+ function useMediaQuery(query, defaultValue = false) {
5
+ const [matches, setMatches] = useState(defaultValue);
6
+ useEffect(() => {
7
+ if (typeof window === "undefined" || !window.matchMedia) {
8
+ return;
9
+ }
10
+ const media = window.matchMedia(query);
11
+ const onChange = () => {
12
+ setMatches(media.matches);
13
+ };
14
+ setMatches(media.matches);
15
+ media.addEventListener("change", onChange);
16
+ return () => {
17
+ media.removeEventListener("change", onChange);
18
+ };
19
+ }, [query]);
20
+ return matches;
21
+ }
22
+
23
+ export { useMediaQuery };
24
+ //# sourceMappingURL=chunk-FT2LMA66.mjs.map
25
+ //# sourceMappingURL=chunk-FT2LMA66.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useMediaQuery/useMediaQuery.ts"],"names":[],"mappings":";;;AAcO,SAAS,aAAA,CACd,KAAA,EACA,YAAA,GAAe,KAAA,EACN;AACT,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,YAAY,CAAA;AAEnD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,OAAO,UAAA,EAAY;AACvD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA;AACrC,IAAA,MAAM,WAAW,MAAM;AACrB,MAAA,UAAA,CAAW,MAAM,OAAO,CAAA;AAAA,IAC1B,CAAA;AACA,IAAA,UAAA,CAAW,MAAM,OAAO,CAAA;AACxB,IAAA,KAAA,CAAM,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AACzC,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,CAAM,mBAAA,CAAoB,UAAU,QAAQ,CAAA;AAAA,IAC9C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,OAAO,OAAA;AACT","file":"chunk-FT2LMA66.mjs","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n/**\n * Subscribes to `window.matchMedia(query)` and returns whether the query currently matches.\n *\n * On the server or when `matchMedia` is missing, `defaultValue` is used for the initial render and the effect no-ops.\n * The `change` listener keeps `matches` updated when the viewport or user settings change.\n *\n * @param query - A valid media query string, e.g. `\"(min-width: 768px)\"`.\n * @param defaultValue - Value to use before hydration or when `matchMedia` is unavailable (default `false`).\n * @returns Current `matches` boolean for the query.\n */\nexport function useMediaQuery(\n query: string,\n defaultValue = false,\n): boolean {\n const [matches, setMatches] = useState(defaultValue);\n\n useEffect(() => {\n if (typeof window === \"undefined\" || !window.matchMedia) {\n return;\n }\n const media = window.matchMedia(query);\n const onChange = () => {\n setMatches(media.matches);\n };\n setMatches(media.matches);\n media.addEventListener(\"change\", onChange);\n return () => {\n media.removeEventListener(\"change\", onChange);\n };\n }, [query]);\n\n return matches;\n}\n"]}
@@ -0,0 +1,107 @@
1
+ 'use strict';
2
+
3
+ var chunkUOZYPWDZ_js = require('./chunk-UOZYPWDZ.js');
4
+ var react = require('react');
5
+
6
+ function usePagination({
7
+ pageCount,
8
+ page,
9
+ defaultPage = 1,
10
+ siblingCount = 1,
11
+ boundaryCount = 1,
12
+ onPageChange
13
+ }) {
14
+ const [internalPage, setInternalPage] = react.useState(
15
+ () => chunkUOZYPWDZ_js.clampPage(defaultPage, pageCount)
16
+ );
17
+ const isControlled = page !== void 0;
18
+ const currentPage = chunkUOZYPWDZ_js.clampPage(isControlled ? page : internalPage, pageCount);
19
+ const setPage = react.useCallback(
20
+ (next) => {
21
+ const clamped = chunkUOZYPWDZ_js.clampPage(next, pageCount);
22
+ if (!isControlled) {
23
+ setInternalPage(clamped);
24
+ }
25
+ onPageChange?.(clamped);
26
+ },
27
+ [isControlled, onPageChange, pageCount]
28
+ );
29
+ const items = react.useMemo(
30
+ () => buildPaginationItems({
31
+ pageCount,
32
+ currentPage,
33
+ siblingCount,
34
+ boundaryCount
35
+ }),
36
+ [boundaryCount, currentPage, pageCount, siblingCount]
37
+ );
38
+ const canGoPrev = pageCount > 0 && currentPage > 1;
39
+ const canGoNext = pageCount > 0 && currentPage < pageCount;
40
+ const goPrev = react.useCallback(() => {
41
+ if (canGoPrev) {
42
+ setPage(currentPage - 1);
43
+ }
44
+ }, [canGoPrev, currentPage, setPage]);
45
+ const goNext = react.useCallback(() => {
46
+ if (canGoNext) {
47
+ setPage(currentPage + 1);
48
+ }
49
+ }, [canGoNext, currentPage, setPage]);
50
+ return {
51
+ currentPage,
52
+ pageCount,
53
+ items,
54
+ setPage,
55
+ goPrev,
56
+ goNext,
57
+ canGoPrev,
58
+ canGoNext
59
+ };
60
+ }
61
+ function buildPaginationItems({
62
+ pageCount,
63
+ currentPage,
64
+ siblingCount,
65
+ boundaryCount
66
+ }) {
67
+ if (pageCount <= 0) {
68
+ return [];
69
+ }
70
+ const safeBoundary = Math.max(1, boundaryCount);
71
+ const safeSibling = Math.max(0, siblingCount);
72
+ const current = chunkUOZYPWDZ_js.clampPage(currentPage, pageCount);
73
+ const totalNumbers = safeBoundary * 2 + safeSibling * 2 + 1;
74
+ if (pageCount <= totalNumbers) {
75
+ return chunkUOZYPWDZ_js.range(1, pageCount).map((value) => ({ type: "page", value }));
76
+ }
77
+ const leftBoundaryEnd = safeBoundary;
78
+ const rightBoundaryStart = pageCount - safeBoundary + 1;
79
+ const siblingsStart = Math.max(current - safeSibling, leftBoundaryEnd + 1);
80
+ const siblingsEnd = Math.min(current + safeSibling, rightBoundaryStart - 1);
81
+ const pages = /* @__PURE__ */ new Set();
82
+ for (let p = 1; p <= leftBoundaryEnd; p += 1) {
83
+ pages.add(p);
84
+ }
85
+ for (let p = rightBoundaryStart; p <= pageCount; p += 1) {
86
+ pages.add(p);
87
+ }
88
+ for (let p = siblingsStart; p <= siblingsEnd; p += 1) {
89
+ pages.add(p);
90
+ }
91
+ const sorted = [...pages].sort((a, b) => a - b);
92
+ const items = [];
93
+ for (let i = 0; i < sorted.length; i += 1) {
94
+ const value = sorted[i];
95
+ const prev = sorted[i - 1];
96
+ if (i > 0 && prev !== void 0 && value && value - prev > 1) {
97
+ items.push({ type: "ellipsis", key: `gap-${prev}-${value}` });
98
+ }
99
+ items.push({ type: "page", value });
100
+ }
101
+ return items;
102
+ }
103
+
104
+ exports.buildPaginationItems = buildPaginationItems;
105
+ exports.usePagination = usePagination;
106
+ //# sourceMappingURL=chunk-JE3PD5ZA.js.map
107
+ //# sourceMappingURL=chunk-JE3PD5ZA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/usePagination/usePagination.ts"],"names":["useState","clampPage","useCallback","useMemo","range"],"mappings":"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","file":"chunk-JE3PD5ZA.js","sourcesContent":["\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\n\nimport type {\n PaginationPageItem,\n UsePaginationParams,\n UsePaginationResult,\n} from \"../../ui/pagination/types\";\nimport { clampPage, range } from \"../../lib/utils\";\n\nexport type { PaginationPageItem } from \"../../ui/pagination/types\";\n\nexport type BuildPaginationItemsParams = {\n pageCount: number;\n currentPage: number;\n siblingCount: number;\n boundaryCount: number;\n};\n\n/**\n * Headless pagination state: current page, derived page button items, and prev/next helpers.\n *\n * Supports controlled mode when `page` is passed from the parent, or internal state seeded by `defaultPage`.\n * All page indices are **1-based** and clamped to `[1, pageCount]` via {@link clampPage}. `items` is memoized from\n * {@link buildPaginationItems} for rendering numeric pages and ellipsis gaps.\n *\n * @param params - See `UsePaginationParams` in `../ui/pagination/types` for full fields (`pageCount`, `page`, `onPageChange`, etc.).\n * @returns Current page, item list, `setPage`, navigation helpers, and `canGoPrev` / `canGoNext` flags.\n */\nexport function usePagination({\n pageCount,\n page,\n defaultPage = 1,\n siblingCount = 1,\n boundaryCount = 1,\n onPageChange,\n}: UsePaginationParams): UsePaginationResult {\n const [internalPage, setInternalPage] = useState(() =>\n clampPage(defaultPage, pageCount),\n );\n\n const isControlled = page !== undefined;\n const currentPage = clampPage(isControlled ? page : internalPage, pageCount);\n\n const setPage = useCallback(\n (next: number) => {\n const clamped = clampPage(next, pageCount);\n if (!isControlled) {\n setInternalPage(clamped);\n }\n onPageChange?.(clamped);\n },\n [isControlled, onPageChange, pageCount],\n );\n\n const items = useMemo(\n () =>\n buildPaginationItems({\n pageCount,\n currentPage,\n siblingCount,\n boundaryCount,\n }),\n [boundaryCount, currentPage, pageCount, siblingCount],\n );\n\n const canGoPrev = pageCount > 0 && currentPage > 1;\n const canGoNext = pageCount > 0 && currentPage < pageCount;\n\n const goPrev = useCallback(() => {\n if (canGoPrev) {\n setPage(currentPage - 1);\n }\n }, [canGoPrev, currentPage, setPage]);\n\n const goNext = useCallback(() => {\n if (canGoNext) {\n setPage(currentPage + 1);\n }\n }, [canGoNext, currentPage, setPage]);\n\n return {\n currentPage,\n pageCount,\n items,\n setPage,\n goPrev,\n goNext,\n canGoPrev,\n canGoNext,\n };\n}\n\n/**\n * Builds the ordered list of page numbers and ellipsis markers for a pagination control.\n *\n * @param params.pageCount - Total number of pages (must be >= 0; empty list when 0).\n * @param params.currentPage - Active page index (1-based).\n * @param params.siblingCount - How many page buttons to show on each side of the current page.\n * @param params.boundaryCount - How many pages to pin at the start and end of the range.\n * @returns Items suitable for rendering, e.g. page `1`, ellipsis gap, middle window, ellipsis, last page.\n */\nexport function buildPaginationItems({\n pageCount,\n currentPage,\n siblingCount,\n boundaryCount,\n}: BuildPaginationItemsParams): PaginationPageItem[] {\n if (pageCount <= 0) {\n return [];\n }\n\n const safeBoundary = Math.max(1, boundaryCount);\n const safeSibling = Math.max(0, siblingCount);\n const current = clampPage(currentPage, pageCount);\n\n const totalNumbers = safeBoundary * 2 + safeSibling * 2 + 1;\n if (pageCount <= totalNumbers) {\n return range(1, pageCount).map((value) => ({ type: \"page\", value }));\n }\n\n const leftBoundaryEnd = safeBoundary;\n const rightBoundaryStart = pageCount - safeBoundary + 1;\n\n const siblingsStart = Math.max(current - safeSibling, leftBoundaryEnd + 1);\n const siblingsEnd = Math.min(current + safeSibling, rightBoundaryStart - 1);\n\n const pages = new Set<number>();\n for (let p = 1; p <= leftBoundaryEnd; p += 1) {\n pages.add(p);\n }\n for (let p = rightBoundaryStart; p <= pageCount; p += 1) {\n pages.add(p);\n }\n for (let p = siblingsStart; p <= siblingsEnd; p += 1) {\n pages.add(p);\n }\n\n const sorted = [...pages].sort((a, b) => a - b);\n const items: PaginationPageItem[] = [];\n\n for (let i = 0; i < sorted.length; i += 1) {\n const value = sorted[i];\n const prev = sorted[i - 1];\n if (i > 0 && prev !== undefined && value && value - prev > 1) {\n items.push({ type: \"ellipsis\", key: `gap-${prev}-${value}` });\n }\n items.push({ type: \"page\", value: value as number });\n }\n\n return items;\n}\n"]}
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useIntersectionObserver/useIntersectionObserver.ts
6
+ function useIntersectionObserver(params = {}) {
7
+ const { enabled = true, root, rootMargin, threshold } = params;
8
+ const [element, setElement] = react.useState(null);
9
+ const [entry, setEntry] = react.useState(
10
+ void 0
11
+ );
12
+ const setRef = react.useCallback((node) => {
13
+ setElement(node);
14
+ }, []);
15
+ react.useEffect(() => {
16
+ if (!enabled || element == null) {
17
+ return;
18
+ }
19
+ if (typeof IntersectionObserver === "undefined") {
20
+ return;
21
+ }
22
+ const observer = new IntersectionObserver(
23
+ (records) => {
24
+ setEntry(records[0]);
25
+ },
26
+ { root, rootMargin, threshold }
27
+ );
28
+ observer.observe(element);
29
+ return () => {
30
+ observer.disconnect();
31
+ };
32
+ }, [element, enabled, root, rootMargin, threshold]);
33
+ return [setRef, entry];
34
+ }
35
+
36
+ exports.useIntersectionObserver = useIntersectionObserver;
37
+ //# sourceMappingURL=chunk-JXCTEAXD.js.map
38
+ //# sourceMappingURL=chunk-JXCTEAXD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useIntersectionObserver/useIntersectionObserver.ts"],"names":["useState","useCallback","useEffect"],"mappings":";;;;;AAoBO,SAAS,uBAAA,CACd,MAAA,GAAwC,EAAC,EACgB;AACzD,EAAA,MAAM,EAAE,OAAA,GAAU,IAAA,EAAM,IAAA,EAAM,UAAA,EAAY,WAAU,GAAI,MAAA;AACxD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAmB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,cAAA;AAAA,IACxB;AAAA,GACF;AAEA,EAAA,MAAM,MAAA,GAASC,iBAAA,CAAY,CAAC,IAAA,KAAmB;AAC7C,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,IAAW,IAAA,EAAM;AAC/B,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,yBAAyB,WAAA,EAAa;AAC/C,MAAA;AAAA,IACF;AACA,IAAA,MAAM,WAAW,IAAI,oBAAA;AAAA,MACnB,CAAC,OAAA,KAAY;AACX,QAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,MACrB,CAAA;AAAA,MACA,EAAE,IAAA,EAAM,UAAA,EAAY,SAAA;AAAU,KAChC;AACA,IAAA,QAAA,CAAS,QAAQ,OAAO,CAAA;AACxB,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AAAA,IACtB,CAAA;AAAA,EACF,GAAG,CAAC,OAAA,EAAS,SAAS,IAAA,EAAM,UAAA,EAAY,SAAS,CAAC,CAAA;AAElD,EAAA,OAAO,CAAC,QAAQ,KAAK,CAAA;AACvB","file":"chunk-JXCTEAXD.js","sourcesContent":["\"use client\";\n\nimport type { RefCallback } from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nexport type UseIntersectionObserverParams = IntersectionObserverInit & {\n /** When `false`, disconnects the observer until re-enabled (saves work for hidden or inactive content). */\n enabled?: boolean;\n};\n\n/**\n * Observes a single element with the browser `IntersectionObserver` API and exposes the latest entry.\n *\n * Returns a callback ref: assign it to the element to measure. When `enabled` is false or `IntersectionObserver`\n * is undefined (unsupported environment), the effect is a no-op and `entry` may stay `undefined`.\n *\n * @typeParam T - Observed element type.\n * @param params - Standard `IntersectionObserverInit` fields plus optional `enabled` (default `true`).\n * @returns `[setRef, entry]` where `entry` is the most recent callback record for the observed target.\n */\nexport function useIntersectionObserver<T extends Element>(\n params: UseIntersectionObserverParams = {},\n): [RefCallback<T>, IntersectionObserverEntry | undefined] {\n const { enabled = true, root, rootMargin, threshold } = params;\n const [element, setElement] = useState<T | null>(null);\n const [entry, setEntry] = useState<IntersectionObserverEntry | undefined>(\n undefined,\n );\n\n const setRef = useCallback((node: T | null) => {\n setElement(node);\n }, []);\n\n useEffect(() => {\n if (!enabled || element == null) {\n return;\n }\n if (typeof IntersectionObserver === \"undefined\") {\n return;\n }\n const observer = new IntersectionObserver(\n (records) => {\n setEntry(records[0]);\n },\n { root, rootMargin, threshold },\n );\n observer.observe(element);\n return () => {\n observer.disconnect();\n };\n }, [element, enabled, root, rootMargin, threshold]);\n\n return [setRef, entry];\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+
3
+ // src/hooks/useIntersectionObserver/useIntersectionObserver.ts
4
+ function useIntersectionObserver(params = {}) {
5
+ const { enabled = true, root, rootMargin, threshold } = params;
6
+ const [element, setElement] = useState(null);
7
+ const [entry, setEntry] = useState(
8
+ void 0
9
+ );
10
+ const setRef = useCallback((node) => {
11
+ setElement(node);
12
+ }, []);
13
+ useEffect(() => {
14
+ if (!enabled || element == null) {
15
+ return;
16
+ }
17
+ if (typeof IntersectionObserver === "undefined") {
18
+ return;
19
+ }
20
+ const observer = new IntersectionObserver(
21
+ (records) => {
22
+ setEntry(records[0]);
23
+ },
24
+ { root, rootMargin, threshold }
25
+ );
26
+ observer.observe(element);
27
+ return () => {
28
+ observer.disconnect();
29
+ };
30
+ }, [element, enabled, root, rootMargin, threshold]);
31
+ return [setRef, entry];
32
+ }
33
+
34
+ export { useIntersectionObserver };
35
+ //# sourceMappingURL=chunk-LIJ6BDGP.mjs.map
36
+ //# sourceMappingURL=chunk-LIJ6BDGP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useIntersectionObserver/useIntersectionObserver.ts"],"names":[],"mappings":";;;AAoBO,SAAS,uBAAA,CACd,MAAA,GAAwC,EAAC,EACgB;AACzD,EAAA,MAAM,EAAE,OAAA,GAAU,IAAA,EAAM,IAAA,EAAM,UAAA,EAAY,WAAU,GAAI,MAAA;AACxD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAmB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAA;AAAA,IACxB;AAAA,GACF;AAEA,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,CAAC,IAAA,KAAmB;AAC7C,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,IAAW,IAAA,EAAM;AAC/B,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,yBAAyB,WAAA,EAAa;AAC/C,MAAA;AAAA,IACF;AACA,IAAA,MAAM,WAAW,IAAI,oBAAA;AAAA,MACnB,CAAC,OAAA,KAAY;AACX,QAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,MACrB,CAAA;AAAA,MACA,EAAE,IAAA,EAAM,UAAA,EAAY,SAAA;AAAU,KAChC;AACA,IAAA,QAAA,CAAS,QAAQ,OAAO,CAAA;AACxB,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AAAA,IACtB,CAAA;AAAA,EACF,GAAG,CAAC,OAAA,EAAS,SAAS,IAAA,EAAM,UAAA,EAAY,SAAS,CAAC,CAAA;AAElD,EAAA,OAAO,CAAC,QAAQ,KAAK,CAAA;AACvB","file":"chunk-LIJ6BDGP.mjs","sourcesContent":["\"use client\";\n\nimport type { RefCallback } from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nexport type UseIntersectionObserverParams = IntersectionObserverInit & {\n /** When `false`, disconnects the observer until re-enabled (saves work for hidden or inactive content). */\n enabled?: boolean;\n};\n\n/**\n * Observes a single element with the browser `IntersectionObserver` API and exposes the latest entry.\n *\n * Returns a callback ref: assign it to the element to measure. When `enabled` is false or `IntersectionObserver`\n * is undefined (unsupported environment), the effect is a no-op and `entry` may stay `undefined`.\n *\n * @typeParam T - Observed element type.\n * @param params - Standard `IntersectionObserverInit` fields plus optional `enabled` (default `true`).\n * @returns `[setRef, entry]` where `entry` is the most recent callback record for the observed target.\n */\nexport function useIntersectionObserver<T extends Element>(\n params: UseIntersectionObserverParams = {},\n): [RefCallback<T>, IntersectionObserverEntry | undefined] {\n const { enabled = true, root, rootMargin, threshold } = params;\n const [element, setElement] = useState<T | null>(null);\n const [entry, setEntry] = useState<IntersectionObserverEntry | undefined>(\n undefined,\n );\n\n const setRef = useCallback((node: T | null) => {\n setElement(node);\n }, []);\n\n useEffect(() => {\n if (!enabled || element == null) {\n return;\n }\n if (typeof IntersectionObserver === \"undefined\") {\n return;\n }\n const observer = new IntersectionObserver(\n (records) => {\n setEntry(records[0]);\n },\n { root, rootMargin, threshold },\n );\n observer.observe(element);\n return () => {\n observer.disconnect();\n };\n }, [element, enabled, root, rootMargin, threshold]);\n\n return [setRef, entry];\n}\n"]}