@waveso/ui 0.0.10 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/dist/accordion.d.ts +24 -8
  2. package/dist/accordion.d.ts.map +1 -0
  3. package/dist/accordion.js +50 -73
  4. package/dist/accordion.js.map +1 -1
  5. package/dist/action-bar.d.ts +83 -0
  6. package/dist/action-bar.d.ts.map +1 -0
  7. package/dist/action-bar.js +264 -0
  8. package/dist/action-bar.js.map +1 -0
  9. package/dist/alert-dialog.d.ts +56 -21
  10. package/dist/alert-dialog.d.ts.map +1 -0
  11. package/dist/alert-dialog.js +75 -127
  12. package/dist/alert-dialog.js.map +1 -1
  13. package/dist/alert.d.ts +26 -11
  14. package/dist/alert.d.ts.map +1 -0
  15. package/dist/alert.js +37 -68
  16. package/dist/alert.js.map +1 -1
  17. package/dist/animate.d.ts +117 -75
  18. package/dist/animate.d.ts.map +1 -0
  19. package/dist/animate.js +259 -223
  20. package/dist/animate.js.map +1 -1
  21. package/dist/aspect-ratio.d.ts +11 -6
  22. package/dist/aspect-ratio.d.ts.map +1 -0
  23. package/dist/aspect-ratio.js +12 -14
  24. package/dist/aspect-ratio.js.map +1 -1
  25. package/dist/autocomplete.d.ts +91 -25
  26. package/dist/autocomplete.d.ts.map +1 -0
  27. package/dist/autocomplete.js +119 -181
  28. package/dist/autocomplete.js.map +1 -1
  29. package/dist/avatar.d.ts +32 -11
  30. package/dist/avatar.d.ts.map +1 -0
  31. package/dist/avatar.js +42 -89
  32. package/dist/avatar.js.map +1 -1
  33. package/dist/badge.d.ts +15 -8
  34. package/dist/badge.d.ts.map +1 -0
  35. package/dist/badge.js +34 -48
  36. package/dist/badge.js.map +1 -1
  37. package/dist/breadcrumb.d.ts +35 -11
  38. package/dist/breadcrumb.d.ts.map +1 -0
  39. package/dist/breadcrumb.js +60 -110
  40. package/dist/breadcrumb.js.map +1 -1
  41. package/dist/button-group.d.ts +26 -13
  42. package/dist/button-group.d.ts.map +1 -0
  43. package/dist/button-group.js +38 -76
  44. package/dist/button-group.js.map +1 -1
  45. package/dist/button.d.ts +17 -10
  46. package/dist/button.d.ts.map +1 -0
  47. package/dist/button.js +50 -3
  48. package/dist/button.js.map +1 -1
  49. package/dist/card.d.ts +35 -11
  50. package/dist/card.d.ts.map +1 -0
  51. package/dist/card.js +43 -82
  52. package/dist/card.js.map +1 -1
  53. package/dist/checkbox.d.ts +6 -4
  54. package/dist/checkbox.d.ts.map +1 -0
  55. package/dist/checkbox.js +21 -29
  56. package/dist/checkbox.js.map +1 -1
  57. package/dist/collapsible.d.ts +15 -7
  58. package/dist/collapsible.d.ts.map +1 -0
  59. package/dist/collapsible.js +19 -8
  60. package/dist/collapsible.js.map +1 -1
  61. package/dist/combobox.d.ts +83 -23
  62. package/dist/combobox.d.ts.map +1 -0
  63. package/dist/combobox.js +149 -247
  64. package/dist/combobox.js.map +1 -1
  65. package/dist/context-menu.d.ts +80 -26
  66. package/dist/context-menu.d.ts.map +1 -0
  67. package/dist/context-menu.js +108 -164
  68. package/dist/context-menu.js.map +1 -1
  69. package/dist/count.d.ts +45 -31
  70. package/dist/count.d.ts.map +1 -0
  71. package/dist/count.js +170 -165
  72. package/dist/count.js.map +1 -1
  73. package/dist/dialog.d.ts +61 -28
  74. package/dist/dialog.d.ts.map +1 -0
  75. package/dist/dialog.js +77 -120
  76. package/dist/dialog.js.map +1 -1
  77. package/dist/direction.d.ts +2 -1
  78. package/dist/direction.js +3 -3
  79. package/dist/drawer.d.ts +45 -15
  80. package/dist/drawer.d.ts.map +1 -0
  81. package/dist/drawer.js +93 -5
  82. package/dist/drawer.js.map +1 -1
  83. package/dist/encrypted-text.d.ts +25 -12
  84. package/dist/encrypted-text.d.ts.map +1 -0
  85. package/dist/encrypted-text.js +102 -134
  86. package/dist/encrypted-text.js.map +1 -1
  87. package/dist/field.d.ts +37 -21
  88. package/dist/field.d.ts.map +1 -0
  89. package/dist/field.js +52 -3
  90. package/dist/field.js.map +1 -1
  91. package/dist/film-grain-shader.d.ts +6 -0
  92. package/dist/film-grain-shader.d.ts.map +1 -0
  93. package/dist/film-grain-shader.js +88 -0
  94. package/dist/film-grain-shader.js.map +1 -0
  95. package/dist/film-grain-webgl.d.ts +20 -0
  96. package/dist/film-grain-webgl.d.ts.map +1 -0
  97. package/dist/film-grain-webgl.js +306 -0
  98. package/dist/film-grain-webgl.js.map +1 -0
  99. package/dist/film-grain.d.ts +21 -11
  100. package/dist/film-grain.d.ts.map +1 -0
  101. package/dist/film-grain.js +28 -420
  102. package/dist/film-grain.js.map +1 -1
  103. package/dist/form.d.ts +64 -49
  104. package/dist/form.d.ts.map +1 -0
  105. package/dist/form.js +112 -91
  106. package/dist/form.js.map +1 -1
  107. package/dist/gradient-reveal-text.d.ts +35 -22
  108. package/dist/gradient-reveal-text.d.ts.map +1 -0
  109. package/dist/gradient-reveal-text.js +238 -205
  110. package/dist/gradient-reveal-text.js.map +1 -1
  111. package/dist/hooks/use-mobile.d.ts +3 -1
  112. package/dist/hooks/use-mobile.d.ts.map +1 -0
  113. package/dist/hooks/use-mobile.js +28 -2
  114. package/dist/hooks/use-mobile.js.map +1 -1
  115. package/dist/infinite-scroll.d.ts +29 -15
  116. package/dist/infinite-scroll.d.ts.map +1 -0
  117. package/dist/infinite-scroll.js +69 -99
  118. package/dist/infinite-scroll.js.map +1 -1
  119. package/dist/input-group.d.ts +41 -18
  120. package/dist/input-group.d.ts.map +1 -0
  121. package/dist/input-group.js +80 -6
  122. package/dist/input-group.js.map +1 -1
  123. package/dist/input-otp.d.ts +26 -10
  124. package/dist/input-otp.d.ts.map +1 -0
  125. package/dist/input-otp.js +40 -70
  126. package/dist/input-otp.js.map +1 -1
  127. package/dist/input.d.ts +10 -4
  128. package/dist/input.d.ts.map +1 -0
  129. package/dist/input.js +16 -3
  130. package/dist/input.js.map +1 -1
  131. package/dist/item.d.ts +58 -23
  132. package/dist/item.d.ts.map +1 -0
  133. package/dist/item.js +102 -160
  134. package/dist/item.js.map +1 -1
  135. package/dist/kbd.d.ts +12 -4
  136. package/dist/kbd.d.ts.map +1 -0
  137. package/dist/kbd.js +15 -24
  138. package/dist/kbd.js.map +1 -1
  139. package/dist/label.d.ts +9 -4
  140. package/dist/label.d.ts.map +1 -0
  141. package/dist/label.js +12 -16
  142. package/dist/label.js.map +1 -1
  143. package/dist/lib/focus.d.ts +42 -0
  144. package/dist/lib/focus.d.ts.map +1 -0
  145. package/dist/lib/focus.js +21 -0
  146. package/dist/lib/focus.js.map +1 -0
  147. package/dist/lib/internal-icons.d.ts +32 -0
  148. package/dist/lib/internal-icons.d.ts.map +1 -0
  149. package/dist/lib/internal-icons.js +222 -0
  150. package/dist/lib/internal-icons.js.map +1 -0
  151. package/dist/lib/utils.d.ts +4 -2
  152. package/dist/lib/utils.d.ts.map +1 -0
  153. package/dist/lib/utils.js +12 -2
  154. package/dist/lib/utils.js.map +1 -1
  155. package/dist/masonry.d.ts +25 -11
  156. package/dist/masonry.d.ts.map +1 -0
  157. package/dist/masonry.js +188 -229
  158. package/dist/masonry.js.map +1 -1
  159. package/dist/menu.d.ts +84 -26
  160. package/dist/menu.d.ts.map +1 -0
  161. package/dist/menu.js +141 -4
  162. package/dist/menu.js.map +1 -1
  163. package/dist/menubar.d.ts +60 -22
  164. package/dist/menubar.d.ts.map +1 -0
  165. package/dist/menubar.js +80 -52
  166. package/dist/menubar.js.map +1 -1
  167. package/dist/pagination.d.ts +38 -17
  168. package/dist/pagination.d.ts.map +1 -0
  169. package/dist/pagination.js +68 -107
  170. package/dist/pagination.js.map +1 -1
  171. package/dist/popover.d.ts +56 -14
  172. package/dist/popover.d.ts.map +1 -0
  173. package/dist/popover.js +62 -87
  174. package/dist/popover.js.map +1 -1
  175. package/dist/preview-card.d.ts +28 -9
  176. package/dist/preview-card.d.ts.map +1 -0
  177. package/dist/preview-card.js +40 -60
  178. package/dist/preview-card.js.map +1 -1
  179. package/dist/progress.d.ts +28 -9
  180. package/dist/progress.d.ts.map +1 -0
  181. package/dist/progress.js +35 -60
  182. package/dist/progress.js.map +1 -1
  183. package/dist/radio-group.d.ts +14 -8
  184. package/dist/radio-group.d.ts.map +1 -0
  185. package/dist/radio-group.js +18 -22
  186. package/dist/radio-group.js.map +1 -1
  187. package/dist/radio.d.ts +14 -6
  188. package/dist/radio.d.ts.map +1 -0
  189. package/dist/radio.js +24 -3
  190. package/dist/radio.js.map +1 -1
  191. package/dist/scroll-area.d.ts +16 -6
  192. package/dist/scroll-area.d.ts.map +1 -0
  193. package/dist/scroll-area.js +34 -55
  194. package/dist/scroll-area.js.map +1 -1
  195. package/dist/select.d.ts +66 -18
  196. package/dist/select.d.ts.map +1 -0
  197. package/dist/select.js +105 -185
  198. package/dist/select.js.map +1 -1
  199. package/dist/separator.d.ts +11 -5
  200. package/dist/separator.d.ts.map +1 -0
  201. package/dist/separator.js +17 -3
  202. package/dist/separator.js.map +1 -1
  203. package/dist/sidebar.d.ts +172 -79
  204. package/dist/sidebar.d.ts.map +1 -0
  205. package/dist/sidebar.js +363 -585
  206. package/dist/sidebar.js.map +1 -1
  207. package/dist/skeleton.d.ts +8 -3
  208. package/dist/skeleton.d.ts.map +1 -0
  209. package/dist/skeleton.js +13 -3
  210. package/dist/skeleton.js.map +1 -1
  211. package/dist/slider.d.ts +16 -6
  212. package/dist/slider.d.ts.map +1 -0
  213. package/dist/slider.js +40 -67
  214. package/dist/slider.js.map +1 -1
  215. package/dist/spinner.d.ts +8 -3
  216. package/dist/spinner.d.ts.map +1 -0
  217. package/dist/spinner.js +15 -4
  218. package/dist/spinner.js.map +1 -1
  219. package/dist/switch.d.ts +12 -6
  220. package/dist/switch.d.ts.map +1 -0
  221. package/dist/switch.js +18 -25
  222. package/dist/switch.js.map +1 -1
  223. package/dist/table.d.ts +37 -11
  224. package/dist/table.d.ts.map +1 -0
  225. package/dist/table.js +51 -88
  226. package/dist/table.js.map +1 -1
  227. package/dist/tabs.d.ts +28 -12
  228. package/dist/tabs.d.ts.map +1 -0
  229. package/dist/tabs.js +40 -74
  230. package/dist/tabs.js.map +1 -1
  231. package/dist/textarea.d.ts +13 -6
  232. package/dist/textarea.d.ts.map +1 -0
  233. package/dist/textarea.js +19 -3
  234. package/dist/textarea.js.map +1 -1
  235. package/dist/toast.d.ts +63 -39
  236. package/dist/toast.d.ts.map +1 -0
  237. package/dist/toast.js +177 -215
  238. package/dist/toast.js.map +1 -1
  239. package/dist/toggle-group.d.ts +26 -12
  240. package/dist/toggle-group.d.ts.map +1 -0
  241. package/dist/toggle-group.js +49 -73
  242. package/dist/toggle-group.js.map +1 -1
  243. package/dist/toggle.d.ts +17 -10
  244. package/dist/toggle.d.ts.map +1 -0
  245. package/dist/toggle.js +38 -3
  246. package/dist/toggle.js.map +1 -1
  247. package/dist/tooltip.d.ts +35 -14
  248. package/dist/tooltip.d.ts.map +1 -0
  249. package/dist/tooltip.js +52 -3
  250. package/dist/tooltip.js.map +1 -1
  251. package/dist/typewriter.d.ts +44 -31
  252. package/dist/typewriter.d.ts.map +1 -0
  253. package/dist/typewriter.js +185 -185
  254. package/dist/typewriter.js.map +1 -1
  255. package/package.json +6 -6
  256. package/dist/chunk-45VQAWIM.js +0 -228
  257. package/dist/chunk-45VQAWIM.js.map +0 -1
  258. package/dist/chunk-6Y7LPQMO.js +0 -11
  259. package/dist/chunk-6Y7LPQMO.js.map +0 -1
  260. package/dist/chunk-76UQO56T.js +0 -19
  261. package/dist/chunk-76UQO56T.js.map +0 -1
  262. package/dist/chunk-7F4MPMLJ.js +0 -17
  263. package/dist/chunk-7F4MPMLJ.js.map +0 -1
  264. package/dist/chunk-BKTJYX4M.js +0 -143
  265. package/dist/chunk-BKTJYX4M.js.map +0 -1
  266. package/dist/chunk-D5XPEJ6T.js +0 -36
  267. package/dist/chunk-D5XPEJ6T.js.map +0 -1
  268. package/dist/chunk-DIGOLJIR.js +0 -105
  269. package/dist/chunk-DIGOLJIR.js.map +0 -1
  270. package/dist/chunk-IQ7YQ5XA.js +0 -141
  271. package/dist/chunk-IQ7YQ5XA.js.map +0 -1
  272. package/dist/chunk-NCHHHWTB.js +0 -85
  273. package/dist/chunk-NCHHHWTB.js.map +0 -1
  274. package/dist/chunk-OUFYQLVN.js +0 -56
  275. package/dist/chunk-OUFYQLVN.js.map +0 -1
  276. package/dist/chunk-QFSEK4M6.js +0 -22
  277. package/dist/chunk-QFSEK4M6.js.map +0 -1
  278. package/dist/chunk-QRW37LRP.js +0 -25
  279. package/dist/chunk-QRW37LRP.js.map +0 -1
  280. package/dist/chunk-RPQHL6C5.js +0 -26
  281. package/dist/chunk-RPQHL6C5.js.map +0 -1
  282. package/dist/chunk-V4ZX4YCP.js +0 -66
  283. package/dist/chunk-V4ZX4YCP.js.map +0 -1
  284. package/dist/chunk-YTSQQTSF.js +0 -44
  285. package/dist/chunk-YTSQQTSF.js.map +0 -1
  286. package/dist/chunk-ZZZH3JGW.js +0 -23
  287. package/dist/chunk-ZZZH3JGW.js.map +0 -1
  288. package/dist/direction.js.map +0 -1
