@waveso/ui 0.0.2 → 0.0.4

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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -52
  3. package/dist/accordion.d.ts +14 -0
  4. package/dist/accordion.js +81 -0
  5. package/dist/accordion.js.map +1 -0
  6. package/dist/alert.d.ts +8 -4
  7. package/dist/alert.js.map +1 -1
  8. package/dist/aspect-ratio.d.ts +10 -0
  9. package/dist/aspect-ratio.js +18 -0
  10. package/dist/aspect-ratio.js.map +1 -0
  11. package/dist/autocomplete.d.ts +48 -0
  12. package/dist/autocomplete.js +222 -0
  13. package/dist/autocomplete.js.map +1 -0
  14. package/dist/avatar.d.ts +13 -7
  15. package/dist/avatar.js.map +1 -1
  16. package/dist/badge.d.ts +3 -2
  17. package/dist/badge.js +1 -1
  18. package/dist/badge.js.map +1 -1
  19. package/dist/breadcrumb.d.ts +20 -0
  20. package/dist/breadcrumb.js +123 -0
  21. package/dist/breadcrumb.js.map +1 -0
  22. package/dist/button-group.d.ts +19 -0
  23. package/dist/button-group.js +81 -0
  24. package/dist/button-group.js.map +1 -0
  25. package/dist/card.d.ts +15 -8
  26. package/dist/card.js.map +1 -1
  27. package/dist/checkbox.js +1 -1
  28. package/dist/chunk-45VQAWIM.js +228 -0
  29. package/dist/chunk-45VQAWIM.js.map +1 -0
  30. package/dist/chunk-6Y7LPQMO.js +11 -0
  31. package/dist/chunk-6Y7LPQMO.js.map +1 -0
  32. package/dist/chunk-7F4MPMLJ.js +17 -0
  33. package/dist/chunk-7F4MPMLJ.js.map +1 -0
  34. package/dist/chunk-7OIQ6YBK.js +66 -0
  35. package/dist/chunk-7OIQ6YBK.js.map +1 -0
  36. package/dist/chunk-D5XPEJ6T.js +36 -0
  37. package/dist/chunk-D5XPEJ6T.js.map +1 -0
  38. package/dist/chunk-DIGOLJIR.js +105 -0
  39. package/dist/chunk-DIGOLJIR.js.map +1 -0
  40. package/dist/chunk-IQ7YQ5XA.js +141 -0
  41. package/dist/chunk-IQ7YQ5XA.js.map +1 -0
  42. package/dist/chunk-NCHHHWTB.js +85 -0
  43. package/dist/chunk-NCHHHWTB.js.map +1 -0
  44. package/dist/chunk-PVX4VQFJ.js +143 -0
  45. package/dist/chunk-PVX4VQFJ.js.map +1 -0
  46. package/dist/chunk-QFSEK4M6.js +22 -0
  47. package/dist/chunk-QFSEK4M6.js.map +1 -0
  48. package/dist/chunk-QRW37LRP.js +25 -0
  49. package/dist/chunk-QRW37LRP.js.map +1 -0
  50. package/dist/chunk-RPQHL6C5.js +26 -0
  51. package/dist/chunk-RPQHL6C5.js.map +1 -0
  52. package/dist/chunk-YTSQQTSF.js +44 -0
  53. package/dist/chunk-YTSQQTSF.js.map +1 -0
  54. package/dist/chunk-ZZZH3JGW.js +23 -0
  55. package/dist/chunk-ZZZH3JGW.js.map +1 -0
  56. package/dist/collapsible.d.ts +12 -0
  57. package/dist/collapsible.js +16 -0
  58. package/dist/collapsible.js.map +1 -0
  59. package/dist/combobox.d.ts +48 -0
  60. package/dist/combobox.js +281 -0
  61. package/dist/combobox.js.map +1 -0
  62. package/dist/context-menu.d.ts +47 -0
  63. package/dist/context-menu.js +193 -0
  64. package/dist/context-menu.js.map +1 -0
  65. package/dist/dialog.js +1 -1
  66. package/dist/direction.d.ts +1 -0
  67. package/dist/direction.js +3 -0
  68. package/dist/direction.js.map +1 -0
  69. package/dist/drawer.d.ts +29 -0
  70. package/dist/drawer.js +6 -0
  71. package/dist/drawer.js.map +1 -0
  72. package/dist/encrypted-text.d.ts +16 -0
  73. package/dist/encrypted-text.js +141 -0
  74. package/dist/encrypted-text.js.map +1 -0
  75. package/dist/field.d.ts +22 -0
  76. package/dist/field.js +4 -0
  77. package/dist/field.js.map +1 -0
  78. package/dist/form.d.ts +80 -0
  79. package/dist/form.js +108 -0
  80. package/dist/form.js.map +1 -0
  81. package/dist/hooks/use-mobile.d.ts +6 -1
  82. package/dist/hooks/use-mobile.js +1 -18
  83. package/dist/hooks/use-mobile.js.map +1 -1
  84. package/dist/infinite-scroll.d.ts +19 -0
  85. package/dist/infinite-scroll.js +102 -0
  86. package/dist/infinite-scroll.js.map +1 -0
  87. package/dist/input-group.d.ts +29 -0
  88. package/dist/input-group.js +7 -0
  89. package/dist/input-group.js.map +1 -0
  90. package/dist/input-otp.d.ts +18 -0
  91. package/dist/input-otp.js +79 -0
  92. package/dist/input-otp.js.map +1 -0
  93. package/dist/input.d.ts +2 -1
  94. package/dist/input.js +2 -20
  95. package/dist/input.js.map +1 -1
  96. package/dist/item.d.ts +37 -0
  97. package/dist/item.js +181 -0
  98. package/dist/item.js.map +1 -0
  99. package/dist/kbd.d.ts +8 -0
  100. package/dist/kbd.js +30 -0
  101. package/dist/kbd.js.map +1 -0
  102. package/dist/label.d.ts +2 -1
  103. package/dist/label.js.map +1 -1
  104. package/dist/masonry.d.ts +17 -0
  105. package/dist/masonry.js +235 -0
  106. package/dist/masonry.js.map +1 -0
  107. package/dist/menu.d.ts +47 -0
  108. package/dist/menu.js +5 -0
  109. package/dist/menu.js.map +1 -0
  110. package/dist/menubar.d.ts +40 -0
  111. package/dist/menubar.js +84 -0
  112. package/dist/menubar.js.map +1 -0
  113. package/dist/pagination.d.ts +29 -0
  114. package/dist/pagination.js +120 -0
  115. package/dist/pagination.js.map +1 -0
  116. package/dist/popover.d.ts +24 -0
  117. package/dist/popover.js +105 -0
  118. package/dist/popover.js.map +1 -0
  119. package/dist/preview-card.d.ts +17 -0
  120. package/dist/preview-card.js +70 -0
  121. package/dist/preview-card.js.map +1 -0
  122. package/dist/radio-group.d.ts +12 -0
  123. package/dist/radio-group.js +28 -0
  124. package/dist/radio-group.js.map +1 -0
  125. package/dist/radio.d.ts +10 -0
  126. package/dist/radio.js +4 -0
  127. package/dist/radio.js.map +1 -0
  128. package/dist/scroll-area.d.ts +10 -0
  129. package/dist/scroll-area.js +59 -0
  130. package/dist/scroll-area.js.map +1 -0
  131. package/dist/select.d.ts +36 -0
  132. package/dist/select.js +208 -0
  133. package/dist/select.js.map +1 -0
  134. package/dist/separator.js +2 -24
  135. package/dist/separator.js.map +1 -1
  136. package/dist/sidebar.d.ts +112 -0
  137. package/dist/sidebar.js +619 -0
  138. package/dist/sidebar.js.map +1 -0
  139. package/dist/skeleton.d.ts +2 -1
  140. package/dist/skeleton.js +2 -15
  141. package/dist/skeleton.js.map +1 -1
  142. package/dist/slider.d.ts +10 -0
  143. package/dist/slider.js +70 -0
  144. package/dist/slider.js.map +1 -0
  145. package/dist/spinner.d.ts +2 -1
  146. package/dist/spinner.js +3 -9
  147. package/dist/spinner.js.map +1 -1
  148. package/dist/styles.css +196 -0
  149. package/dist/table.d.ts +21 -0
  150. package/dist/table.js +106 -0
  151. package/dist/table.js.map +1 -0
  152. package/dist/tabs.d.ts +20 -0
  153. package/dist/tabs.js +82 -0
  154. package/dist/tabs.js.map +1 -0
  155. package/dist/textarea.js +2 -23
  156. package/dist/textarea.js.map +1 -1
  157. package/dist/toast.d.ts +57 -0
  158. package/dist/toast.js +239 -0
  159. package/dist/toast.js.map +1 -0
  160. package/dist/toggle-group.d.ts +17 -0
  161. package/dist/toggle-group.js +78 -0
  162. package/dist/toggle-group.js.map +1 -0
  163. package/dist/toggle.d.ts +14 -0
  164. package/dist/toggle.js +4 -0
  165. package/dist/toggle.js.map +1 -0
  166. package/dist/tooltip.d.ts +21 -0
  167. package/dist/tooltip.js +4 -0
  168. package/dist/tooltip.js.map +1 -0
  169. package/package.json +10 -3
  170. package/dist/chunk-L3UIJEIQ.js +0 -41
  171. package/dist/chunk-L3UIJEIQ.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"direction.js","sourcesContent":[]}
