react-marketing-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 (178) hide show
  1. package/dist/accordion.js +1 -1
  2. package/dist/accordion.js.map +1 -1
  3. package/dist/accordion.mjs +222 -2
  4. package/dist/accordion.mjs.map +1 -1
  5. package/dist/action-swap.js +1 -0
  6. package/dist/action-swap.mjs +77 -3
  7. package/dist/action-swap.mjs.map +1 -1
  8. package/dist/animated-beam.js +1 -0
  9. package/dist/animated-beam.mjs +127 -2
  10. package/dist/animated-beam.mjs.map +1 -1
  11. package/dist/button.js +1 -1
  12. package/dist/button.js.map +1 -1
  13. package/dist/button.mjs +115 -2
  14. package/dist/button.mjs.map +1 -1
  15. package/dist/card.js +1 -2
  16. package/dist/card.js.map +1 -1
  17. package/dist/card.mjs +135 -3
  18. package/dist/card.mjs.map +1 -1
  19. package/dist/dia-text-reveal.js +1 -0
  20. package/dist/dia-text-reveal.mjs +331 -2
  21. package/dist/dia-text-reveal.mjs.map +1 -1
  22. package/dist/elevated-input.js +1 -1
  23. package/dist/elevated-input.js.map +1 -1
  24. package/dist/elevated-input.mjs +48 -2
  25. package/dist/elevated-input.mjs.map +1 -1
  26. package/dist/fade-in.js +1 -0
  27. package/dist/fade-in.mjs +84 -2
  28. package/dist/fade-in.mjs.map +1 -1
  29. package/dist/feature-card.js +1 -1
  30. package/dist/feature-card.js.map +1 -1
  31. package/dist/feature-card.mjs +34 -2
  32. package/dist/feature-card.mjs.map +1 -1
  33. package/dist/flowchart-parts.js +1 -1
  34. package/dist/flowchart-parts.js.map +1 -1
  35. package/dist/flowchart-parts.mjs +91 -2
  36. package/dist/flowchart-parts.mjs.map +1 -1
  37. package/dist/glossy-button.js +1 -1
  38. package/dist/glossy-button.js.map +1 -1
  39. package/dist/glossy-button.mjs +82 -2
  40. package/dist/glossy-button.mjs.map +1 -1
  41. package/dist/grainient.js +1 -0
  42. package/dist/grainient.mjs +327 -2
  43. package/dist/grainient.mjs.map +1 -1
  44. package/dist/highlighter.js +1 -0
  45. package/dist/highlighter.mjs +122 -3
  46. package/dist/highlighter.mjs.map +1 -1
  47. package/dist/index.js +1 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs +2642 -32
  50. package/dist/index.mjs.map +1 -1
  51. package/dist/input.js +1 -0
  52. package/dist/input.mjs +107 -2
  53. package/dist/input.mjs.map +1 -1
  54. package/dist/lib/breakpoints.js +1 -1
  55. package/dist/lib/breakpoints.js.map +1 -1
  56. package/dist/lib/breakpoints.mjs +34 -1
  57. package/dist/lib/breakpoints.mjs.map +1 -1
  58. package/dist/lib/cn.js +1 -1
  59. package/dist/lib/cn.js.map +1 -1
  60. package/dist/lib/cn.mjs +17 -1
  61. package/dist/lib/cn.mjs.map +1 -1
  62. package/dist/lib/ease.js +1 -0
  63. package/dist/lib/ease.mjs +9 -1
  64. package/dist/lib/ease.mjs.map +1 -1
  65. package/dist/lib/surface.js +1 -0
  66. package/dist/lib/surface.mjs +37 -1
  67. package/dist/lib/surface.mjs.map +1 -1
  68. package/dist/lib/use-media-query.js +1 -0
  69. package/dist/lib/use-media-query.mjs +16 -1
  70. package/dist/lib/use-media-query.mjs.map +1 -1
  71. package/dist/liquid-metal.js +1 -0
  72. package/dist/liquid-metal.mjs +40 -2
  73. package/dist/liquid-metal.mjs.map +1 -1
  74. package/dist/navigation-menu-icons.js +1 -1
  75. package/dist/navigation-menu-icons.js.map +1 -1
  76. package/dist/navigation-menu-icons.mjs +36 -1
  77. package/dist/navigation-menu-icons.mjs.map +1 -1
  78. package/dist/navigation-menu-styles.js +1 -1
  79. package/dist/navigation-menu-styles.js.map +1 -1
  80. package/dist/navigation-menu-styles.mjs +11 -1
  81. package/dist/navigation-menu-styles.mjs.map +1 -1
  82. package/dist/navigation-menu.js +1 -2
  83. package/dist/navigation-menu.js.map +1 -1
  84. package/dist/navigation-menu.mjs +350 -5
  85. package/dist/navigation-menu.mjs.map +1 -1
  86. package/dist/password-input.js +1 -0
  87. package/dist/password-input.mjs +171 -3
  88. package/dist/password-input.mjs.map +1 -1
  89. package/dist/rainbow-button.js +1 -0
  90. package/dist/rainbow-button.mjs +45 -2
  91. package/dist/rainbow-button.mjs.map +1 -1
  92. package/dist/range-slider.js +1 -0
  93. package/dist/range-slider.mjs +82 -1
  94. package/dist/range-slider.mjs.map +1 -1
  95. package/dist/rolling-badge.js +1 -0
  96. package/dist/rolling-badge.mjs +68 -2
  97. package/dist/rolling-badge.mjs.map +1 -1
  98. package/dist/savings-badge.js +1 -1
  99. package/dist/savings-badge.js.map +1 -1
  100. package/dist/savings-badge.mjs +22 -2
  101. package/dist/savings-badge.mjs.map +1 -1
  102. package/dist/shine-border.js +1 -0
  103. package/dist/shine-border.mjs +44 -2
  104. package/dist/shine-border.mjs.map +1 -1
  105. package/dist/sparkles-text.js +1 -0
  106. package/dist/sparkles-text.mjs +84 -3
  107. package/dist/sparkles-text.mjs.map +1 -1
  108. package/dist/tabs.js +1 -0
  109. package/dist/tabs.mjs +118 -2
  110. package/dist/tabs.mjs.map +1 -1
  111. package/dist/theme-toggle.js +1 -0
  112. package/dist/theme-toggle.mjs +248 -5
  113. package/dist/theme-toggle.mjs.map +1 -1
  114. package/package.json +68 -68
  115. package/dist/chunk-3SB6HUBA.mjs +0 -31
  116. package/dist/chunk-3SB6HUBA.mjs.map +0 -1
  117. package/dist/chunk-4PBVBXGY.mjs +0 -84
  118. package/dist/chunk-4PBVBXGY.mjs.map +0 -1
  119. package/dist/chunk-4VCFWVSJ.mjs +0 -42
  120. package/dist/chunk-4VCFWVSJ.mjs.map +0 -1
  121. package/dist/chunk-5QQAPGR2.mjs +0 -109
  122. package/dist/chunk-5QQAPGR2.mjs.map +0 -1
  123. package/dist/chunk-6MB4UKRX.mjs +0 -19
  124. package/dist/chunk-6MB4UKRX.mjs.map +0 -1
  125. package/dist/chunk-6T5LR34O.mjs +0 -45
  126. package/dist/chunk-6T5LR34O.mjs.map +0 -1
  127. package/dist/chunk-AYLCYDUM.mjs +0 -275
  128. package/dist/chunk-AYLCYDUM.mjs.map +0 -1
  129. package/dist/chunk-AYY7D2RJ.mjs +0 -112
  130. package/dist/chunk-AYY7D2RJ.mjs.map +0 -1
  131. package/dist/chunk-CTZEI2YS.mjs +0 -324
  132. package/dist/chunk-CTZEI2YS.mjs.map +0 -1
  133. package/dist/chunk-DA3I3Y5O.mjs +0 -71
  134. package/dist/chunk-DA3I3Y5O.mjs.map +0 -1
  135. package/dist/chunk-EYHT2EWJ.mjs +0 -18
  136. package/dist/chunk-EYHT2EWJ.mjs.map +0 -1
  137. package/dist/chunk-IHLGCS63.mjs +0 -36
  138. package/dist/chunk-IHLGCS63.mjs.map +0 -1
  139. package/dist/chunk-JVXJ6SFX.mjs +0 -38
  140. package/dist/chunk-JVXJ6SFX.mjs.map +0 -1
  141. package/dist/chunk-KBHYXLRG.mjs +0 -13
  142. package/dist/chunk-KBHYXLRG.mjs.map +0 -1
  143. package/dist/chunk-KMXUQYR3.mjs +0 -74
  144. package/dist/chunk-KMXUQYR3.mjs.map +0 -1
  145. package/dist/chunk-KNPOZ34H.mjs +0 -88
  146. package/dist/chunk-KNPOZ34H.mjs.map +0 -1
  147. package/dist/chunk-KRNWCJ4D.mjs +0 -219
  148. package/dist/chunk-KRNWCJ4D.mjs.map +0 -1
  149. package/dist/chunk-M5MESV26.mjs +0 -124
  150. package/dist/chunk-M5MESV26.mjs.map +0 -1
  151. package/dist/chunk-MJYBPJBA.mjs +0 -115
  152. package/dist/chunk-MJYBPJBA.mjs.map +0 -1
  153. package/dist/chunk-NNHPQ67J.mjs +0 -10
  154. package/dist/chunk-NNHPQ67J.mjs.map +0 -1
  155. package/dist/chunk-OCZFHVVD.mjs +0 -71
  156. package/dist/chunk-OCZFHVVD.mjs.map +0 -1
  157. package/dist/chunk-QAWSH567.mjs +0 -19
  158. package/dist/chunk-QAWSH567.mjs.map +0 -1
  159. package/dist/chunk-R2E2J42H.mjs +0 -38
  160. package/dist/chunk-R2E2J42H.mjs.map +0 -1
  161. package/dist/chunk-TPGLLSYV.mjs +0 -65
  162. package/dist/chunk-TPGLLSYV.mjs.map +0 -1
  163. package/dist/chunk-VJENJHXJ.mjs +0 -72
  164. package/dist/chunk-VJENJHXJ.mjs.map +0 -1
  165. package/dist/chunk-W22G7XHR.mjs +0 -104
  166. package/dist/chunk-W22G7XHR.mjs.map +0 -1
  167. package/dist/chunk-WDR5VPZJ.mjs +0 -79
  168. package/dist/chunk-WDR5VPZJ.mjs.map +0 -1
  169. package/dist/chunk-WLUGKBH7.mjs +0 -37
  170. package/dist/chunk-WLUGKBH7.mjs.map +0 -1
  171. package/dist/chunk-WYJYLDUA.mjs +0 -84
  172. package/dist/chunk-WYJYLDUA.mjs.map +0 -1
  173. package/dist/chunk-XZEDZVXT.mjs +0 -38
  174. package/dist/chunk-XZEDZVXT.mjs.map +0 -1
  175. package/dist/chunk-YKGP5JIL.mjs +0 -328
  176. package/dist/chunk-YKGP5JIL.mjs.map +0 -1
  177. package/dist/chunk-YM3U2OBE.mjs +0 -99
  178. package/dist/chunk-YM3U2OBE.mjs.map +0 -1
