@zentauri-ui/zentauri-components 1.1.0 → 1.2.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.
- package/README.md +62 -21
- package/dist/chunk-2VQJ6OIL.js +31 -0
- package/dist/chunk-2VQJ6OIL.js.map +1 -0
- package/dist/chunk-73VCO5TE.mjs +29 -0
- package/dist/chunk-73VCO5TE.mjs.map +1 -0
- package/dist/chunk-BSWYZTYK.js +31 -0
- package/dist/chunk-BSWYZTYK.js.map +1 -0
- package/dist/chunk-CY5BQKRZ.mjs +29 -0
- package/dist/chunk-CY5BQKRZ.mjs.map +1 -0
- package/dist/chunk-DFEZH7TC.mjs +27 -0
- package/dist/chunk-DFEZH7TC.mjs.map +1 -0
- package/dist/chunk-FT2LMA66.mjs +25 -0
- package/dist/chunk-FT2LMA66.mjs.map +1 -0
- package/dist/chunk-JE3PD5ZA.js +107 -0
- package/dist/chunk-JE3PD5ZA.js.map +1 -0
- package/dist/chunk-JXCTEAXD.js +38 -0
- package/dist/chunk-JXCTEAXD.js.map +1 -0
- package/dist/chunk-LIJ6BDGP.mjs +36 -0
- package/dist/chunk-LIJ6BDGP.mjs.map +1 -0
- package/dist/chunk-PMAF6FBF.mjs +37 -0
- package/dist/chunk-PMAF6FBF.mjs.map +1 -0
- package/dist/chunk-TZ2JVWTZ.mjs +104 -0
- package/dist/chunk-TZ2JVWTZ.mjs.map +1 -0
- package/dist/chunk-UIYFEP3I.js +39 -0
- package/dist/chunk-UIYFEP3I.js.map +1 -0
- package/dist/chunk-UOZYPWDZ.js +32 -0
- package/dist/chunk-UOZYPWDZ.js.map +1 -0
- package/dist/chunk-WL5I7RVS.mjs +54 -0
- package/dist/chunk-WL5I7RVS.mjs.map +1 -0
- package/dist/chunk-WP7GYBRI.js +27 -0
- package/dist/chunk-WP7GYBRI.js.map +1 -0
- package/dist/chunk-YPLVTUYL.js +56 -0
- package/dist/chunk-YPLVTUYL.js.map +1 -0
- package/dist/hooks/useBodyScrollLock.d.mts +14 -0
- package/dist/hooks/useBodyScrollLock.d.ts +14 -0
- package/dist/hooks/useBodyScrollLock.js +13 -0
- package/dist/hooks/useBodyScrollLock.js.map +1 -0
- package/dist/hooks/useBodyScrollLock.mjs +4 -0
- package/dist/hooks/useBodyScrollLock.mjs.map +1 -0
- package/dist/hooks/useClickOutside.d.mts +23 -0
- package/dist/hooks/useClickOutside.d.ts +23 -0
- package/dist/hooks/useClickOutside.js +13 -0
- package/dist/hooks/useClickOutside.js.map +1 -0
- package/dist/hooks/useClickOutside.mjs +4 -0
- package/dist/hooks/useClickOutside.mjs.map +1 -0
- package/dist/hooks/useClipboard.d.mts +22 -0
- package/dist/hooks/useClipboard.d.ts +22 -0
- package/dist/hooks/useClipboard.js +51 -0
- package/dist/hooks/useClipboard.js.map +1 -0
- package/dist/hooks/useClipboard.mjs +49 -0
- package/dist/hooks/useClipboard.mjs.map +1 -0
- package/dist/hooks/useControllableState.d.mts +22 -0
- package/dist/hooks/useControllableState.d.ts +22 -0
- package/dist/hooks/useControllableState.js +13 -0
- package/dist/hooks/useControllableState.js.map +1 -0
- package/dist/hooks/useControllableState.mjs +4 -0
- package/dist/hooks/useControllableState.mjs.map +1 -0
- package/dist/hooks/useDebouncedValue.d.mts +14 -0
- package/dist/hooks/useDebouncedValue.d.ts +14 -0
- package/dist/hooks/useDebouncedValue.js +22 -0
- package/dist/hooks/useDebouncedValue.js.map +1 -0
- package/dist/hooks/useDebouncedValue.mjs +20 -0
- package/dist/hooks/useDebouncedValue.mjs.map +1 -0
- package/dist/hooks/useDisclosure.d.mts +25 -0
- package/dist/hooks/useDisclosure.d.ts +25 -0
- package/dist/hooks/useDisclosure.js +37 -0
- package/dist/hooks/useDisclosure.js.map +1 -0
- package/dist/hooks/useDisclosure.mjs +35 -0
- package/dist/hooks/useDisclosure.mjs.map +1 -0
- package/dist/hooks/useDocumentTitle.d.mts +19 -0
- package/dist/hooks/useDocumentTitle.d.ts +19 -0
- package/dist/hooks/useDocumentTitle.js +40 -0
- package/dist/hooks/useDocumentTitle.js.map +1 -0
- package/dist/hooks/useDocumentTitle.mjs +38 -0
- package/dist/hooks/useDocumentTitle.mjs.map +1 -0
- package/dist/hooks/useFocusManagement.d.mts +24 -0
- package/dist/hooks/useFocusManagement.d.ts +24 -0
- package/dist/hooks/useFocusManagement.js +14 -0
- package/dist/hooks/useFocusManagement.js.map +1 -0
- package/dist/hooks/useFocusManagement.mjs +5 -0
- package/dist/hooks/useFocusManagement.mjs.map +1 -0
- package/dist/hooks/useHover.d.mts +15 -0
- package/dist/hooks/useHover.d.ts +15 -0
- package/dist/hooks/useHover.js +37 -0
- package/dist/hooks/useHover.js.map +1 -0
- package/dist/hooks/useHover.mjs +35 -0
- package/dist/hooks/useHover.mjs.map +1 -0
- package/dist/hooks/useInView.d.mts +19 -0
- package/dist/hooks/useInView.d.ts +19 -0
- package/dist/hooks/useInView.js +15 -0
- package/dist/hooks/useInView.js.map +1 -0
- package/dist/hooks/useInView.mjs +13 -0
- package/dist/hooks/useInView.mjs.map +1 -0
- package/dist/hooks/useIntersectionObserver.d.mts +19 -0
- package/dist/hooks/useIntersectionObserver.d.ts +19 -0
- package/dist/hooks/useIntersectionObserver.js +13 -0
- package/dist/hooks/useIntersectionObserver.js.map +1 -0
- package/dist/hooks/useIntersectionObserver.mjs +4 -0
- package/dist/hooks/useIntersectionObserver.mjs.map +1 -0
- package/dist/hooks/useIsMounted.d.mts +11 -0
- package/dist/hooks/useIsMounted.d.ts +11 -0
- package/dist/hooks/useIsMounted.js +20 -0
- package/dist/hooks/useIsMounted.js.map +1 -0
- package/dist/hooks/useIsMounted.mjs +18 -0
- package/dist/hooks/useIsMounted.mjs.map +1 -0
- package/dist/hooks/useIsomorphicLayoutEffect.d.mts +11 -0
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts +11 -0
- package/dist/hooks/useIsomorphicLayoutEffect.js +11 -0
- package/dist/hooks/useIsomorphicLayoutEffect.js.map +1 -0
- package/dist/hooks/useIsomorphicLayoutEffect.mjs +9 -0
- package/dist/hooks/useIsomorphicLayoutEffect.mjs.map +1 -0
- package/dist/hooks/useLocalStorage.d.mts +22 -0
- package/dist/hooks/useLocalStorage.d.ts +22 -0
- package/dist/hooks/useLocalStorage.js +84 -0
- package/dist/hooks/useLocalStorage.js.map +1 -0
- package/dist/hooks/useLocalStorage.mjs +82 -0
- package/dist/hooks/useLocalStorage.mjs.map +1 -0
- package/dist/hooks/useMediaQuery.d.mts +13 -0
- package/dist/hooks/useMediaQuery.d.ts +13 -0
- package/dist/hooks/useMediaQuery.js +13 -0
- package/dist/hooks/useMediaQuery.js.map +1 -0
- package/dist/hooks/useMediaQuery.mjs +4 -0
- package/dist/hooks/useMediaQuery.mjs.map +1 -0
- package/dist/hooks/useNetworkStatus.d.mts +10 -0
- package/dist/hooks/useNetworkStatus.d.ts +10 -0
- package/dist/hooks/useNetworkStatus.js +30 -0
- package/dist/hooks/useNetworkStatus.js.map +1 -0
- package/dist/hooks/useNetworkStatus.mjs +28 -0
- package/dist/hooks/useNetworkStatus.mjs.map +1 -0
- package/dist/hooks/usePageVisibility.d.mts +10 -0
- package/dist/hooks/usePageVisibility.d.ts +10 -0
- package/dist/hooks/usePageVisibility.js +28 -0
- package/dist/hooks/usePageVisibility.js.map +1 -0
- package/dist/hooks/usePageVisibility.mjs +26 -0
- package/dist/hooks/usePageVisibility.mjs.map +1 -0
- package/dist/hooks/usePagination.d.mts +5 -0
- package/dist/hooks/usePagination.d.ts +5 -0
- package/dist/hooks/usePagination.js +18 -0
- package/dist/hooks/usePagination.js.map +1 -0
- package/dist/hooks/usePagination.mjs +5 -0
- package/dist/hooks/usePagination.mjs.map +1 -0
- package/dist/hooks/usePrefersColorScheme.d.mts +10 -0
- package/dist/hooks/usePrefersColorScheme.d.ts +10 -0
- package/dist/hooks/usePrefersColorScheme.js +17 -0
- package/dist/hooks/usePrefersColorScheme.js.map +1 -0
- package/dist/hooks/usePrefersColorScheme.mjs +15 -0
- package/dist/hooks/usePrefersColorScheme.mjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.d.mts +10 -0
- package/dist/hooks/usePrefersReducedMotion.d.ts +10 -0
- package/dist/hooks/usePrefersReducedMotion.js +13 -0
- package/dist/hooks/usePrefersReducedMotion.js.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.mjs +11 -0
- package/dist/hooks/usePrefersReducedMotion.mjs.map +1 -0
- package/dist/hooks/useResizeObserver.d.mts +23 -0
- package/dist/hooks/useResizeObserver.d.ts +23 -0
- package/dist/hooks/useResizeObserver.js +38 -0
- package/dist/hooks/useResizeObserver.js.map +1 -0
- package/dist/hooks/useResizeObserver.mjs +36 -0
- package/dist/hooks/useResizeObserver.mjs.map +1 -0
- package/dist/hooks/useSessionStorage.d.mts +22 -0
- package/dist/hooks/useSessionStorage.d.ts +22 -0
- package/dist/hooks/useSessionStorage.js +58 -0
- package/dist/hooks/useSessionStorage.js.map +1 -0
- package/dist/hooks/useSessionStorage.mjs +56 -0
- package/dist/hooks/useSessionStorage.mjs.map +1 -0
- package/dist/hooks/useThrottledCallback.d.mts +14 -0
- package/dist/hooks/useThrottledCallback.d.ts +14 -0
- package/dist/hooks/useThrottledCallback.js +27 -0
- package/dist/hooks/useThrottledCallback.js.map +1 -0
- package/dist/hooks/useThrottledCallback.mjs +25 -0
- package/dist/hooks/useThrottledCallback.mjs.map +1 -0
- package/dist/hooks/useToggle.d.mts +9 -0
- package/dist/hooks/useToggle.d.ts +9 -0
- package/dist/hooks/useToggle.js +20 -0
- package/dist/hooks/useToggle.js.map +1 -0
- package/dist/hooks/useToggle.mjs +18 -0
- package/dist/hooks/useToggle.mjs.map +1 -0
- package/dist/hooks/useWindowSize.d.mts +14 -0
- package/dist/hooks/useWindowSize.d.ts +14 -0
- package/dist/hooks/useWindowSize.js +30 -0
- package/dist/hooks/useWindowSize.js.map +1 -0
- package/dist/hooks/useWindowSize.mjs +28 -0
- package/dist/hooks/useWindowSize.mjs.map +1 -0
- package/dist/hooks/utils.d.mts +8 -0
- package/dist/hooks/utils.d.ts +8 -0
- package/dist/hooks/utils.js +24 -0
- package/dist/hooks/utils.js.map +1 -0
- package/dist/hooks/utils.mjs +3 -0
- package/dist/hooks/utils.mjs.map +1 -0
- package/dist/index-ClPu5gDp.d.ts +86 -0
- package/dist/index-D4p9fn1o.d.mts +86 -0
- package/dist/ui/accordion.js +5 -5
- package/dist/ui/accordion.mjs +1 -1
- package/dist/ui/alert.js +7 -7
- package/dist/ui/alert.mjs +1 -1
- package/dist/ui/avatar.js +6 -6
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/avatar.mjs +1 -1
- package/dist/ui/avatar.mjs.map +1 -1
- package/dist/ui/badge.js +2 -2
- package/dist/ui/badge.mjs +1 -1
- package/dist/ui/breadcrumb.js +7 -7
- package/dist/ui/breadcrumb.mjs +1 -1
- package/dist/ui/buttons.js +3 -3
- package/dist/ui/buttons.mjs +1 -1
- package/dist/ui/card.js +7 -7
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/card.mjs +1 -1
- package/dist/ui/card.mjs.map +1 -1
- package/dist/ui/divider.js +6 -6
- package/dist/ui/divider.mjs +1 -1
- package/dist/ui/drawer.js +15 -60
- package/dist/ui/drawer.js.map +1 -1
- package/dist/ui/drawer.mjs +9 -54
- package/dist/ui/drawer.mjs.map +1 -1
- package/dist/ui/dropdown.js +6 -13
- package/dist/ui/dropdown.js.map +1 -1
- package/dist/ui/dropdown.mjs +4 -11
- package/dist/ui/dropdown.mjs.map +1 -1
- package/dist/ui/empty-state.js +6 -6
- package/dist/ui/empty-state.js.map +1 -1
- package/dist/ui/empty-state.mjs +1 -1
- package/dist/ui/empty-state.mjs.map +1 -1
- package/dist/ui/file-upload.js +3 -3
- package/dist/ui/file-upload.mjs +1 -1
- package/dist/ui/inputs.js +3 -3
- package/dist/ui/inputs.mjs +1 -1
- package/dist/ui/modal.js +16 -61
- package/dist/ui/modal.js.map +1 -1
- package/dist/ui/modal.mjs +9 -54
- package/dist/ui/modal.mjs.map +1 -1
- package/dist/ui/pagination.d.mts +3 -81
- package/dist/ui/pagination.d.ts +3 -81
- package/dist/ui/pagination.js +13 -122
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/pagination.mjs +5 -114
- package/dist/ui/pagination.mjs.map +1 -1
- package/dist/ui/progress.js +7 -10
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/progress.mjs +1 -4
- package/dist/ui/progress.mjs.map +1 -1
- package/dist/ui/select.js +6 -6
- package/dist/ui/select.mjs +1 -1
- package/dist/ui/skeleton.js +7 -7
- package/dist/ui/skeleton.mjs +1 -1
- package/dist/ui/slider.js +9 -9
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/slider.mjs +1 -1
- package/dist/ui/slider.mjs.map +1 -1
- package/dist/ui/spinner.js +24 -10
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/spinner.mjs +17 -3
- package/dist/ui/spinner.mjs.map +1 -1
- package/dist/ui/stepper.js +6 -6
- package/dist/ui/stepper.mjs +1 -1
- package/dist/ui/table.js +9 -9
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/table.mjs +1 -1
- package/dist/ui/table.mjs.map +1 -1
- package/dist/ui/tabs.js +5 -5
- package/dist/ui/tabs.mjs +1 -1
- package/dist/ui/toast.js +7 -7
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toast.mjs +1 -1
- package/dist/ui/toast.mjs.map +1 -1
- package/dist/ui/toggle.js +3 -3
- package/dist/ui/toggle.mjs +1 -1
- package/dist/ui/tooltip.js +2 -2
- package/dist/ui/tooltip.mjs +1 -1
- package/package.json +7 -2
- package/dist/chunk-B23TPTVG.mjs +0 -11
- package/dist/chunk-B23TPTVG.mjs.map +0 -1
- package/dist/chunk-WZ2GOU2J.js +0 -13
- 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/`.
|
|
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
|
|
14
|
-
|
|
|
15
|
-
| `@zentauri-ui/zentauri-components/ui
|
|
16
|
-
| `@zentauri-ui/zentauri-components/
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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 (
|
|
213
|
+
#### Imports (hooks alongside UI)
|
|
167
214
|
|
|
168
215
|
```tsx
|
|
169
|
-
import {
|
|
170
|
-
|
|
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"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
// src/hooks/useBodyScrollLock/useBodyScrollLock.ts
|
|
4
|
+
var activeLockCount = 0;
|
|
5
|
+
var storedOverflow;
|
|
6
|
+
var acquireBodyScrollLock = () => {
|
|
7
|
+
if (activeLockCount === 0) {
|
|
8
|
+
storedOverflow = document.body.style.overflow;
|
|
9
|
+
document.body.style.overflow = "hidden";
|
|
10
|
+
}
|
|
11
|
+
activeLockCount += 1;
|
|
12
|
+
};
|
|
13
|
+
var releaseBodyScrollLock = () => {
|
|
14
|
+
if (activeLockCount <= 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
activeLockCount -= 1;
|
|
18
|
+
if (activeLockCount === 0) {
|
|
19
|
+
document.body.style.overflow = storedOverflow ?? "";
|
|
20
|
+
storedOverflow = void 0;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var useBodyScrollLock = (locked) => {
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!locked) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
acquireBodyScrollLock();
|
|
29
|
+
return () => {
|
|
30
|
+
releaseBodyScrollLock();
|
|
31
|
+
};
|
|
32
|
+
}, [locked]);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { useBodyScrollLock };
|
|
36
|
+
//# sourceMappingURL=chunk-PMAF6FBF.mjs.map
|
|
37
|
+
//# sourceMappingURL=chunk-PMAF6FBF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useBodyScrollLock/useBodyScrollLock.ts"],"names":[],"mappings":";;;AAIA,IAAI,eAAA,GAAkB,CAAA;AACtB,IAAI,cAAA;AAEJ,IAAM,wBAAwB,MAAM;AAClC,EAAA,IAAI,oBAAoB,CAAA,EAAG;AACzB,IAAA,cAAA,GAAiB,QAAA,CAAS,KAAK,KAAA,CAAM,QAAA;AACrC,IAAA,QAAA,CAAS,IAAA,CAAK,MAAM,QAAA,GAAW,QAAA;AAAA,EACjC;AACA,EAAA,eAAA,IAAmB,CAAA;AACrB,CAAA;AAEA,IAAM,wBAAwB,MAAM;AAClC,EAAA,IAAI,mBAAmB,CAAA,EAAG;AACxB,IAAA;AAAA,EACF;AACA,EAAA,eAAA,IAAmB,CAAA;AACnB,EAAA,IAAI,oBAAoB,CAAA,EAAG;AACzB,IAAA,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,QAAA,GAAW,cAAA,IAAkB,EAAA;AACjD,IAAA,cAAA,GAAiB,MAAA;AAAA,EACnB;AACF,CAAA;AAaO,IAAM,iBAAA,GAAoB,CAAC,MAAA,KAAoB;AACpD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AACA,IAAA,qBAAA,EAAsB;AACtB,IAAA,OAAO,MAAM;AACX,MAAA,qBAAA,EAAsB;AAAA,IACxB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACb","file":"chunk-PMAF6FBF.mjs","sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\n\nlet activeLockCount = 0;\nlet storedOverflow: string | undefined;\n\nconst acquireBodyScrollLock = () => {\n if (activeLockCount === 0) {\n storedOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n activeLockCount += 1;\n};\n\nconst releaseBodyScrollLock = () => {\n if (activeLockCount <= 0) {\n return;\n }\n activeLockCount -= 1;\n if (activeLockCount === 0) {\n document.body.style.overflow = storedOverflow ?? \"\";\n storedOverflow = undefined;\n }\n};\n\n/**\n * Locks the document body scroll while `locked` is true by setting `document.body.style.overflow`\n * to `\"hidden\"`. Uses a module-level lock count so multiple concurrent callers (nested modals,\n * drawer + modal, several hook instances) only restore the original inline `overflow` after the\n * last lock releases.\n *\n * Typical use: modals, drawers, and full-screen overlays where background content must not scroll.\n *\n * @param locked - When `true`, body scroll is hidden; when `false`, this instance releases its\n * lock; the prior overflow is restored only when no instance still holds a lock.\n */\nexport const useBodyScrollLock = (locked: boolean) => {\n useEffect(() => {\n if (!locked) {\n return;\n }\n acquireBodyScrollLock();\n return () => {\n releaseBodyScrollLock();\n };\n }, [locked]);\n};\n"]}
|