@@ -0,0 +1,29 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { DrawerPreview } from '@base-ui/react/drawer';
4
+
5
+ type DrawerProps = React.ComponentProps<typeof DrawerPreview.Root>;
6
+ type DrawerTriggerProps = React.ComponentProps<typeof DrawerPreview.Trigger>;
7
+ type DrawerPortalProps = React.ComponentProps<typeof DrawerPreview.Portal>;
8
+ type DrawerCloseProps = React.ComponentProps<typeof DrawerPreview.Close>;
9
+ type DrawerOverlayProps = React.ComponentProps<typeof DrawerPreview.Backdrop>;
10
+ type DrawerPopupProps = React.ComponentProps<typeof DrawerPreview.Popup>;
11
+ type DrawerTitleProps = React.ComponentProps<typeof DrawerPreview.Title>;
12
+ type DrawerDescriptionProps = React.ComponentProps<typeof DrawerPreview.Description>;
13
+ type DrawerHeaderProps = React.ComponentProps<"div">;
14
+ type DrawerFooterProps = React.ComponentProps<"div">;
15
+ type DrawerContentProps = DrawerPopupProps & {
16
+ showCloseButton?: boolean;
17
+ };
18
+ declare function Drawer({ ...props }: DrawerProps): react_jsx_runtime.JSX.Element;
19
+ declare function DrawerTrigger({ ...props }: DrawerTriggerProps): react_jsx_runtime.JSX.Element;
20
+ declare function DrawerPortal({ ...props }: DrawerPortalProps): react_jsx_runtime.JSX.Element;
21
+ declare function DrawerClose({ ...props }: DrawerCloseProps): react_jsx_runtime.JSX.Element;
22
+ declare function DrawerOverlay({ className, ...props }: DrawerOverlayProps): react_jsx_runtime.JSX.Element;
23
+ declare function DrawerContent({ className, children, showCloseButton, ...props }: DrawerContentProps): react_jsx_runtime.JSX.Element;
24
+ declare function DrawerHeader({ className, ...props }: DrawerHeaderProps): react_jsx_runtime.JSX.Element;
25
+ declare function DrawerFooter({ className, ...props }: DrawerFooterProps): react_jsx_runtime.JSX.Element;
26
+ declare function DrawerTitle({ className, ...props }: DrawerTitleProps): react_jsx_runtime.JSX.Element;
27
+ declare function DrawerDescription({ className, ...props }: DrawerDescriptionProps): react_jsx_runtime.JSX.Element;
28
+
29
+ export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger };
package/dist/drawer.js ADDED
@@ -0,0 +1,6 @@
1
+ export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from './chunk-PVX4VQFJ.js';
2
+ import './chunk-OUFYQLVN.js';
3
+ import './chunk-DIGOLJIR.js';
4
+ import './chunk-76UQO56T.js';
5
+ //# sourceMappingURL=drawer.js.map
6
+ //# sourceMappingURL=drawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"drawer.js"}
@@ -0,0 +1,16 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+
4
+ type EncryptedTextProps = React.ComponentProps<"span"> & {
5
+ text: string;
6
+ revealDelayMs?: number;
7
+ charset?: string;
8
+ flipDelayMs?: number;
9
+ encryptedClassName?: string;
10
+ revealedClassName?: string;
11
+ scrambleOnly?: boolean;
12
+ scrambleOneChar?: boolean;
13
+ };
14
+ declare function EncryptedText({ text, className, revealDelayMs, charset, flipDelayMs, encryptedClassName, revealedClassName, scrambleOnly, scrambleOneChar, ...props }: EncryptedTextProps): react_jsx_runtime.JSX.Element | null;
15
+
16
+ export { EncryptedText };
@@ -0,0 +1,141 @@
1
+ import { cn } from './chunk-76UQO56T.js';
2
+ import * as React from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ var DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[];:,.<>/?";
6
+ function randomChar(charset) {
7
+ return charset.charAt(Math.floor(Math.random() * charset.length));
8
+ }
9
+ function scramblePreservingSpaces(original, charset) {
10
+ if (!original) return "";
11
+ let result = "";
12
+ for (let i = 0; i < original.length; i += 1) {
13
+ result += original[i] === " " ? " " : randomChar(charset);
14
+ }
15
+ return result;
16
+ }
17
+ function EncryptedText({
18
+ text,
19
+ className,
20
+ revealDelayMs = 50,
21
+ charset = DEFAULT_CHARSET,
22
+ flipDelayMs = 50,
23
+ encryptedClassName,
24
+ revealedClassName,
25
+ scrambleOnly = false,
26
+ scrambleOneChar = false,
27
+ ...props
28
+ }) {
29
+ const ref = React.useRef(null);
30
+ const [isInView, setIsInView] = React.useState(false);
31
+ const [revealCount, setRevealCount] = React.useState(0);
32
+ const [, setFlipTick] = React.useState(0);
33
+ const animationFrameRef = React.useRef(null);
34
+ const startTimeRef = React.useRef(0);
35
+ const lastFlipTimeRef = React.useRef(0);
36
+ const scrambleCharsRef = React.useRef(
37
+ text ? scramblePreservingSpaces(text, charset).split("") : []
38
+ );
39
+ React.useEffect(() => {
40
+ const el = ref.current;
41
+ if (!el) return;
42
+ const observer = new IntersectionObserver(
43
+ ([entry]) => {
44
+ if (entry?.isIntersecting) {
45
+ setIsInView(true);
46
+ observer.disconnect();
47
+ }
48
+ },
49
+ { threshold: 0 }
50
+ );
51
+ observer.observe(el);
52
+ return () => observer.disconnect();
53
+ }, []);
54
+ React.useEffect(() => {
55
+ if (!isInView) return;
56
+ const initial = text ? scramblePreservingSpaces(text, charset) : "";
57
+ scrambleCharsRef.current = initial.split("");
58
+ startTimeRef.current = performance.now();
59
+ lastFlipTimeRef.current = startTimeRef.current;
60
+ setRevealCount(0);
61
+ let isCancelled = false;
62
+ const update = (now) => {
63
+ if (isCancelled) return;
64
+ const totalLength = text.length;
65
+ if (scrambleOnly) {
66
+ const timeSinceLastFlip2 = now - lastFlipTimeRef.current;
67
+ if (timeSinceLastFlip2 >= Math.max(0, flipDelayMs)) {
68
+ if (scrambleOneChar) {
69
+ const indices = [];
70
+ for (let i = 0; i < totalLength; i++) {
71
+ if (text[i] !== " ") indices.push(i);
72
+ }
73
+ if (indices.length > 0) {
74
+ const idx = indices[Math.floor(Math.random() * indices.length)];
75
+ scrambleCharsRef.current[idx] = randomChar(charset);
76
+ }
77
+ } else {
78
+ for (let index = 0; index < totalLength; index += 1) {
79
+ scrambleCharsRef.current[index] = text[index] === " " ? " " : randomChar(charset);
80
+ }
81
+ }
82
+ lastFlipTimeRef.current = now;
83
+ setFlipTick((t) => t + 1 & 65535);
84
+ }
85
+ animationFrameRef.current = requestAnimationFrame(update);
86
+ return;
87
+ }
88
+ const elapsedMs = now - startTimeRef.current;
89
+ const currentRevealCount = Math.min(
90
+ totalLength,
91
+ Math.floor(elapsedMs / Math.max(1, revealDelayMs))
92
+ );
93
+ setRevealCount(currentRevealCount);
94
+ if (currentRevealCount >= totalLength) return;
95
+ const timeSinceLastFlip = now - lastFlipTimeRef.current;
96
+ if (timeSinceLastFlip >= Math.max(0, flipDelayMs)) {
97
+ for (let index = currentRevealCount; index < totalLength; index += 1) {
98
+ scrambleCharsRef.current[index] = text[index] === " " ? " " : randomChar(charset);
99
+ }
100
+ lastFlipTimeRef.current = now;
101
+ }
102
+ animationFrameRef.current = requestAnimationFrame(update);
103
+ };
104
+ animationFrameRef.current = requestAnimationFrame(update);
105
+ return () => {
106
+ isCancelled = true;
107
+ if (animationFrameRef.current !== null) {
108
+ cancelAnimationFrame(animationFrameRef.current);
109
+ }
110
+ };
111
+ }, [isInView, text, revealDelayMs, charset, flipDelayMs, scrambleOnly, scrambleOneChar]);
112
+ if (!text) return null;
113
+ return /* @__PURE__ */ jsx(
114
+ "span",
115
+ {
116
+ ref,
117
+ "data-slot": "encrypted-text",
118
+ className,
119
+ "aria-label": text,
120
+ ...props,
121
+ children: text.split("").map((char, index) => {
122
+ const isRevealed = !scrambleOnly && index < revealCount;
123
+ const displayChar = isRevealed ? char : char === " " ? " " : scrambleCharsRef.current[index] ?? randomChar(charset);
124
+ return /* @__PURE__ */ jsx(
125
+ "span",
126
+ {
127
+ "data-slot": "encrypted-text-char",
128
+ "data-revealed": isRevealed || void 0,
129
+ className: cn(isRevealed ? revealedClassName : encryptedClassName),
130
+ children: displayChar
131
+ },
132
+ index
133
+ );
134
+ })
135
+ }
136
+ );
137
+ }
138
+
139
+ export { EncryptedText };
140
+ //# sourceMappingURL=encrypted-text.js.map
141
+ //# sourceMappingURL=encrypted-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/encrypted-text.tsx"],"names":["timeSinceLastFlip"],"mappings":"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","file":"encrypted-text.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\n\ntype EncryptedTextProps = React.ComponentProps<\"span\"> & {\n text: string\n revealDelayMs?: number\n charset?: string\n flipDelayMs?: number\n encryptedClassName?: string\n revealedClassName?: string\n scrambleOnly?: boolean\n scrambleOneChar?: boolean\n}\n\nconst DEFAULT_CHARSET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[];:,.<>/?\"\n\nfunction randomChar(charset: string): string {\n return charset.charAt(Math.floor(Math.random() * charset.length))\n}\n\nfunction scramblePreservingSpaces(original: string, charset: string): string {\n if (!original) return \"\"\n let result = \"\"\n for (let i = 0; i < original.length; i += 1) {\n result += original[i] === \" \" ? \" \" : randomChar(charset)\n }\n return result\n}\n\nfunction EncryptedText({\n text,\n className,\n revealDelayMs = 50,\n charset = DEFAULT_CHARSET,\n flipDelayMs = 50,\n encryptedClassName,\n revealedClassName,\n scrambleOnly = false,\n scrambleOneChar = false,\n ...props\n}: EncryptedTextProps) {\n const ref = React.useRef<HTMLSpanElement>(null)\n const [isInView, setIsInView] = React.useState(false)\n const [revealCount, setRevealCount] = React.useState(0)\n const [, setFlipTick] = React.useState(0)\n\n const animationFrameRef = React.useRef<number | null>(null)\n const startTimeRef = React.useRef(0)\n const lastFlipTimeRef = React.useRef(0)\n const scrambleCharsRef = React.useRef<string[]>(\n text ? scramblePreservingSpaces(text, charset).split(\"\") : []\n )\n\n React.useEffect(() => {\n const el = ref.current\n if (!el) return\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry?.isIntersecting) {\n setIsInView(true)\n observer.disconnect()\n }\n },\n { threshold: 0 }\n )\n\n observer.observe(el)\n return () => observer.disconnect()\n }, [])\n\n React.useEffect(() => {\n if (!isInView) return\n\n const initial = text\n ? scramblePreservingSpaces(text, charset)\n : \"\"\n scrambleCharsRef.current = initial.split(\"\")\n startTimeRef.current = performance.now()\n lastFlipTimeRef.current = startTimeRef.current\n setRevealCount(0)\n\n let isCancelled = false\n\n const update = (now: number) => {\n if (isCancelled) return\n\n const totalLength = text.length\n\n if (scrambleOnly) {\n const timeSinceLastFlip = now - lastFlipTimeRef.current\n if (timeSinceLastFlip >= Math.max(0, flipDelayMs)) {\n if (scrambleOneChar) {\n const indices: number[] = []\n for (let i = 0; i < totalLength; i++) {\n if (text[i] !== \" \") indices.push(i)\n }\n if (indices.length > 0) {\n const idx = indices[Math.floor(Math.random() * indices.length)]!\n scrambleCharsRef.current[idx] = randomChar(charset)\n }\n } else {\n for (let index = 0; index < totalLength; index += 1) {\n scrambleCharsRef.current[index] =\n text[index] === \" \" ? \" \" : randomChar(charset)\n }\n }\n lastFlipTimeRef.current = now\n setFlipTick((t) => (t + 1) & 0xffff)\n }\n animationFrameRef.current = requestAnimationFrame(update)\n return\n }\n\n const elapsedMs = now - startTimeRef.current\n const currentRevealCount = Math.min(\n totalLength,\n Math.floor(elapsedMs / Math.max(1, revealDelayMs))\n )\n\n setRevealCount(currentRevealCount)\n\n if (currentRevealCount >= totalLength) return\n\n const timeSinceLastFlip = now - lastFlipTimeRef.current\n if (timeSinceLastFlip >= Math.max(0, flipDelayMs)) {\n for (let index = currentRevealCount; index < totalLength; index += 1) {\n scrambleCharsRef.current[index] =\n text[index] === \" \" ? \" \" : randomChar(charset)\n }\n lastFlipTimeRef.current = now\n }\n\n animationFrameRef.current = requestAnimationFrame(update)\n }\n\n animationFrameRef.current = requestAnimationFrame(update)\n\n return () => {\n isCancelled = true\n if (animationFrameRef.current !== null) {\n cancelAnimationFrame(animationFrameRef.current)\n }\n }\n }, [isInView, text, revealDelayMs, charset, flipDelayMs, scrambleOnly, scrambleOneChar])\n\n if (!text) return null\n\n return (\n <span\n ref={ref}\n data-slot=\"encrypted-text\"\n className={className}\n aria-label={text}\n {...props}\n >\n {text.split(\"\").map((char, index) => {\n const isRevealed = !scrambleOnly && index < revealCount\n const displayChar = isRevealed\n ? char\n : char === \" \"\n ? \" \"\n : (scrambleCharsRef.current[index] ?? randomChar(charset))\n\n return (\n <span\n key={index}\n data-slot=\"encrypted-text-char\"\n data-revealed={isRevealed || undefined}\n className={cn(isRevealed ? revealedClassName : encryptedClassName)}\n >\n {displayChar}\n </span>\n )\n })}\n </span>\n )\n}\n\nexport { EncryptedText }\n"]}
@@ -0,0 +1,22 @@
1
+ import * as _base_ui_react from '@base-ui/react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { Field as Field$1 } from '@base-ui/react/field';
5
+ export { Field as FieldPrimitive } from '@base-ui/react/field';
6
+
7
+ type FieldProps = React.ComponentProps<typeof Field$1.Root>;
8
+ type FieldLabelProps = React.ComponentProps<typeof Field$1.Label>;
9
+ type FieldDescriptionProps = React.ComponentProps<typeof Field$1.Description>;
10
+ type FieldItemProps = React.ComponentProps<typeof Field$1.Item>;
11
+ type FieldErrorProps = React.ComponentProps<typeof Field$1.Error>;
12
+ type FieldValidityProps = React.ComponentProps<typeof Field$1.Validity>;
13
+ type FieldControlProps = React.ComponentPropsWithoutRef<typeof Field$1.Control>;
14
+ declare function Field({ className, ...props }: FieldProps): react_jsx_runtime.JSX.Element;
15
+ declare function FieldLabel({ className, ...props }: FieldLabelProps): react_jsx_runtime.JSX.Element;
16
+ declare const FieldControl: React.ForwardRefExoticComponent<Omit<Omit<_base_ui_react.FieldControlProps, "ref"> & React.RefAttributes<HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
17
+ declare function FieldDescription({ className, ...props }: FieldDescriptionProps): react_jsx_runtime.JSX.Element;
18
+ declare function FieldItem({ className, ...props }: FieldItemProps): react_jsx_runtime.JSX.Element;
19
+ declare function FieldError({ className, ...props }: FieldErrorProps): react_jsx_runtime.JSX.Element;
20
+ declare const FieldValidity: React.FC<_base_ui_react.FieldValidityProps>;
21
+
22
+ export { Field, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, FieldItem, type FieldItemProps, FieldLabel, type FieldLabelProps, type FieldProps, FieldValidity, type FieldValidityProps };
package/dist/field.js ADDED
@@ -0,0 +1,4 @@
1
+ export { Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldPrimitive, FieldValidity } from './chunk-NCHHHWTB.js';
2
+ import './chunk-76UQO56T.js';
3
+ //# sourceMappingURL=field.js.map
4
+ //# sourceMappingURL=field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"field.js"}
package/dist/form.d.ts ADDED
@@ -0,0 +1,80 @@
1
+ import * as react_hook_form from 'react-hook-form';
2
+ import { FieldValues, UseFormReturn, SubmitHandler, FieldPath, RegisterOptions, ControllerRenderProps, ControllerFieldState } from 'react-hook-form';
3
+ export { useForm } from 'react-hook-form';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import * as React from 'react';
6
+ import { Form as Form$1 } from '@base-ui/react/form';
7
+ import { Field } from './field.js';
8
+ import '@base-ui/react';
9
+ import '@base-ui/react/field';
10
+
11
+ type FormProps<TFieldValues extends FieldValues> = {
12
+ form: UseFormReturn<TFieldValues>;
13
+ onSubmit: SubmitHandler<TFieldValues>;
14
+ } & Omit<React.ComponentProps<typeof Form$1>, "onSubmit">;
15
+ type FormRootProps = React.ComponentProps<typeof Form$1>;
16
+ type FormErrorProps = React.ComponentProps<"p">;
17
+ type FormActionsProps = React.ComponentProps<"div">;
18
+ type FormMessageProps = React.ComponentProps<"p">;
19
+ declare function Form<TFieldValues extends FieldValues>({ form, onSubmit, ...props }: FormProps<TFieldValues>): react_jsx_runtime.JSX.Element;
20
+ /**
21
+ * Base UI form element.
22
+ *
23
+ * This is the element that actually renders the <form> tag.
24
+ */
25
+ declare function FormRoot({ className, ...props }: FormRootProps): react_jsx_runtime.JSX.Element;
26
+ type FormFieldRenderArgs<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>> = {
27
+ id: string;
28
+ field: ControllerRenderProps<TFieldValues, TName>;
29
+ fieldState: ControllerFieldState;
30
+ };
31
+ type FormFieldProps<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>> = {
32
+ name: TName;
33
+ id?: string;
34
+ required?: boolean;
35
+ label?: React.ReactNode;
36
+ description?: React.ReactNode;
37
+ rules?: RegisterOptions<TFieldValues, TName>;
38
+ /**
39
+ * Render the actual control.
40
+ *
41
+ * - For Base UI controls, prefer `onValueChange`.
42
+ * - For native/standard inputs, use `onChange`.
43
+ *
44
+ * Use `fieldControlProps(field)` to get both.
45
+ */
46
+ render: (args: FormFieldRenderArgs<TFieldValues, TName>) => React.ReactNode;
47
+ } & Omit<React.ComponentProps<typeof Field>, "children" | "name" | "invalid" | "touched" | "dirty" | "render">;
48
+ /**
49
+ * Base UI + React Hook Form field helper.
50
+ *
51
+ * It maps RHF Controller state onto Base UI's <Field> state so styling can
52
+ * rely on `data-[invalid]`, `data-[touched]`, `data-[dirty]`, etc.
53
+ */
54
+ declare function FormField<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>(props: FormFieldProps<TFieldValues, TName>): react_jsx_runtime.JSX.Element;
55
+ declare function FormError({ className, ...props }: FormErrorProps): react_jsx_runtime.JSX.Element | null;
56
+ declare function FormActions({ className, ...props }: FormActionsProps): react_jsx_runtime.JSX.Element;
57
+ declare function FormMessage({ className, ...props }: FormMessageProps): react_jsx_runtime.JSX.Element;
58
+ /**
59
+ * Convenience helper for mapping RHF field props onto either:
60
+ * - Base UI controls (use `onValueChange`)
61
+ * - Native/standard inputs (use `onChange`)
62
+ */
63
+ declare function fieldControlProps<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>(field: ControllerRenderProps<TFieldValues, TName>, opts?: {
64
+ id?: string;
65
+ describedBy?: string;
66
+ invalid?: boolean;
67
+ native?: boolean;
68
+ }): {
69
+ "aria-describedby": string | undefined;
70
+ "aria-invalid": boolean | undefined;
71
+ onValueChange?: ((...event: any[]) => void) | undefined;
72
+ id: string | undefined;
73
+ name: TName;
74
+ ref: react_hook_form.RefCallBack;
75
+ value: string;
76
+ onBlur: react_hook_form.Noop;
77
+ onChange: (...event: any[]) => void;
78
+ };
79
+
80
+ export { Form, FormActions, FormError, FormField, type FormFieldProps, type FormFieldRenderArgs, FormMessage, FormRoot, fieldControlProps };
package/dist/form.js ADDED
@@ -0,0 +1,108 @@
1
+ import { Field, FieldLabel, FieldDescription, FieldError } from './chunk-NCHHHWTB.js';
2
+ import { cn } from './chunk-76UQO56T.js';
3
+ import * as React from 'react';
4
+ import { Form as Form$1 } from '@base-ui/react/form';
5
+ import { FormProvider, useFormContext, Controller } from 'react-hook-form';
6
+ export { useForm } from 'react-hook-form';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ function Form({ form, onSubmit, ...props }) {
10
+ return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx(FormRoot, { ...props, onSubmit: form.handleSubmit(onSubmit) }) });
11
+ }
12
+ function FormRoot({ className, ...props }) {
13
+ return /* @__PURE__ */ jsx(Form$1, { "data-slot": "form", className: cn("flex flex-col gap-6", className), ...props });
14
+ }
15
+ function FormField(props) {
16
+ const { name, id, required, label, description, rules, render, ...rootProps } = props;
17
+ const { control } = useFormContext();
18
+ const reactId = React.useId();
19
+ const safeName = String(name).replace(/[^a-zA-Z0-9_-]/g, "-");
20
+ const controlId = id ?? `field-${safeName}-${reactId}`;
21
+ const inferredRequired = (() => {
22
+ if (!rules || !("required" in rules)) return false;
23
+ const req = rules.required;
24
+ if (typeof req === "boolean") return req;
25
+ if (typeof req === "string") return true;
26
+ if (req && typeof req === "object" && "value" in req) {
27
+ return Boolean(req.value);
28
+ }
29
+ return Boolean(req);
30
+ })();
31
+ const isRequired = required ?? inferredRequired;
32
+ return /* @__PURE__ */ jsx(
33
+ Controller,
34
+ {
35
+ name,
36
+ control,
37
+ rules,
38
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsxs(
39
+ Field,
40
+ {
41
+ ...rootProps,
42
+ name: field.name,
43
+ invalid: fieldState.invalid,
44
+ touched: fieldState.isTouched,
45
+ dirty: fieldState.isDirty,
46
+ children: [
47
+ label ? /* @__PURE__ */ jsxs(FieldLabel, { children: [
48
+ label,
49
+ isRequired ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-destructive ml-1", children: "*" }) : null
50
+ ] }) : null,
51
+ description ? /* @__PURE__ */ jsx(FieldDescription, { children: description }) : null,
52
+ render({ id: controlId, field, fieldState }),
53
+ fieldState.error ? /* @__PURE__ */ jsx(FieldError, { children: fieldState.error.message }) : null
54
+ ]
55
+ }
56
+ )
57
+ }
58
+ );
59
+ }
60
+ function FormError({ className, ...props }) {
61
+ const {
62
+ formState: { errors }
63
+ } = useFormContext();
64
+ const message = errors?.root && typeof errors.root?.message === "string" ? String(errors.root?.message) : null;
65
+ if (!message) return null;
66
+ return /* @__PURE__ */ jsx(
67
+ "p",
68
+ {
69
+ "data-slot": "form-error",
70
+ className: cn(
71
+ "text-destructive rounded-2xl border border-destructive/30 bg-destructive/5 p-4 text-sm",
72
+ className
73
+ ),
74
+ ...props,
75
+ children: message
76
+ }
77
+ );
78
+ }
79
+ function FormActions({ className, ...props }) {
80
+ return /* @__PURE__ */ jsx(
81
+ "div",
82
+ {
83
+ "data-slot": "form-actions",
84
+ className: cn("flex flex-wrap items-center gap-2", className),
85
+ ...props
86
+ }
87
+ );
88
+ }
89
+ function FormMessage({ className, ...props }) {
90
+ return /* @__PURE__ */ jsx("p", { "data-slot": "form-message", className: cn("text-sm text-foreground/80", className), ...props });
91
+ }
92
+ function fieldControlProps(field, opts) {
93
+ return {
94
+ id: opts?.id,
95
+ name: field.name,
96
+ ref: field.ref,
97
+ value: field.value ?? "",
98
+ onBlur: field.onBlur,
99
+ onChange: field.onChange,
100
+ ...opts?.native ? {} : { onValueChange: field.onChange },
101
+ "aria-describedby": opts?.describedBy,
102
+ "aria-invalid": opts?.invalid
103
+ };
104
+ }
105
+
106
+ export { Form, FormActions, FormError, FormField, FormMessage, FormRoot, fieldControlProps };
107
+ //# sourceMappingURL=form.js.map
108
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/form.tsx"],"names":["FormPrimitive"],"mappings":"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","file":"form.js","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Form as FormPrimitive } from \"@base-ui/react/form\";\nimport {\n Controller,\n FormProvider,\n useFormContext,\n useForm,\n type SubmitHandler,\n type UseFormReturn,\n type ControllerFieldState,\n type ControllerRenderProps,\n type FieldPath,\n type FieldValues,\n type RegisterOptions,\n} from \"react-hook-form\";\n\nimport { Field, FieldDescription, FieldError, FieldLabel } from \"./field\";\n\nimport { cn } from \"./lib/utils\";\n\ntype FormProps<TFieldValues extends FieldValues> = {\n form: UseFormReturn<TFieldValues>;\n onSubmit: SubmitHandler<TFieldValues>;\n} & Omit<React.ComponentProps<typeof FormPrimitive>, \"onSubmit\">;\n\ntype FormRootProps = React.ComponentProps<typeof FormPrimitive>;\ntype FormErrorProps = React.ComponentProps<\"p\">;\ntype FormActionsProps = React.ComponentProps<\"div\">;\ntype FormMessageProps = React.ComponentProps<\"p\">;\n\nfunction Form<TFieldValues extends FieldValues>({ form, onSubmit, ...props }: FormProps<TFieldValues>) {\n return (\n <FormProvider {...form}>\n <FormRoot {...props} onSubmit={form.handleSubmit(onSubmit)} />\n </FormProvider>\n );\n}\n\n/**\n * Base UI form element.\n *\n * This is the element that actually renders the <form> tag.\n */\nfunction FormRoot({ className, ...props }: FormRootProps) {\n return (\n <FormPrimitive data-slot=\"form\" className={cn(\"flex flex-col gap-6\", className)} {...props} />\n );\n}\n\ntype FormFieldRenderArgs<\n TFieldValues extends FieldValues,\n TName extends FieldPath<TFieldValues>,\n> = {\n id: string;\n field: ControllerRenderProps<TFieldValues, TName>;\n fieldState: ControllerFieldState;\n};\n\ntype FormFieldProps<\n TFieldValues extends FieldValues,\n TName extends FieldPath<TFieldValues>,\n> = {\n name: TName;\n id?: string;\n required?: boolean;\n label?: React.ReactNode;\n description?: React.ReactNode;\n rules?: RegisterOptions<TFieldValues, TName>;\n /**\n * Render the actual control.\n *\n * - For Base UI controls, prefer `onValueChange`.\n * - For native/standard inputs, use `onChange`.\n *\n * Use `fieldControlProps(field)` to get both.\n */\n render: (args: FormFieldRenderArgs<TFieldValues, TName>) => React.ReactNode;\n} & Omit<\n React.ComponentProps<typeof Field>,\n \"children\" | \"name\" | \"invalid\" | \"touched\" | \"dirty\" | \"render\"\n>;\n\n/**\n * Base UI + React Hook Form field helper.\n *\n * It maps RHF Controller state onto Base UI's <Field> state so styling can\n * rely on `data-[invalid]`, `data-[touched]`, `data-[dirty]`, etc.\n */\nfunction FormField<\n TFieldValues extends FieldValues,\n TName extends FieldPath<TFieldValues>,\n>(props: FormFieldProps<TFieldValues, TName>) {\n const { name, id, required, label, description, rules, render, ...rootProps } = props;\n const { control } = useFormContext<TFieldValues>();\n\n const reactId = React.useId();\n const safeName = String(name).replace(/[^a-zA-Z0-9_-]/g, \"-\");\n const controlId = id ?? `field-${safeName}-${reactId}`;\n\n const inferredRequired = (() => {\n if (!rules || !(\"required\" in rules)) return false;\n const req = (rules as { required?: unknown }).required;\n if (typeof req === \"boolean\") return req;\n if (typeof req === \"string\") return true;\n if (req && typeof req === \"object\" && \"value\" in (req as Record<string, unknown>)) {\n return Boolean((req as { value?: unknown }).value);\n }\n return Boolean(req);\n })();\n\n const isRequired = required ?? inferredRequired;\n\n return (\n <Controller\n name={name}\n control={control}\n rules={rules}\n render={({ field, fieldState }) => (\n <Field\n {...rootProps}\n name={field.name}\n invalid={fieldState.invalid}\n touched={fieldState.isTouched}\n dirty={fieldState.isDirty}\n >\n {label ? (\n <FieldLabel>\n {label}\n {isRequired ? (\n <span aria-hidden=\"true\" className=\"text-destructive ml-1\">\n *\n </span>\n ) : null}\n </FieldLabel>\n ) : null}\n {description ? <FieldDescription>{description}</FieldDescription> : null}\n\n {render({ id: controlId, field, fieldState })}\n\n {fieldState.error ? (\n <FieldError>{fieldState.error.message}</FieldError>\n ) : null}\n </Field>\n )}\n />\n );\n}\n\nfunction FormError({ className, ...props }: FormErrorProps) {\n const {\n formState: { errors },\n } = useFormContext();\n\n const message =\n (errors as Record<string, unknown>)?.root &&\n typeof (errors as { root?: { message?: unknown } }).root?.message === \"string\"\n ? String((errors as { root?: { message?: unknown } }).root?.message)\n : null;\n\n if (!message) return null;\n\n return (\n <p\n data-slot=\"form-error\"\n className={cn(\n \"text-destructive rounded-2xl border border-destructive/30 bg-destructive/5 p-4 text-sm\",\n className,\n )}\n {...props}\n >\n {message}\n </p>\n );\n}\n\nfunction FormActions({ className, ...props }: FormActionsProps) {\n return (\n <div\n data-slot=\"form-actions\"\n className={cn(\"flex flex-wrap items-center gap-2\", className)}\n {...props}\n />\n );\n}\n\nfunction FormMessage({ className, ...props }: FormMessageProps) {\n return (\n <p data-slot=\"form-message\" className={cn(\"text-sm text-foreground/80\", className)} {...props} />\n );\n}\n\n/**\n * Convenience helper for mapping RHF field props onto either:\n * - Base UI controls (use `onValueChange`)\n * - Native/standard inputs (use `onChange`)\n */\nfunction fieldControlProps<\n TFieldValues extends FieldValues,\n TName extends FieldPath<TFieldValues>,\n>(\n field: ControllerRenderProps<TFieldValues, TName>,\n opts?: {\n id?: string;\n describedBy?: string;\n invalid?: boolean;\n native?: boolean;\n },\n) {\n return {\n id: opts?.id,\n name: field.name,\n ref: field.ref,\n value: field.value ?? \"\",\n onBlur: field.onBlur,\n onChange: field.onChange,\n ...(opts?.native ? {} : { onValueChange: field.onChange }),\n \"aria-describedby\": opts?.describedBy,\n \"aria-invalid\": opts?.invalid,\n };\n}\n\nexport {\n Form,\n FormRoot,\n FormField,\n FormError,\n FormActions,\n FormMessage,\n fieldControlProps,\n useForm,\n type FormFieldRenderArgs,\n type FormFieldProps,\n};\n"]}
@@ -1,3 +1,8 @@
1
- declare function useIsMobile(): boolean;
1
+ /**
2
+ * Returns `true` when the viewport is below the given breakpoint.
3
+ *
4
+ * @param breakpoint - Width in pixels. Defaults to 768.
5
+ */
6
+ declare function useIsMobile(breakpoint?: number): boolean;
2
7
 