@@ -1,141 +1,109 @@
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!@#$%^&*()_+-={}[];:,.<>/?";
1
+ "use client";
2
+ import { cn } from "./lib/utils.js";
3
+ import * as React from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/encrypted-text.tsx
6
+ const DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[];:,.<>/?";
6
7
  function randomChar(charset) {
7
- return charset.charAt(Math.floor(Math.random() * charset.length));
8
+ return charset.charAt(Math.floor(Math.random() * charset.length));
8
9
  }
9
10
  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;
11
+ if (!original) return "";
12
+ let result = "";
13
+ for (let i = 0; i < original.length; i += 1) result += original[i] === " " ? " " : randomChar(charset);
14
+ return result;
16
15
  }
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
- );
16
+ function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_CHARSET, flipDelayMs = 50, encryptedClassName, revealedClassName, scrambleOnly = false, scrambleOneChar = false, ...props }) {
17
+ const ref = React.useRef(null);
18
+ const [isInView, setIsInView] = React.useState(false);
19
+ const [revealCount, setRevealCount] = React.useState(0);
20
+ const [, setFlipTick] = React.useState(0);
21
+ const animationFrameRef = React.useRef(null);
22
+ const startTimeRef = React.useRef(0);
23
+ const lastFlipTimeRef = React.useRef(0);
24
+ const scrambleCharsRef = React.useRef(text ? scramblePreservingSpaces(text, charset).split("") : []);
25
+ React.useEffect(() => {
26
+ const el = ref.current;
27
+ if (!el) return;
28
+ const observer = new IntersectionObserver(([entry]) => {
29
+ if (entry?.isIntersecting) {
30
+ setIsInView(true);
31
+ observer.disconnect();
32
+ }
33
+ }, { threshold: 0 });
34
+ observer.observe(el);
35
+ return () => observer.disconnect();
36
+ }, []);
37
+ React.useEffect(() => {
38
+ if (!isInView) return;
39
+ scrambleCharsRef.current = (text ? scramblePreservingSpaces(text, charset) : "").split("");
40
+ startTimeRef.current = performance.now();
41
+ lastFlipTimeRef.current = startTimeRef.current;
42
+ setRevealCount(0);
43
+ let isCancelled = false;
44
+ const update = (now) => {
45
+ if (isCancelled) return;
46
+ const totalLength = text.length;
47
+ if (scrambleOnly) {
48
+ if (now - lastFlipTimeRef.current >= Math.max(0, flipDelayMs)) {
49
+ if (scrambleOneChar) {
50
+ const indices = [];
51
+ for (let i = 0; i < totalLength; i++) if (text[i] !== " ") indices.push(i);
52
+ if (indices.length > 0) {
53
+ const idx = indices[Math.floor(Math.random() * indices.length)];
54
+ scrambleCharsRef.current[idx] = randomChar(charset);
55
+ }
56
+ } else for (let index = 0; index < totalLength; index += 1) scrambleCharsRef.current[index] = text[index] === " " ? " " : randomChar(charset);
57
+ lastFlipTimeRef.current = now;
58
+ setFlipTick((t) => t + 1 & 65535);
59
+ }
60
+ animationFrameRef.current = requestAnimationFrame(update);
61
+ return;
62
+ }
63
+ const elapsedMs = now - startTimeRef.current;
64
+ const currentRevealCount = Math.min(totalLength, Math.floor(elapsedMs / Math.max(1, revealDelayMs)));
65
+ setRevealCount(currentRevealCount);
66
+ if (currentRevealCount >= totalLength) return;
67
+ if (now - lastFlipTimeRef.current >= Math.max(0, flipDelayMs)) {
68
+ for (let index = currentRevealCount; index < totalLength; index += 1) scrambleCharsRef.current[index] = text[index] === " " ? " " : randomChar(charset);
69
+ lastFlipTimeRef.current = now;
70
+ }
71
+ animationFrameRef.current = requestAnimationFrame(update);
72
+ };
73
+ animationFrameRef.current = requestAnimationFrame(update);
74
+ return () => {
75
+ isCancelled = true;
76
+ if (animationFrameRef.current !== null) cancelAnimationFrame(animationFrameRef.current);
77
+ };
78
+ }, [
79
+ isInView,
80
+ text,
81
+ revealDelayMs,
82
+ charset,
83
+ flipDelayMs,
84
+ scrambleOnly,
85
+ scrambleOneChar
86
+ ]);
87
+ if (!text) return null;
88
+ return /* @__PURE__ */ jsx("span", {
89
+ ref,
90
+ "data-slot": "encrypted-text",
91
+ className,
92
+ "aria-label": text,
93
+ ...props,
94
+ children: text.split("").map((char, index) => {
95
+ const isRevealed = !scrambleOnly && index < revealCount;
96
+ const displayChar = isRevealed ? char : char === " " ? " " : scrambleCharsRef.current[index] ?? randomChar(charset);
97
+ return /* @__PURE__ */ jsx("span", {
98
+ "data-slot": "encrypted-text-char",
99
+ "data-revealed": isRevealed || void 0,
100
+ className: cn(isRevealed ? revealedClassName : encryptedClassName),
101
+ children: displayChar
102
+ }, index);
103
+ })
104
+ });
137
105
  }