@@ -1,4 +1,333 @@
1
- export { DiaTextReveal } from './chunk-YKGP5JIL.mjs';
2
- import './chunk-QAWSH567.mjs';
1
+ "use client";
2
+ import { useReducedMotion, useInView, motion } from 'framer-motion';
3
+ import { useMemo, useRef, useState, useCallback, useEffect } from 'react';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ function cn(...inputs) {
9
+ return twMerge(clsx(inputs));
10
+ }
11
+ function HeightClipper({ height, delay, children }) {
12
+ return /* @__PURE__ */ jsx(
13
+ motion.span,
14
+ {
15
+ className: "block w-full overflow-hidden",
16
+ animate: height === void 0 ? {} : { height },
17
+ transition: {
18
+ height: { duration: 0.4, ease: [0.4, 0, 0.2, 1], delay }
19
+ },
20
+ children
21
+ }
22
+ );
23
+ }
24
+ function ExitingLine({ text, textColor, duration, fallDuration, opacityEase, wrap = false, onDone }) {
25
+ return /* @__PURE__ */ jsx(
26
+ motion.span,
27
+ {
28
+ "aria-hidden": true,
29
+ className: cn(
30
+ wrap ? "pointer-events-none absolute top-0 left-0 w-full" : "pointer-events-none absolute top-0 left-1/2 whitespace-nowrap"
31
+ ),
32
+ style: { color: textColor },
33
+ initial: wrap ? { opacity: 1, y: 0 } : { opacity: 1, x: "-50%", y: 0 },
34
+ animate: wrap ? { opacity: 0, y: 14 } : { opacity: 0, x: "-50%", y: 14 },
35
+ transition: {
36
+ opacity: { duration, ease: opacityEase },
37
+ y: { duration: fallDuration, ease: [0.22, 0.61, 0.36, 1] }
38
+ },
39
+ onAnimationComplete: onDone,
40
+ children: text
41
+ }
42
+ );
43
+ }
44
+ function WidthReservation({ texts }) {
45
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "invisible block h-0 overflow-hidden", children: texts.map((t) => /* @__PURE__ */ jsx("span", { className: "block", children: t }, t)) });
46
+ }
47
+
48
+ // src/components/dia-text-reveal.sweep.ts
49
+ var BAND_HALF = 17;
50
+ var SWEEP_START = -BAND_HALF;
51
+ var SWEEP_END = 100 + BAND_HALF;
52
+ var sweepEaseFn = (t) => t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2;
53
+ var coverageAt = (progress) => Math.min(1, sweepEaseFn(progress) * (SWEEP_END - SWEEP_START) / 100);
54
+ var COVERAGE_SPAN = (() => {
55
+ let lo = 0;
56
+ let hi = 1;
57
+ for (let i = 0; i < 40; i += 1) {
58
+ const mid = (lo + hi) / 2;
59
+ if (coverageAt(mid) < 1) lo = mid;
60
+ else hi = mid;
61
+ }
62
+ return hi;
63
+ })();
64
+ var EXIT_FADE_BIAS = 0.4;
65
+ var exitEase = (t) => coverageAt(t * COVERAGE_SPAN) ** EXIT_FADE_BIAS;
66
+ var makeExitEase = (leadFraction) => {
67
+ if (leadFraction <= 0) return exitEase;
68
+ if (leadFraction >= 1) return () => 0;
69
+ return (t) => t <= leadFraction ? 0 : exitEase((t - leadFraction) / (1 - leadFraction));
70
+ };
71
+ var SWEEP_SCALE = 3;
72
+ var BAND_HALF_IMAGE = BAND_HALF / SWEEP_SCALE;
73
+ var positionFor = (pos) => (pos - 50 * SWEEP_SCALE) / (1 - SWEEP_SCALE);
74
+ var SWEEP_FROM = `${positionFor(SWEEP_START).toFixed(3)}%`;
75
+ var SWEEP_TO = `${positionFor(SWEEP_END).toFixed(3)}%`;
76
+ var SWEEP_SIZE = `${SWEEP_SCALE * 100}% 100%`;
77
+ var EASE_SAMPLES = 24;
78
+ var sweepEaseCss = `linear(${Array.from({ length: EASE_SAMPLES + 1 }, (_, i) => sweepEaseFn(i / EASE_SAMPLES).toFixed(5)).join(
79
+ ", "
80
+ )})`;
81
+ function buildSweepGradient(colors, textColor) {
82
+ const bandStart = 50 - BAND_HALF_IMAGE;
83
+ const bandEnd = 50 + BAND_HALF_IMAGE;
84
+ const n = colors.length;
85
+ const parts = [`${textColor} 0%`, `${textColor} ${bandStart.toFixed(3)}%`];
86
+ for (const [i, c] of colors.entries()) {
87
+ const pct = n === 1 ? 50 : bandStart + i / (n - 1) * BAND_HALF_IMAGE * 2;
88
+ parts.push(`${c} ${pct.toFixed(3)}%`);
89
+ }
90
+ parts.push(`transparent ${bandEnd.toFixed(3)}%`, "transparent 100%");
91
+ return `linear-gradient(90deg, ${parts.join(", ")})`;
92
+ }
93
+ function buildSweepStyle({ colors, textColor, duration, delay, sweep, paused, reduced }) {
94
+ return {
95
+ color: "transparent",
96
+ backgroundClip: "text",
97
+ WebkitBackgroundClip: "text",
98
+ backgroundImage: buildSweepGradient(colors, textColor),
99
+ backgroundRepeat: "no-repeat",
100
+ backgroundSize: SWEEP_SIZE,
101
+ backgroundPositionX: reduced ? SWEEP_TO : SWEEP_FROM,
102
+ "--dia-sweep-from": SWEEP_FROM,
103
+ "--dia-sweep-to": SWEEP_TO,
104
+ ...sweep !== null && !reduced && {
105
+ animationName: sweep.cycle % 2 === 0 ? "dia-sweep-a" : "dia-sweep-b",
106
+ animationDuration: `${duration}s`,
107
+ animationDelay: `${delay}s`,
108
+ animationTimingFunction: sweepEaseCss,
109
+ animationFillMode: "both",
110
+ animationIterationCount: 1,
111
+ animationPlayState: paused ? "paused" : "running"
112
+ }
113
+ };
114
+ }
115
+
116
+ // src/components/dia-text-reveal.utils.ts
117
+ function measureWidths(el, texts) {
118
+ const parent = el.parentElement;
119
+ if (!parent) return texts.map(() => 0);
120
+ const ghost = el.cloneNode();
121
+ if (!(ghost instanceof HTMLElement)) return texts.map(() => 0);
122
+ Object.assign(ghost.style, {
123
+ position: "absolute",
124
+ visibility: "hidden",
125
+ pointerEvents: "none",
126
+ width: "auto",
127
+ whiteSpace: "nowrap"
128
+ });
129
+ parent.appendChild(ghost);
130
+ const widths = texts.map((t) => {
131
+ ghost.textContent = t;
132
+ return ghost.getBoundingClientRect().width;
133
+ });
134
+ ghost.remove();
135
+ return widths;
136
+ }
137
+ var DEFAULT_COLORS = ["#c679c4", "#fa3d1d", "#ffb005", "#e1e1fe", "#0358f7"];
138
+ var EXIT_LEAD_RATIO = 0.3;
139
+ function DiaTextReveal({
140
+ text,
141
+ colors = DEFAULT_COLORS,
142
+ textColor = "var(--color-foreground)",
143
+ duration = 1,
144
+ delay = 0,
145
+ repeat = false,
146
+ repeatDelay = 0.5,
147
+ exitDuration,
148
+ exitLead,
149
+ startOnView = true,
150
+ start = true,
151
+ once = true,
152
+ className,
153
+ fixedWidth = false,
154
+ wrap = false,
155
+ ...props
156
+ }) {
157
+ const texts = Array.isArray(text) ? text : [text];
158
+ const isMulti = texts.length > 1;
159
+ const prefersReducedMotion = useReducedMotion();
160
+ const exitSpan = exitDuration ?? duration * COVERAGE_SPAN;
161
+ const lead = Math.max(0, exitLead ?? duration * EXIT_LEAD_RATIO);
162
+ const exitTotal = lead + exitSpan;
163
+ const leadFraction = exitTotal > 0 ? lead / exitTotal : 0;
164
+ const exitOpacityEase = useMemo(() => makeExitEase(leadFraction), [leadFraction]);
165
+ const spanRef = useRef(null);
166
+ const optsRef = useRef({ repeat, repeatDelay, texts });
167
+ optsRef.current = { repeat, repeatDelay, texts };
168
+ const indexRef = useRef(0);
169
+ const hasPlayedRef = useRef(false);
170
+ const timerRef = useRef(void 0);
171
+ const pendingRepeatRef = useRef(false);
172
+ const [activeIndex, setActiveIndex] = useState(0);
173
+ const [sweep, setSweep] = useState(null);
174
+ const [exiting, setExiting] = useState(null);
175
+ const clearExiting = useCallback(() => setExiting(null), []);
176
+ const [measuredWidths, setMeasuredWidths] = useState([]);
177
+ const [wrapHeight, setWrapHeight] = useState(null);
178
+ const innerRef = useRef(null);
179
+ const isInView = useInView(spanRef, { once, amount: 0.1 });
180
+ const isLiveInView = useInView(spanRef, {
181
+ once: false,
182
+ amount: 0.1
183
+ });
184
+ useEffect(() => {
185
+ const el = spanRef.current;
186
+ if (!(el && isMulti) || wrap) return;
187
+ const measure = () => setMeasuredWidths(measureWidths(el, texts));
188
+ measure();
189
+ if (document.fonts.status !== "loaded") document.fonts.ready.then(measure);
190
+ }, [Array.isArray(text) ? text.join("\0") : text, isMulti, wrap, texts]);
191
+ useEffect(() => {
192
+ const el = innerRef.current;
193
+ if (!(el && wrap && isMulti)) return;
194
+ const observer = new ResizeObserver(([entry]) => {
195
+ if (!entry) return;
196
+ const h = entry.contentRect.height;
197
+ setWrapHeight(
198
+ (prev) => prev !== null && prev.h === h ? prev : {
199
+ h,
200
+ shrink: prev !== null && h < prev.h
201
+ }
202
+ );
203
+ });
204
+ observer.observe(el);
205
+ return () => observer.disconnect();
206
+ }, [wrap, isMulti]);
207
+ const advance = useCallback(() => {
208
+ const opts = optsRef.current;
209
+ const current = indexRef.current;
210
+ const next = (current + 1) % opts.texts.length;
211
+ indexRef.current = next;
212
+ setExiting({ index: current, token: Date.now() });
213
+ setActiveIndex(next);
214
+ setSweep((prev) => ({
215
+ cycle: (prev?.cycle ?? 0) + 1,
216
+ lead: true
217
+ }));
218
+ }, []);
219
+ const scheduleRepeat = useCallback(() => {
220
+ timerRef.current = setTimeout(() => {
221
+ timerRef.current = void 0;
222
+ advance();
223
+ }, optsRef.current.repeatDelay * 1e3);
224
+ }, [advance]);
225
+ const onSweepEnd = useCallback(
226
+ (event) => {
227
+ if (!event.animationName.startsWith("dia-sweep")) return;
228
+ if (!optsRef.current.repeat) return;
229
+ scheduleRepeat();
230
+ },
231
+ [scheduleRepeat]
232
+ );
233
+ useEffect(() => {
234
+ if (prefersReducedMotion) return;
235
+ if (startOnView && !isInView) return;
236
+ if (!start) return;
237
+ if (once && hasPlayedRef.current) return;
238
+ hasPlayedRef.current = true;
239
+ setSweep((prev) => prev === null ? { cycle: 0, lead: false } : { cycle: prev.cycle + 1, lead: false });
240
+ }, [isInView, start, startOnView, once, prefersReducedMotion]);
241
+ useEffect(() => {
242
+ if (!repeat || prefersReducedMotion) return;
243
+ if (!isLiveInView) {
244
+ if (timerRef.current === void 0) return;
245
+ clearTimeout(timerRef.current);
246
+ timerRef.current = void 0;
247
+ pendingRepeatRef.current = true;
248
+ } else if (pendingRepeatRef.current) {
249
+ pendingRepeatRef.current = false;
250
+ scheduleRepeat();
251
+ }
252
+ }, [isLiveInView, repeat, prefersReducedMotion, scheduleRepeat]);
253
+ useEffect(() => () => clearTimeout(timerRef.current), []);
254
+ const paused = repeat && sweep !== null && !isLiveInView;
255
+ const revealStyle = buildSweepStyle({
256
+ colors,
257
+ textColor,
258
+ duration,
259
+ delay: delay + (sweep?.lead ? lead : 0),
260
+ sweep,
261
+ paused,
262
+ reduced: prefersReducedMotion === true
263
+ });
264
+ if (!isMulti)
265
+ return /* @__PURE__ */ jsx(
266
+ motion.span,
267
+ {
268
+ ref: spanRef,
269
+ className: cn("align-baseline text-inherit leading-[100%]", className),
270
+ style: revealStyle,
271
+ ...props,
272
+ onAnimationEnd: onSweepEnd,
273
+ children: texts[activeIndex]
274
+ }
275
+ );
276
+ const fixedW = !wrap && fixedWidth && measuredWidths.length > 0 ? Math.max(...measuredWidths) : void 0;
277
+ const animatedW = wrap || fixedWidth ? void 0 : measuredWidths[activeIndex];
278
+ const animatedH = wrap ? wrapHeight?.h : void 0;
279
+ const heightDelay = exiting !== null && wrapHeight?.shrink ? exitTotal : 0;
280
+ const incoming = /* @__PURE__ */ jsx(
281
+ "span",
282
+ {
283
+ ref: innerRef,
284
+ className: cn("inline-block", wrap && "w-full", !wrap && "whitespace-nowrap"),
285
+ style: revealStyle,
286
+ onAnimationEnd: onSweepEnd,
287
+ children: texts[activeIndex]
288
+ }
289
+ );
290
+ return /* @__PURE__ */ jsxs(
291
+ motion.span,
292
+ {
293
+ ref: spanRef,
294
+ className: cn(
295
+ wrap ? "relative inline-block w-full text-center align-baseline text-inherit" : "relative inline-block whitespace-nowrap text-center align-baseline text-inherit leading-[100%]",
296
+ className
297
+ ),
298
+ style: {
299
+ ...fixedW !== void 0 && { width: fixedW }
300
+ },
301
+ animate: {
302
+ ...animatedW !== void 0 && { width: animatedW }
303
+ },
304
+ transition: {
305
+ width: { duration: 0.4, ease: [0.4, 0, 0.2, 1] }
306
+ },
307
+ ...props,
308
+ children: [
309
+ wrap ? /* @__PURE__ */ jsxs(HeightClipper, { height: animatedH, delay: heightDelay, children: [
310
+ /* @__PURE__ */ jsx(WidthReservation, { texts }),
311
+ incoming
312
+ ] }) : incoming,
313
+ exiting && !prefersReducedMotion && /* @__PURE__ */ jsx(
314
+ ExitingLine,
315
+ {
316
+ text: texts[exiting.index],
317
+ textColor,
318
+ duration: 0.4,
319
+ fallDuration: 0.25,
320
+ opacityEase: exitOpacityEase,
321
+ wrap,
322
+ onDone: clearExiting
323
+ },
324
+ exiting.token
325
+ )
326
+ ]
327
+ }
328
+ );
329
+ }
330
+
331
+ export { DiaTextReveal };
3
332
  //# sourceMappingURL=dia-text-reveal.mjs.map
