@waveso/ui 0.7.2 → 0.7.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"animate.d.ts","names":[],"sources":["../src/animate.tsx"],"mappings":";;;;;;KAkBK,SAAA;AAAA,UAEK,kBAAA;EACR,QAAA,EAAU,YAAA;;EAEV,KAAA;EALY;EAOZ,IAAA,GAAO,SAAA;EAPK;EASZ,QAAA;EAPQ;EASR,KAAA;;EAEA,IAAA;EANO;EAQP,MAAA;EAQuB;EANvB,IAAA;EAdA;EAgBA,MAAA;EAdA;EAgBA,IAAA;EAdO;EAgBP,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,cAAA;EACR,QAAA,EAAU,YAAA;EAVV;EAYA,KAAA;EARA;EAUA,IAAA,GAAO,SAAA;EARM;EAUb,QAAA;EAVuB;EAYvB,KAAA;EATsB;EAWtB,IAAA;EAVU;EAYV,MAAA;EAMa;EAJb,IAAA;EAIuB;EAFvB,MAAA;EAhBU;EAkBV,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,YAAA;EACR,QAAA,EAAU,YAAA;EAdV;EAgBA,QAAA;EAZA;EAcA,SAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAZa;EAcvB,GAAA;EAXQ;EAaR,GAAA;;EAEA,QAAA;EAdA;EAgBA,OAAA;EAdA;EAgBA,MAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAfQ;EAiBlB,QAAA;EAhBsB;EAkBtB,QAAA;EAlBU;EAoBV,MAAA;EAhBA;EAkBA,MAAA;AAAA;;;;AAZM;;;;;;;;;;;;AAYA;iBA+HC,aAAA,CAAA;EACP,QAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA;AAAA,GACC,kBAAA,GAAkB,YAAA,mBAAA,OAAA,CAAA,qBAAA;;;;;;;;;;;;;;iBAoDZ,SAAA,CAAA;EACP,QAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,MAAA;EACA;AAAA,GACC,cAAA,GAAc,YAAA,mBAAA,OAAA,CAAA,qBAAA;;;;;;;;;;;;;iBA8CR,OAAA,CAAA;EACP,QAAA;EACA,QAAA;EACA;AAAA,GACC,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;;;;iBA0BN,KAAA,CAAA;EACP,QAAA;EACA,GAAA;EACA,GAAA;EACA,QAAA;EACA,OAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;AAlJQ;;;;;;iBAsMZ,KAAA,CAAA;EACP,QAAA;EACA,QAAA;EACA,QAAA;EACA,MAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"animate.d.ts","names":[],"sources":["../src/animate.tsx"],"mappings":";;;;;;KAkBK,SAAA;AAAA,UAEK,kBAAA;EACR,QAAA,EAAU,YAAA;;EAEV,KAAA;EALY;EAOZ,IAAA,GAAO,SAAA;EAPK;EASZ,QAAA;EAPQ;EASR,KAAA;;EAEA,IAAA;EANO;EAQP,MAAA;EAQuB;EANvB,IAAA;EAdA;EAgBA,MAAA;EAdA;EAgBA,IAAA;EAdO;EAgBP,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,cAAA;EACR,QAAA,EAAU,YAAA;EAVV;EAYA,KAAA;EARA;EAUA,IAAA,GAAO,SAAA;EARM;EAUb,QAAA;EAVuB;EAYvB,KAAA;EATsB;EAWtB,IAAA;EAVU;EAYV,MAAA;EAMa;EAJb,IAAA;EAIuB;EAFvB,MAAA;EAhBU;EAkBV,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,YAAA;EACR,QAAA,EAAU,YAAA;EAdV;EAgBA,QAAA;EAZA;EAcA,SAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAZa;EAcvB,GAAA;EAXQ;EAaR,GAAA;;EAEA,QAAA;EAdA;EAgBA,OAAA;EAdA;EAgBA,MAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAfQ;EAiBlB,QAAA;EAhBsB;EAkBtB,QAAA;EAlBU;EAoBV,MAAA;EAhBA;EAkBA,MAAA;AAAA;;;;AAZM;;;;;;;;;;;;AAYA;iBA+HC,aAAA,CAAA;EACP,QAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA;AAAA,GACC,kBAAA,GAAkB,YAAA,mBAAA,OAAA,CAAA,qBAAA;;;;;;;;;;;;;;iBAkEZ,SAAA,CAAA;EACP,QAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,MAAA;EACA;AAAA,GACC,cAAA,GAAc,YAAA,mBAAA,OAAA,CAAA,qBAAA;;;;;;;;;;;;;iBA4DR,OAAA,CAAA;EACP,QAAA;EACA,QAAA;EACA;AAAA,GACC,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;;;;iBA0BN,KAAA,CAAA;EACP,QAAA;EACA,GAAA;EACA,GAAA;EACA,QAAA;EACA,OAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;AA9KQ;;;;;;iBA4OZ,KAAA,CAAA;EACP,QAAA;EACA,QAAA;EACA,QAAA;EACA,MAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/animate.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Children, cloneElement, isValidElement, useEffect, useId, useRef, useState } from "react";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- import { useInView } from "motion/react";
4
+ import { useInView, useReducedMotion } from "motion/react";
5
5
  //#region src/animate.tsx