138
-
106
+ //#endregion
139
107
  export { EncryptedText };
140
- //# sourceMappingURL=encrypted-text.js.map
108
+
141
109
  //# sourceMappingURL=encrypted-text.js.map
@@ -1 +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"]}
1
+ {"version":3,"file":"encrypted-text.js","names":[],"sources":["../src/encrypted-text.tsx"],"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"],"mappings":";;;;;AAiBA,MAAM,kBACJ;AAEF,SAAS,WAAW,SAAyB;AAC3C,QAAO,QAAQ,OAAO,KAAK,MAAM,KAAK,QAAQ,GAAG,QAAQ,OAAO,CAAC;;AAGnE,SAAS,yBAAyB,UAAkB,SAAyB;AAC3E,KAAI,CAAC,SAAU,QAAO;CACtB,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,EACxC,WAAU,SAAS,OAAO,MAAM,MAAM,WAAW,QAAQ;AAE3D,QAAO;;AAGT,SAAS,cAAc,EACrB,MACA,WACA,gBAAgB,IAChB,UAAU,iBACV,cAAc,IACd,oBACA,mBACA,eAAe,OACf,kBAAkB,OAClB,GAAG,SACkB;CACrB,MAAM,MAAM,MAAM,OAAwB,KAAK;CAC/C,MAAM,CAAC,UAAU,eAAe,MAAM,SAAS,MAAM;CACrD,MAAM,CAAC,aAAa,kBAAkB,MAAM,SAAS,EAAE;CACvD,MAAM,GAAG,eAAe,MAAM,SAAS,EAAE;CAEzC,MAAM,oBAAoB,MAAM,OAAsB,KAAK;CAC3D,MAAM,eAAe,MAAM,OAAO,EAAE;CACpC,MAAM,kBAAkB,MAAM,OAAO,EAAE;CACvC,MAAM,mBAAmB,MAAM,OAC7B,OAAO,yBAAyB,MAAM,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAC9D;AAED,OAAM,gBAAgB;EACpB,MAAM,KAAK,IAAI;AACf,MAAI,CAAC,GAAI;EAET,MAAM,WAAW,IAAI,sBAClB,CAAC,WAAW;AACX,OAAI,OAAO,gBAAgB;AACzB,gBAAY,KAAK;AACjB,aAAS,YAAY;;KAGzB,EAAE,WAAW,GAAG,CACjB;AAED,WAAS,QAAQ,GAAG;AACpB,eAAa,SAAS,YAAY;IACjC,EAAE,CAAC;AAEN,OAAM,gBAAgB;AACpB,MAAI,CAAC,SAAU;AAKf,mBAAiB,WAHD,OACZ,yBAAyB,MAAM,QAAQ,GACvC,IAC+B,MAAM,GAAG;AAC5C,eAAa,UAAU,YAAY,KAAK;AACxC,kBAAgB,UAAU,aAAa;AACvC,iBAAe,EAAE;EAEjB,IAAI,cAAc;EAElB,MAAM,UAAU,QAAgB;AAC9B,OAAI,YAAa;GAEjB,MAAM,cAAc,KAAK;AAEzB,OAAI,cAAc;AAEhB,QAD0B,MAAM,gBAAgB,WACvB,KAAK,IAAI,GAAG,YAAY,EAAE;AACjD,SAAI,iBAAiB;MACnB,MAAM,UAAoB,EAAE;AAC5B,WAAK,IAAI,IAAI,GAAG,IAAI,aAAa,IAC/B,KAAI,KAAK,OAAO,IAAK,SAAQ,KAAK,EAAE;AAEtC,UAAI,QAAQ,SAAS,GAAG;OACtB,MAAM,MAAM,QAAQ,KAAK,MAAM,KAAK,QAAQ,GAAG,QAAQ,OAAO;AAC9D,wBAAiB,QAAQ,OAAO,WAAW,QAAQ;;WAGrD,MAAK,IAAI,QAAQ,GAAG,QAAQ,aAAa,SAAS,EAChD,kBAAiB,QAAQ,SACvB,KAAK,WAAW,MAAM,MAAM,WAAW,QAAQ;AAGrD,qBAAgB,UAAU;AAC1B,kBAAa,MAAO,IAAI,IAAK,MAAO;;AAEtC,sBAAkB,UAAU,sBAAsB,OAAO;AACzD;;GAGF,MAAM,YAAY,MAAM,aAAa;GACrC,MAAM,qBAAqB,KAAK,IAC9B,aACA,KAAK,MAAM,YAAY,KAAK,IAAI,GAAG,cAAc,CAAC,CACnD;AAED,kBAAe,mBAAmB;AAElC,OAAI,sBAAsB,YAAa;AAGvC,OAD0B,MAAM,gBAAgB,WACvB,KAAK,IAAI,GAAG,YAAY,EAAE;AACjD,SAAK,IAAI,QAAQ,oBAAoB,QAAQ,aAAa,SAAS,EACjE,kBAAiB,QAAQ,SACvB,KAAK,WAAW,MAAM,MAAM,WAAW,QAAQ;AAEnD,oBAAgB,UAAU;;AAG5B,qBAAkB,UAAU,sBAAsB,OAAO;;AAG3D,oBAAkB,UAAU,sBAAsB,OAAO;AAEzD,eAAa;AACX,iBAAc;AACd,OAAI,kBAAkB,YAAY,KAChC,sBAAqB,kBAAkB,QAAQ;;IAGlD;EAAC;EAAU;EAAM;EAAe;EAAS;EAAa;EAAc;EAAgB,CAAC;AAExF,KAAI,CAAC,KAAM,QAAO;AAElB,QACE,oBAAC,QAAD;EACO;EACL,aAAU;EACC;EACX,cAAY;EACZ,GAAI;YAEH,KAAK,MAAM,GAAG,CAAC,KAAK,MAAM,UAAU;GACnC,MAAM,aAAa,CAAC,gBAAgB,QAAQ;GAC5C,MAAM,cAAc,aAChB,OACA,SAAS,MACP,MACC,iBAAiB,QAAQ,UAAU,WAAW,QAAQ;AAE7D,UACE,oBAAC,QAAD;IAEE,aAAU;IACV,iBAAe,cAAc,KAAA;IAC7B,WAAW,GAAG,aAAa,oBAAoB,mBAAmB;cAEjE;IACI,EANA,MAMA;IAET;EACG,CAAA"}
package/dist/field.d.ts CHANGED
@@ -1,22 +1,38 @@
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';
1
+ import * as React from "react";
2
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { Field as FieldPrimitive } from "@base-ui/react/field";
4
+ import * as _$_base_ui_react0 from "@base-ui/react";
6
5
 
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 };
6
+ //#region src/field.d.ts
7
+ type FieldProps = React.ComponentProps<typeof FieldPrimitive.Root>;
8
+ type FieldLabelProps = React.ComponentProps<typeof FieldPrimitive.Label>;
9
+ type FieldDescriptionProps = React.ComponentProps<typeof FieldPrimitive.Description>;
10
+ type FieldItemProps = React.ComponentProps<typeof FieldPrimitive.Item>;
11
+ type FieldErrorProps = React.ComponentProps<typeof FieldPrimitive.Error>;
12
+ type FieldValidityProps = React.ComponentProps<typeof FieldPrimitive.Validity>;
13
+ type FieldControlProps = React.ComponentPropsWithoutRef<typeof FieldPrimitive.Control>;
14
+ declare function Field({
15
+ className,
16
+ ...props
17
+ }: FieldProps): _$react_jsx_runtime0.JSX.Element;
18
+ declare function FieldLabel({
19
+ className,
20
+ ...props
21
+ }: FieldLabelProps): _$react_jsx_runtime0.JSX.Element;
22
+ declare const FieldControl: React.ForwardRefExoticComponent<Omit<Omit<_$_base_ui_react0.FieldControlProps, "ref"> & React.RefAttributes<HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
23
+ declare function FieldDescription({
24
+ className,
25
+ ...props
26
+ }: FieldDescriptionProps): _$react_jsx_runtime0.JSX.Element;
27
+ declare function FieldItem({
28
+ className,
29
+ ...props
30
+ }: FieldItemProps): _$react_jsx_runtime0.JSX.Element;
31
+ declare function FieldError({
32
+ className,
33
+ ...props
34
+ }: FieldErrorProps): _$react_jsx_runtime0.JSX.Element;
35
+ declare const FieldValidity: React.FC<_$_base_ui_react0.FieldValidityProps>;
36
+ //#endregion
37
+ export { Field, FieldControl, FieldControlProps, FieldDescription, FieldDescriptionProps, FieldError, FieldErrorProps, FieldItem, FieldItemProps, FieldLabel, FieldLabelProps, FieldPrimitive, FieldProps, FieldValidity, FieldValidityProps };
38
+ //# sourceMappingURL=field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.d.ts","names":[],"sources":["../src/field.tsx"],"mappings":";;;;;;KAOY,UAAA,GAAa,KAAA,CAAM,cAAA,QAAsB,cAAA,CAAe,IAAA;AAAA,KACxD,eAAA,GAAkB,KAAA,CAAM,cAAA,QAAsB,cAAA,CAAe,KAAA;AAAA,KAC7D,qBAAA,GAAwB,KAAA,CAAM,cAAA,QAAsB,cAAA,CAAe,WAAA;AAAA,KACnE,cAAA,GAAiB,KAAA,CAAM,cAAA,QAAsB,cAAA,CAAe,IAAA;AAAA,KAC5D,eAAA,GAAkB,KAAA,CAAM,cAAA,QAAsB,cAAA,CAAe,KAAA;AAAA,KAC7D,kBAAA,GAAqB,KAAA,CAAM,cAAA,QAAsB,cAAA,CAAe,QAAA;AAAA,KAGhE,iBAAA,GAAoB,KAAA,CAAM,wBAAA,QAAgC,cAAA,CAAe,OAAA;AAAA,iBAErE,KAAA,CAAA;EAAQ,SAAA;EAAA,GAAc;AAAA,GAAS,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAazC,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,eAAA,GAAe,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAatD,YAAA,EAAY,KAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,IAAA,CAavB,iBAAA,CAbuB,iBAAA,WAAA,KAAA,CAAA,aAAA,CAAA,WAAA,YAAA,KAAA,CAAA,aAAA,CAAA,WAAA;AAAA,iBAgBT,gBAAA,CAAA;EAAmB,SAAA;EAAA,GAAc;AAAA,GAAS,qBAAA,GAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAe/D,SAAA,CAAA;EAAY,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUjD,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,eAAA,GAAe,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWtD,aAAA,EAAa,KAAA,CAAA,EAAA,CAA0B,iBAAA,CAA1B,kBAAA"}
package/dist/field.js CHANGED
@@ -1,4 +1,53 @@
1
- export { Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldPrimitive, FieldValidity } from './chunk-NCHHHWTB.js';
2
- import './chunk-76UQO56T.js';
3
- //# sourceMappingURL=field.js.map
1
+ "use client";
2
+ import { cn } from "./lib/utils.js";
3
+ import * as React from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { Field as FieldPrimitive } from "@base-ui/react/field";
6
+ //#region src/field.tsx
7
+ function Field({ className, ...props }) {
8
+ return /* @__PURE__ */ jsx(FieldPrimitive.Root, {
9
+ "data-slot": "field",
10
+ className: cn("grid w-full gap-2 data-[invalid]:text-destructive", className),
11
+ ...props
12
+ });
13
+ }
14
+ function FieldLabel({ className, ...props }) {
15
+ return /* @__PURE__ */ jsx(FieldPrimitive.Label, {
16
+ "data-slot": "field-label",
17
+ className: cn("text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70", className),
18
+ ...props
19
+ });
20
+ }
21
+ const FieldControl = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(FieldPrimitive.Control, {
22
+ ref,
23
+ "data-slot": "field-control",
24
+ className: cn("rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", className),
25
+ ...props
26
+ }));
27
+ FieldControl.displayName = "FieldControl";
28
+ function FieldDescription({ className, ...props }) {
29
+ return /* @__PURE__ */ jsx(FieldPrimitive.Description, {
30
+ "data-slot": "field-description",
31
+ className: cn("text-muted-foreground text-left text-sm leading-normal font-normal group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1", "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4", className),
32
+ ...props
33
+ });
34
+ }
35
+ function FieldItem({ className, ...props }) {
36
+ return /* @__PURE__ */ jsx(FieldPrimitive.Item, {
37
+ "data-slot": "field-item",
38
+ className: cn("flex items-center gap-2", className),
39
+ ...props
40
+ });
41
+ }
42
+ function FieldError({ className, ...props }) {
43
+ return /* @__PURE__ */ jsx(FieldPrimitive.Error, {
44
+ "data-slot": "field-error",
45
+ className: cn("text-destructive text-sm font-normal", className),
46
+ ...props
47
+ });
48
+ }
49
+ const FieldValidity = FieldPrimitive.Validity;
50
+ //#endregion
51
+ export { Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldPrimitive, FieldValidity };
52
+
4
53
  //# sourceMappingURL=field.js.map