4
333
  //# sourceMappingURL=dia-text-reveal.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"dia-text-reveal.mjs"}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/dia-text-reveal.lines.tsx","../src/components/dia-text-reveal.sweep.ts","../src/components/dia-text-reveal.utils.ts","../src/components/dia-text-reveal.tsx"],"names":["jsx","motion"],"mappings":"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","file":"dia-text-reveal.mjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","'use client';\n\nimport { motion } from 'framer-motion';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '../lib/utils.js';\n\ntype ExitingLineProps = {\n text: string;\n textColor: string;\n duration: number;\n fallDuration: number;\n opacityEase: (t: number) => number;\n wrap?: boolean;\n onDone: () => void;\n};\n\ntype HeightClipperProps = {\n height?: number;\n delay: number;\n children: ReactNode;\n};\n\ntype WidthReservationProps = { texts: string[] };\n\nexport function HeightClipper({ height, delay, children }: HeightClipperProps) {\n return (\n <motion.span\n className=\"block w-full overflow-hidden\"\n animate={height === undefined ? {} : { height }}\n transition={{\n height: { duration: 0.4, ease: [0.4, 0, 0.2, 1], delay },\n }}\n >\n {children}\n </motion.span>\n );\n}\n\nexport function ExitingLine({ text, textColor, duration, fallDuration, opacityEase, wrap = false, onDone }: ExitingLineProps) {\n return (\n <motion.span\n aria-hidden={true}\n className={cn(\n wrap\n ? 'pointer-events-none absolute top-0 left-0 w-full'\n : 'pointer-events-none absolute top-0 left-1/2 whitespace-nowrap',\n )}\n style={{ color: textColor }}\n initial={wrap ? { opacity: 1, y: 0 } : { opacity: 1, x: '-50%', y: 0 }}\n animate={wrap ? { opacity: 0, y: 14 } : { opacity: 0, x: '-50%', y: 14 }}\n transition={{\n opacity: { duration, ease: opacityEase },\n y: { duration: fallDuration, ease: [0.22, 0.61, 0.36, 1] },\n }}\n onAnimationComplete={onDone}\n >\n {text}\n </motion.span>\n );\n}\n\nexport function WidthReservation({ texts }: WidthReservationProps) {\n return (\n <span aria-hidden={true} className=\"invisible block h-0 overflow-hidden\">\n {texts.map((t) => (\n <span key={t} className=\"block\">\n {t}\n </span>\n ))}\n </span>\n );\n}\n","/**\n * The moving gradient band that paints DiaTextReveal's glyphs, and the coverage math that\n * lets the outgoing line's fade track it exactly.\n *\n * The band moves by *sliding a static gradient*, not by rebuilding one per frame. Rebuilding\n * meant a JS callback, a style recalc, a fresh gradient rasterization and a\n * `background-clip: text` repaint on every frame — all main-thread-only work, so the sweep\n * stalled whenever the thread was contended (scrolling, WebGL render loops, React commits).\n * A fixed image offset by a CSS animation needs no script at all and lets the browser cache\n * the raster, which is what keeps the sweep moving while the page is being scrolled.\n */\n\nimport type { CSSProperties } from 'react';\n\n/** Half-width of the colour band, in percent of the line. */\nconst BAND_HALF = 17;\n/** Band centre at the start of a sweep — fully left of the line, so nothing is painted. */\nconst SWEEP_START = -BAND_HALF;\n/** Band centre at the end of a sweep — fully right of the line, so everything is painted. */\nconst SWEEP_END = 100 + BAND_HALF;\n\n/** Cubic in-out: the band accelerates in, then eases out. */\nconst sweepEaseFn = (t: number) => (t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2);\n\n/**\n * Fraction of the line the sweep has painted at `progress` (0–1 of the sweep's duration).\n */\nconst coverageAt = (progress: number) => Math.min(1, (sweepEaseFn(progress) * (SWEEP_END - SWEEP_START)) / 100);\n\n/**\n * Point in the sweep (0–1) at which the whole line is painted.\n */\nconst COVERAGE_SPAN = (() => {\n let lo = 0;\n let hi = 1;\n for (let i = 0; i < 40; i += 1) {\n const mid = (lo + hi) / 2;\n if (coverageAt(mid) < 1) lo = mid;\n else hi = mid;\n }\n return hi;\n})();\n\nconst EXIT_FADE_BIAS = 0.4;\n\n/** Easing for the outgoing line's fade, tracking how much of the incoming line is painted. */\nconst exitEase = (t: number) => coverageAt(t * COVERAGE_SPAN) ** EXIT_FADE_BIAS;\n\nconst makeExitEase = (leadFraction: number) => {\n if (leadFraction <= 0) return exitEase;\n if (leadFraction >= 1) return () => 0;\n return (t: number) => (t <= leadFraction ? 0 : exitEase((t - leadFraction) / (1 - leadFraction)));\n};\n\n/* ── Sliding-gradient geometry ───────────────────────────────────────── */\n\nconst SWEEP_SCALE = 3;\nconst BAND_HALF_IMAGE = BAND_HALF / SWEEP_SCALE;\n\nconst positionFor = (pos: number) => (pos - 50 * SWEEP_SCALE) / (1 - SWEEP_SCALE);\n\n/** Position holding the band fully left of the line — nothing painted. */\nconst SWEEP_FROM = `${positionFor(SWEEP_START).toFixed(3)}%`;\n/** Position holding the band fully right of the line — everything painted. */\nconst SWEEP_TO = `${positionFor(SWEEP_END).toFixed(3)}%`;\n/** `background-size` for the oversized image the animation slides. */\nconst SWEEP_SIZE = `${SWEEP_SCALE * 100}% 100%`;\n\nconst EASE_SAMPLES = 24;\nconst sweepEaseCss = `linear(${Array.from({ length: EASE_SAMPLES + 1 }, (_, i) => sweepEaseFn(i / EASE_SAMPLES).toFixed(5)).join(\n ', ',\n)})`;\n\nfunction buildSweepGradient(colors: string[], textColor: string) {\n const bandStart = 50 - BAND_HALF_IMAGE;\n const bandEnd = 50 + BAND_HALF_IMAGE;\n const n = colors.length;\n\n const parts: string[] = [`${textColor} 0%`, `${textColor} ${bandStart.toFixed(3)}%`];\n for (const [i, c] of colors.entries()) {\n const pct = n === 1 ? 50 : bandStart + (i / (n - 1)) * BAND_HALF_IMAGE * 2;\n parts.push(`${c} ${pct.toFixed(3)}%`);\n }\n parts.push(`transparent ${bandEnd.toFixed(3)}%`, 'transparent 100%');\n\n return `linear-gradient(90deg, ${parts.join(', ')})`;\n}\n\nexport type Sweep = { cycle: number; lead: boolean } | null;\n\ntype SweepStyleArgs = {\n colors: string[];\n textColor: string;\n duration: number;\n delay: number;\n sweep: Sweep;\n paused: boolean;\n reduced: boolean;\n};\n\nfunction buildSweepStyle({ colors, textColor, duration, delay, sweep, paused, reduced }: SweepStyleArgs) {\n return {\n color: 'transparent',\n backgroundClip: 'text',\n WebkitBackgroundClip: 'text',\n backgroundImage: buildSweepGradient(colors, textColor),\n backgroundRepeat: 'no-repeat',\n backgroundSize: SWEEP_SIZE,\n backgroundPositionX: reduced ? SWEEP_TO : SWEEP_FROM,\n '--dia-sweep-from': SWEEP_FROM,\n '--dia-sweep-to': SWEEP_TO,\n ...(sweep !== null &&\n !reduced && {\n animationName: sweep.cycle % 2 === 0 ? 'dia-sweep-a' : 'dia-sweep-b',\n animationDuration: `${duration}s`,\n animationDelay: `${delay}s`,\n animationTimingFunction: sweepEaseCss,\n animationFillMode: 'both',\n animationIterationCount: 1,\n animationPlayState: paused ? 'paused' : 'running',\n }),\n } satisfies CSSProperties & Record<`--${string}`, string>;\n}\n\nexport { buildSweepStyle, COVERAGE_SPAN, makeExitEase };\n","/** Measures the single-line (nowrap) rendered width of each text string. */\nexport function measureWidths(el: HTMLElement, texts: string[]) {\n const parent = el.parentElement;\n if (!parent) return texts.map(() => 0);\n\n const ghost = el.cloneNode();\n if (!(ghost instanceof HTMLElement)) return texts.map(() => 0);\n\n Object.assign(ghost.style, {\n position: 'absolute',\n visibility: 'hidden',\n pointerEvents: 'none',\n width: 'auto',\n whiteSpace: 'nowrap',\n });\n parent.appendChild(ghost);\n const widths = texts.map((t) => {\n ghost.textContent = t;\n return ghost.getBoundingClientRect().width;\n });\n ghost.remove();\n return widths;\n}\n","'use client';\n\nimport { motion, useInView, useReducedMotion } from 'framer-motion';\nimport type { AnimationEvent, ComponentPropsWithoutRef } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { cn } from '../lib/utils.js';\n\nimport { ExitingLine, HeightClipper, WidthReservation } from './dia-text-reveal.lines.js';\nimport { buildSweepStyle, COVERAGE_SPAN, makeExitEase, type Sweep } from './dia-text-reveal.sweep.js';\nimport { measureWidths } from './dia-text-reveal.utils.js';\nimport './dia-text-reveal.css';\n\nconst DEFAULT_COLORS = ['#c679c4', '#fa3d1d', '#ffb005', '#e1e1fe', '#0358f7'];\n\nconst EXIT_LEAD_RATIO = 0.3;\n\nexport interface DiaTextRevealProps\n extends Omit<ComponentPropsWithoutRef<typeof motion.span>, 'ref' | 'children' | 'style' | 'animate' | 'transition' | 'color'> {\n /** Text to reveal. Pass multiple strings to rotate when `repeat` is `true`. */\n text: string | string[];\n /** Colors sampled across the moving gradient band. */\n colors?: string[];\n /** CSS color for revealed text after the sweep. @defaultValue `\"var(--color-foreground)\"` */\n textColor?: string;\n /** Duration of one sweep pass, in seconds. @defaultValue `1` */\n duration?: number;\n /** Delay before the sweep starts, in seconds. @defaultValue `0` */\n delay?: number;\n /** When `text` is an array, replay the sweep and advance to the next string after each completion. */\n repeat?: boolean;\n /** Pause between cycles when `repeat` is `true`, in seconds. @defaultValue `0.5` */\n repeatDelay?: number;\n /** How long the outgoing line takes to fade/slide away, in seconds. @defaultValue the sweep's coverage window */\n exitDuration?: number;\n /** Head start given to the outgoing line, in seconds. @defaultValue `0.15 * duration` */\n exitLead?: number;\n /** If `true`, the animation starts only after the element enters the viewport. @defaultValue `true` */\n startOnView?: boolean;\n /** External gate: while `false`, the sweep is held at its start. @defaultValue `true` */\n start?: boolean;\n /** Passed to `useInView`: if `true`, in-view detection fires at most once. @defaultValue `true` */\n once?: boolean;\n /** Additional class names for the animated `span`. */\n className?: string;\n /** When `text` has multiple entries, use the widest string's width for layout. @defaultValue `false` */\n fixedWidth?: boolean;\n /** Allow the text to wrap onto multiple lines. @defaultValue `false` */\n wrap?: boolean;\n}\n\nexport function DiaTextReveal({\n text,\n colors = DEFAULT_COLORS,\n textColor = 'var(--color-foreground)',\n duration = 1,\n delay = 0,\n repeat = false,\n repeatDelay = 0.5,\n exitDuration,\n exitLead,\n startOnView = true,\n start = true,\n once = true,\n className,\n fixedWidth = false,\n wrap = false,\n ...props\n}: DiaTextRevealProps) {\n const texts = Array.isArray(text) ? text : [text];\n const isMulti = texts.length > 1;\n const prefersReducedMotion = useReducedMotion();\n const exitSpan = exitDuration ?? duration * COVERAGE_SPAN;\n const lead = Math.max(0, exitLead ?? duration * EXIT_LEAD_RATIO);\n const exitTotal = lead + exitSpan;\n const leadFraction = exitTotal > 0 ? lead / exitTotal : 0;\n const exitOpacityEase = useMemo(() => makeExitEase(leadFraction), [leadFraction]);\n\n const spanRef = useRef<HTMLSpanElement>(null);\n const optsRef = useRef({ repeat, repeatDelay, texts });\n optsRef.current = { repeat, repeatDelay, texts };\n\n const indexRef = useRef(0);\n const hasPlayedRef = useRef(false);\n const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n const pendingRepeatRef = useRef(false);\n\n const [activeIndex, setActiveIndex] = useState(0);\n const [sweep, setSweep] = useState<Sweep>(null);\n const [exiting, setExiting] = useState<{\n index: number;\n token: number;\n } | null>(null);\n const clearExiting = useCallback(() => setExiting(null), []);\n const [measuredWidths, setMeasuredWidths] = useState<number[]>([]);\n const [wrapHeight, setWrapHeight] = useState<{\n h: number;\n shrink: boolean;\n } | null>(null);\n const innerRef = useRef<HTMLSpanElement>(null);\n\n const isInView = useInView(spanRef, { once, amount: 0.1 });\n const isLiveInView = useInView(spanRef, {\n once: false,\n amount: 0.1,\n });\n\n // biome-ignore lint/plugin: measures live DOM layout (getBoundingClientRect on a ghost clone) — post-render measurement.\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-measures only when the text content changes; isMulti/texts are derived from the same text prop.\n useEffect(() => {\n const el = spanRef.current;\n if (!(el && isMulti) || wrap) return;\n const measure = () => setMeasuredWidths(measureWidths(el, texts));\n measure();\n if (document.fonts.status !== 'loaded') document.fonts.ready.then(measure);\n }, [Array.isArray(text) ? text.join('\\0') : text, isMulti, wrap, texts]);\n\n // biome-ignore lint/plugin: subscribes a ResizeObserver to live DOM layout.\n useEffect(() => {\n const el = innerRef.current;\n if (!(el && wrap && isMulti)) return;\n const observer = new ResizeObserver(([entry]) => {\n if (!entry) return;\n const h = entry.contentRect.height;\n setWrapHeight((prev) =>\n prev !== null && prev.h === h\n ? prev\n : {\n h,\n shrink: prev !== null && h < prev.h,\n },\n );\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, [wrap, isMulti]);\n\n const advance = useCallback(() => {\n const opts = optsRef.current;\n const current = indexRef.current;\n const next = (current + 1) % opts.texts.length;\n indexRef.current = next;\n setExiting({ index: current, token: Date.now() });\n setActiveIndex(next);\n setSweep((prev) => ({\n cycle: (prev?.cycle ?? 0) + 1,\n lead: true,\n }));\n }, []);\n\n const scheduleRepeat = useCallback(() => {\n timerRef.current = setTimeout(() => {\n timerRef.current = undefined;\n advance();\n }, optsRef.current.repeatDelay * 1000);\n }, [advance]);\n\n const onSweepEnd = useCallback(\n (event: AnimationEvent<HTMLSpanElement>) => {\n if (!event.animationName.startsWith('dia-sweep')) return;\n if (!optsRef.current.repeat) return;\n scheduleRepeat();\n },\n [scheduleRepeat],\n );\n\n // biome-ignore lint/plugin: flips imperative animation state on a viewport/gate edge.\n useEffect(() => {\n if (prefersReducedMotion) return;\n if (startOnView && !isInView) return;\n if (!start) return;\n if (once && hasPlayedRef.current) return;\n hasPlayedRef.current = true;\n setSweep((prev) => (prev === null ? { cycle: 0, lead: false } : { cycle: prev.cycle + 1, lead: false }));\n }, [isInView, start, startOnView, once, prefersReducedMotion]);\n\n // biome-ignore lint/plugin: pauses/re-arms a pending timer on live viewport presence.\n useEffect(() => {\n if (!repeat || prefersReducedMotion) return;\n if (!isLiveInView) {\n if (timerRef.current === undefined) return;\n clearTimeout(timerRef.current);\n timerRef.current = undefined;\n pendingRepeatRef.current = true;\n } else if (pendingRepeatRef.current) {\n pendingRepeatRef.current = false;\n scheduleRepeat();\n }\n }, [isLiveInView, repeat, prefersReducedMotion, scheduleRepeat]);\n\n // biome-ignore lint/plugin: releases a pending timer on unmount.\n useEffect(() => () => clearTimeout(timerRef.current), []);\n\n const paused = repeat && sweep !== null && !isLiveInView;\n\n const revealStyle = buildSweepStyle({\n colors,\n textColor,\n duration,\n delay: delay + (sweep?.lead ? lead : 0),\n sweep,\n paused,\n reduced: prefersReducedMotion === true,\n });\n\n if (!isMulti)\n return (\n <motion.span\n ref={spanRef}\n className={cn('align-baseline text-inherit leading-[100%]', className)}\n style={revealStyle}\n {...props}\n onAnimationEnd={onSweepEnd}\n >\n {texts[activeIndex]}\n </motion.span>\n );\n\n const fixedW = !wrap && fixedWidth && measuredWidths.length > 0 ? Math.max(...measuredWidths) : undefined;\n const animatedW = wrap || fixedWidth ? undefined : measuredWidths[activeIndex];\n const animatedH = wrap ? wrapHeight?.h : undefined;\n const heightDelay = exiting !== null && wrapHeight?.shrink ? exitTotal : 0;\n\n const incoming = (\n <span\n ref={innerRef}\n className={cn('inline-block', wrap && 'w-full', !wrap && 'whitespace-nowrap')}\n style={revealStyle}\n onAnimationEnd={onSweepEnd}\n >\n {texts[activeIndex]}\n </span>\n );\n\n return (\n <motion.span\n ref={spanRef}\n className={cn(\n wrap\n ? 'relative inline-block w-full text-center align-baseline text-inherit'\n : 'relative inline-block whitespace-nowrap text-center align-baseline text-inherit leading-[100%]',\n className,\n )}\n style={{\n ...(fixedW !== undefined && { width: fixedW }),\n }}\n animate={{\n ...(animatedW !== undefined && { width: animatedW }),\n }}\n transition={{\n width: { duration: 0.4, ease: [0.4, 0, 0.2, 1] },\n }}\n {...props}\n >\n {wrap ? (\n <HeightClipper height={animatedH} delay={heightDelay}>\n <WidthReservation texts={texts} />\n {incoming}\n </HeightClipper>\n ) : (\n incoming\n )}\n\n {exiting && !prefersReducedMotion && (\n <ExitingLine\n key={exiting.token}\n text={texts[exiting.index]!}\n textColor={textColor}\n duration={0.4}\n fallDuration={0.25}\n opacityEase={exitOpacityEase}\n wrap={wrap}\n onDone={clearExiting}\n />\n )}\n </motion.span>\n );\n}\n"]}