6
6
  /**
7
7
  * Direction map: `from` means where the element COMES FROM.
@@ -112,6 +112,7 @@ function AnimateOnView({ children, delay = 0, from = "down", distance = 16, scal
112
112
  once,
113
113
  margin: "-50px"
114
114
  });
115
+ const prefersReducedMotion = useReducedMotion();
115
116
  useEffect(() => {
116
117
  setHydrated(true);
117
118
  }, []);
@@ -128,6 +129,13 @@ function AnimateOnView({ children, delay = 0, from = "down", distance = 16, scal
128
129
  rotate,
129
130
  flip
130
131
  });
132
+ if (prefersReducedMotion) return cloneElement(children, {
133
+ ref: mergeRefs(ref, existingRef),
134
+ style: {
135
+ ...existingStyle,
136
+ ...styles.visible
137
+ }
138
+ });
131
139
  const { duration, ease } = getTransitionParams(transition, spring, .4);
132
140
  const currentStyle = isInView ? styles.visible : styles.hidden;
133
141
  const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter);
@@ -157,6 +165,7 @@ function AnimateOnView({ children, delay = 0, from = "down", distance = 16, scal
157
165
  function AnimateIn({ children, delay = 0, from = "down", distance = 4, scale = false, blur = false, rotate = 0, flip = false, spring = false, transition }) {
158
166
  const ref = useRef(null);
159
167
  const [visible, setVisible] = useState(false);
168
+ const prefersReducedMotion = useReducedMotion();
160
169
  useEffect(() => {
161
170
  requestAnimationFrame(() => {
162
171
  requestAnimationFrame(() => setVisible(true));
@@ -174,6 +183,13 @@ function AnimateIn({ children, delay = 0, from = "down", distance = 4, scale = f
174
183
  rotate,
175
184
  flip
176
185
  });
186
+ if (prefersReducedMotion) return cloneElement(children, {
187
+ ref: mergeRefs(ref, existingRef),
188
+ style: {
189
+ ...existingStyle,
190
+ ...styles.visible
191
+ }
192
+ });
177
193
  const { duration, ease } = getTransitionParams(transition, spring);
178
194
  const currentStyle = visible ? styles.visible : styles.hidden;
179
195
  const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter);
@@ -219,20 +235,24 @@ function Stagger({ children, interval = .08, baseDelay = 0 }) {
219
235
  function Pulse({ children, min = .97, max = 1.03, duration = 2, opacity, paused = false }) {
220
236
  const id = useId().replace(/:/g, "");
221
237
  const [hydrated, setHydrated] = useState(false);
238
+ const prefersReducedMotion = useReducedMotion();
222
239
  useEffect(() => {
223
240
  setHydrated(true);
224
241
  }, []);
225
242
  if (!isValidElement(children)) return children;
226
243
  if (!hydrated) return children;
227
- const name = `pulse-${id}`;
228
- const keyframes = `@keyframes ${name} {
229
- 0%, 100% { transform: scale(${min}); opacity: ${opacity?.[0] ?? 1}; }
230
- 50% { transform: scale(${max}); opacity: ${opacity?.[1] ?? 1}; }
231
- }`;
232
244
  const childProps = children.props;
233
245
  const existingStyle = childProps.style ?? {};
234
246
  const existingRef = childProps.ref;
235
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: keyframes }), cloneElement(children, {
247
+ if (prefersReducedMotion) return cloneElement(children, {
248
+ ref: existingRef ? mergeRefs(existingRef) : void 0,
249
+ style: existingStyle
250
+ });
251
+ const name = `pulse-${id}`;
252
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: `@keyframes ${name} {
253
+ 0%, 100% { transform: scale(${min}); opacity: ${opacity?.[0] ?? 1}; }
254
+ 50% { transform: scale(${max}); opacity: ${opacity?.[1] ?? 1}; }
255
+ }` }), cloneElement(children, {
236
256
  ref: existingRef ? mergeRefs(existingRef) : void 0,
237
257
  style: {
238
258
  ...existingStyle,
@@ -255,22 +275,26 @@ function Pulse({ children, min = .97, max = 1.03, duration = 2, opacity, paused
255
275
  function Float({ children, distance = 6, duration = 3, rotate = 0, paused = false }) {
256
276
  const id = useId().replace(/:/g, "");
257
277
  const [hydrated, setHydrated] = useState(false);
278
+ const prefersReducedMotion = useReducedMotion();
258
279
  useEffect(() => {
259
280
  setHydrated(true);
260
281
  }, []);
261
282
  if (!isValidElement(children)) return children;
262
283
  if (!hydrated) return children;
284
+ const childProps = children.props;
285
+ const existingStyle = childProps.style ?? {};
286
+ const existingRef = childProps.ref;
287
+ if (prefersReducedMotion) return cloneElement(children, {
288
+ ...existingRef ? { ref: existingRef } : {},
289
+ style: existingStyle
290
+ });
263
291
  const name = `float-${id}`;
264
292
  const rotA = rotate ? ` rotate(${-rotate}deg)` : "";
265
293
  const rotB = rotate ? ` rotate(${rotate}deg)` : "";
266
- const keyframes = `@keyframes ${name} {
294
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: `@keyframes ${name} {
267
295
  0%, 100% { transform: translateY(0px)${rotA}; }
268
296
  50% { transform: translateY(${-distance}px)${rotB}; }
269
- }`;
270
- const childProps = children.props;
271
- const existingStyle = childProps.style ?? {};
272
- const existingRef = childProps.ref;
273
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", { children: keyframes }), cloneElement(children, {
297
+ }` }), cloneElement(children, {
274
298
  ...existingRef ? { ref: existingRef } : {},
275
299
  style: {
276
300
  ...existingStyle,
@@ -1 +1 @@
1
- {"version":3,"file":"animate.js","names":[],"sources":["../src/animate.tsx"],"sourcesContent":["\"use client\"\n\nimport {\n Children,\n type CSSProperties,\n type ReactElement,\n type Ref,\n cloneElement,\n isValidElement,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\"\nimport { useInView, type Transition } from \"motion/react\"\n\n// ── Types ────────────────────────────────────────────────────────────\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\"\n\ninterface AnimateOnViewProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 16 (scroll reveals need more travel than `AnimateIn`) */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Trigger once or every time it enters view. Default: true */\n once?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface AnimateInProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 4 */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface StaggerProps {\n children: ReactElement[]\n /** Delay increment between each child in seconds. Default: 0.08 */\n interval?: number\n /** Base delay before the first child animates in seconds. Default: 0 */\n baseDelay?: number\n}\n\ninterface PulseProps {\n children: ReactElement\n /** Min scale factor. Default: 0.97 */\n min?: number\n /** Max scale factor. Default: 1.03 */\n max?: number\n /** Animation duration in seconds. Default: 2 */\n duration?: number\n /** Also pulse opacity between these bounds [min, max]. Off by default. */\n opacity?: [number, number]\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\ninterface FloatProps {\n children: ReactElement\n /** Vertical float distance in px. Default: 6 */\n distance?: number\n /** Animation duration in seconds. Default: 3 */\n duration?: number\n /** Also rotate slightly while floating (degrees). Default: 0 */\n rotate?: number\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\n/**\n * Direction map: `from` means where the element COMES FROM.\n * `from=\"left\"` = starts to the left, slides right into place.\n */\nconst DIRECTION_MAP = {\n up: { prop: \"translateY\", value: -1 },\n down: { prop: \"translateY\", value: 1 },\n left: { prop: \"translateX\", value: -1 },\n right: { prop: \"translateX\", value: 1 },\n} as const\n\n/** Flip axis: vertical directions flip around X, horizontal around Y */\nconst FLIP_MAP = {\n up: \"rotateX(90deg)\",\n down: \"rotateX(-90deg)\",\n left: \"rotateY(-90deg)\",\n right: \"rotateY(90deg)\",\n} as const\n\n/** Overshoot (\"spring\") easing for the opt-in `spring` prop on\n * `AnimateIn` / `AnimateOnView`. This is `animate.tsx`'s own page-entrance\n * bounce — the CSS recipe system intentionally has no spring, so this is a standalone constant, not a shared token. */\nconst SPRING_EASE = \"cubic-bezier(0.34, 1.45, 0.64, 1)\"\n\ninterface BuildStylesOptions {\n from: Direction\n distance: number\n doScale: boolean\n blur: boolean | number\n rotate: number\n flip: boolean\n}\n\nfunction buildStyles(opts: BuildStylesOptions) {\n const { from, distance, doScale, blur, rotate, flip } = opts\n const dir = DIRECTION_MAP[from]\n\n const hiddenParts: string[] = []\n if (flip) hiddenParts.push(\"perspective(800px)\")\n hiddenParts.push(`${dir.prop}(${dir.value * distance}px)`)\n if (doScale) hiddenParts.push(\"scale(0.85)\")\n if (rotate) hiddenParts.push(`rotate(${rotate}deg)`)\n if (flip) hiddenParts.push(FLIP_MAP[from])\n\n const visibleParts: string[] = []\n if (flip) visibleParts.push(\"perspective(800px)\")\n visibleParts.push(\"translateX(0) translateY(0)\")\n if (doScale) visibleParts.push(\"scale(1)\")\n if (rotate) visibleParts.push(\"rotate(0deg)\")\n if (flip) visibleParts.push(from === \"up\" || from === \"down\" ? \"rotateX(0deg)\" : \"rotateY(0deg)\")\n\n const blurPx = blur === true ? 8 : typeof blur === \"number\" ? blur : 0\n\n const hidden: CSSProperties = {\n opacity: \"0\",\n transform: hiddenParts.join(\" \"),\n }\n\n const visible: CSSProperties = {\n opacity: \"1\",\n transform: visibleParts.join(\" \"),\n }\n\n if (blurPx > 0) {\n hidden.filter = `blur(${blurPx}px)`\n visible.filter = \"blur(0px)\"\n }\n\n return { hidden, visible, hasFilter: blurPx > 0 }\n}\n\nfunction mergeRefs<T>(...refs: (Ref<T> | undefined)[]) {\n return (el: T | null) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") ref(el)\n else if (ref && typeof ref === \"object\") {\n ;(ref as { current: T | null }).current = el\n }\n })\n }\n}\n\nfunction getTransitionParams(transition?: Transition, useSpring?: boolean, fallbackDuration = 0.15) {\n const duration =\n (transition as Record<string, number>)?.duration ?? fallbackDuration\n const ease =\n useSpring ? SPRING_EASE : ((transition as Record<string, string>)?.ease ?? \"ease-out\")\n return { duration, ease }\n}\n\nfunction buildTransitionStr(\n duration: number,\n ease: string,\n delay: number,\n hasFilter: boolean,\n) {\n const parts = [\n `opacity ${duration}s ${ease} ${delay}s`,\n `transform ${duration}s ${ease} ${delay}s`,\n ]\n if (hasFilter) parts.push(`filter ${duration}s ${ease} ${delay}s`)\n return parts.join(\", \")\n}\n\n// ── AnimateOnView ────────────────────────────────────────────────────\n\n/**\n * Animates a child element when it scrolls into view.\n *\n * Defaults are tuned for scroll reveals — larger travel and a slower duration\n * than `AnimateIn` — so the motion reads as the content enters the viewport.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Renders children unchanged on server to avoid hydration mismatch.\n *\n * @example\n * ```tsx\n * <AnimateOnView from=\"up\" blur scale>\n * <Card>Hello</Card>\n * </AnimateOnView>\n * ```\n */\nfunction AnimateOnView({\n children,\n delay = 0,\n from = \"down\",\n distance = 16,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n once = true,\n transition,\n}: AnimateOnViewProps) {\n const ref = useRef<HTMLElement>(null)\n const [hydrated, setHydrated] = useState(false)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n if (!hydrated) {\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n } as Record<string, unknown>)\n }\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n const { duration, ease } = getTransitionParams(transition, spring, 0.4)\n const currentStyle = isInView ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(isInView ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── AnimateIn ────────────────────────────────────────────────────────\n\n/**\n * Animates a child element immediately on mount.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Uses a two-phase approach: hidden → visible with requestAnimationFrame.\n *\n * @example\n * ```tsx\n * <AnimateIn from=\"up\" blur spring>\n * <h1>Welcome</h1>\n * </AnimateIn>\n * ```\n */\nfunction AnimateIn({\n children,\n delay = 0,\n from = \"down\",\n distance = 4,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n transition,\n}: AnimateInProps) {\n const ref = useRef<HTMLElement>(null)\n const [visible, setVisible] = useState(false)\n\n useEffect(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => setVisible(true))\n })\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n const { duration, ease } = getTransitionParams(transition, spring)\n const currentStyle = visible ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(visible ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── Stagger ──────────────────────────────────────────────────────────\n\n/**\n * Auto-staggers delay on child AnimateIn/AnimateOnView elements.\n * Eliminates manual `delay={i * 0.08}` math.\n *\n * @example\n * ```tsx\n * <Stagger interval={0.1}>\n * <AnimateIn from=\"up\"><Card>One</Card></AnimateIn>\n * <AnimateIn from=\"up\"><Card>Two</Card></AnimateIn>\n * </Stagger>\n * ```\n */\nfunction Stagger({\n children,\n interval = 0.08,\n baseDelay = 0,\n}: StaggerProps) {\n return (\n <>\n {Children.map(children, (child, index) => {\n if (!isValidElement(child)) return child\n return cloneElement(child as ReactElement<{ delay?: number }>, {\n delay: baseDelay + index * interval,\n })\n })}\n </>\n )\n}\n\n// ── Pulse ────────────────────────────────────────────────────────────\n\n/**\n * Continuous, subtle scale pulse. Great for live indicators and CTAs.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Pulse>\n * <span className=\"size-3 rounded-full bg-green-500\" />\n * </Pulse>\n * ```\n */\nfunction Pulse({\n children,\n min = 0.97,\n max = 1.03,\n duration = 2,\n opacity,\n paused = false,\n}: PulseProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const name = `pulse-${id}`\n const opacityFrom = opacity?.[0] ?? 1\n const opacityTo = opacity?.[1] ?? 1\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: scale(${min}); opacity: ${opacityFrom}; }\n 50% { transform: scale(${max}); opacity: ${opacityTo}; }\n}`\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ref: existingRef ? mergeRefs(existingRef) : undefined,\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Float ────────────────────────────────────────────────────────────\n\n/**\n * Gentle continuous up/down float. Perfect for decorative elements.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Float distance={10} duration={4}>\n * <Card>Floating</Card>\n * </Float>\n * ```\n */\nfunction Float({\n children,\n distance = 6,\n duration = 3,\n rotate = 0,\n paused = false,\n}: FloatProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const name = `float-${id}`\n const rotA = rotate ? ` rotate(${-rotate}deg)` : \"\"\n const rotB = rotate ? ` rotate(${rotate}deg)` : \"\"\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: translateY(0px)${rotA}; }\n 50% { transform: translateY(${-distance}px)${rotB}; }\n}`\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ...(existingRef ? { ref: existingRef } : {}),\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Exports ──────────────────────────────────────────────────────────\n\nexport { AnimateOnView, AnimateIn, Stagger, Pulse, Float }\nexport type {\n AnimateOnViewProps,\n AnimateInProps,\n StaggerProps,\n PulseProps,\n FloatProps,\n Direction,\n}\n"],"mappings":";;;;;;;;;AA0GA,MAAM,gBAAgB;CACpB,IAAI;EAAE,MAAM;EAAc,OAAO;EAAI;CACrC,MAAM;EAAE,MAAM;EAAc,OAAO;EAAG;CACtC,MAAM;EAAE,MAAM;EAAc,OAAO;EAAI;CACvC,OAAO;EAAE,MAAM;EAAc,OAAO;EAAG;CACxC;;AAGD,MAAM,WAAW;CACf,IAAI;CACJ,MAAM;CACN,MAAM;CACN,OAAO;CACR;;;;AAKD,MAAM,cAAc;AAWpB,SAAS,YAAY,MAA0B;CAC7C,MAAM,EAAE,MAAM,UAAU,SAAS,MAAM,QAAQ,SAAS;CACxD,MAAM,MAAM,cAAc;CAE1B,MAAM,cAAwB,EAAE;AAChC,KAAI,KAAM,aAAY,KAAK,qBAAqB;AAChD,aAAY,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,QAAQ,SAAS,KAAK;AAC1D,KAAI,QAAS,aAAY,KAAK,cAAc;AAC5C,KAAI,OAAQ,aAAY,KAAK,UAAU,OAAO,MAAM;AACpD,KAAI,KAAM,aAAY,KAAK,SAAS,MAAM;CAE1C,MAAM,eAAyB,EAAE;AACjC,KAAI,KAAM,cAAa,KAAK,qBAAqB;AACjD,cAAa,KAAK,8BAA8B;AAChD,KAAI,QAAS,cAAa,KAAK,WAAW;AAC1C,KAAI,OAAQ,cAAa,KAAK,eAAe;AAC7C,KAAI,KAAM,cAAa,KAAK,SAAS,QAAQ,SAAS,SAAS,kBAAkB,gBAAgB;CAEjG,MAAM,SAAS,SAAS,OAAO,IAAI,OAAO,SAAS,WAAW,OAAO;CAErE,MAAM,SAAwB;EAC5B,SAAS;EACT,WAAW,YAAY,KAAK,IAAI;EACjC;CAED,MAAM,UAAyB;EAC7B,SAAS;EACT,WAAW,aAAa,KAAK,IAAI;EAClC;AAED,KAAI,SAAS,GAAG;AACd,SAAO,SAAS,QAAQ,OAAO;AAC/B,UAAQ,SAAS;;AAGnB,QAAO;EAAE;EAAQ;EAAS,WAAW,SAAS;EAAG;;AAGnD,SAAS,UAAa,GAAG,MAA8B;AACrD,SAAQ,OAAiB;AACvB,OAAK,SAAS,QAAQ;AACpB,OAAI,OAAO,QAAQ,WAAY,KAAI,GAAG;YAC7B,OAAO,OAAO,QAAQ,SAC3B,KAA8B,UAAU;IAE5C;;;AAIN,SAAS,oBAAoB,YAAyB,WAAqB,mBAAmB,KAAM;AAKlG,QAAO;EAAE,UAHN,YAAuC,YAAY;EAGnC,MADjB,YAAY,cAAgB,YAAuC,QAAQ;EACpD;;AAG3B,SAAS,mBACP,UACA,MACA,OACA,WACA;CACA,MAAM,QAAQ,CACZ,WAAW,SAAS,IAAI,KAAK,GAAG,MAAM,IACtC,aAAa,SAAS,IAAI,KAAK,GAAG,MAAM,GACzC;AACD,KAAI,UAAW,OAAM,KAAK,UAAU,SAAS,IAAI,KAAK,GAAG,MAAM,GAAG;AAClE,QAAO,MAAM,KAAK,KAAK;;;;;;;;;;;;;;;;;;AAqBzB,SAAS,cAAc,EACrB,UACA,QAAQ,GACR,OAAO,QACP,WAAW,IACX,QAAQ,OACR,OAAO,OACP,SAAS,GACT,OAAO,OACP,SAAS,OACT,OAAO,MACP,cACqB;CACrB,MAAM,MAAM,OAAoB,KAAK;CACrC,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;CAC/C,MAAM,WAAW,UAAU,KAAK;EAAE;EAAM,QAAQ;EAAS,CAAC;AAE1D,iBAAgB;AACd,cAAY,KAAK;IAChB,EAAE,CAAC;AAEN,KAAI,CAAC,eAAe,SAAS,CAAE,QAAO;CAEtC,MAAM,aAAa,SAAS;CAC5B,MAAM,gBAAiB,WAAW,SAAS,EAAE;CAC7C,MAAM,cAAe,WAA0C;AAE/D,KAAI,CAAC,SACH,QAAO,aAAa,UAAU,EAC5B,KAAK,UAAU,KAAK,YAAY,EACjC,CAA4B;CAG/B,MAAM,SAAS,YAAY;EAAE;EAAM;EAAU,SAAS;EAAO;EAAM;EAAQ;EAAM,CAAC;CAClF,MAAM,EAAE,UAAU,SAAS,oBAAoB,YAAY,QAAQ,GAAI;CACvE,MAAM,eAAe,WAAW,OAAO,UAAU,OAAO;CACxD,MAAM,gBAAgB,mBAAmB,UAAU,MAAM,OAAO,OAAO,UAAU;AAEjF,QAAO,aAAa,UAAU;EAC5B,KAAK,UAAU,KAAK,YAAY;EAChC,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAI,WAAW,EAAE,YAAY,eAAe,GAAG,EAAE;GACjD,YAAY;GACb;EACF,CAA4B;;;;;;;;;;;;;;;AAkB/B,SAAS,UAAU,EACjB,UACA,QAAQ,GACR,OAAO,QACP,WAAW,GACX,QAAQ,OACR,OAAO,OACP,SAAS,GACT,OAAO,OACP,SAAS,OACT,cACiB;CACjB,MAAM,MAAM,OAAoB,KAAK;CACrC,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;AAE7C,iBAAgB;AACd,8BAA4B;AAC1B,+BAA4B,WAAW,KAAK,CAAC;IAC7C;IACD,EAAE,CAAC;AAEN,KAAI,CAAC,eAAe,SAAS,CAAE,QAAO;CAEtC,MAAM,aAAa,SAAS;CAC5B,MAAM,gBAAiB,WAAW,SAAS,EAAE;CAC7C,MAAM,cAAe,WAA0C;CAE/D,MAAM,SAAS,YAAY;EAAE;EAAM;EAAU,SAAS;EAAO;EAAM;EAAQ;EAAM,CAAC;CAClF,MAAM,EAAE,UAAU,SAAS,oBAAoB,YAAY,OAAO;CAClE,MAAM,eAAe,UAAU,OAAO,UAAU,OAAO;CACvD,MAAM,gBAAgB,mBAAmB,UAAU,MAAM,OAAO,OAAO,UAAU;AAEjF,QAAO,aAAa,UAAU;EAC5B,KAAK,UAAU,KAAK,YAAY;EAChC,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAI,UAAU,EAAE,YAAY,eAAe,GAAG,EAAE;GAChD,YAAY;GACb;EACF,CAA4B;;;;;;;;;;;;;;AAiB/B,SAAS,QAAQ,EACf,UACA,WAAW,KACX,YAAY,KACG;AACf,QACE,oBAAA,UAAA,EAAA,UACG,SAAS,IAAI,WAAW,OAAO,UAAU;AACxC,MAAI,CAAC,eAAe,MAAM,CAAE,QAAO;AACnC,SAAO,aAAa,OAA2C,EAC7D,OAAO,YAAY,QAAQ,UAC5B,CAAC;GACF,EACD,CAAA;;;;;;;;;;;;;AAiBP,SAAS,MAAM,EACb,UACA,MAAM,KACN,MAAM,MACN,WAAW,GACX,SACA,SAAS,SACI;CACb,MAAM,KAAK,OAAO,CAAC,QAAQ,MAAM,GAAG;CACpC,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;AAE/C,iBAAgB;AACd,cAAY,KAAK;IAChB,EAAE,CAAC;AAEN,KAAI,CAAC,eAAe,SAAS,CAAE,QAAO;AACtC,KAAI,CAAC,SAAU,QAAO;CAEtB,MAAM,OAAO,SAAS;CAItB,MAAM,YAAY,cAAc,KAAK;gCACP,IAAI,cAJd,UAAU,MAAM,EAIwB;2BACnC,IAAI,cAJX,UAAU,MAAM,EAImB;;CAGrD,MAAM,aAAa,SAAS;CAC5B,MAAM,gBAAiB,WAAW,SAAS,EAAE;CAC7C,MAAM,cAAe,WAA0C;AAE/D,QACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,EACzB,aAAa,UAAU;EACtB,KAAK,cAAc,UAAU,YAAY,GAAG,KAAA;EAC5C,OAAO;GACL,GAAG;GACH,WAAW,GAAG,KAAK,GAAG,SAAS;GAC/B,oBAAoB,SAAS,WAAW;GACzC;EACF,CAA4B,CAC5B,EAAA,CAAA;;;;;;;;;;;;;AAiBP,SAAS,MAAM,EACb,UACA,WAAW,GACX,WAAW,GACX,SAAS,GACT,SAAS,SACI;CACb,MAAM,KAAK,OAAO,CAAC,QAAQ,MAAM,GAAG;CACpC,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;AAE/C,iBAAgB;AACd,cAAY,KAAK;IAChB,EAAE,CAAC;AAEN,KAAI,CAAC,eAAe,SAAS,CAAE,QAAO;AACtC,KAAI,CAAC,SAAU,QAAO;CAEtB,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,SAAS,WAAW,CAAC,OAAO,QAAQ;CACjD,MAAM,OAAO,SAAS,WAAW,OAAO,QAAQ;CAEhD,MAAM,YAAY,cAAc,KAAK;yCACE,KAAK;gCACd,CAAC,SAAS,KAAK,KAAK;;CAGlD,MAAM,aAAa,SAAS;CAC5B,MAAM,gBAAiB,WAAW,SAAS,EAAE;CAC7C,MAAM,cAAe,WAA0C;AAE/D,QACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,EACzB,aAAa,UAAU;EACtB,GAAI,cAAc,EAAE,KAAK,aAAa,GAAG,EAAE;EAC3C,OAAO;GACL,GAAG;GACH,WAAW,GAAG,KAAK,GAAG,SAAS;GAC/B,oBAAoB,SAAS,WAAW;GACzC;EACF,CAA4B,CAC5B,EAAA,CAAA"}
1
+ {"version":3,"file":"animate.js","names":[],"sources":["../src/animate.tsx"],"sourcesContent":["\"use client\"\n\nimport {\n Children,\n type CSSProperties,\n type ReactElement,\n type Ref,\n cloneElement,\n isValidElement,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\"\nimport { useInView, useReducedMotion, type Transition } from \"motion/react\"\n\n// ── Types ────────────────────────────────────────────────────────────\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\"\n\ninterface AnimateOnViewProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 16 (scroll reveals need more travel than `AnimateIn`) */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Trigger once or every time it enters view. Default: true */\n once?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface AnimateInProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 4 */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface StaggerProps {\n children: ReactElement[]\n /** Delay increment between each child in seconds. Default: 0.08 */\n interval?: number\n /** Base delay before the first child animates in seconds. Default: 0 */\n baseDelay?: number\n}\n\ninterface PulseProps {\n children: ReactElement\n /** Min scale factor. Default: 0.97 */\n min?: number\n /** Max scale factor. Default: 1.03 */\n max?: number\n /** Animation duration in seconds. Default: 2 */\n duration?: number\n /** Also pulse opacity between these bounds [min, max]. Off by default. */\n opacity?: [number, number]\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\ninterface FloatProps {\n children: ReactElement\n /** Vertical float distance in px. Default: 6 */\n distance?: number\n /** Animation duration in seconds. Default: 3 */\n duration?: number\n /** Also rotate slightly while floating (degrees). Default: 0 */\n rotate?: number\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\n/**\n * Direction map: `from` means where the element COMES FROM.\n * `from=\"left\"` = starts to the left, slides right into place.\n */\nconst DIRECTION_MAP = {\n up: { prop: \"translateY\", value: -1 },\n down: { prop: \"translateY\", value: 1 },\n left: { prop: \"translateX\", value: -1 },\n right: { prop: \"translateX\", value: 1 },\n} as const\n\n/** Flip axis: vertical directions flip around X, horizontal around Y */\nconst FLIP_MAP = {\n up: \"rotateX(90deg)\",\n down: \"rotateX(-90deg)\",\n left: \"rotateY(-90deg)\",\n right: \"rotateY(90deg)\",\n} as const\n\n/** Overshoot (\"spring\") easing for the opt-in `spring` prop on\n * `AnimateIn` / `AnimateOnView`. This is `animate.tsx`'s own page-entrance\n * bounce — the CSS recipe system intentionally has no spring, so this is a standalone constant, not a shared token. */\nconst SPRING_EASE = \"cubic-bezier(0.34, 1.45, 0.64, 1)\"\n\ninterface BuildStylesOptions {\n from: Direction\n distance: number\n doScale: boolean\n blur: boolean | number\n rotate: number\n flip: boolean\n}\n\nfunction buildStyles(opts: BuildStylesOptions) {\n const { from, distance, doScale, blur, rotate, flip } = opts\n const dir = DIRECTION_MAP[from]\n\n const hiddenParts: string[] = []\n if (flip) hiddenParts.push(\"perspective(800px)\")\n hiddenParts.push(`${dir.prop}(${dir.value * distance}px)`)\n if (doScale) hiddenParts.push(\"scale(0.85)\")\n if (rotate) hiddenParts.push(`rotate(${rotate}deg)`)\n if (flip) hiddenParts.push(FLIP_MAP[from])\n\n const visibleParts: string[] = []\n if (flip) visibleParts.push(\"perspective(800px)\")\n visibleParts.push(\"translateX(0) translateY(0)\")\n if (doScale) visibleParts.push(\"scale(1)\")\n if (rotate) visibleParts.push(\"rotate(0deg)\")\n if (flip) visibleParts.push(from === \"up\" || from === \"down\" ? \"rotateX(0deg)\" : \"rotateY(0deg)\")\n\n const blurPx = blur === true ? 8 : typeof blur === \"number\" ? blur : 0\n\n const hidden: CSSProperties = {\n opacity: \"0\",\n transform: hiddenParts.join(\" \"),\n }\n\n const visible: CSSProperties = {\n opacity: \"1\",\n transform: visibleParts.join(\" \"),\n }\n\n if (blurPx > 0) {\n hidden.filter = `blur(${blurPx}px)`\n visible.filter = \"blur(0px)\"\n }\n\n return { hidden, visible, hasFilter: blurPx > 0 }\n}\n\nfunction mergeRefs<T>(...refs: (Ref<T> | undefined)[]) {\n return (el: T | null) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") ref(el)\n else if (ref && typeof ref === \"object\") {\n ;(ref as { current: T | null }).current = el\n }\n })\n }\n}\n\nfunction getTransitionParams(transition?: Transition, useSpring?: boolean, fallbackDuration = 0.15) {\n const duration =\n (transition as Record<string, number>)?.duration ?? fallbackDuration\n const ease =\n useSpring ? SPRING_EASE : ((transition as Record<string, string>)?.ease ?? \"ease-out\")\n return { duration, ease }\n}\n\nfunction buildTransitionStr(\n duration: number,\n ease: string,\n delay: number,\n hasFilter: boolean,\n) {\n const parts = [\n `opacity ${duration}s ${ease} ${delay}s`,\n `transform ${duration}s ${ease} ${delay}s`,\n ]\n if (hasFilter) parts.push(`filter ${duration}s ${ease} ${delay}s`)\n return parts.join(\", \")\n}\n\n// ── AnimateOnView ────────────────────────────────────────────────────\n\n/**\n * Animates a child element when it scrolls into view.\n *\n * Defaults are tuned for scroll reveals — larger travel and a slower duration\n * than `AnimateIn` — so the motion reads as the content enters the viewport.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Renders children unchanged on server to avoid hydration mismatch.\n *\n * @example\n * ```tsx\n * <AnimateOnView from=\"up\" blur scale>\n * <Card>Hello</Card>\n * </AnimateOnView>\n * ```\n */\nfunction AnimateOnView({\n children,\n delay = 0,\n from = \"down\",\n distance = 16,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n once = true,\n transition,\n}: AnimateOnViewProps) {\n const ref = useRef<HTMLElement>(null)\n const [hydrated, setHydrated] = useState(false)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n const prefersReducedMotion = useReducedMotion()\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n if (!hydrated) {\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n } as Record<string, unknown>)\n }\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n\n // Reduced motion: render the final, resting state immediately — no\n // travel, blur, scale, or transition. Keeps the same DOM/output shape.\n if (prefersReducedMotion) {\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...styles.visible,\n },\n } as Record<string, unknown>)\n }\n\n const { duration, ease } = getTransitionParams(transition, spring, 0.4)\n const currentStyle = isInView ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(isInView ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── AnimateIn ────────────────────────────────────────────────────────\n\n/**\n * Animates a child element immediately on mount.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Uses a two-phase approach: hidden → visible with requestAnimationFrame.\n *\n * @example\n * ```tsx\n * <AnimateIn from=\"up\" blur spring>\n * <h1>Welcome</h1>\n * </AnimateIn>\n * ```\n */\nfunction AnimateIn({\n children,\n delay = 0,\n from = \"down\",\n distance = 4,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n transition,\n}: AnimateInProps) {\n const ref = useRef<HTMLElement>(null)\n const [visible, setVisible] = useState(false)\n const prefersReducedMotion = useReducedMotion()\n\n useEffect(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => setVisible(true))\n })\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n\n // Reduced motion: render the final, resting state immediately — no\n // travel, blur, scale, or transition. Keeps the same DOM/output shape.\n if (prefersReducedMotion) {\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...styles.visible,\n },\n } as Record<string, unknown>)\n }\n\n const { duration, ease } = getTransitionParams(transition, spring)\n const currentStyle = visible ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(visible ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── Stagger ──────────────────────────────────────────────────────────\n\n/**\n * Auto-staggers delay on child AnimateIn/AnimateOnView elements.\n * Eliminates manual `delay={i * 0.08}` math.\n *\n * @example\n * ```tsx\n * <Stagger interval={0.1}>\n * <AnimateIn from=\"up\"><Card>One</Card></AnimateIn>\n * <AnimateIn from=\"up\"><Card>Two</Card></AnimateIn>\n * </Stagger>\n * ```\n */\nfunction Stagger({\n children,\n interval = 0.08,\n baseDelay = 0,\n}: StaggerProps) {\n return (\n <>\n {Children.map(children, (child, index) => {\n if (!isValidElement(child)) return child\n return cloneElement(child as ReactElement<{ delay?: number }>, {\n delay: baseDelay + index * interval,\n })\n })}\n </>\n )\n}\n\n// ── Pulse ────────────────────────────────────────────────────────────\n\n/**\n * Continuous, subtle scale pulse. Great for live indicators and CTAs.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Pulse>\n * <span className=\"size-3 rounded-full bg-green-500\" />\n * </Pulse>\n * ```\n */\nfunction Pulse({\n children,\n min = 0.97,\n max = 1.03,\n duration = 2,\n opacity,\n paused = false,\n}: PulseProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n const prefersReducedMotion = useReducedMotion()\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n // Reduced motion: no continuous pulse — render the child at rest, no\n // keyframe injected. Same ref/style handling as the animated path.\n if (prefersReducedMotion) {\n return cloneElement(children, {\n ref: existingRef ? mergeRefs(existingRef) : undefined,\n style: existingStyle,\n } as Record<string, unknown>)\n }\n\n const name = `pulse-${id}`\n const opacityFrom = opacity?.[0] ?? 1\n const opacityTo = opacity?.[1] ?? 1\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: scale(${min}); opacity: ${opacityFrom}; }\n 50% { transform: scale(${max}); opacity: ${opacityTo}; }\n}`\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ref: existingRef ? mergeRefs(existingRef) : undefined,\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Float ────────────────────────────────────────────────────────────\n\n/**\n * Gentle continuous up/down float. Perfect for decorative elements.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Float distance={10} duration={4}>\n * <Card>Floating</Card>\n * </Float>\n * ```\n */\nfunction Float({\n children,\n distance = 6,\n duration = 3,\n rotate = 0,\n paused = false,\n}: FloatProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n const prefersReducedMotion = useReducedMotion()\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n // Reduced motion: no continuous float — render the child at rest, no\n // keyframe injected. Same ref/style handling as the animated path.\n if (prefersReducedMotion) {\n return cloneElement(children, {\n ...(existingRef ? { ref: existingRef } : {}),\n style: existingStyle,\n } as Record<string, unknown>)\n }\n\n const name = `float-${id}`\n const rotA = rotate ? ` rotate(${-rotate}deg)` : \"\"\n const rotB = rotate ? ` rotate(${rotate}deg)` : \"\"\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: translateY(0px)${rotA}; }\n 50% { transform: translateY(${-distance}px)${rotB}; }\n}`\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ...(existingRef ? { ref: existingRef } : {}),\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Exports ──────────────────────────────────────────────────────────\n\nexport { AnimateOnView, AnimateIn, Stagger, Pulse, Float }\nexport type {\n AnimateOnViewProps,\n AnimateInProps,\n StaggerProps,\n PulseProps,\n FloatProps,\n Direction,\n}\n"],"mappings":"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"}
package/dist/badge.d.ts CHANGED
@@ -5,7 +5,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
5
5
 
6
6
  //#region src/badge.d.ts
7
7
  declare const badgeVariants: (props?: ({
8
- variant?: "default" | "link" | "outline" | "destructive" | "secondary" | "ghost" | "success" | "warning" | null | undefined;
8
+ variant?: "default" | "outline" | "secondary" | "ghost" | "success" | "destructive" | "link" | "warning" | null | undefined;
9
9
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  type BadgeProps = useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>;
11
11
  declare function Badge({
package/dist/button.d.ts CHANGED
@@ -6,8 +6,8 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
6
6
 
7
7
  //#region src/button.d.ts
8
8
  declare const buttonVariants: (props?: ({
9
- variant?: "default" | "link" | "outline" | "destructive" | "secondary" | "ghost" | "success" | null | undefined;
10
- size?: "default" | "sm" | "xs" | "icon" | "lg" | "icon-xs" | "icon-sm" | "xl" | "icon-lg" | null | undefined;
9
+ variant?: "default" | "outline" | "secondary" | "ghost" | "success" | "destructive" | "link" | null | undefined;
10
+ size?: "default" | "xs" | "sm" | "icon-xs" | "icon-sm" | "lg" | "xl" | "icon" | "icon-lg" | null | undefined;
11
11
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
12
12
  type ButtonProps = React.ComponentProps<typeof Button$1> & VariantProps<typeof buttonVariants>;
13
13
  declare function Button({
@@ -1 +1 @@
1
- {"version":3,"file":"count.d.ts","names":[],"sources":["../src/count.tsx"],"mappings":";;;;UAeU,UAAA;;EAER,EAAA,WAAa,IAAA;EAFL;EAIR,IAAA;;EAEA,QAAA;EAJA;EAMA,KAAA;EAJA;;;;;;EAWA,MAAA,IAAU,KAAA;EAMV;EAJA,MAAA;EAMA;EAJA,MAAA;EAMU;EAJV,QAAA,EAAU,YAAA;EAMA;EAJV,IAAA;EAQG;EANH,MAAA,IAAU,CAAA;;EAEV,UAAA;AAAA;AAI4B;AAAA,KAAzB,YAAA,GAAe,UAAA;;iBAKX,OAAA,CAAQ,CAAA;;AAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwEjB,KAAA,CAAA;EACP,EAAA;EACA,IAAA,EAAM,KAAA;EACN,QAAA;EACA,KAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,QAAA;EACA,IAAA;EACA,MAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;cAkMP,OAAA,SAAO,KAAA"}
1
+ {"version":3,"file":"count.d.ts","names":[],"sources":["../src/count.tsx"],"mappings":";;;;UAeU,UAAA;;EAER,EAAA,WAAa,IAAA;EAFL;EAIR,IAAA;;EAEA,QAAA;EAJA;EAMA,KAAA;EAJA;;;;;;EAWA,MAAA,IAAU,KAAA;EAMV;EAJA,MAAA;EAMA;EAJA,MAAA;EAMU;EAJV,QAAA,EAAU,YAAA;EAMA;EAJV,IAAA;EAQG;EANH,MAAA,IAAU,CAAA;;EAEV,UAAA;AAAA;AAI4B;AAAA,KAAzB,YAAA,GAAe,UAAA;;iBAKX,OAAA,CAAQ,CAAA;;AAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwEjB,KAAA,CAAA;EACP,EAAA;EACA,IAAA,EAAM,KAAA;EACN,QAAA;EACA,KAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,QAAA;EACA,IAAA;EACA,MAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;cAiNP,OAAA,SAAO,KAAA"}
package/dist/count.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cloneElement, isValidElement, useEffect, useRef, useState } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
- import { useInView } from "motion/react";
4
+ import { useInView, useReducedMotion } from "motion/react";
5
5
  //#region src/count.tsx
6
6
  /** Cubic ease-out: fast start, smooth deceleration */
7
7
  function easeOut(t) {
@@ -88,6 +88,7 @@ function NumberCount({ to, from: start, duration, delay, format, prefix, suffix,
88
88
  once,
89
89
  margin: "-50px"
90
90
  });
91
+ const prefersReducedMotion = useReducedMotion();
91
92
  const [display, setDisplay] = useState(start);
92
93
  const easingRef = useRef(easing);
93
94
  const onCompleteRef = useRef(onComplete);
@@ -99,6 +100,13 @@ function NumberCount({ to, from: start, duration, delay, format, prefix, suffix,
99
100
  useEffect(() => {
100
101
  if (!isInView) return;
101
102
  const delayMs = delay * 1e3;
103
+ if (prefersReducedMotion) {
104
+ const timer = setTimeout(() => {
105
+ setDisplay(to);
106
+ onCompleteRef.current?.();
107
+ }, delayMs);
108
+ return () => clearTimeout(timer);
109
+ }
102
110
  let raf;
103
111
  let startTime;
104
112
  const timer = setTimeout(() => {
@@ -121,7 +129,8 @@ function NumberCount({ to, from: start, duration, delay, format, prefix, suffix,
121
129
  to,
122
130
  start,
123
131
  duration,
124
- delay
132
+ delay,
133
+ prefersReducedMotion
125
134
  ]);
126
135
  if (!isValidElement(children)) return children;
127
136
  const existingRef = children.props.ref;
package/dist/count.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"count.js","names":[],"sources":["../src/count.tsx"],"sourcesContent":["\"use client\"\n\nimport {\n type ReactElement,\n type Ref,\n cloneElement,\n isValidElement,\n useEffect,\n useRef,\n useState,\n} from \"react\"\nimport { useInView } from \"motion/react\"\n\n// ── Types ────────────────────────────────────────────────────────────\n\ninterface CountProps {\n /** Target number or Date to count to */\n to: number | Date\n /** Starting number. Default: 0. Ignored when `to` is a Date. */\n from?: number\n /** Animation duration in milliseconds. Default: 900. Ignored when `to` is a Date. */\n duration?: number\n /** Delay before starting in seconds. Default: 0 */\n delay?: number\n /**\n * Format the value for display.\n * - For numbers: receives the current interpolated number.\n * - For dates: receives remaining milliseconds.\n * Default: toLocaleString() for numbers, dd:hh:mm:ss for dates.\n */\n format?: (value: number) => string\n /** Prefix string (e.g., \"$\"). Default: '' */\n prefix?: string\n /** Suffix string (e.g., \"%\", \"+\"). Default: '' */\n suffix?: string\n /** Element to render into. Receives the formatted value as children. */\n children: ReactElement\n /** Trigger once. Default: true */\n once?: boolean\n /** Easing function. Default: easeOut. Ignored when `to` is a Date. */\n easing?: (t: number) => number\n /** Called when the count finishes (reaches target or date passes). */\n onComplete?: () => void\n}\n\n/** @deprecated Use `Count` instead. `CountUp` is an alias kept for backwards compatibility. */\ntype CountUpProps = CountProps\n\n// ── Easing ───────────────────────────────────────────────────────────\n\n/** Cubic ease-out: fast start, smooth deceleration */\nfunction easeOut(t: number): number {\n return 1 - Math.pow(1 - t, 3)\n}\n\n// ── Date Formatting ──────────────────────────────────────────────────\n\nfunction formatCountdown(ms: number): string {\n if (ms <= 0) return \"00:00:00\"\n\n const totalSeconds = Math.floor(ms / 1000)\n const days = Math.floor(totalSeconds / 86400)\n const hours = Math.floor((totalSeconds % 86400) / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n const pad = (n: number) => String(n).padStart(2, \"0\")\n\n if (days > 0) {\n return `${days}d ${pad(hours)}:${pad(minutes)}:${pad(seconds)}`\n }\n return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`\n}\n\n// ── Ref Merge ────────────────────────────────────────────────────────\n\nfunction mergeRef(\n internalRef: React.RefObject<HTMLElement | null>,\n externalRef?: Ref<HTMLElement>,\n) {\n return (el: HTMLElement | null) => {\n ;(internalRef as { current: HTMLElement | null }).current = el\n if (typeof externalRef === \"function\") externalRef(el)\n else if (externalRef && typeof externalRef === \"object\") {\n ;(externalRef as { current: HTMLElement | null }).current = el\n }\n }\n}\n\n// ── Count ────────────────────────────────────────────────────────────\n\n/**\n * Animated number counter. Counts up, counts down, or live-counts to a date.\n *\n * Direction is automatic — if `from < to` it counts up, if `from > to` it\n * counts down. When `to` is a Date, it becomes a live countdown that ticks\n * every second.\n *\n * Zero wrapper — injects the formatted value as children via cloneElement.\n *\n * @example\n * ```tsx\n * // Count up\n * <Count to={1234}>\n * <span className=\"text-4xl font-bold tabular-nums\" />\n * </Count>\n *\n * // Count down\n * <Count from={100} to={0} onComplete={() => alert(\"Done!\")}>\n * <span className=\"text-4xl font-bold tabular-nums\" />\n * </Count>\n *\n * // Live countdown to a date\n * <Count to={new Date(\"2026-04-01T00:00:00\")}>\n * <span className=\"text-2xl font-mono tabular-nums\" />\n * </Count>\n *\n * // Custom date format\n * <Count to={launchDate} format={(ms) => `${Math.ceil(ms / 86400000)} days left`}>\n * <span className=\"text-xl\" />\n * </Count>\n * ```\n */\nfunction Count({\n to,\n from: start = 0,\n duration = 900,\n delay = 0,\n format,\n prefix = \"\",\n suffix = \"\",\n children,\n once = true,\n easing = easeOut,\n onComplete,\n}: CountProps) {\n const isDate = to instanceof Date\n\n if (isDate) {\n return (\n <DateCount\n to={to}\n delay={delay}\n format={format}\n prefix={prefix}\n suffix={suffix}\n once={once}\n onComplete={onComplete}\n >\n {children}\n </DateCount>\n )\n }\n\n return (\n <NumberCount\n to={to}\n from={start}\n duration={duration}\n delay={delay}\n format={format}\n prefix={prefix}\n suffix={suffix}\n once={once}\n easing={easing}\n onComplete={onComplete}\n >\n {children}\n </NumberCount>\n )\n}\n\n// ── Number Count (up or down) ────────────────────────────────────────\n\nfunction NumberCount({\n to,\n from: start,\n duration,\n delay,\n format,\n prefix,\n suffix,\n children,\n once,\n easing,\n onComplete,\n}: {\n to: number\n from: number\n duration: number\n delay: number\n format?: (value: number) => string\n prefix: string\n suffix: string\n children: ReactElement\n once: boolean\n easing: (t: number) => number\n onComplete?: () => void\n}) {\n const ref = useRef<HTMLElement>(null)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n const [display, setDisplay] = useState(start)\n\n // Keep the callbacks in refs so a parent re-render with inline `easing` /\n // `onComplete` props doesn't re-run the animation effect — which would cancel\n // the in-flight rAF and freeze the counter mid-count. The effect below keys\n // only on the values that should actually (re)start the animation, so a live\n // `to` change or a re-entry (with `once={false}`) restarts cleanly.\n const easingRef = useRef(easing)\n const onCompleteRef = useRef(onComplete)\n useEffect(() => {\n easingRef.current = easing\n onCompleteRef.current = onComplete\n })\n\n const formatFn = format ?? ((n: number) =>\n Number.isInteger(to) ? Math.round(n).toLocaleString() : n.toLocaleString()\n )\n\n useEffect(() => {\n if (!isInView) return\n\n const delayMs = delay * 1000\n let raf: number\n let startTime: number\n\n const timer = setTimeout(() => {\n const animate = (timestamp: number) => {\n if (!startTime) startTime = timestamp\n const elapsed = timestamp - startTime\n const progress = Math.min(elapsed / duration, 1)\n const current = start + (to - start) * easingRef.current(progress)\n\n setDisplay(current)\n\n if (progress < 1) {\n raf = requestAnimationFrame(animate)\n } else {\n onCompleteRef.current?.()\n }\n }\n\n raf = requestAnimationFrame(animate)\n }, delayMs)\n\n return () => {\n clearTimeout(timer)\n cancelAnimationFrame(raf)\n }\n }, [isInView, to, start, duration, delay])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return cloneElement(children, {\n ref: mergeRef(ref, existingRef),\n children: `${prefix}${formatFn(display)}${suffix}`,\n } as Record<string, unknown>)\n}\n\n// ── Date Count (live countdown) ──────────────────────────────────────\n\nfunction DateCount({\n to,\n delay,\n format,\n prefix,\n suffix,\n children,\n once,\n onComplete,\n}: {\n to: Date\n delay: number\n format?: (value: number) => string\n prefix: string\n suffix: string\n children: ReactElement\n once: boolean\n onComplete?: () => void\n}) {\n const ref = useRef<HTMLElement>(null)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n const [remaining, setRemaining] = useState(() => Math.max(0, to.getTime() - Date.now()))\n const [started, setStarted] = useState(false)\n const completedRef = useRef(false)\n\n const formatFn = format ?? formatCountdown\n\n useEffect(() => {\n if (!isInView || started) return\n const timer = setTimeout(() => setStarted(true), delay * 1000)\n return () => clearTimeout(timer)\n }, [isInView, delay, started])\n\n useEffect(() => {\n if (!started) return\n\n const tick = () => {\n const ms = Math.max(0, to.getTime() - Date.now())\n setRemaining(ms)\n\n if (ms <= 0 && !completedRef.current) {\n completedRef.current = true\n onComplete?.()\n }\n }\n\n tick()\n const interval = setInterval(tick, 1000)\n return () => clearInterval(interval)\n }, [started, to, onComplete])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return cloneElement(children, {\n ref: mergeRef(ref, existingRef),\n children: `${prefix}${formatFn(remaining)}${suffix}`,\n } as Record<string, unknown>)\n}\n\n// ── Exports ──────────────────────────────────────────────────────────\n\n/** @deprecated Use `Count` instead */\nconst CountUp = Count\n\nexport { Count, CountUp, easeOut }\nexport type { CountProps, CountUpProps }\n"],"mappings":"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"}
1
+ {"version":3,"file":"count.js","names":[],"sources":["../src/count.tsx"],"sourcesContent":["\"use client\"\n\nimport {\n type ReactElement,\n type Ref,\n cloneElement,\n isValidElement,\n useEffect,\n useRef,\n useState,\n} from \"react\"\nimport { useInView, useReducedMotion } from \"motion/react\"\n\n// ── Types ────────────────────────────────────────────────────────────\n\ninterface CountProps {\n /** Target number or Date to count to */\n to: number | Date\n /** Starting number. Default: 0. Ignored when `to` is a Date. */\n from?: number\n /** Animation duration in milliseconds. Default: 900. Ignored when `to` is a Date. */\n duration?: number\n /** Delay before starting in seconds. Default: 0 */\n delay?: number\n /**\n * Format the value for display.\n * - For numbers: receives the current interpolated number.\n * - For dates: receives remaining milliseconds.\n * Default: toLocaleString() for numbers, dd:hh:mm:ss for dates.\n */\n format?: (value: number) => string\n /** Prefix string (e.g., \"$\"). Default: '' */\n prefix?: string\n /** Suffix string (e.g., \"%\", \"+\"). Default: '' */\n suffix?: string\n /** Element to render into. Receives the formatted value as children. */\n children: ReactElement\n /** Trigger once. Default: true */\n once?: boolean\n /** Easing function. Default: easeOut. Ignored when `to` is a Date. */\n easing?: (t: number) => number\n /** Called when the count finishes (reaches target or date passes). */\n onComplete?: () => void\n}\n\n/** @deprecated Use `Count` instead. `CountUp` is an alias kept for backwards compatibility. */\ntype CountUpProps = CountProps\n\n// ── Easing ───────────────────────────────────────────────────────────\n\n/** Cubic ease-out: fast start, smooth deceleration */\nfunction easeOut(t: number): number {\n return 1 - Math.pow(1 - t, 3)\n}\n\n// ── Date Formatting ──────────────────────────────────────────────────\n\nfunction formatCountdown(ms: number): string {\n if (ms <= 0) return \"00:00:00\"\n\n const totalSeconds = Math.floor(ms / 1000)\n const days = Math.floor(totalSeconds / 86400)\n const hours = Math.floor((totalSeconds % 86400) / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n const pad = (n: number) => String(n).padStart(2, \"0\")\n\n if (days > 0) {\n return `${days}d ${pad(hours)}:${pad(minutes)}:${pad(seconds)}`\n }\n return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`\n}\n\n// ── Ref Merge ────────────────────────────────────────────────────────\n\nfunction mergeRef(\n internalRef: React.RefObject<HTMLElement | null>,\n externalRef?: Ref<HTMLElement>,\n) {\n return (el: HTMLElement | null) => {\n ;(internalRef as { current: HTMLElement | null }).current = el\n if (typeof externalRef === \"function\") externalRef(el)\n else if (externalRef && typeof externalRef === \"object\") {\n ;(externalRef as { current: HTMLElement | null }).current = el\n }\n }\n}\n\n// ── Count ────────────────────────────────────────────────────────────\n\n/**\n * Animated number counter. Counts up, counts down, or live-counts to a date.\n *\n * Direction is automatic — if `from < to` it counts up, if `from > to` it\n * counts down. When `to` is a Date, it becomes a live countdown that ticks\n * every second.\n *\n * Zero wrapper — injects the formatted value as children via cloneElement.\n *\n * @example\n * ```tsx\n * // Count up\n * <Count to={1234}>\n * <span className=\"text-4xl font-bold tabular-nums\" />\n * </Count>\n *\n * // Count down\n * <Count from={100} to={0} onComplete={() => alert(\"Done!\")}>\n * <span className=\"text-4xl font-bold tabular-nums\" />\n * </Count>\n *\n * // Live countdown to a date\n * <Count to={new Date(\"2026-04-01T00:00:00\")}>\n * <span className=\"text-2xl font-mono tabular-nums\" />\n * </Count>\n *\n * // Custom date format\n * <Count to={launchDate} format={(ms) => `${Math.ceil(ms / 86400000)} days left`}>\n * <span className=\"text-xl\" />\n * </Count>\n * ```\n */\nfunction Count({\n to,\n from: start = 0,\n duration = 900,\n delay = 0,\n format,\n prefix = \"\",\n suffix = \"\",\n children,\n once = true,\n easing = easeOut,\n onComplete,\n}: CountProps) {\n const isDate = to instanceof Date\n\n if (isDate) {\n return (\n <DateCount\n to={to}\n delay={delay}\n format={format}\n prefix={prefix}\n suffix={suffix}\n once={once}\n onComplete={onComplete}\n >\n {children}\n </DateCount>\n )\n }\n\n return (\n <NumberCount\n to={to}\n from={start}\n duration={duration}\n delay={delay}\n format={format}\n prefix={prefix}\n suffix={suffix}\n once={once}\n easing={easing}\n onComplete={onComplete}\n >\n {children}\n </NumberCount>\n )\n}\n\n// ── Number Count (up or down) ────────────────────────────────────────\n\nfunction NumberCount({\n to,\n from: start,\n duration,\n delay,\n format,\n prefix,\n suffix,\n children,\n once,\n easing,\n onComplete,\n}: {\n to: number\n from: number\n duration: number\n delay: number\n format?: (value: number) => string\n prefix: string\n suffix: string\n children: ReactElement\n once: boolean\n easing: (t: number) => number\n onComplete?: () => void\n}) {\n const ref = useRef<HTMLElement>(null)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n const prefersReducedMotion = useReducedMotion()\n const [display, setDisplay] = useState(start)\n\n // Keep the callbacks in refs so a parent re-render with inline `easing` /\n // `onComplete` props doesn't re-run the animation effect — which would cancel\n // the in-flight rAF and freeze the counter mid-count. The effect below keys\n // only on the values that should actually (re)start the animation, so a live\n // `to` change or a re-entry (with `once={false}`) restarts cleanly.\n const easingRef = useRef(easing)\n const onCompleteRef = useRef(onComplete)\n useEffect(() => {\n easingRef.current = easing\n onCompleteRef.current = onComplete\n })\n\n const formatFn = format ?? ((n: number) =>\n Number.isInteger(to) ? Math.round(n).toLocaleString() : n.toLocaleString()\n )\n\n useEffect(() => {\n if (!isInView) return\n\n const delayMs = delay * 1000\n\n // Vestibular safety: skip the count-up/down tween entirely under\n // prefers-reduced-motion and snap to the final value. We still honor the\n // in-view gate and `delay`, then fire `onComplete` once — matching the\n // resting state and lifecycle of the animated path.\n if (prefersReducedMotion) {\n const timer = setTimeout(() => {\n setDisplay(to)\n onCompleteRef.current?.()\n }, delayMs)\n\n return () => clearTimeout(timer)\n }\n\n let raf: number\n let startTime: number\n\n const timer = setTimeout(() => {\n const animate = (timestamp: number) => {\n if (!startTime) startTime = timestamp\n const elapsed = timestamp - startTime\n const progress = Math.min(elapsed / duration, 1)\n const current = start + (to - start) * easingRef.current(progress)\n\n setDisplay(current)\n\n if (progress < 1) {\n raf = requestAnimationFrame(animate)\n } else {\n onCompleteRef.current?.()\n }\n }\n\n raf = requestAnimationFrame(animate)\n }, delayMs)\n\n return () => {\n clearTimeout(timer)\n cancelAnimationFrame(raf)\n }\n }, [isInView, to, start, duration, delay, prefersReducedMotion])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return cloneElement(children, {\n ref: mergeRef(ref, existingRef),\n children: `${prefix}${formatFn(display)}${suffix}`,\n } as Record<string, unknown>)\n}\n\n// ── Date Count (live countdown) ──────────────────────────────────────\n\nfunction DateCount({\n to,\n delay,\n format,\n prefix,\n suffix,\n children,\n once,\n onComplete,\n}: {\n to: Date\n delay: number\n format?: (value: number) => string\n prefix: string\n suffix: string\n children: ReactElement\n once: boolean\n onComplete?: () => void\n}) {\n const ref = useRef<HTMLElement>(null)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n const [remaining, setRemaining] = useState(() => Math.max(0, to.getTime() - Date.now()))\n const [started, setStarted] = useState(false)\n const completedRef = useRef(false)\n\n const formatFn = format ?? formatCountdown\n\n useEffect(() => {\n if (!isInView || started) return\n const timer = setTimeout(() => setStarted(true), delay * 1000)\n return () => clearTimeout(timer)\n }, [isInView, delay, started])\n\n useEffect(() => {\n if (!started) return\n\n const tick = () => {\n const ms = Math.max(0, to.getTime() - Date.now())\n setRemaining(ms)\n\n if (ms <= 0 && !completedRef.current) {\n completedRef.current = true\n onComplete?.()\n }\n }\n\n tick()\n const interval = setInterval(tick, 1000)\n return () => clearInterval(interval)\n }, [started, to, onComplete])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return cloneElement(children, {\n ref: mergeRef(ref, existingRef),\n children: `${prefix}${formatFn(remaining)}${suffix}`,\n } as Record<string, unknown>)\n}\n\n// ── Exports ──────────────────────────────────────────────────────────\n\n/** @deprecated Use `Count` instead */\nconst CountUp = Count\n\nexport { Count, CountUp, easeOut }\nexport type { CountProps, CountUpProps }\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"encrypted-text.d.ts","names":[],"sources":["../src/encrypted-text.tsx"],"mappings":";;;;KAMK,kBAAA,GAAqB,KAAA,CAAM,cAAA;EAC9B,IAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,kBAAA;EACA,iBAAA;EACA,YAAA;EACA,eAAA;AAAA;AAAA,iBAmBO,aAAA,CAAA;EACP,IAAA;EACA,SAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,kBAAA;EACA,iBAAA;EACA,YAAA;EACA,eAAA;EAAA,GACG;AAAA,GACF,kBAAA,GAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"encrypted-text.d.ts","names":[],"sources":["../src/encrypted-text.tsx"],"mappings":";;;;KAOK,kBAAA,GAAqB,KAAA,CAAM,cAAA;EAC9B,IAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,kBAAA;EACA,iBAAA;EACA,YAAA;EACA,eAAA;AAAA;AAAA,iBAmBO,aAAA,CAAA;EACP,IAAA;EACA,SAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,kBAAA;EACA,iBAAA;EACA,YAAA;EACA,eAAA;EAAA,GACG;AAAA,GACF,kBAAA,GAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -2,6 +2,7 @@
2
2
  import { cn } from "./lib/utils.js";
3
3
  import * as React from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useReducedMotion } from "motion/react";
5
6
  //#region src/encrypted-text.tsx
6
7
  const DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[];:,.<>/?";
7
8
  function randomChar(charset) {
@@ -14,6 +15,7 @@ function scramblePreservingSpaces(original, charset) {
14
15
  return result;
15
16
  }
16
17
  function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_CHARSET, flipDelayMs = 50, encryptedClassName, revealedClassName, scrambleOnly = false, scrambleOneChar = false, ...props }) {
18
+ const prefersReducedMotion = useReducedMotion();
17
19
  const ref = React.useRef(null);
18
20
  const [isInView, setIsInView] = React.useState(false);
19
21
  const [revealCount, setRevealCount] = React.useState(0);
@@ -23,6 +25,7 @@ function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_
23
25
  const lastFlipTimeRef = React.useRef(0);
24
26
  const scrambleCharsRef = React.useRef(text ? scramblePreservingSpaces(text, charset).split("") : []);
25
27
  React.useEffect(() => {
28
+ if (prefersReducedMotion) return;
26
29
  const el = ref.current;
27
30
  if (!el) return;
28
31
  const observer = new IntersectionObserver(([entry]) => {
@@ -33,8 +36,9 @@ function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_
33
36
  }, { threshold: 0 });
34
37
  observer.observe(el);
35
38
  return () => observer.disconnect();
36
- }, []);
39
+ }, [prefersReducedMotion]);
37
40
  React.useEffect(() => {
41
+ if (prefersReducedMotion) return;
38
42
  if (!isInView) return;
39
43
  scrambleCharsRef.current = (text ? scramblePreservingSpaces(text, charset) : "").split("");
40
44
  startTimeRef.current = performance.now();
@@ -76,6 +80,7 @@ function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_
76
80
  if (animationFrameRef.current !== null) cancelAnimationFrame(animationFrameRef.current);
77
81
  };
78
82
  }, [
83
+ prefersReducedMotion,
79
84
  isInView,
80
85
  text,
81
86
  revealDelayMs,
@@ -94,7 +99,7 @@ function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_
94
99
  className: "sr-only",
95
100
  children: text
96
101
  }), text.split("").map((char, index) => {
97
- const isRevealed = !scrambleOnly && index < revealCount;
102
+ const isRevealed = prefersReducedMotion || !scrambleOnly && index < revealCount;
98
103
  const displayChar = isRevealed ? char : char === " " ? " " : scrambleCharsRef.current[index] ?? randomChar(charset);
99
104
  return /* @__PURE__ */ jsx("span", {
100
105
  "aria-hidden": "true",
@@ -1 +1 @@
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 {...props}\n >\n {/* Real text for assistive tech; the animated glyphs below are decorative\n * (aria-label on a role-less span is unreliable, and the scrambled\n * characters must not be read out). */}\n <span className=\"sr-only\">{text}</span>\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 aria-hidden=\"true\"\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":"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"}
1
+ {"version":3,"file":"encrypted-text.js","names":[],"sources":["../src/encrypted-text.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { useReducedMotion } from \"motion/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 prefersReducedMotion = useReducedMotion()\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 if (prefersReducedMotion) return\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 }, [prefersReducedMotion])\n\n React.useEffect(() => {\n if (prefersReducedMotion) return\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 }, [prefersReducedMotion, 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 {...props}\n >\n {/* Real text for assistive tech; the animated glyphs below are decorative\n * (aria-label on a role-less span is unreliable, and the scrambled\n * characters must not be read out). */}\n <span className=\"sr-only\">{text}</span>\n {text.split(\"\").map((char, index) => {\n // Reduced motion: skip the scramble entirely and show every\n // character in its final revealed form from the first frame.\n const isRevealed =\n prefersReducedMotion || (!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 aria-hidden=\"true\"\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":"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"}
package/dist/field.js CHANGED
@@ -21,7 +21,7 @@ function FieldLabel({ className, ...props }) {
21
21
  function FieldControl({ className, ...props }) {
22
22
  return /* @__PURE__ */ jsx(FieldPrimitive.Control, {
23
23
  "data-slot": "field-control",
24
- className: cn("rounded-md outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", className),
24
+ className: cn("rounded-md outline-none focus-visible:ring-3 focus-visible:ring-focus/50 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", className),
25
25
  ...props
26
26
  });
27
27
  }
package/dist/field.js.map CHANGED
@@ -1 +1 @@
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` matters here for React Hook Form / focus management; it flows\n// through to the control via standard prop forwarding (React 19).\nexport type FieldControlProps = React.ComponentProps<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 function FieldControl({ className, ...props }: FieldControlProps) {\n return (\n <FieldPrimitive.Control\n data-slot=\"field-control\"\n className={cn(\n \"rounded-md outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n />\n )\n}\n\nexport function FieldDescription({ className, ...props }: FieldDescriptionProps) {\n return (\n <FieldPrimitive.Description\n data-slot=\"field-description\"\n className={cn(\n \"text-muted 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":";;;;;;AAkBA,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,SAAgB,aAAa,EAAE,WAAW,GAAG,SAA4B;AACvE,QACE,oBAAC,eAAe,SAAhB;EACE,aAAU;EACV,WAAW,GACT,mKACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAgB,iBAAiB,EAAE,WAAW,GAAG,SAAgC;AAC/E,QACE,oBAAC,eAAe,aAAhB;EACE,aAAU;EACV,WAAW,GACT,0IACA,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"}
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` matters here for React Hook Form / focus management; it flows\n// through to the control via standard prop forwarding (React 19).\nexport type FieldControlProps = React.ComponentProps<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 function FieldControl({ className, ...props }: FieldControlProps) {\n return (\n <FieldPrimitive.Control\n data-slot=\"field-control\"\n className={cn(\n \"rounded-md outline-none focus-visible:ring-3 focus-visible:ring-focus/50 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n />\n )\n}\n\nexport function FieldDescription({ className, ...props }: FieldDescriptionProps) {\n return (\n <FieldPrimitive.Description\n data-slot=\"field-description\"\n className={cn(\n \"text-muted 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":";;;;;;AAkBA,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,SAAgB,aAAa,EAAE,WAAW,GAAG,SAA4B;AACvE,QACE,oBAAC,eAAe,SAAhB;EACE,aAAU;EACV,WAAW,GACT,0IACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAgB,iBAAiB,EAAE,WAAW,GAAG,SAAgC;AAC/E,QACE,oBAAC,eAAe,aAAhB;EACE,aAAU;EACV,WAAW,GACT,0IACA,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"}
@@ -18,7 +18,7 @@ declare function InputGroup({
18
18
  ...props
19
19
  }: InputGroupProps): _$react_jsx_runtime0.JSX.Element;
20
20
  declare const inputGroupAddonVariants: (props?: ({
21
- align?: "inline-end" | "inline-start" | "block-end" | "block-start" | null | undefined;
21
+ align?: "inline-start" | "inline-end" | "block-start" | "block-end" | null | undefined;
22
22
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
23
23
  declare function InputGroupAddon({
24
24
  className,
@@ -26,7 +26,7 @@ declare function InputGroupAddon({
26
26
  ...props
27
27
  }: InputGroupAddonProps): _$react_jsx_runtime0.JSX.Element;
28
28
  declare const inputGroupButtonVariants: (props?: ({
29
- size?: "sm" | "xs" | "icon-xs" | "icon-sm" | null | undefined;
29
+ size?: "xs" | "sm" | "icon-xs" | "icon-sm" | null | undefined;
30
30
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
31
31
  declare function InputGroupButton({
32
32
  className,
package/dist/item.d.ts CHANGED
@@ -8,10 +8,10 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
8
8
  //#region src/item.d.ts
9
9
  declare const itemVariants: (props?: ({
10
10
  variant?: "default" | "outline" | "muted" | null | undefined;
11
- size?: "default" | "sm" | "xs" | null | undefined;
11
+ size?: "default" | "xs" | "sm" | null | undefined;
12
12
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
13
13
  declare const itemMediaVariants: (props?: ({
14
- variant?: "default" | "image" | "icon" | null | undefined;
14
+ variant?: "default" | "icon" | "image" | null | undefined;
15
15
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
16
16
  type ItemGroupProps = React.ComponentProps<"div">;
17
17
  type ItemSeparatorProps = React.ComponentProps<typeof Separator>;
@@ -1 +1 @@
1
- {"version":3,"file":"item.d.ts","names":[],"sources":["../src/item.tsx"],"mappings":";;;;;;;;cAUM,YAAA,GAAY,KAAA;;;IAoBjB,iCAAA,CAAA,SAAA;AAAA,cAEK,iBAAA,GAAiB,KAAA;;IActB,iCAAA,CAAA,SAAA;AAAA,KAEI,cAAA,GAAiB,KAAA,CAAM,cAAA;AAAA,KACvB,kBAAA,GAAqB,KAAA,CAAM,cAAA,QAAsB,SAAA;AAAA,KACjD,SAAA,GAAY,SAAA,CAAU,cAAA,UAAwB,YAAA,QAAoB,YAAA;AAAA,KAClE,cAAA,GAAiB,KAAA,CAAM,cAAA,UAAwB,YAAA,QAAoB,iBAAA;AAAA,KACnE,gBAAA,GAAmB,KAAA,CAAM,cAAA;AAAA,KACzB,cAAA,GAAiB,KAAA,CAAM,cAAA;AAAA,KACvB,oBAAA,GAAuB,KAAA,CAAM,cAAA;AAAA,KAC7B,gBAAA,GAAmB,KAAA,CAAM,cAAA;AAAA,KACzB,eAAA,GAAkB,KAAA,CAAM,cAAA;AAAA,KACxB,eAAA,GAAkB,KAAA,CAAM,cAAA;AAAA,iBAEpB,SAAA,CAAA;EAAY,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAcjD,aAAA,CAAA;EAAgB,SAAA;EAAA,GAAc;AAAA,GAAS,kBAAA,GAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAWzD,IAAA,CAAA;EACP,SAAA;EACA,OAAA;EACA,IAAA;EACA,MAAA;EAAA,GACG;AAAA,GACF,SAAA,GAAS,KAAA,CAAA,YAAA,mBAAA,KAAA,CAAA,qBAAA;AAAA,iBAkBH,SAAA,CAAA;EAAY,SAAA;EAAW,OAAA;EAAA,GAAwB;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAWtE,WAAA,CAAA;EAAc,SAAA;EAAA,GAAc;AAAA,GAAS,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAarD,SAAA,CAAA;EAAY,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAajD,eAAA,CAAA;EAAkB,SAAA;EAAA,GAAc;AAAA,GAAS,oBAAA,GAAoB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAa7D,WAAA,CAAA;EAAc,SAAA;EAAA,GAAc;AAAA,GAAS,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUrD,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,eAAA,GAAe,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAanD,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,eAAA,GAAe,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"item.d.ts","names":[],"sources":["../src/item.tsx"],"mappings":";;;;;;;;cAUM,YAAA,GAAY,KAAA;;;IAoBjB,iCAAA,CAAA,SAAA;AAAA,cAEK,iBAAA,GAAiB,KAAA;;IActB,iCAAA,CAAA,SAAA;AAAA,KAEI,cAAA,GAAiB,KAAA,CAAM,cAAA;AAAA,KACvB,kBAAA,GAAqB,KAAA,CAAM,cAAA,QAAsB,SAAA;AAAA,KACjD,SAAA,GAAY,SAAA,CAAU,cAAA,UAAwB,YAAA,QAAoB,YAAA;AAAA,KAClE,cAAA,GAAiB,KAAA,CAAM,cAAA,UAAwB,YAAA,QAAoB,iBAAA;AAAA,KACnE,gBAAA,GAAmB,KAAA,CAAM,cAAA;AAAA,KACzB,cAAA,GAAiB,KAAA,CAAM,cAAA;AAAA,KACvB,oBAAA,GAAuB,KAAA,CAAM,cAAA;AAAA,KAC7B,gBAAA,GAAmB,KAAA,CAAM,cAAA;AAAA,KACzB,eAAA,GAAkB,KAAA,CAAM,cAAA;AAAA,KACxB,eAAA,GAAkB,KAAA,CAAM,cAAA;AAAA,iBAEpB,SAAA,CAAA;EAAY,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAajD,aAAA,CAAA;EAAgB,SAAA;EAAA,GAAc;AAAA,GAAS,kBAAA,GAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAWzD,IAAA,CAAA;EACP,SAAA;EACA,OAAA;EACA,IAAA;EACA,MAAA;EAAA,GACG;AAAA,GACF,SAAA,GAAS,KAAA,CAAA,YAAA,mBAAA,KAAA,CAAA,qBAAA;AAAA,iBAkBH,SAAA,CAAA;EAAY,SAAA;EAAW,OAAA;EAAA,GAAwB;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAWtE,WAAA,CAAA;EAAc,SAAA;EAAA,GAAc;AAAA,GAAS,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAarD,SAAA,CAAA;EAAY,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAajD,eAAA,CAAA;EAAkB,SAAA;EAAA,GAAc;AAAA,GAAS,oBAAA,GAAoB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAa7D,WAAA,CAAA;EAAc,SAAA;EAAA,GAAc;AAAA,GAAS,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUrD,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,eAAA,GAAe,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAanD,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,eAAA,GAAe,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/item.js CHANGED
@@ -35,7 +35,6 @@ const itemMediaVariants = cva("gap-2 group-has-data-[slot=item-description]/item
35
35
  });
36
36
  function ItemGroup({ className, ...props }) {
37
37
  return /* @__PURE__ */ jsx("div", {
38
- role: "list",
39
38
  "data-slot": "item-group",
40
39
  className: cn("group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2", className),
41
40
  ...props
package/dist/item.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"item.js","names":[],"sources":["../src/item.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"./lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst itemVariants = cva(\n \"[a]:hover:bg-secondary rounded-md border text-sm w-full group/item focus-visible:border-focus focus-visible:ring-focus/50 flex items-center flex-wrap outline-none transition-colors duration-200 focus-visible:ring-3 [a]:transition-colors\",\n {\n variants: {\n variant: {\n default: \"border-transparent\",\n outline: \"border-line\",\n muted: \"bg-secondary/50 border-transparent\",\n },\n size: {\n default: \"gap-2.5 px-3 py-2.5\",\n sm: \"gap-2.5 px-3 py-2.5\",\n xs: \"gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nconst itemMediaVariants = cva(\n \"gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"[&_svg:not([class*='size-'])]:size-4\",\n image: \"size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\ntype ItemGroupProps = React.ComponentProps<\"div\">\ntype ItemSeparatorProps = React.ComponentProps<typeof Separator>\ntype ItemProps = useRender.ComponentProps<\"div\"> & VariantProps<typeof itemVariants>\ntype ItemMediaProps = React.ComponentProps<\"div\"> & VariantProps<typeof itemMediaVariants>\ntype ItemContentProps = React.ComponentProps<\"div\">\ntype ItemTitleProps = React.ComponentProps<\"div\">\ntype ItemDescriptionProps = React.ComponentProps<\"p\">\ntype ItemActionsProps = React.ComponentProps<\"div\">\ntype ItemHeaderProps = React.ComponentProps<\"div\">\ntype ItemFooterProps = React.ComponentProps<\"div\">\n\nfunction ItemGroup({ className, ...props }: ItemGroupProps) {\n return (\n <div\n role=\"list\"\n data-slot=\"item-group\"\n className={cn(\n \"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemSeparator({ className, ...props }: ItemSeparatorProps) {\n return (\n <Separator\n data-slot=\"item-separator\"\n orientation=\"horizontal\"\n className={cn(\"my-2\", className)}\n {...props}\n />\n )\n}\n\nfunction Item({\n className,\n variant = \"default\",\n size = \"default\",\n render,\n ...props\n}: ItemProps) {\n return useRender({\n defaultTagName: \"div\",\n props: mergeProps<\"div\">(\n {\n className: cn(itemVariants({ variant, size, className })),\n },\n props\n ),\n render,\n state: {\n slot: \"item\",\n variant,\n size,\n },\n })\n}\n\nfunction ItemMedia({ className, variant = \"default\", ...props }: ItemMediaProps) {\n return (\n <div\n data-slot=\"item-media\"\n data-variant={variant}\n className={cn(itemMediaVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\nfunction ItemContent({ className, ...props }: ItemContentProps) {\n return (\n <div\n data-slot=\"item-content\"\n className={cn(\n \"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemTitle({ className, ...props }: ItemTitleProps) {\n return (\n <div\n data-slot=\"item-title\"\n className={cn(\n \"line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemDescription({ className, ...props }: ItemDescriptionProps) {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(\n \"text-muted [&>a:hover]:text-primary line-clamp-2 text-left text-sm leading-normal font-normal group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemActions({ className, ...props }: ItemActionsProps) {\n return (\n <div\n data-slot=\"item-actions\"\n className={cn(\"flex items-center gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction ItemHeader({ className, ...props }: ItemHeaderProps) {\n return (\n <div\n data-slot=\"item-header\"\n className={cn(\n \"flex basis-full items-center justify-between gap-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemFooter({ className, ...props }: ItemFooterProps) {\n return (\n <div\n data-slot=\"item-footer\"\n className={cn(\n \"flex basis-full items-center justify-between gap-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Item,\n ItemMedia,\n ItemContent,\n ItemActions,\n ItemGroup,\n ItemSeparator,\n ItemTitle,\n ItemDescription,\n ItemHeader,\n ItemFooter,\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,eAAe,IACnB,gPACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,SAAS;GACT,OAAO;GACR;EACD,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACL;EACF;CACD,iBAAiB;EACf,SAAS;EACT,MAAM;EACP;CACF,CACF;AAED,MAAM,oBAAoB,IACxB,kMACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,MAAM;EACN,OAAO;EACR,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACF;AAaD,SAAS,UAAU,EAAE,WAAW,GAAG,SAAyB;AAC1D,QACE,oBAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,WAAW,GACT,mGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EAAE,WAAW,GAAG,SAA6B;AAClE,QACE,oBAAC,WAAD;EACE,aAAU;EACV,aAAY;EACZ,WAAW,GAAG,QAAQ,UAAU;EAChC,GAAI;EACJ,CAAA;;AAIN,SAAS,KAAK,EACZ,WACA,UAAU,WACV,OAAO,WACP,QACA,GAAG,SACS;AACZ,QAAO,UAAU;EACf,gBAAgB;EAChB,OAAO,WACL,EACE,WAAW,GAAG,aAAa;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC,EAC1D,EACD,MACD;EACD;EACA,OAAO;GACL,MAAM;GACN;GACA;GACD;EACF,CAAC;;AAGJ,SAAS,UAAU,EAAE,WAAW,UAAU,WAAW,GAAG,SAAyB;AAC/E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,WAAW,GAAG,kBAAkB;GAAE;GAAS;GAAW,CAAC,CAAC;EACxD,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,qGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,UAAU,EAAE,WAAW,GAAG,SAAyB;AAC1D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,kGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAA+B;AACtE,QACE,oBAAC,KAAD;EACE,aAAU;EACV,WAAW,GACT,4KACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,2BAA2B,UAAU;EACnD,GAAI;EACJ,CAAA;;AAIN,SAAS,WAAW,EAAE,WAAW,GAAG,SAA0B;AAC5D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,sDACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,WAAW,EAAE,WAAW,GAAG,SAA0B;AAC5D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,sDACA,UACD;EACD,GAAI;EACJ,CAAA"}
1
+ {"version":3,"file":"item.js","names":[],"sources":["../src/item.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"./lib/utils\"\nimport { Separator } from \"./separator\"\n\nconst itemVariants = cva(\n \"[a]:hover:bg-secondary rounded-md border text-sm w-full group/item focus-visible:border-focus focus-visible:ring-focus/50 flex items-center flex-wrap outline-none transition-colors duration-200 focus-visible:ring-3 [a]:transition-colors\",\n {\n variants: {\n variant: {\n default: \"border-transparent\",\n outline: \"border-line\",\n muted: \"bg-secondary/50 border-transparent\",\n },\n size: {\n default: \"gap-2.5 px-3 py-2.5\",\n sm: \"gap-2.5 px-3 py-2.5\",\n xs: \"gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nconst itemMediaVariants = cva(\n \"gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"[&_svg:not([class*='size-'])]:size-4\",\n image: \"size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\ntype ItemGroupProps = React.ComponentProps<\"div\">\ntype ItemSeparatorProps = React.ComponentProps<typeof Separator>\ntype ItemProps = useRender.ComponentProps<\"div\"> & VariantProps<typeof itemVariants>\ntype ItemMediaProps = React.ComponentProps<\"div\"> & VariantProps<typeof itemMediaVariants>\ntype ItemContentProps = React.ComponentProps<\"div\">\ntype ItemTitleProps = React.ComponentProps<\"div\">\ntype ItemDescriptionProps = React.ComponentProps<\"p\">\ntype ItemActionsProps = React.ComponentProps<\"div\">\ntype ItemHeaderProps = React.ComponentProps<\"div\">\ntype ItemFooterProps = React.ComponentProps<\"div\">\n\nfunction ItemGroup({ className, ...props }: ItemGroupProps) {\n return (\n <div\n data-slot=\"item-group\"\n className={cn(\n \"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemSeparator({ className, ...props }: ItemSeparatorProps) {\n return (\n <Separator\n data-slot=\"item-separator\"\n orientation=\"horizontal\"\n className={cn(\"my-2\", className)}\n {...props}\n />\n )\n}\n\nfunction Item({\n className,\n variant = \"default\",\n size = \"default\",\n render,\n ...props\n}: ItemProps) {\n return useRender({\n defaultTagName: \"div\",\n props: mergeProps<\"div\">(\n {\n className: cn(itemVariants({ variant, size, className })),\n },\n props\n ),\n render,\n state: {\n slot: \"item\",\n variant,\n size,\n },\n })\n}\n\nfunction ItemMedia({ className, variant = \"default\", ...props }: ItemMediaProps) {\n return (\n <div\n data-slot=\"item-media\"\n data-variant={variant}\n className={cn(itemMediaVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\nfunction ItemContent({ className, ...props }: ItemContentProps) {\n return (\n <div\n data-slot=\"item-content\"\n className={cn(\n \"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemTitle({ className, ...props }: ItemTitleProps) {\n return (\n <div\n data-slot=\"item-title\"\n className={cn(\n \"line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemDescription({ className, ...props }: ItemDescriptionProps) {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(\n \"text-muted [&>a:hover]:text-primary line-clamp-2 text-left text-sm leading-normal font-normal group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemActions({ className, ...props }: ItemActionsProps) {\n return (\n <div\n data-slot=\"item-actions\"\n className={cn(\"flex items-center gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction ItemHeader({ className, ...props }: ItemHeaderProps) {\n return (\n <div\n data-slot=\"item-header\"\n className={cn(\n \"flex basis-full items-center justify-between gap-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ItemFooter({ className, ...props }: ItemFooterProps) {\n return (\n <div\n data-slot=\"item-footer\"\n className={cn(\n \"flex basis-full items-center justify-between gap-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Item,\n ItemMedia,\n ItemContent,\n ItemActions,\n ItemGroup,\n ItemSeparator,\n ItemTitle,\n ItemDescription,\n ItemHeader,\n ItemFooter,\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,eAAe,IACnB,gPACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,SAAS;GACT,OAAO;GACR;EACD,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACL;EACF;CACD,iBAAiB;EACf,SAAS;EACT,MAAM;EACP;CACF,CACF;AAED,MAAM,oBAAoB,IACxB,kMACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,MAAM;EACN,OAAO;EACR,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACF;AAaD,SAAS,UAAU,EAAE,WAAW,GAAG,SAAyB;AAC1D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,mGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EAAE,WAAW,GAAG,SAA6B;AAClE,QACE,oBAAC,WAAD;EACE,aAAU;EACV,aAAY;EACZ,WAAW,GAAG,QAAQ,UAAU;EAChC,GAAI;EACJ,CAAA;;AAIN,SAAS,KAAK,EACZ,WACA,UAAU,WACV,OAAO,WACP,QACA,GAAG,SACS;AACZ,QAAO,UAAU;EACf,gBAAgB;EAChB,OAAO,WACL,EACE,WAAW,GAAG,aAAa;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC,EAC1D,EACD,MACD;EACD;EACA,OAAO;GACL,MAAM;GACN;GACA;GACD;EACF,CAAC;;AAGJ,SAAS,UAAU,EAAE,WAAW,UAAU,WAAW,GAAG,SAAyB;AAC/E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,WAAW,GAAG,kBAAkB;GAAE;GAAS;GAAW,CAAC,CAAC;EACxD,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,qGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,UAAU,EAAE,WAAW,GAAG,SAAyB;AAC1D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,kGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAA+B;AACtE,QACE,oBAAC,KAAD;EACE,aAAU;EACV,WAAW,GACT,4KACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,2BAA2B,UAAU;EACnD,GAAI;EACJ,CAAA;;AAIN,SAAS,WAAW,EAAE,WAAW,GAAG,SAA0B;AAC5D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,sDACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,WAAW,EAAE,WAAW,GAAG,SAA0B;AAC5D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,sDACA,UACD;EACD,GAAI;EACJ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"masonry.d.ts","names":[],"sources":["../src/masonry.tsx"],"mappings":";;;;;KAaK,YAAA,GAAe,KAAA,CAAM,cAAA;EACxB,OAAA;EACA,WAAA;EACA,GAAA;AAAA;AAAA,KAGG,gBAAA,GAAmB,IAAA,CAAK,eAAA;EAC3B,IAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;AAAA;AAAA,iBAGV,OAAA,CAAA;EACP,OAAA;EACA,WAAA;EACA,GAAA;EACA,SAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBA0NN,WAAA,CAAA;EACP,SAAA;EACA,IAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"masonry.d.ts","names":[],"sources":["../src/masonry.tsx"],"mappings":";;;;;KAkBK,YAAA,GAAe,KAAA,CAAM,cAAA;EACxB,OAAA;EACA,WAAA;EACA,GAAA;AAAA;AAAA,KAGG,gBAAA,GAAmB,IAAA,CAAK,eAAA;EAC3B,IAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;AAAA;AAAA,iBAGV,OAAA,CAAA;EACP,OAAA;EACA,WAAA;EACA,GAAA;EACA,SAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBA0NN,WAAA,CAAA;EACP,SAAA;EACA,IAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA"}