3
8
  export { useIsMobile };
@@ -1,20 +1,3 @@
1
- import * as React from 'react';
2
-
3
- var MOBILE_BREAKPOINT = 768;
4
- function useIsMobile() {
5
- const [isMobile, setIsMobile] = React.useState(void 0);
6
- React.useEffect(() => {
7
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
8
- const onChange = () => {
9
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
10
- };
11
- mql.addEventListener("change", onChange);
12
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
13
- return () => mql.removeEventListener("change", onChange);
14
- }, []);
15
- return !!isMobile;
16
- }
17
-
18
- export { useIsMobile };
1
+ export { useIsMobile } from '../chunk-ZZZH3JGW.js';
19
2
  //# sourceMappingURL=use-mobile.js.map
20
3
  //# sourceMappingURL=use-mobile.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/use-mobile.ts"],"names":[],"mappings":";;AAIA,IAAM,iBAAA,GAAoB,GAAA;AAEnB,SAAS,WAAA,GAAc;AAC5B,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAU,eAA8B,MAAS,CAAA;AAE7E,EAAM,gBAAU,MAAM;AACpB,IAAA,MAAM,MAAM,MAAA,CAAO,UAAA,CAAW,CAAA,YAAA,EAAe,iBAAA,GAAoB,CAAC,CAAA,GAAA,CAAK,CAAA;AACvE,IAAA,MAAM,WAAW,MAAM;AACrB,MAAA,WAAA,CAAY,MAAA,CAAO,aAAa,iBAAiB,CAAA;AAAA,IACnD,CAAA;AACA,IAAA,GAAA,CAAI,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AACvC,IAAA,WAAA,CAAY,MAAA,CAAO,aAAa,iBAAiB,CAAA;AACjD,IAAA,OAAO,MAAM,GAAA,CAAI,mBAAA,CAAoB,QAAA,EAAU,QAAQ,CAAA;AAAA,EACzD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,CAAC,CAAC,QAAA;AACX","file":"use-mobile.js","sourcesContent":["'use client';\n\nimport * as React from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return !!isMobile;\n}\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"use-mobile.js"}