@@ -1,10 +1,10 @@
1
+ "use client";
1
2
  'use strict';
2
3
 
3
4
  var clsx = require('clsx');
4
5
  var tailwindMerge = require('tailwind-merge');
5
6
  var jsxRuntime = require('react/jsx-runtime');
6
7
 
7
- // src/lib/utils.ts
8
8
  function cn(...inputs) {
9
9
  return tailwindMerge.twMerge(clsx.clsx(inputs));
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/components/elevated-input.tsx"],"names":["twMerge","clsx","jsx"],"mappings":";;;;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAOA,qBAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACGO,SAAS,aAAA,CAAc;AAAA,EAC5B,SAAA;AAAA,EACA,IAAA,GAAO,MAAA;AAAA,EACP,GAAA;AAAA,EACA,GAAG;AACL,CAAA,EAEG;AACD,EAAA,uBACEC,cAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA;AAAA,QAET,4CAAA;AAAA;AAAA,QAEA,+EAAA;AAAA;AAAA,QAEA,UAAA;AAAA;AAAA,QAEA,0CAAA;AAAA;AAAA,QAGA,+DAAA;AAAA,QACA,oEAAA;AAAA;AAAA,QAGA,wLAAA;AAAA;AAAA,QAEA,4LAAA;AAAA;AAAA,QAGA,wMAAA;AAAA,QACA,6MAAA;AAAA,QAEA,gCAAA;AAAA,QACA,iDAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ","file":"elevated-input.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","import type { InputHTMLAttributes, RefObject } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/**\n * Physically-recessed input: the inverse read of GlossyButton.\n * The illusion is built entirely from `box-shadow` layers (no wrapper div).\n *\n * Server-renderable: no browser APIs are used.\n */\nexport function ElevatedInput({\n className,\n type = 'text',\n ref,\n ...props\n}: InputHTMLAttributes<HTMLInputElement> & {\n ref?: RefObject<HTMLInputElement | null>;\n}) {\n return (\n <input\n ref={ref}\n type={type}\n className={cn(\n // Layout & shape\n 'relative w-full overflow-hidden rounded-lg',\n // Typography\n 'text-(--color-foreground) text-sm placeholder:text-(--color-muted-foreground)',\n // Sizing\n 'h-9 px-3',\n // Reset native input chrome\n 'appearance-none border-none outline-none',\n\n // Background — a barely-there top darkening that reads as cavity depth.\n 'bg-[linear-gradient(to_bottom,oklch(0_0_0/0.04),transparent)]',\n 'dark:bg-[linear-gradient(to_bottom,oklch(1_0_0/0.04),transparent)]',\n\n // Shadow stack — light mode\n 'shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.08),inset_0_4px_4px_-2px_oklch(0_0_0/0.08),0_1px_0_0_oklch(0_0_0/0.12),inset_0_0_0_1px_oklch(0_0_0/0.16)]',\n // Shadow stack — dark mode\n 'dark:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.1),inset_0_2px_2px_-1px_oklch(0_0_0/0.28),inset_0_4px_4px_-2px_oklch(0_0_0/0.22),0_1px_0_0_oklch(0_0_0/0.36),inset_0_0_0_1px_oklch(1_0_0/0.16)]',\n\n // Focus\n 'focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.04),inset_0_4px_4px_-2px_oklch(0_0_0/0.04),0_0_0_3px_oklch(0_0_0/0.08),inset_0_0_0_1.5px_oklch(0_0_0/0.36)]',\n 'dark:focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.12),inset_0_2px_2px_-1px_oklch(0_0_0/0.16),inset_0_4px_4px_-2px_oklch(0_0_0/0.12),0_0_0_3px_oklch(1_0_0/0.08),inset_0_0_0_1.5px_oklch(1_0_0/0.28)]',\n\n 'transition-shadow duration-150',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/elevated-input.tsx"],"names":["twMerge","clsx","jsx"],"mappings":";;;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAOA,qBAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACGO,SAAS,aAAA,CAAc;AAAA,EAC5B,SAAA;AAAA,EACA,IAAA,GAAO,MAAA;AAAA,EACP,GAAA;AAAA,EACA,GAAG;AACL,CAAA,EAEG;AACD,EAAA,uBACEC,cAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA;AAAA,QAET,4CAAA;AAAA;AAAA,QAEA,+EAAA;AAAA;AAAA,QAEA,UAAA;AAAA;AAAA,QAEA,0CAAA;AAAA;AAAA,QAGA,+DAAA;AAAA,QACA,oEAAA;AAAA;AAAA,QAGA,wLAAA;AAAA;AAAA,QAEA,4LAAA;AAAA;AAAA,QAGA,wMAAA;AAAA,QACA,6MAAA;AAAA,QAEA,gCAAA;AAAA,QACA,iDAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ","file":"elevated-input.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","import type { InputHTMLAttributes, RefObject } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/**\n * Physically-recessed input: the inverse read of GlossyButton.\n * The illusion is built entirely from `box-shadow` layers (no wrapper div).\n *\n * Server-renderable: no browser APIs are used.\n */\nexport function ElevatedInput({\n className,\n type = 'text',\n ref,\n ...props\n}: InputHTMLAttributes<HTMLInputElement> & {\n ref?: RefObject<HTMLInputElement | null>;\n}) {\n return (\n <input\n ref={ref}\n type={type}\n className={cn(\n // Layout & shape\n 'relative w-full overflow-hidden rounded-lg',\n // Typography\n 'text-(--color-foreground) text-sm placeholder:text-(--color-muted-foreground)',\n // Sizing\n 'h-9 px-3',\n // Reset native input chrome\n 'appearance-none border-none outline-none',\n\n // Background — a barely-there top darkening that reads as cavity depth.\n 'bg-[linear-gradient(to_bottom,oklch(0_0_0/0.04),transparent)]',\n 'dark:bg-[linear-gradient(to_bottom,oklch(1_0_0/0.04),transparent)]',\n\n // Shadow stack — light mode\n 'shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.08),inset_0_4px_4px_-2px_oklch(0_0_0/0.08),0_1px_0_0_oklch(0_0_0/0.12),inset_0_0_0_1px_oklch(0_0_0/0.16)]',\n // Shadow stack — dark mode\n 'dark:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.1),inset_0_2px_2px_-1px_oklch(0_0_0/0.28),inset_0_4px_4px_-2px_oklch(0_0_0/0.22),0_1px_0_0_oklch(0_0_0/0.36),inset_0_0_0_1px_oklch(1_0_0/0.16)]',\n\n // Focus\n 'focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.04),inset_0_4px_4px_-2px_oklch(0_0_0/0.04),0_0_0_3px_oklch(0_0_0/0.08),inset_0_0_0_1.5px_oklch(0_0_0/0.36)]',\n 'dark:focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.12),inset_0_2px_2px_-1px_oklch(0_0_0/0.16),inset_0_4px_4px_-2px_oklch(0_0_0/0.12),0_0_0_3px_oklch(1_0_0/0.08),inset_0_0_0_1.5px_oklch(1_0_0/0.28)]',\n\n 'transition-shadow duration-150',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n}\n"]}
@@ -1,4 +1,50 @@
1
- export { ElevatedInput } from './chunk-6T5LR34O.mjs';
2
- import './chunk-QAWSH567.mjs';
1
+ "use client";
2
+ import { clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ function cn(...inputs) {
7
+ return twMerge(clsx(inputs));
8
+ }
9
+ function ElevatedInput({
10
+ className,
11
+ type = "text",
12
+ ref,
13
+ ...props
14
+ }) {
15
+ return /* @__PURE__ */ jsx(
16
+ "input",
17
+ {
18
+ ref,
19
+ type,
20
+ className: cn(
21
+ // Layout & shape
22
+ "relative w-full overflow-hidden rounded-lg",
23
+ // Typography
24
+ "text-(--color-foreground) text-sm placeholder:text-(--color-muted-foreground)",
25
+ // Sizing
26
+ "h-9 px-3",
27
+ // Reset native input chrome
28
+ "appearance-none border-none outline-none",
29
+ // Background — a barely-there top darkening that reads as cavity depth.
30
+ "bg-[linear-gradient(to_bottom,oklch(0_0_0/0.04),transparent)]",
31
+ "dark:bg-[linear-gradient(to_bottom,oklch(1_0_0/0.04),transparent)]",
32
+ // Shadow stack — light mode
33
+ "shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.08),inset_0_4px_4px_-2px_oklch(0_0_0/0.08),0_1px_0_0_oklch(0_0_0/0.12),inset_0_0_0_1px_oklch(0_0_0/0.16)]",
34
+ // Shadow stack — dark mode
35
+ "dark:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.1),inset_0_2px_2px_-1px_oklch(0_0_0/0.28),inset_0_4px_4px_-2px_oklch(0_0_0/0.22),0_1px_0_0_oklch(0_0_0/0.36),inset_0_0_0_1px_oklch(1_0_0/0.16)]",
36
+ // Focus
37
+ "focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.04),inset_0_4px_4px_-2px_oklch(0_0_0/0.04),0_0_0_3px_oklch(0_0_0/0.08),inset_0_0_0_1.5px_oklch(0_0_0/0.36)]",
38
+ "dark:focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.12),inset_0_2px_2px_-1px_oklch(0_0_0/0.16),inset_0_4px_4px_-2px_oklch(0_0_0/0.12),0_0_0_3px_oklch(1_0_0/0.08),inset_0_0_0_1.5px_oklch(1_0_0/0.28)]",
39
+ "transition-shadow duration-150",
40
+ "disabled:cursor-not-allowed disabled:opacity-50",
41
+ className
42
+ ),
43
+ ...props
44
+ }
45
+ );
46
+ }
47
+
48
+ export { ElevatedInput };
3
49
  //# sourceMappingURL=elevated-input.mjs.map
4
50
  //# sourceMappingURL=elevated-input.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"elevated-input.mjs"}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/elevated-input.tsx"],"names":[],"mappings":";;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACGO,SAAS,aAAA,CAAc;AAAA,EAC5B,SAAA;AAAA,EACA,IAAA,GAAO,MAAA;AAAA,EACP,GAAA;AAAA,EACA,GAAG;AACL,CAAA,EAEG;AACD,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA;AAAA,QAET,4CAAA;AAAA;AAAA,QAEA,+EAAA;AAAA;AAAA,QAEA,UAAA;AAAA;AAAA,QAEA,0CAAA;AAAA;AAAA,QAGA,+DAAA;AAAA,QACA,oEAAA;AAAA;AAAA,QAGA,wLAAA;AAAA;AAAA,QAEA,4LAAA;AAAA;AAAA,QAGA,wMAAA;AAAA,QACA,6MAAA;AAAA,QAEA,gCAAA;AAAA,QACA,iDAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ","file":"elevated-input.mjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","import type { InputHTMLAttributes, RefObject } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/**\n * Physically-recessed input: the inverse read of GlossyButton.\n * The illusion is built entirely from `box-shadow` layers (no wrapper div).\n *\n * Server-renderable: no browser APIs are used.\n */\nexport function ElevatedInput({\n className,\n type = 'text',\n ref,\n ...props\n}: InputHTMLAttributes<HTMLInputElement> & {\n ref?: RefObject<HTMLInputElement | null>;\n}) {\n return (\n <input\n ref={ref}\n type={type}\n className={cn(\n // Layout & shape\n 'relative w-full overflow-hidden rounded-lg',\n // Typography\n 'text-(--color-foreground) text-sm placeholder:text-(--color-muted-foreground)',\n // Sizing\n 'h-9 px-3',\n // Reset native input chrome\n 'appearance-none border-none outline-none',\n\n // Background — a barely-there top darkening that reads as cavity depth.\n 'bg-[linear-gradient(to_bottom,oklch(0_0_0/0.04),transparent)]',\n 'dark:bg-[linear-gradient(to_bottom,oklch(1_0_0/0.04),transparent)]',\n\n // Shadow stack — light mode\n 'shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.08),inset_0_4px_4px_-2px_oklch(0_0_0/0.08),0_1px_0_0_oklch(0_0_0/0.12),inset_0_0_0_1px_oklch(0_0_0/0.16)]',\n // Shadow stack — dark mode\n 'dark:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.1),inset_0_2px_2px_-1px_oklch(0_0_0/0.28),inset_0_4px_4px_-2px_oklch(0_0_0/0.22),0_1px_0_0_oklch(0_0_0/0.36),inset_0_0_0_1px_oklch(1_0_0/0.16)]',\n\n // Focus\n 'focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.08),inset_0_2px_2px_-1px_oklch(0_0_0/0.04),inset_0_4px_4px_-2px_oklch(0_0_0/0.04),0_0_0_3px_oklch(0_0_0/0.08),inset_0_0_0_1.5px_oklch(0_0_0/0.36)]',\n 'dark:focus-visible:shadow-[inset_0_1px_0_0_oklch(1_0_0/0.12),inset_0_2px_2px_-1px_oklch(0_0_0/0.16),inset_0_4px_4px_-2px_oklch(0_0_0/0.12),0_0_0_3px_oklch(1_0_0/0.08),inset_0_0_0_1.5px_oklch(1_0_0/0.28)]',\n\n 'transition-shadow duration-150',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n}\n"]}
package/dist/fade-in.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  'use strict';
2
3
 
3
4
  var framerMotion = require('framer-motion');
package/dist/fade-in.mjs CHANGED
@@ -1,4 +1,86 @@
1
- export { FadeIn, Stagger, StaggerItem } from './chunk-WYJYLDUA.mjs';
2
- import './chunk-NNHPQ67J.mjs';
1
+ "use client";
2
+ import { useInView, motion } from 'framer-motion';
3
+ import { createContext, useRef, useCallback, useEffect, useContext, useState } from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/lib/ease.ts
7
+ var easeOut = [0.22, 1, 0.36, 1];
8
+ var viewport = { once: true, margin: "-60px" };
9
+ var ROW_TOLERANCE = 8;
10
+ var StaggerContext = createContext(null);
11
+ function FadeIn({ children, className, delay = 0, duration = 1, yOffset = 20, start = true }) {
12
+ const ref = useRef(null);
13
+ const inView = useInView(ref, viewport);
14
+ const hidden = { opacity: 0, y: yOffset };
15
+ return /* @__PURE__ */ jsx(
16
+ motion.div,
17
+ {
18
+ ref,
19
+ className,
20
+ initial: hidden,
21
+ animate: inView && start ? { opacity: 1, y: 0 } : hidden,
22
+ transition: { duration, delay, ease: easeOut },
23
+ children
24
+ }
25
+ );
26
+ }
27
+ function Stagger({ children, className, staggerDelay = 0.15, baseDelay = 0, start = true }) {
28
+ const queue = useRef([]);
29
+ const frame = useRef(null);
30
+ const started = useRef(start);
31
+ started.current = start;
32
+ const flush = useCallback(() => {
33
+ frame.current = null;
34
+ const batch = queue.current;
35
+ queue.current = [];
36
+ const positioned = batch.map((entry) => ({
37
+ ...entry,
38
+ rect: entry.element.getBoundingClientRect()
39
+ }));
40
+ positioned.sort(
41
+ (a, b) => Math.abs(a.rect.top - b.rect.top) > ROW_TOLERANCE ? a.rect.top - b.rect.top : a.rect.left - b.rect.left
42
+ );
43
+ for (const [index, entry] of positioned.entries()) entry.reveal(baseDelay + index * staggerDelay);
44
+ }, [baseDelay, staggerDelay]);
45
+ const register = useCallback(
46
+ (element, reveal) => {
47
+ queue.current.push({ element, reveal });
48
+ if (started.current) frame.current ??= requestAnimationFrame(flush);
49
+ },
50
+ [flush]
51
+ );
52
+ useEffect(() => {
53
+ if (start && queue.current.length > 0) frame.current ??= requestAnimationFrame(flush);
54
+ }, [start, flush]);
55
+ return /* @__PURE__ */ jsx(StaggerContext, { value: register, children: /* @__PURE__ */ jsx("div", { className, children }) });
56
+ }
57
+ function StaggerItem({ children, className }) {
58
+ const register = useContext(StaggerContext);
59
+ const ref = useRef(null);
60
+ const claimed = useRef(false);
61
+ const [delay, setDelay] = useState(null);
62
+ const onViewportEnter = useCallback(() => {
63
+ if (claimed.current) return;
64
+ claimed.current = true;
65
+ const element = ref.current;
66
+ if (register && element) register(element, setDelay);
67
+ else setDelay(0);
68
+ }, [register]);
69
+ return /* @__PURE__ */ jsx(
70
+ motion.div,
71
+ {
72
+ ref,
73
+ className,
74
+ initial: { opacity: 0, y: 18 },
75
+ animate: delay === null ? { opacity: 0, y: 18 } : { opacity: 1, y: 0 },
76
+ transition: { duration: 0.45, delay: delay ?? 0, ease: easeOut },
77
+ viewport,
78
+ onViewportEnter,
79
+ children
80
+ }
81
+ );
82
+ }
83
+
84
+ export { FadeIn, Stagger, StaggerItem };
3
85
  //# sourceMappingURL=fade-in.mjs.map
4
86
  //# sourceMappingURL=fade-in.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"fade-in.mjs"}
1
+ {"version":3,"sources":["../src/lib/ease.ts","../src/components/fade-in.tsx"],"names":[],"mappings":"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","file":"fade-in.mjs","sourcesContent":["/**\n * Easing curves shared across landing-ui components.\n */\n\n/** Smooth deceleration — matches the former CSS `ease-out-expo`. */\nexport const easeOut = [0.22, 1, 0.36, 1] as const;\n\n/** Gentle overshoot — bounce-like settle for spring alternatives. */\nexport const easeOutBack = [0.34, 1.56, 0.64, 1] as const;\n\n// ── Content-swap tokens (action-swap) ─────────────────────────────────────\n// Values mirror beui.dev's `lib/ease.ts` so vendored action-swap primitives\n// keep their upstream timing.\n\n/** Strong ease-out — the default `ease-out` reads weak at these durations. */\nexport const EASE_OUT = [0.16, 1, 0.3, 1] as const;\n\n/** CSS string form of {@link EASE_OUT} for inline style transitions. */\nexport const EASE_OUT_CSS = 'cubic-bezier(0.16, 1, 0.3, 1)';\n\n/** Content swaps — label/icon slots trading places inside a control. */\nexport const SPRING_SWAP = { type: 'spring', stiffness: 460, damping: 30, mass: 0.55 } as const;\n","'use client';\n\nimport { motion, useInView } from 'framer-motion';\nimport { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport { easeOut } from '../lib/ease.js';\n\n/** Holds an entrance back until an external cue is ready. */\ntype Gate = {\n /** While `false`, the entrance stays in its initial state even once in view. @defaultValue `true` */\n start?: boolean;\n};\n\nexport type FadeInProps = Gate & {\n children: React.ReactNode;\n className?: string;\n delay?: number;\n duration?: number;\n yOffset?: number;\n};\n\nexport type StaggerProps = Gate & {\n children: React.ReactNode;\n className?: string;\n staggerDelay?: number;\n baseDelay?: number;\n};\n\nexport type StaggerItemProps = {\n children: React.ReactNode;\n className?: string;\n};\n\n/** Shared viewport config so every entrance in this file triggers at the same threshold. */\nconst viewport = { once: true, margin: '-60px' } as const;\n\n/** Rows in a grid can differ by a fraction of a pixel; treat near-equal tops as the same row. */\nconst ROW_TOLERANCE = 8;\n\n/** Registers a newly visible item and receives back the delay it should animate with. */\ntype RegisterItem = (element: Element, reveal: (delay: number) => void) => void;\n\nconst StaggerContext = createContext<RegisterItem | null>(null);\n\n/**\n * Wraps children in a framer-motion div that fades+slides up\n * when it enters the viewport.\n */\nexport function FadeIn({ children, className, delay = 0, duration = 1, yOffset = 20, start = true }: FadeInProps) {\n const ref = useRef<HTMLDivElement>(null);\n const inView = useInView(ref, viewport);\n const hidden = { opacity: 0, y: yOffset };\n\n return (\n <motion.div\n ref={ref}\n className={className}\n initial={hidden}\n animate={inView && start ? { opacity: 1, y: 0 } : hidden}\n transition={{ duration, delay, ease: easeOut }}\n >\n {children}\n </motion.div>\n );\n}\n\n/**\n * Coordinates staggered entrances for the `<StaggerItem>`s inside it.\n *\n * Unlike framer-motion's `staggerChildren`, the cascade is driven by each\n * item's own visibility rather than the container's: items that scroll into\n * view together are batched into one frame, sorted top-to-bottom then\n * left-to-right, and given progressively later delays.\n *\n * While `start` is `false`, items that come into view queue up instead of\n * revealing, so the whole cascade lands as one batch when the cue arrives.\n */\nexport function Stagger({ children, className, staggerDelay = 0.15, baseDelay = 0, start = true }: StaggerProps) {\n const queue = useRef<{ element: Element; reveal: (delay: number) => void }[]>([]);\n const frame = useRef<number | null>(null);\n const started = useRef(start);\n started.current = start;\n\n const flush = useCallback(() => {\n frame.current = null;\n const batch = queue.current;\n queue.current = [];\n\n const positioned = batch.map((entry) => ({\n ...entry,\n rect: entry.element.getBoundingClientRect(),\n }));\n positioned.sort((a, b) =>\n Math.abs(a.rect.top - b.rect.top) > ROW_TOLERANCE ? a.rect.top - b.rect.top : a.rect.left - b.rect.left,\n );\n for (const [index, entry] of positioned.entries()) entry.reveal(baseDelay + index * staggerDelay);\n }, [baseDelay, staggerDelay]);\n\n const register = useCallback<RegisterItem>(\n (element, reveal) => {\n queue.current.push({ element, reveal });\n if (started.current) frame.current ??= requestAnimationFrame(flush);\n },\n [flush],\n );\n\n // biome-ignore lint/plugin: drains an imperative queue of pending reveals when the gate opens.\n useEffect(() => {\n if (start && queue.current.length > 0) frame.current ??= requestAnimationFrame(flush);\n }, [start, flush]);\n\n return (\n <StaggerContext value={register}>\n <div className={className}>{children}</div>\n </StaggerContext>\n );\n}\n\n/** Use inside <Stagger> to mark each animated child. */\nexport function StaggerItem({ children, className }: StaggerItemProps) {\n const register = useContext(StaggerContext);\n const ref = useRef<HTMLDivElement>(null);\n const claimed = useRef(false);\n const [delay, setDelay] = useState<number | null>(null);\n\n const onViewportEnter = useCallback(() => {\n if (claimed.current) return;\n claimed.current = true;\n const element = ref.current;\n if (register && element) register(element, setDelay);\n else setDelay(0);\n }, [register]);\n\n return (\n <motion.div\n ref={ref}\n className={className}\n initial={{ opacity: 0, y: 18 }}\n animate={delay === null ? { opacity: 0, y: 18 } : { opacity: 1, y: 0 }}\n transition={{ duration: 0.45, delay: delay ?? 0, ease: easeOut }}\n viewport={viewport}\n onViewportEnter={onViewportEnter}\n >\n {children}\n </motion.div>\n );\n}\n"]}
@@ -1,10 +1,10 @@
1
+ "use client";
1
2
  'use strict';
2
3
 
3
4
  var clsx = require('clsx');
4
5
  var tailwindMerge = require('tailwind-merge');
5
6
  var jsxRuntime = require('react/jsx-runtime');
6
7
 
7
- // src/lib/utils.ts
8
8
  function cn(...inputs) {
9
9
  return tailwindMerge.twMerge(clsx.clsx(inputs));
10
10
  }