package/dist/field.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"field.js"}
1
+ {"version":3,"file":"field.js","names":[],"sources":["../src/field.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Field as FieldPrimitive } from \"@base-ui/react/field\"\n\nimport { cn } from \"./lib/utils\"\n\nexport type FieldProps = React.ComponentProps<typeof FieldPrimitive.Root>\nexport type FieldLabelProps = React.ComponentProps<typeof FieldPrimitive.Label>\nexport type FieldDescriptionProps = React.ComponentProps<typeof FieldPrimitive.Description>\nexport type FieldItemProps = React.ComponentProps<typeof FieldPrimitive.Item>\nexport type FieldErrorProps = React.ComponentProps<typeof FieldPrimitive.Error>\nexport type FieldValidityProps = React.ComponentProps<typeof FieldPrimitive.Validity>\n\n// `ref` is important for React Hook Form / focus management, so we forward it only on the control.\nexport type FieldControlProps = React.ComponentPropsWithoutRef<typeof FieldPrimitive.Control>\n\nexport function Field({ className, ...props }: FieldProps) {\n return (\n <FieldPrimitive.Root\n data-slot=\"field\"\n className={cn(\n \"grid w-full gap-2 data-[invalid]:text-destructive\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport function FieldLabel({ className, ...props }: FieldLabelProps) {\n return (\n <FieldPrimitive.Label\n data-slot=\"field-label\"\n className={cn(\n \"text-sm font-medium leading-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70\",\n className,\n )}\n {...props}\n />\n )\n}\n\nexport const FieldControl = React.forwardRef<\n React.ComponentRef<typeof FieldPrimitive.Control>,\n FieldControlProps\n>(({ className, ...props }, ref) => (\n <FieldPrimitive.Control\n ref={ref}\n data-slot=\"field-control\"\n className={cn(\n \"rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n />\n))\nFieldControl.displayName = \"FieldControl\"\n\nexport function FieldDescription({ className, ...props }: FieldDescriptionProps) {\n return (\n <FieldPrimitive.Description\n data-slot=\"field-description\"\n className={cn(\n \"text-muted-foreground text-left text-sm leading-normal font-normal group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5\",\n \"last:mt-0 nth-last-2:-mt-1\",\n \"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport function FieldItem({ className, ...props }: FieldItemProps) {\n return (\n <FieldPrimitive.Item\n data-slot=\"field-item\"\n className={cn(\"flex items-center gap-2\", className)}\n {...props}\n />\n )\n}\n\nexport function FieldError({ className, ...props }: FieldErrorProps) {\n return (\n <FieldPrimitive.Error\n data-slot=\"field-error\"\n className={cn(\"text-destructive text-sm font-normal\", className)}\n {...props}\n />\n )\n}\n\n// Base UI's Validity does not accept `className`/`ref` (and we don't need to style it yet), so we export it as-is.\nexport const FieldValidity = FieldPrimitive.Validity\n\nexport { FieldPrimitive }"],"mappings":";;;;;;AAiBA,SAAgB,MAAM,EAAE,WAAW,GAAG,SAAqB;AACzD,QACE,oBAAC,eAAe,MAAhB;EACE,aAAU;EACV,WAAW,GACT,qDACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAgB,WAAW,EAAE,WAAW,GAAG,SAA0B;AACnE,QACE,oBAAC,eAAe,OAAhB;EACE,aAAU;EACV,WAAW,GACT,kGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,MAAa,eAAe,MAAM,YAG/B,EAAE,WAAW,GAAG,SAAS,QAC1B,oBAAC,eAAe,SAAhB;CACO;CACL,aAAU;CACV,WAAW,GACT,kKACA,UACD;CACD,GAAI;CACJ,CAAA,CACF;AACF,aAAa,cAAc;AAE3B,SAAgB,iBAAiB,EAAE,WAAW,GAAG,SAAgC;AAC/E,QACE,oBAAC,eAAe,aAAhB;EACE,aAAU;EACV,WAAW,GACT,qJACA,8BACA,qEACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAgB,UAAU,EAAE,WAAW,GAAG,SAAyB;AACjE,QACE,oBAAC,eAAe,MAAhB;EACE,aAAU;EACV,WAAW,GAAG,2BAA2B,UAAU;EACnD,GAAI;EACJ,CAAA;;AAIN,SAAgB,WAAW,EAAE,WAAW,GAAG,SAA0B;AACnE,QACE,oBAAC,eAAe,OAAhB;EACE,aAAU;EACV,WAAW,GAAG,wCAAwC,UAAU;EAChE,GAAI;EACJ,CAAA;;AAKN,MAAa,gBAAgB,eAAe"}
@@ -0,0 +1,6 @@
1
+ //#region src/film-grain-shader.d.ts
2
+ declare const vertexShader = "\nattribute vec2 position;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = position * 0.5 + 0.5;\n gl_Position = vec4(position, 0.0, 1.0);\n}\n";
3
+ declare const fragmentShader = "\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uDensity;\nuniform float uOpacity;\nuniform float uFps;\nuniform vec3 uColor;\n\nvarying vec2 vUv;\n\n// Stable hash\nfloat hash(vec2 p, float seed) {\n return fract(sin(dot(p + seed, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\n// Film response curve (soft toe + shoulder rolloff)\nfloat filmCurve(float x) {\n return smoothstep(0.0, 0.2, x) * (1.0 - smoothstep(0.8, 1.0, x));\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy;\n vec2 p = floor(uv);\n\n // Temporal coherence: blend between current and next frame seed\n float frame = floor(uTime * uFps);\n float t = fract(uTime * uFps);\n float seed = frame * 0.1731;\n\n // Multi-scale grain with inter-frame blending on fine layer\n float fineA = hash(p, seed);\n float fineB = hash(p, seed + 0.1731);\n float fine = mix(fineA, fineB, t);\n\n float medium = hash(floor(uv * 0.5), seed + 3.1);\n float coarse = hash(floor(uv * 0.25), seed + 7.93);\n\n float grain = fine * 0.65 + medium * 0.25 + coarse * 0.10;\n\n // Emulsion clumping (organic structure)\n float cluster = hash(floor(uv * 0.18), seed + 9.2);\n grain *= mix(0.75, 1.35, cluster);\n\n // Density threshold\n grain = smoothstep(1.0 - uDensity, 1.0, grain);\n\n // Film response curve (replaces raw pow gamma)\n grain = filmCurve(grain);\n\n // Micro-blur: sample neighbors for optical diffusion\n float n1 = hash(p + vec2(1.0, 0.0), seed);\n float n2 = hash(p - vec2(1.0, 0.0), seed);\n float n3 = hash(p + vec2(0.0, 1.0), seed);\n float n4 = hash(p - vec2(0.0, 1.0), seed);\n float neighbors = (n1 + n2 + n3 + n4) * 0.25;\n grain = mix(grain, neighbors, 0.15);\n\n // Chromatic aberration (reuse neighbor hashes)\n float rShift = n1 * 0.015;\n float bShift = n2 * 0.015;\n\n vec3 color = uColor * vec3(\n grain + rShift,\n grain,\n grain + bShift\n );\n\n color = clamp(color, 0.0, 1.0);\n\n gl_FragColor = vec4(color, grain * uOpacity);\n}\n";
4
+ //#endregion
5
+ export { fragmentShader, vertexShader };
6
+ //# sourceMappingURL=film-grain-shader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"film-grain-shader.d.ts","names":[],"sources":["../src/film-grain-shader.ts"],"mappings":";cAAa,YAAA;AAAA,cAUA,cAAA"}
@@ -0,0 +1,88 @@
1
+ //#region src/film-grain-shader.ts
2
+ const vertexShader = `
3
+ attribute vec2 position;
4
+ varying vec2 vUv;
5
+
6
+ void main() {
7
+ vUv = position * 0.5 + 0.5;
8
+ gl_Position = vec4(position, 0.0, 1.0);
9
+ }
10
+ `;
11
+ const fragmentShader = `
12
+ precision highp float;
13
+
14
+ uniform float uTime;
15
+ uniform vec2 uResolution;
16
+ uniform float uDensity;
17
+ uniform float uOpacity;
18
+ uniform float uFps;
19
+ uniform vec3 uColor;
20
+
21
+ varying vec2 vUv;
22
+
23
+ // Stable hash
24
+ float hash(vec2 p, float seed) {
25
+ return fract(sin(dot(p + seed, vec2(127.1, 311.7))) * 43758.5453123);
26
+ }
27
+
28
+ // Film response curve (soft toe + shoulder rolloff)
29
+ float filmCurve(float x) {
30
+ return smoothstep(0.0, 0.2, x) * (1.0 - smoothstep(0.8, 1.0, x));
31
+ }
32
+
33
+ void main() {
34
+ vec2 uv = gl_FragCoord.xy;
35
+ vec2 p = floor(uv);
36
+
37
+ // Temporal coherence: blend between current and next frame seed
38
+ float frame = floor(uTime * uFps);
39
+ float t = fract(uTime * uFps);
40
+ float seed = frame * 0.1731;
41
+
42
+ // Multi-scale grain with inter-frame blending on fine layer
43
+ float fineA = hash(p, seed);
44
+ float fineB = hash(p, seed + 0.1731);
45
+ float fine = mix(fineA, fineB, t);
46
+
47
+ float medium = hash(floor(uv * 0.5), seed + 3.1);
48
+ float coarse = hash(floor(uv * 0.25), seed + 7.93);
49
+
50
+ float grain = fine * 0.65 + medium * 0.25 + coarse * 0.10;
51
+
52
+ // Emulsion clumping (organic structure)
53
+ float cluster = hash(floor(uv * 0.18), seed + 9.2);
54
+ grain *= mix(0.75, 1.35, cluster);
55
+
56
+ // Density threshold
57
+ grain = smoothstep(1.0 - uDensity, 1.0, grain);
58
+
59
+ // Film response curve (replaces raw pow gamma)
60
+ grain = filmCurve(grain);
61
+
62
+ // Micro-blur: sample neighbors for optical diffusion
63
+ float n1 = hash(p + vec2(1.0, 0.0), seed);
64
+ float n2 = hash(p - vec2(1.0, 0.0), seed);
65
+ float n3 = hash(p + vec2(0.0, 1.0), seed);
66
+ float n4 = hash(p - vec2(0.0, 1.0), seed);
67
+ float neighbors = (n1 + n2 + n3 + n4) * 0.25;
68
+ grain = mix(grain, neighbors, 0.15);
69
+
70
+ // Chromatic aberration (reuse neighbor hashes)
71
+ float rShift = n1 * 0.015;
72
+ float bShift = n2 * 0.015;
73
+
74
+ vec3 color = uColor * vec3(
75
+ grain + rShift,
76
+ grain,
77
+ grain + bShift
78
+ );
79
+
80
+ color = clamp(color, 0.0, 1.0);
81
+
82
+ gl_FragColor = vec4(color, grain * uOpacity);
83
+ }
84
+ `;
85
+ //#endregion
86
+ export { fragmentShader, vertexShader };
87
+
88
+ //# sourceMappingURL=film-grain-shader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"film-grain-shader.js","names":[],"sources":["../src/film-grain-shader.ts"],"sourcesContent":["export const vertexShader = `\nattribute vec2 position;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = position * 0.5 + 0.5;\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`\n\nexport const fragmentShader = `\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uDensity;\nuniform float uOpacity;\nuniform float uFps;\nuniform vec3 uColor;\n\nvarying vec2 vUv;\n\n// Stable hash\nfloat hash(vec2 p, float seed) {\n return fract(sin(dot(p + seed, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\n// Film response curve (soft toe + shoulder rolloff)\nfloat filmCurve(float x) {\n return smoothstep(0.0, 0.2, x) * (1.0 - smoothstep(0.8, 1.0, x));\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy;\n vec2 p = floor(uv);\n\n // Temporal coherence: blend between current and next frame seed\n float frame = floor(uTime * uFps);\n float t = fract(uTime * uFps);\n float seed = frame * 0.1731;\n\n // Multi-scale grain with inter-frame blending on fine layer\n float fineA = hash(p, seed);\n float fineB = hash(p, seed + 0.1731);\n float fine = mix(fineA, fineB, t);\n\n float medium = hash(floor(uv * 0.5), seed + 3.1);\n float coarse = hash(floor(uv * 0.25), seed + 7.93);\n\n float grain = fine * 0.65 + medium * 0.25 + coarse * 0.10;\n\n // Emulsion clumping (organic structure)\n float cluster = hash(floor(uv * 0.18), seed + 9.2);\n grain *= mix(0.75, 1.35, cluster);\n\n // Density threshold\n grain = smoothstep(1.0 - uDensity, 1.0, grain);\n\n // Film response curve (replaces raw pow gamma)\n grain = filmCurve(grain);\n\n // Micro-blur: sample neighbors for optical diffusion\n float n1 = hash(p + vec2(1.0, 0.0), seed);\n float n2 = hash(p - vec2(1.0, 0.0), seed);\n float n3 = hash(p + vec2(0.0, 1.0), seed);\n float n4 = hash(p - vec2(0.0, 1.0), seed);\n float neighbors = (n1 + n2 + n3 + n4) * 0.25;\n grain = mix(grain, neighbors, 0.15);\n\n // Chromatic aberration (reuse neighbor hashes)\n float rShift = n1 * 0.015;\n float bShift = n2 * 0.015;\n\n vec3 color = uColor * vec3(\n grain + rShift,\n grain,\n grain + bShift\n );\n\n color = clamp(color, 0.0, 1.0);\n\n gl_FragColor = vec4(color, grain * uOpacity);\n}\n`\n"],"mappings":";AAAA,MAAa,eAAe;;;;;;;;;AAU5B,MAAa,iBAAiB"}
@@ -0,0 +1,20 @@
1
+ import * as _$react from "react";
2
+
3
+ //#region src/film-grain-webgl.d.ts
4
+ interface UseFilmGrainOptions {
5
+ density: number;
6
+ opacity: number;
7
+ /** Target FPS for both WebGL and canvas fallback. Default 18 */
8
+ fps?: number;
9
+ /** Hex color for canvas fallback grain. Default '#ffffff' */
10
+ color?: string;
11
+ }
12
+ declare function useFilmGrain({
13
+ density,
14
+ opacity,
15
+ fps,
16
+ color
17
+ }: UseFilmGrainOptions): _$react.RefObject<HTMLCanvasElement | null>;
18
+ //#endregion
19
+ export { useFilmGrain };
20
+ //# sourceMappingURL=film-grain-webgl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"film-grain-webgl.d.ts","names":[],"sources":["../src/film-grain-webgl.ts"],"mappings":";;;UAGU,mBAAA;EACR,OAAA;EACA,OAAA;EAFQ;EAIR,GAAA;;EAEA,KAAA;AAAA;AAAA,iBAgJc,YAAA,CAAA;EACd,OAAA;EACA,OAAA;EACA,GAAA;EACA;AAAA,GACC,mBAAA,GAAmB,OAAA,CAAA,SAAA,CAAA,iBAAA"}