@@ -0,0 +1,19 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+
4
+ type InfiniteScrollProps = {
5
+ onLoadMore: () => void;
6
+ hasMore: boolean;
7
+ isLoading?: boolean;
8
+ direction?: "down" | "up";
9
+ root?: React.RefObject<Element | null>;
10
+ rootMargin?: string;
11
+ threshold?: number;
12
+ loader?: React.ReactNode;
13
+ endMessage?: React.ReactNode;
14
+ className?: string;
15
+ children?: React.ReactNode;
16
+ };
17
+ declare function InfiniteScroll({ onLoadMore, hasMore, isLoading, direction, root, rootMargin, threshold, loader, endMessage, className, children, }: InfiniteScrollProps): react_jsx_runtime.JSX.Element;
18
+
19
+ export { InfiniteScroll, type InfiniteScrollProps };
@@ -0,0 +1,102 @@
1
+ import { Spinner } from './chunk-6Y7LPQMO.js';
2
+ import './chunk-DIGOLJIR.js';
3
+ import { cn } from './chunk-76UQO56T.js';
4
+ import * as React from 'react';
5
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
+
7
+ function InfiniteScroll({
8
+ onLoadMore,
9
+ hasMore,
10
+ isLoading = false,
11
+ direction = "down",
12
+ root,
13
+ rootMargin = "200px",
14
+ threshold = 0,
15
+ loader,
16
+ endMessage,
17
+ className,
18
+ children
19
+ }) {
20
+ const sentinelRef = React.useRef(null);
21
+ const loadingRef = React.useRef(false);
22
+ const onLoadMoreRef = React.useRef(onLoadMore);
23
+ React.useEffect(() => {
24
+ onLoadMoreRef.current = onLoadMore;
25
+ }, [onLoadMore]);
26
+ React.useEffect(() => {
27
+ if (!isLoading) {
28
+ loadingRef.current = false;
29
+ }
30
+ }, [isLoading]);
31
+ React.useEffect(() => {
32
+ const sentinel2 = sentinelRef.current;
33
+ if (!sentinel2 || !hasMore) return;
34
+ const observer = new IntersectionObserver(
35
+ (entries) => {
36
+ const [entry] = entries;
37
+ if (entry?.isIntersecting && !loadingRef.current) {
38
+ loadingRef.current = true;
39
+ onLoadMoreRef.current();
40
+ }
41
+ },
42
+ {
43
+ root: root?.current ?? null,
44
+ rootMargin,
45
+ threshold
46
+ }
47
+ );
48
+ observer.observe(sentinel2);
49
+ return () => {
50
+ observer.disconnect();
51
+ };
52
+ }, [hasMore, root, rootMargin, threshold]);
53
+ const loaderContent = isLoading && /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ "data-slot": "infinite-scroll-loader",
57
+ className: "flex items-center justify-center py-6",
58
+ children: loader ?? /* @__PURE__ */ jsx(Spinner, { className: "size-6 text-muted-foreground" })
59
+ }
60
+ );
61
+ const endContent = !hasMore && !isLoading && endMessage && /* @__PURE__ */ jsx(
62
+ "div",
63
+ {
64
+ "data-slot": "infinite-scroll-end",
65
+ className: "flex items-center justify-center py-6 text-sm text-muted-foreground",
66
+ children: endMessage
67
+ }
68
+ );
69
+ const sentinel = /* @__PURE__ */ jsx(
70
+ "div",
71
+ {
72
+ ref: sentinelRef,
73
+ "data-slot": "infinite-scroll-sentinel",
74
+ "aria-hidden": "true",
75
+ className: "h-px"
76
+ }
77
+ );
78
+ return /* @__PURE__ */ jsxs(
79
+ "div",
80
+ {
81
+ "data-slot": "infinite-scroll",
82
+ "aria-busy": isLoading,
83
+ className: cn("flex flex-col", className),
84
+ children: [
85
+ direction === "up" && /* @__PURE__ */ jsxs(Fragment, { children: [
86
+ sentinel,
87
+ loaderContent
88
+ ] }),
89
+ children,
90
+ direction === "down" && /* @__PURE__ */ jsxs(Fragment, { children: [
91
+ sentinel,
92
+ loaderContent
93
+ ] }),
94
+ endContent
95
+ ]
96
+ }
97
+ );
98
+ }
99
+
100
+ export { InfiniteScroll };
101
+ //# sourceMappingURL=infinite-scroll.js.map
102
+ //# sourceMappingURL=infinite-scroll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/infinite-scroll.tsx"],"names":["sentinel"],"mappings":"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","file":"infinite-scroll.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\nimport { Spinner } from \"./spinner\"\n\ntype InfiniteScrollProps = {\n onLoadMore: () => void\n hasMore: boolean\n isLoading?: boolean\n direction?: \"down\" | \"up\"\n root?: React.RefObject<Element | null>\n rootMargin?: string\n threshold?: number\n loader?: React.ReactNode\n endMessage?: React.ReactNode\n className?: string\n children?: React.ReactNode\n}\n\nfunction InfiniteScroll({\n onLoadMore,\n hasMore,\n isLoading = false,\n direction = \"down\",\n root,\n rootMargin = \"200px\",\n threshold = 0,\n loader,\n endMessage,\n className,\n children,\n}: InfiniteScrollProps) {\n const sentinelRef = React.useRef<HTMLDivElement>(null)\n const loadingRef = React.useRef(false)\n\n const onLoadMoreRef = React.useRef(onLoadMore)\n React.useEffect(() => {\n onLoadMoreRef.current = onLoadMore\n }, [onLoadMore])\n\n React.useEffect(() => {\n if (!isLoading) {\n loadingRef.current = false\n }\n }, [isLoading])\n\n React.useEffect(() => {\n const sentinel = sentinelRef.current\n if (!sentinel || !hasMore) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const [entry] = entries\n if (entry?.isIntersecting && !loadingRef.current) {\n loadingRef.current = true\n onLoadMoreRef.current()\n }\n },\n {\n root: root?.current ?? null,\n rootMargin,\n threshold,\n }\n )\n\n observer.observe(sentinel)\n\n return () => {\n observer.disconnect()\n }\n }, [hasMore, root, rootMargin, threshold])\n\n const loaderContent = isLoading && (\n <div\n data-slot=\"infinite-scroll-loader\"\n className=\"flex items-center justify-center py-6\"\n >\n {loader ?? <Spinner className=\"size-6 text-muted-foreground\" />}\n </div>\n )\n\n const endContent = !hasMore && !isLoading && endMessage && (\n <div\n data-slot=\"infinite-scroll-end\"\n className=\"flex items-center justify-center py-6 text-sm text-muted-foreground\"\n >\n {endMessage}\n </div>\n )\n\n const sentinel = (\n <div\n ref={sentinelRef}\n data-slot=\"infinite-scroll-sentinel\"\n aria-hidden=\"true\"\n className=\"h-px\"\n />\n )\n\n return (\n <div\n data-slot=\"infinite-scroll\"\n aria-busy={isLoading}\n className={cn(\"flex flex-col\", className)}\n >\n {direction === \"up\" && (\n <>\n {sentinel}\n {loaderContent}\n </>\n )}\n\n {children}\n\n {direction === \"down\" && (\n <>\n {sentinel}\n {loaderContent}\n </>\n )}\n\n {endContent}\n </div>\n )\n}\n\nexport { InfiniteScroll, type InfiniteScrollProps }\n"]}