@waveso/ui 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +152 -68
  2. package/dist/accordion.js +1 -1
  3. package/dist/accordion.js.map +1 -1
  4. package/dist/alert-dialog.js +1 -1
  5. package/dist/alert-dialog.js.map +1 -1
  6. package/dist/badge.d.ts +1 -1
  7. package/dist/button.d.ts +1 -1
  8. package/dist/card.js +1 -1
  9. package/dist/card.js.map +1 -1
  10. package/dist/combobox.d.ts.map +1 -1
  11. package/dist/combobox.js +3 -1
  12. package/dist/combobox.js.map +1 -1
  13. package/dist/count.d.ts.map +1 -1
  14. package/dist/count.js +10 -9
  15. package/dist/count.js.map +1 -1
  16. package/dist/dialog.js +1 -1
  17. package/dist/dialog.js.map +1 -1
  18. package/dist/drawer.js +1 -1
  19. package/dist/drawer.js.map +1 -1
  20. package/dist/encrypted-text.js +8 -5
  21. package/dist/encrypted-text.js.map +1 -1
  22. package/dist/gradient-reveal-text.js +2 -1
  23. package/dist/gradient-reveal-text.js.map +1 -1
  24. package/dist/infinite-scroll.js +3 -9
  25. package/dist/infinite-scroll.js.map +1 -1
  26. package/dist/item.d.ts +1 -1
  27. package/dist/label.js +1 -1
  28. package/dist/label.js.map +1 -1
  29. package/dist/lib/internal-icons.d.ts +1 -1
  30. package/dist/lib/internal-icons.d.ts.map +1 -1
  31. package/dist/lib/internal-icons.js +4 -2
  32. package/dist/lib/internal-icons.js.map +1 -1
  33. package/dist/spinner.js +2 -0
  34. package/dist/spinner.js.map +1 -1
  35. package/dist/styles.css +167 -108
  36. package/dist/table.js +3 -3
  37. package/dist/table.js.map +1 -1
  38. package/dist/textarea.d.ts.map +1 -1
  39. package/dist/textarea.js +1 -0
  40. package/dist/textarea.js.map +1 -1
  41. package/dist/toggle-group.d.ts +0 -1
  42. package/dist/toggle-group.d.ts.map +1 -1
  43. package/dist/toggle-group.js +1 -1
  44. package/dist/toggle-group.js.map +1 -1
  45. package/package.json +8 -16
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 const hasAnimated = useRef(false)\n\n const formatFn = format ?? ((n: number) =>\n Number.isInteger(to) ? Math.round(n).toLocaleString() : n.toLocaleString()\n )\n\n useEffect(() => {\n if (!isInView || hasAnimated.current) return\n hasAnimated.current = true\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 easedProgress = easing(progress)\n const current = start + (to - start) * easedProgress\n\n setDisplay(current)\n\n if (progress < 1) {\n raf = requestAnimationFrame(animate)\n } else {\n onComplete?.()\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, easing, 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(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":";;;;;;AAmDA,SAAS,QAAQ,GAAmB;AAClC,QAAO,IAAI,KAAK,IAAI,IAAI,GAAG,EAAE;;AAK/B,SAAS,gBAAgB,IAAoB;AAC3C,KAAI,MAAM,EAAG,QAAO;CAEpB,MAAM,eAAe,KAAK,MAAM,KAAK,IAAK;CAC1C,MAAM,OAAO,KAAK,MAAM,eAAe,MAAM;CAC7C,MAAM,QAAQ,KAAK,MAAO,eAAe,QAAS,KAAK;CACvD,MAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,GAAG;CACtD,MAAM,UAAU,eAAe;CAE/B,MAAM,OAAO,MAAc,OAAO,EAAE,CAAC,SAAS,GAAG,IAAI;AAErD,KAAI,OAAO,EACT,QAAO,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG,IAAI,QAAQ;AAE/D,QAAO,GAAG,IAAI,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG,IAAI,QAAQ;;AAKtD,SAAS,SACP,aACA,aACA;AACA,SAAQ,OAA2B;AAC/B,cAAgD,UAAU;AAC5D,MAAI,OAAO,gBAAgB,WAAY,aAAY,GAAG;WAC7C,eAAe,OAAO,gBAAgB,SAC3C,aAAgD,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuClE,SAAS,MAAM,EACb,IACA,MAAM,QAAQ,GACd,WAAW,KACX,QAAQ,GACR,QACA,SAAS,IACT,SAAS,IACT,UACA,OAAO,MACP,SAAS,SACT,cACa;AAGb,KAFe,cAAc,KAG3B,QACE,oBAAC,WAAD;EACM;EACG;EACC;EACA;EACA;EACF;EACM;EAEX;EACS,CAAA;AAIhB,QACE,oBAAC,aAAD;EACM;EACJ,MAAM;EACI;EACH;EACC;EACA;EACA;EACF;EACE;EACI;EAEX;EACW,CAAA;;AAMlB,SAAS,YAAY,EACnB,IACA,MAAM,OACN,UACA,OACA,QACA,QACA,QACA,UACA,MACA,QACA,cAaC;CACD,MAAM,MAAM,OAAoB,KAAK;CACrC,MAAM,WAAW,UAAU,KAAK;EAAE;EAAM,QAAQ;EAAS,CAAC;CAC1D,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,cAAc,OAAO,MAAM;CAEjC,MAAM,WAAW,YAAY,MAC3B,OAAO,UAAU,GAAG,GAAG,KAAK,MAAM,EAAE,CAAC,gBAAgB,GAAG,EAAE,gBAAgB;AAG5E,iBAAgB;AACd,MAAI,CAAC,YAAY,YAAY,QAAS;AACtC,cAAY,UAAU;EAEtB,MAAM,UAAU,QAAQ;EACxB,IAAI;EACJ,IAAI;EAEJ,MAAM,QAAQ,iBAAiB;GAC7B,MAAM,WAAW,cAAsB;AACrC,QAAI,CAAC,UAAW,aAAY;IAC5B,MAAM,UAAU,YAAY;IAC5B,MAAM,WAAW,KAAK,IAAI,UAAU,UAAU,EAAE;IAChD,MAAM,gBAAgB,OAAO,SAAS;AAGtC,eAFgB,SAAS,KAAK,SAAS,cAEpB;AAEnB,QAAI,WAAW,EACb,OAAM,sBAAsB,QAAQ;QAEpC,eAAc;;AAIlB,SAAM,sBAAsB,QAAQ;KACnC,QAAQ;AAEX,eAAa;AACX,gBAAa,MAAM;AACnB,wBAAqB,IAAI;;IAE1B;EAAC;EAAU;EAAI;EAAO;EAAU;EAAO;EAAQ;EAAW,CAAC;AAE9D,KAAI,CAAC,eAAe,SAAS,CAAE,QAAO;CAGtC,MAAM,cADa,SAAS,MACmC;AAE/D,QAAO,aAAa,UAAU;EAC5B,KAAK,SAAS,KAAK,YAAY;EAC/B,UAAU,GAAG,SAAS,SAAS,QAAQ,GAAG;EAC3C,CAA4B;;AAK/B,SAAS,UAAU,EACjB,IACA,OACA,QACA,QACA,QACA,UACA,MACA,cAUC;CACD,MAAM,MAAM,OAAoB,KAAK;CACrC,MAAM,WAAW,UAAU,KAAK;EAAE;EAAM,QAAQ;EAAS,CAAC;CAC1D,MAAM,CAAC,WAAW,gBAAgB,eAAe,KAAK,IAAI,GAAG,GAAG,SAAS,GAAG,KAAK,KAAK,CAAC,CAAC;CACxF,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,eAAe,OAAO,MAAM;CAElC,MAAM,WAAW,UAAU;AAE3B,iBAAgB;AACd,MAAI,CAAC,YAAY,QAAS;EAC1B,MAAM,QAAQ,iBAAiB,WAAW,KAAK,EAAE,QAAQ,IAAK;AAC9D,eAAa,aAAa,MAAM;IAC/B;EAAC;EAAU;EAAO;EAAQ,CAAC;AAE9B,iBAAgB;AACd,MAAI,CAAC,QAAS;EAEd,MAAM,aAAa;GACjB,MAAM,KAAK,KAAK,IAAI,GAAG,GAAG,SAAS,GAAG,KAAK,KAAK,CAAC;AACjD,gBAAa,GAAG;AAEhB,OAAI,MAAM,KAAK,CAAC,aAAa,SAAS;AACpC,iBAAa,UAAU;AACvB,kBAAc;;;AAIlB,QAAM;EACN,MAAM,WAAW,YAAY,MAAM,IAAK;AACxC,eAAa,cAAc,SAAS;IACnC;EAAC;EAAS;EAAI;EAAW,CAAC;AAE7B,KAAI,CAAC,eAAe,SAAS,CAAE,QAAO;CAGtC,MAAM,cADa,SAAS,MACmC;AAE/D,QAAO,aAAa,UAAU;EAC5B,KAAK,SAAS,KAAK,YAAY;EAC/B,UAAU,GAAG,SAAS,SAAS,UAAU,GAAG;EAC7C,CAA4B;;;AAM/B,MAAM,UAAU"}
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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"}
package/dist/dialog.js CHANGED
@@ -67,7 +67,7 @@ function DialogHeader({ className, ...props }) {
67
67
  function DialogFooter({ className, showCloseButton = false, children, ...props }) {
68
68
  return /* @__PURE__ */ jsxs("div", {
69
69
  "data-slot": "dialog-footer",
70
- className: cn("bg-secondary/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-lg border-t p-4 sm:flex-row sm:justify-end", className),
70
+ className: cn("bg-secondary/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-lg border-t border-line p-4 sm:flex-row sm:justify-end", className),
71
71
  ...props,
72
72
  children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog$1.Close, {
73
73
  render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.js","names":["DialogPrimitive"],"sources":["../src/dialog.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { CloseIcon } from \"./lib/internal-icons\"\n\ntype DialogProps = React.ComponentProps<typeof DialogPrimitive.Root> & {\n /**\n * When `true`, clicking outside the dialog (backdrop / pointer\n * dismissal) does not close it. It can then only be closed via an\n * explicit action — the close button, `Esc`, or programmatically.\n *\n * Use this for dialogs containing forms, wizards, or other content\n * where an accidental outside click shouldn't discard the user's work.\n *\n * @default false\n */\n disablePointerDismissal?: boolean\n}\ntype DialogTriggerProps = React.ComponentProps<typeof DialogPrimitive.Trigger>\ntype DialogPortalProps = React.ComponentProps<typeof DialogPrimitive.Portal>\ntype DialogCloseProps = React.ComponentProps<typeof DialogPrimitive.Close>\ntype DialogOverlayProps = React.ComponentProps<typeof DialogPrimitive.Backdrop>\ntype DialogPopupProps = React.ComponentProps<typeof DialogPrimitive.Popup>\ntype DialogTitleProps = React.ComponentProps<typeof DialogPrimitive.Title>\ntype DialogDescriptionProps = React.ComponentProps<typeof DialogPrimitive.Description>\n\ntype DialogContentProps = DialogPopupProps & {\n showCloseButton?: boolean\n}\n\ntype DialogFooterProps = React.ComponentProps<\"div\"> & {\n showCloseButton?: boolean\n}\n\nfunction Dialog({ disablePointerDismissal, ...props }: DialogProps) {\n return <DialogPrimitive.Root data-slot=\"dialog\" disablePointerDismissal={disablePointerDismissal} {...props} />\n}\n\nfunction DialogTrigger({ ...props }: DialogTriggerProps) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({ ...props }: DialogPortalProps) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({ ...props }: DialogCloseProps) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: DialogOverlayProps) {\n return (\n <DialogPrimitive.Backdrop\n data-slot=\"dialog-overlay\"\n className={cn(\n \"motion-scrim fixed inset-0 isolate z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: DialogContentProps) {\n return (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Popup\n data-slot=\"dialog-content\"\n className={cn(\n \"motion-scale-lg bg-foundation ring-contrast/10 fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg p-4 text-sm ring-1 outline-none sm:max-w-sm\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n render={\n <Button\n variant=\"ghost\"\n className=\"absolute top-2 right-2\"\n size=\"icon-sm\"\n />\n }\n >\n <CloseIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Popup>\n </DialogPortal>\n )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: DialogFooterProps) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"bg-secondary/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-lg border-t p-4 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close render={<Button variant=\"outline\" />}>\n Close\n </DialogPrimitive.Close>\n )}\n </div>\n )\n}\n\nfunction DialogTitle({ className, ...props }: DialogTitleProps) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n // pr-8 reserves room for the close button (absolute, top-2 right-2) so a\n // long title wraps before it instead of running underneath.\n className={cn(\"text-base leading-none font-medium pr-8\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: DialogDescriptionProps) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n \"text-muted *:[a]:hover:text-contrast text-sm *:[a]:underline *:[a]:underline-offset-3\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n}\n"],"mappings":";;;;;;;;AAsCA,SAAS,OAAO,EAAE,yBAAyB,GAAG,SAAsB;AAClE,QAAO,oBAACA,SAAgB,MAAjB;EAAsB,aAAU;EAAkC;EAAyB,GAAI;EAAS,CAAA;;AAGjH,SAAS,cAAc,EAAE,GAAG,SAA6B;AACvD,QAAO,oBAACA,SAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;EAAS,CAAA;;AAG1E,SAAS,aAAa,EAAE,GAAG,SAA4B;AACrD,QAAO,oBAACA,SAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;EAAS,CAAA;;AAGxE,SAAS,YAAY,EAAE,GAAG,SAA2B;AACnD,QAAO,oBAACA,SAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;EAAS,CAAA;;AAGtE,SAAS,cAAc,EACrB,WACA,GAAG,SACkB;AACrB,QACE,oBAACA,SAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,iGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,MAClB,GAAG,SACkB;AACrB,QACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,eAAD,EAAiB,CAAA,EACjB,qBAACA,SAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GACT,iNACA,UACD;EACD,GAAI;YANN,CAQG,UACA,mBACC,qBAACA,SAAgB,OAAjB;GACE,aAAU;GACV,QACE,oBAAC,QAAD;IACE,SAAQ;IACR,WAAU;IACV,MAAK;IACL,CAAA;aAPN,CAUE,oBAAC,WAAD,EAAa,CAAA,EACb,oBAAC,QAAD;IAAM,WAAU;cAAU;IAAY,CAAA,CAChB;KAEJ;IACX,EAAA,CAAA;;AAInB,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;AAC1E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,uBAAuB,UAAU;EAC/C,GAAI;EACJ,CAAA;;AAIN,SAAS,aAAa,EACpB,WACA,kBAAkB,OAClB,UACA,GAAG,SACiB;AACpB,QACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,gHACA,UACD;EACD,GAAI;YANN,CAQG,UACA,mBACC,oBAACA,SAAgB,OAAjB;GAAuB,QAAQ,oBAAC,QAAD,EAAQ,SAAQ,WAAY,CAAA;aAAE;GAErC,CAAA,CAEtB;;;AAIV,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAACA,SAAgB,OAAjB;EACE,aAAU;EAGV,WAAW,GAAG,2CAA2C,UAAU;EACnE,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EACzB,WACA,GAAG,SACsB;AACzB,QACE,oBAACA,SAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GACT,yFACA,UACD;EACD,GAAI;EACJ,CAAA"}
1
+ {"version":3,"file":"dialog.js","names":["DialogPrimitive"],"sources":["../src/dialog.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { CloseIcon } from \"./lib/internal-icons\"\n\ntype DialogProps = React.ComponentProps<typeof DialogPrimitive.Root> & {\n /**\n * When `true`, clicking outside the dialog (backdrop / pointer\n * dismissal) does not close it. It can then only be closed via an\n * explicit action — the close button, `Esc`, or programmatically.\n *\n * Use this for dialogs containing forms, wizards, or other content\n * where an accidental outside click shouldn't discard the user's work.\n *\n * @default false\n */\n disablePointerDismissal?: boolean\n}\ntype DialogTriggerProps = React.ComponentProps<typeof DialogPrimitive.Trigger>\ntype DialogPortalProps = React.ComponentProps<typeof DialogPrimitive.Portal>\ntype DialogCloseProps = React.ComponentProps<typeof DialogPrimitive.Close>\ntype DialogOverlayProps = React.ComponentProps<typeof DialogPrimitive.Backdrop>\ntype DialogPopupProps = React.ComponentProps<typeof DialogPrimitive.Popup>\ntype DialogTitleProps = React.ComponentProps<typeof DialogPrimitive.Title>\ntype DialogDescriptionProps = React.ComponentProps<typeof DialogPrimitive.Description>\n\ntype DialogContentProps = DialogPopupProps & {\n showCloseButton?: boolean\n}\n\ntype DialogFooterProps = React.ComponentProps<\"div\"> & {\n showCloseButton?: boolean\n}\n\nfunction Dialog({ disablePointerDismissal, ...props }: DialogProps) {\n return <DialogPrimitive.Root data-slot=\"dialog\" disablePointerDismissal={disablePointerDismissal} {...props} />\n}\n\nfunction DialogTrigger({ ...props }: DialogTriggerProps) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />\n}\n\nfunction DialogPortal({ ...props }: DialogPortalProps) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />\n}\n\nfunction DialogClose({ ...props }: DialogCloseProps) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: DialogOverlayProps) {\n return (\n <DialogPrimitive.Backdrop\n data-slot=\"dialog-overlay\"\n className={cn(\n \"motion-scrim fixed inset-0 isolate z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: DialogContentProps) {\n return (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Popup\n data-slot=\"dialog-content\"\n className={cn(\n \"motion-scale-lg bg-foundation ring-contrast/10 fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg p-4 text-sm ring-1 outline-none sm:max-w-sm\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n render={\n <Button\n variant=\"ghost\"\n className=\"absolute top-2 right-2\"\n size=\"icon-sm\"\n />\n }\n >\n <CloseIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Popup>\n </DialogPortal>\n )\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: DialogFooterProps) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"bg-secondary/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-lg border-t border-line p-4 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close render={<Button variant=\"outline\" />}>\n Close\n </DialogPrimitive.Close>\n )}\n </div>\n )\n}\n\nfunction DialogTitle({ className, ...props }: DialogTitleProps) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n // pr-8 reserves room for the close button (absolute, top-2 right-2) so a\n // long title wraps before it instead of running underneath.\n className={cn(\"text-base leading-none font-medium pr-8\", className)}\n {...props}\n />\n )\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: DialogDescriptionProps) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n \"text-muted *:[a]:hover:text-contrast text-sm *:[a]:underline *:[a]:underline-offset-3\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n}\n"],"mappings":";;;;;;;;AAsCA,SAAS,OAAO,EAAE,yBAAyB,GAAG,SAAsB;AAClE,QAAO,oBAACA,SAAgB,MAAjB;EAAsB,aAAU;EAAkC;EAAyB,GAAI;EAAS,CAAA;;AAGjH,SAAS,cAAc,EAAE,GAAG,SAA6B;AACvD,QAAO,oBAACA,SAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;EAAS,CAAA;;AAG1E,SAAS,aAAa,EAAE,GAAG,SAA4B;AACrD,QAAO,oBAACA,SAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;EAAS,CAAA;;AAGxE,SAAS,YAAY,EAAE,GAAG,SAA2B;AACnD,QAAO,oBAACA,SAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;EAAS,CAAA;;AAGtE,SAAS,cAAc,EACrB,WACA,GAAG,SACkB;AACrB,QACE,oBAACA,SAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,iGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,MAClB,GAAG,SACkB;AACrB,QACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,eAAD,EAAiB,CAAA,EACjB,qBAACA,SAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GACT,iNACA,UACD;EACD,GAAI;YANN,CAQG,UACA,mBACC,qBAACA,SAAgB,OAAjB;GACE,aAAU;GACV,QACE,oBAAC,QAAD;IACE,SAAQ;IACR,WAAU;IACV,MAAK;IACL,CAAA;aAPN,CAUE,oBAAC,WAAD,EAAa,CAAA,EACb,oBAAC,QAAD;IAAM,WAAU;cAAU;IAAY,CAAA,CAChB;KAEJ;IACX,EAAA,CAAA;;AAInB,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;AAC1E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,uBAAuB,UAAU;EAC/C,GAAI;EACJ,CAAA;;AAIN,SAAS,aAAa,EACpB,WACA,kBAAkB,OAClB,UACA,GAAG,SACiB;AACpB,QACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,4HACA,UACD;EACD,GAAI;YANN,CAQG,UACA,mBACC,oBAACA,SAAgB,OAAjB;GAAuB,QAAQ,oBAAC,QAAD,EAAQ,SAAQ,WAAY,CAAA;aAAE;GAErC,CAAA,CAEtB;;;AAIV,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAACA,SAAgB,OAAjB;EACE,aAAU;EAGV,WAAW,GAAG,2CAA2C,UAAU;EACnE,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EACzB,WACA,GAAG,SACsB;AACzB,QACE,oBAACA,SAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GACT,yFACA,UACD;EACD,GAAI;EACJ,CAAA"}
package/dist/drawer.js CHANGED
@@ -43,7 +43,7 @@ function DrawerContent({ className, children, showCloseButton = false, ...props
43
43
  className: "fixed inset-0 z-50 outline-none",
44
44
  children: /* @__PURE__ */ jsxs(Drawer$1.Popup, {
45
45
  "data-slot": "drawer-content",
46
- className: cn("group/drawer-content bg-foundation fixed z-50 flex flex-col overflow-y-auto text-sm shadow-lg outline-none", "transition-[translate] duration-(--duration-lg) ease-(--ease) data-[swiping]:duration-0", "data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:mt-24 data-[swipe-direction=down]:max-h-[80vh] data-[swipe-direction=down]:rounded-t-lg data-[swipe-direction=down]:border-t", "data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:mb-24 data-[swipe-direction=up]:max-h-[80vh] data-[swipe-direction=up]:rounded-b-lg data-[swipe-direction=up]:border-b", "data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:w-3/4 data-[swipe-direction=left]:rounded-r-lg data-[swipe-direction=left]:border-r data-[swipe-direction=left]:sm:max-w-sm", "data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:w-3/4 data-[swipe-direction=right]:rounded-l-lg data-[swipe-direction=right]:border-l data-[swipe-direction=right]:sm:max-w-sm", "data-[swipe-direction=down]:data-[starting-style]:translate-y-full data-[swipe-direction=down]:data-[ending-style]:translate-y-full", "data-[swipe-direction=up]:data-[starting-style]:-translate-y-full data-[swipe-direction=up]:data-[ending-style]:-translate-y-full", "data-[swipe-direction=left]:data-[starting-style]:-translate-x-full data-[swipe-direction=left]:data-[ending-style]:-translate-x-full", "data-[swipe-direction=right]:data-[starting-style]:translate-x-full data-[swipe-direction=right]:data-[ending-style]:translate-x-full", className),
46
+ className: cn("group/drawer-content bg-foundation fixed z-50 flex flex-col overflow-y-auto border-edge text-sm shadow-lg outline-none", "transition-[translate] duration-(--duration-lg) ease-(--ease) data-[swiping]:duration-0", "data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:mt-24 data-[swipe-direction=down]:max-h-[80vh] data-[swipe-direction=down]:rounded-t-lg data-[swipe-direction=down]:border-t", "data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:mb-24 data-[swipe-direction=up]:max-h-[80vh] data-[swipe-direction=up]:rounded-b-lg data-[swipe-direction=up]:border-b", "data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:w-3/4 data-[swipe-direction=left]:rounded-r-lg data-[swipe-direction=left]:border-r data-[swipe-direction=left]:sm:max-w-sm", "data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:w-3/4 data-[swipe-direction=right]:rounded-l-lg data-[swipe-direction=right]:border-l data-[swipe-direction=right]:sm:max-w-sm", "data-[swipe-direction=down]:data-[starting-style]:translate-y-full data-[swipe-direction=down]:data-[ending-style]:translate-y-full", "data-[swipe-direction=up]:data-[starting-style]:-translate-y-full data-[swipe-direction=up]:data-[ending-style]:-translate-y-full", "data-[swipe-direction=left]:data-[starting-style]:-translate-x-full data-[swipe-direction=left]:data-[ending-style]:-translate-x-full", "data-[swipe-direction=right]:data-[starting-style]:translate-x-full data-[swipe-direction=right]:data-[ending-style]:translate-x-full", className),
47
47
  ...props,
48
48
  children: [
49
49
  /* @__PURE__ */ jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.js","names":["DrawerPrimitive"],"sources":["../src/drawer.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"@base-ui/react/drawer\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { CloseIcon } from \"./lib/internal-icons\"\n\ntype DrawerProps = React.ComponentProps<typeof DrawerPrimitive.Root>\ntype DrawerTriggerProps = React.ComponentProps<typeof DrawerPrimitive.Trigger>\ntype DrawerPortalProps = React.ComponentProps<typeof DrawerPrimitive.Portal>\ntype DrawerCloseProps = React.ComponentProps<typeof DrawerPrimitive.Close>\ntype DrawerOverlayProps = React.ComponentProps<typeof DrawerPrimitive.Backdrop>\ntype DrawerPopupProps = React.ComponentProps<typeof DrawerPrimitive.Popup>\ntype DrawerTitleProps = React.ComponentProps<typeof DrawerPrimitive.Title>\ntype DrawerDescriptionProps = React.ComponentProps<typeof DrawerPrimitive.Description>\ntype DrawerHeaderProps = React.ComponentProps<\"div\">\ntype DrawerFooterProps = React.ComponentProps<\"div\">\n\ntype DrawerContentProps = DrawerPopupProps & {\n showCloseButton?: boolean\n}\n\nfunction Drawer({ ...props }: DrawerProps) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({ ...props }: DrawerTriggerProps) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({ ...props }: DrawerPortalProps) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({ ...props }: DrawerCloseProps) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({ className, ...props }: DrawerOverlayProps) {\n return (\n <DrawerPrimitive.Backdrop\n data-slot=\"drawer-overlay\"\n className={cn(\n \"motion-scrim fixed inset-0 z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n showCloseButton = false,\n ...props\n}: DrawerContentProps) {\n return (\n <DrawerPortal>\n <DrawerOverlay />\n <DrawerPrimitive.Viewport\n data-slot=\"drawer-viewport\"\n className=\"fixed inset-0 z-50 outline-none\"\n >\n <DrawerPrimitive.Popup\n data-slot=\"drawer-content\"\n className={cn(\n // Base layout & appearance\n \"group/drawer-content bg-foundation fixed z-50 flex flex-col overflow-y-auto text-sm shadow-lg outline-none\",\n // Transition — animate translate at the lg tier + the one curve; disable during swipe\n \"transition-[translate] duration-(--duration-lg) ease-(--ease) data-[swiping]:duration-0\",\n // Bottom drawer (swipeDirection=\"down\")\n \"data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:mt-24 data-[swipe-direction=down]:max-h-[80vh] data-[swipe-direction=down]:rounded-t-lg data-[swipe-direction=down]:border-t\",\n // Top drawer (swipeDirection=\"up\")\n \"data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:mb-24 data-[swipe-direction=up]:max-h-[80vh] data-[swipe-direction=up]:rounded-b-lg data-[swipe-direction=up]:border-b\",\n // Left drawer (swipeDirection=\"left\")\n \"data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:w-3/4 data-[swipe-direction=left]:rounded-r-lg data-[swipe-direction=left]:border-r data-[swipe-direction=left]:sm:max-w-sm\",\n // Right drawer (swipeDirection=\"right\")\n \"data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:w-3/4 data-[swipe-direction=right]:rounded-l-lg data-[swipe-direction=right]:border-l data-[swipe-direction=right]:sm:max-w-sm\",\n // Enter/exit slide — bottom\n \"data-[swipe-direction=down]:data-[starting-style]:translate-y-full data-[swipe-direction=down]:data-[ending-style]:translate-y-full\",\n // Enter/exit slide — top\n \"data-[swipe-direction=up]:data-[starting-style]:-translate-y-full data-[swipe-direction=up]:data-[ending-style]:-translate-y-full\",\n // Enter/exit slide — left\n \"data-[swipe-direction=left]:data-[starting-style]:-translate-x-full data-[swipe-direction=left]:data-[ending-style]:-translate-x-full\",\n // Enter/exit slide — right\n \"data-[swipe-direction=right]:data-[starting-style]:translate-x-full data-[swipe-direction=right]:data-[ending-style]:translate-x-full\",\n className,\n )}\n {...props}\n >\n {/* Drag handle — visible only for bottom drawers */}\n <div\n data-slot=\"drawer-drag-handle\"\n className=\"bg-secondary mx-auto mt-4 hidden h-1 w-[100px] shrink-0 rounded-full group-data-[swipe-direction=down]/drawer-content:block\"\n />\n {children}\n {showCloseButton && (\n <DrawerPrimitive.Close\n data-slot=\"drawer-close\"\n render={\n <Button\n variant=\"ghost\"\n className=\"absolute top-2 right-2\"\n size=\"icon-sm\"\n />\n }\n >\n <CloseIcon />\n <span className=\"sr-only\">Close</span>\n </DrawerPrimitive.Close>\n )}\n </DrawerPrimitive.Popup>\n </DrawerPrimitive.Viewport>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: DrawerHeaderProps) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\n \"flex flex-col gap-0.5 p-4 group-data-[swipe-direction=down]/drawer-content:text-center group-data-[swipe-direction=up]/drawer-content:text-center md:text-left\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: DrawerFooterProps) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({ className, ...props }: DrawerTitleProps) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-contrast text-base font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: DrawerDescriptionProps) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n"],"mappings":";;;;;;;;AAwBA,SAAS,OAAO,EAAE,GAAG,SAAsB;AACzC,QAAO,oBAACA,SAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;EAAS,CAAA;;AAG/D,SAAS,cAAc,EAAE,GAAG,SAA6B;AACvD,QAAO,oBAACA,SAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;EAAS,CAAA;;AAG1E,SAAS,aAAa,EAAE,GAAG,SAA4B;AACrD,QAAO,oBAACA,SAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;EAAS,CAAA;;AAGxE,SAAS,YAAY,EAAE,GAAG,SAA2B;AACnD,QAAO,oBAACA,SAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;EAAS,CAAA;;AAGtE,SAAS,cAAc,EAAE,WAAW,GAAG,SAA6B;AAClE,QACE,oBAACA,SAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,yFACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,OAClB,GAAG,SACkB;AACrB,QACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,eAAD,EAAiB,CAAA,EACjB,oBAACA,SAAgB,UAAjB;EACE,aAAU;EACV,WAAU;YAEV,qBAACA,SAAgB,OAAjB;GACE,aAAU;GACV,WAAW,GAET,8GAEA,2FAEA,uOAEA,wNAEA,oOAEA,2OAEA,uIAEA,qIAEA,yIAEA,yIACA,UACD;GACD,GAAI;aAzBN;IA4BE,oBAAC,OAAD;KACE,aAAU;KACV,WAAU;KACV,CAAA;IACD;IACA,mBACC,qBAACA,SAAgB,OAAjB;KACE,aAAU;KACV,QACE,oBAAC,QAAD;MACE,SAAQ;MACR,WAAU;MACV,MAAK;MACL,CAAA;eAPN,CAUE,oBAAC,WAAD,EAAa,CAAA,EACb,oBAAC,QAAD;MAAM,WAAU;gBAAU;MAAY,CAAA,CAChB;;IAEJ;;EACC,CAAA,CACd,EAAA,CAAA;;AAInB,SAAS,aAAa,EAAE,WAAW,GAAG,SAA4B;AAChE,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,kKACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,aAAa,EAAE,WAAW,GAAG,SAA4B;AAChE,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,mCAAmC,UAAU;EAC3D,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAACA,SAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GAAG,uCAAuC,UAAU;EAC/D,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EACzB,WACA,GAAG,SACsB;AACzB,QACE,oBAACA,SAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GAAG,sBAAsB,UAAU;EAC9C,GAAI;EACJ,CAAA"}
1
+ {"version":3,"file":"drawer.js","names":["DrawerPrimitive"],"sources":["../src/drawer.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"@base-ui/react/drawer\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { CloseIcon } from \"./lib/internal-icons\"\n\ntype DrawerProps = React.ComponentProps<typeof DrawerPrimitive.Root>\ntype DrawerTriggerProps = React.ComponentProps<typeof DrawerPrimitive.Trigger>\ntype DrawerPortalProps = React.ComponentProps<typeof DrawerPrimitive.Portal>\ntype DrawerCloseProps = React.ComponentProps<typeof DrawerPrimitive.Close>\ntype DrawerOverlayProps = React.ComponentProps<typeof DrawerPrimitive.Backdrop>\ntype DrawerPopupProps = React.ComponentProps<typeof DrawerPrimitive.Popup>\ntype DrawerTitleProps = React.ComponentProps<typeof DrawerPrimitive.Title>\ntype DrawerDescriptionProps = React.ComponentProps<typeof DrawerPrimitive.Description>\ntype DrawerHeaderProps = React.ComponentProps<\"div\">\ntype DrawerFooterProps = React.ComponentProps<\"div\">\n\ntype DrawerContentProps = DrawerPopupProps & {\n showCloseButton?: boolean\n}\n\nfunction Drawer({ ...props }: DrawerProps) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({ ...props }: DrawerTriggerProps) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({ ...props }: DrawerPortalProps) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({ ...props }: DrawerCloseProps) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({ className, ...props }: DrawerOverlayProps) {\n return (\n <DrawerPrimitive.Backdrop\n data-slot=\"drawer-overlay\"\n className={cn(\n \"motion-scrim fixed inset-0 z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n showCloseButton = false,\n ...props\n}: DrawerContentProps) {\n return (\n <DrawerPortal>\n <DrawerOverlay />\n <DrawerPrimitive.Viewport\n data-slot=\"drawer-viewport\"\n className=\"fixed inset-0 z-50 outline-none\"\n >\n <DrawerPrimitive.Popup\n data-slot=\"drawer-content\"\n className={cn(\n // Base layout & appearance\n \"group/drawer-content bg-foundation fixed z-50 flex flex-col overflow-y-auto border-edge text-sm shadow-lg outline-none\",\n // Transition — animate translate at the lg tier + the one curve; disable during swipe\n \"transition-[translate] duration-(--duration-lg) ease-(--ease) data-[swiping]:duration-0\",\n // Bottom drawer (swipeDirection=\"down\")\n \"data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:mt-24 data-[swipe-direction=down]:max-h-[80vh] data-[swipe-direction=down]:rounded-t-lg data-[swipe-direction=down]:border-t\",\n // Top drawer (swipeDirection=\"up\")\n \"data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:mb-24 data-[swipe-direction=up]:max-h-[80vh] data-[swipe-direction=up]:rounded-b-lg data-[swipe-direction=up]:border-b\",\n // Left drawer (swipeDirection=\"left\")\n \"data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:w-3/4 data-[swipe-direction=left]:rounded-r-lg data-[swipe-direction=left]:border-r data-[swipe-direction=left]:sm:max-w-sm\",\n // Right drawer (swipeDirection=\"right\")\n \"data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:w-3/4 data-[swipe-direction=right]:rounded-l-lg data-[swipe-direction=right]:border-l data-[swipe-direction=right]:sm:max-w-sm\",\n // Enter/exit slide — bottom\n \"data-[swipe-direction=down]:data-[starting-style]:translate-y-full data-[swipe-direction=down]:data-[ending-style]:translate-y-full\",\n // Enter/exit slide — top\n \"data-[swipe-direction=up]:data-[starting-style]:-translate-y-full data-[swipe-direction=up]:data-[ending-style]:-translate-y-full\",\n // Enter/exit slide — left\n \"data-[swipe-direction=left]:data-[starting-style]:-translate-x-full data-[swipe-direction=left]:data-[ending-style]:-translate-x-full\",\n // Enter/exit slide — right\n \"data-[swipe-direction=right]:data-[starting-style]:translate-x-full data-[swipe-direction=right]:data-[ending-style]:translate-x-full\",\n className,\n )}\n {...props}\n >\n {/* Drag handle — visible only for bottom drawers */}\n <div\n data-slot=\"drawer-drag-handle\"\n className=\"bg-secondary mx-auto mt-4 hidden h-1 w-[100px] shrink-0 rounded-full group-data-[swipe-direction=down]/drawer-content:block\"\n />\n {children}\n {showCloseButton && (\n <DrawerPrimitive.Close\n data-slot=\"drawer-close\"\n render={\n <Button\n variant=\"ghost\"\n className=\"absolute top-2 right-2\"\n size=\"icon-sm\"\n />\n }\n >\n <CloseIcon />\n <span className=\"sr-only\">Close</span>\n </DrawerPrimitive.Close>\n )}\n </DrawerPrimitive.Popup>\n </DrawerPrimitive.Viewport>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: DrawerHeaderProps) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\n \"flex flex-col gap-0.5 p-4 group-data-[swipe-direction=down]/drawer-content:text-center group-data-[swipe-direction=up]/drawer-content:text-center md:text-left\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: DrawerFooterProps) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({ className, ...props }: DrawerTitleProps) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-contrast text-base font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: DrawerDescriptionProps) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n"],"mappings":";;;;;;;;AAwBA,SAAS,OAAO,EAAE,GAAG,SAAsB;AACzC,QAAO,oBAACA,SAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;EAAS,CAAA;;AAG/D,SAAS,cAAc,EAAE,GAAG,SAA6B;AACvD,QAAO,oBAACA,SAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;EAAS,CAAA;;AAG1E,SAAS,aAAa,EAAE,GAAG,SAA4B;AACrD,QAAO,oBAACA,SAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;EAAS,CAAA;;AAGxE,SAAS,YAAY,EAAE,GAAG,SAA2B;AACnD,QAAO,oBAACA,SAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;EAAS,CAAA;;AAGtE,SAAS,cAAc,EAAE,WAAW,GAAG,SAA6B;AAClE,QACE,oBAACA,SAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,yFACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,OAClB,GAAG,SACkB;AACrB,QACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,eAAD,EAAiB,CAAA,EACjB,oBAACA,SAAgB,UAAjB;EACE,aAAU;EACV,WAAU;YAEV,qBAACA,SAAgB,OAAjB;GACE,aAAU;GACV,WAAW,GAET,0HAEA,2FAEA,uOAEA,wNAEA,oOAEA,2OAEA,uIAEA,qIAEA,yIAEA,yIACA,UACD;GACD,GAAI;aAzBN;IA4BE,oBAAC,OAAD;KACE,aAAU;KACV,WAAU;KACV,CAAA;IACD;IACA,mBACC,qBAACA,SAAgB,OAAjB;KACE,aAAU;KACV,QACE,oBAAC,QAAD;MACE,SAAQ;MACR,WAAU;MACV,MAAK;MACL,CAAA;eAPN,CAUE,oBAAC,WAAD,EAAa,CAAA,EACb,oBAAC,QAAD;MAAM,WAAU;gBAAU;MAAY,CAAA,CAChB;;IAEJ;;EACC,CAAA,CACd,EAAA,CAAA;;AAInB,SAAS,aAAa,EAAE,WAAW,GAAG,SAA4B;AAChE,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,kKACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,aAAa,EAAE,WAAW,GAAG,SAA4B;AAChE,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,mCAAmC,UAAU;EAC3D,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAACA,SAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GAAG,uCAAuC,UAAU;EAC/D,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EACzB,WACA,GAAG,SACsB;AACzB,QACE,oBAACA,SAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GAAG,sBAAsB,UAAU;EAC9C,GAAI;EACJ,CAAA"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "./lib/utils.js";
3
3
  import * as React from "react";
4
- import { jsx } from "react/jsx-runtime";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
5
  //#region src/encrypted-text.tsx
6
6
  const DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[];:,.<>/?";
7
7
  function randomChar(charset) {
@@ -85,22 +85,25 @@ function EncryptedText({ text, className, revealDelayMs = 50, charset = DEFAULT_
85
85
  scrambleOneChar
86
86
  ]);
87
87
  if (!text) return null;
88
- return /* @__PURE__ */ jsx("span", {
88
+ return /* @__PURE__ */ jsxs("span", {
89
89
  ref,
90
90
  "data-slot": "encrypted-text",
91
91
  className,
92
- "aria-label": text,
93
92
  ...props,
94
- children: text.split("").map((char, index) => {
93
+ children: [/* @__PURE__ */ jsx("span", {
94
+ className: "sr-only",
95
+ children: text
96
+ }), text.split("").map((char, index) => {
95
97
  const isRevealed = !scrambleOnly && index < revealCount;
96
98
  const displayChar = isRevealed ? char : char === " " ? " " : scrambleCharsRef.current[index] ?? randomChar(charset);
97
99
  return /* @__PURE__ */ jsx("span", {
100
+ "aria-hidden": "true",
98
101
  "data-slot": "encrypted-text-char",
99
102
  "data-revealed": isRevealed || void 0,
100
103
  className: cn(isRevealed ? revealedClassName : encryptedClassName),
101
104
  children: displayChar
102
105
  }, index);
103
- })
106
+ })]
104
107
  });
105
108
  }
106
109
  //#endregion
@@ -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 aria-label={text}\n {...props}\n >\n {text.split(\"\").map((char, index) => {\n const isRevealed = !scrambleOnly && index < revealCount\n const displayChar = isRevealed\n ? char\n : char === \" \"\n ? \" \"\n : (scrambleCharsRef.current[index] ?? randomChar(charset))\n\n return (\n <span\n key={index}\n data-slot=\"encrypted-text-char\"\n data-revealed={isRevealed || undefined}\n className={cn(isRevealed ? revealedClassName : encryptedClassName)}\n >\n {displayChar}\n </span>\n )\n })}\n </span>\n )\n}\n\nexport { EncryptedText }\n"],"mappings":"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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\"\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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"}
@@ -152,7 +152,8 @@ function GradientRevealText({ text, duration = 0, colors = DEFAULT_COLORS, baseO
152
152
  onMouseMove: updatePos,
153
153
  className: cn("select-none", className),
154
154
  style: { opacity: measured ? 1 : 0 },
155
- "aria-hidden": true,
155
+ role: "img",
156
+ "aria-label": text,
156
157
  children: [
157
158
  /* @__PURE__ */ jsxs("defs", { children: [
158
159
  /* @__PURE__ */ jsx("linearGradient", {
@@ -1 +1 @@
1
- {"version":3,"file":"gradient-reveal-text.js","names":[],"sources":["../src/gradient-reveal-text.tsx"],"sourcesContent":["\"use client\"\n\nimport { useRef, useEffect, useState, useId, useCallback } from \"react\"\nimport { cn } from \"./lib/utils\"\n\ninterface GradientRevealTextProps {\n /** The text to display */\n text: string\n /** Spotlight follow speed in seconds. Default: 0 (instant) */\n duration?: number\n /** Gradient colors for the reveal effect. Default: rainbow */\n colors?: string[]\n /** Base stroke opacity when not hovered. Default: 0.3 */\n baseOpacity?: number\n /** Hovered stroke opacity. Default: 0.7 */\n hoverOpacity?: number\n /** Font family for SVG text. Default: Helvetica Neue */\n fontFamily?: string\n /** Spotlight radius multiplier relative to text height. Default: 0.6 */\n spotlightSize?: number\n /** Stroke width in px. Default: auto (1.5% of text height) */\n strokeWidth?: number\n /** Base stroke color. Default: neutral-200 (light) / neutral-800 (dark) via Tailwind */\n baseColor?: string\n className?: string\n}\n\nconst DEFAULT_COLORS = [\n \"#eab308\",\n \"#ef4444\",\n \"#3b82f6\",\n \"#06b6d4\",\n \"#8b5cf6\",\n]\n\n/**\n * Large decorative text with a gradient spotlight that follows the cursor.\n *\n * Renders as an SVG that auto-sizes to fit the text with zero padding.\n * The gradient reveal effect activates on hover — a circular spotlight\n * follows the mouse, revealing rainbow-colored strokes beneath.\n *\n * @example\n * ```tsx\n * <GradientRevealText text=\"HELLO\" />\n * <GradientRevealText text=\"BRAND\" colors={[\"#ff0000\", \"#00ff00\"]} />\n * ```\n */\nfunction GradientRevealText({\n text,\n duration = 0,\n colors = DEFAULT_COLORS,\n baseOpacity = 0.3,\n hoverOpacity = 0.7,\n fontFamily = \"Helvetica Neue, Helvetica, Arial, sans-serif\",\n spotlightSize = 0.6,\n strokeWidth: strokeWidthPx,\n baseColor,\n className,\n}: GradientRevealTextProps) {\n const uid = useId()\n const svgRef = useRef<SVGSVGElement>(null)\n const textRef = useRef<SVGTextElement>(null)\n const gradientRef = useRef<SVGRadialGradientElement>(null)\n\n const [vb, setVb] = useState({ x: 0, y: 0, w: 100, h: 20 })\n const [measured, setMeasured] = useState(false)\n const [hovered, setHovered] = useState(false)\n\n // Target position (where cursor is) and current animated position\n const targetPos = useRef({ cx: 0.5, cy: 0.5 })\n const currentPos = useRef({ cx: 0.5, cy: 0.5 })\n const rafId = useRef<number>(0)\n\n // Measure text bbox → set viewBox to fit exactly\n const measure = useCallback(() => {\n const el = textRef.current\n if (!el) return\n const bbox = el.getBBox()\n if (bbox.width === 0) return\n\n setVb({ x: bbox.x, y: bbox.y, w: bbox.width, h: bbox.height })\n setMeasured(true)\n }, [])\n\n useEffect(() => {\n measure()\n document.fonts?.ready?.then(measure)\n }, [text, measure])\n\n // Update the SVG gradient attributes directly (no React re-render)\n const applyGradientPos = useCallback((cx: number, cy: number) => {\n const el = gradientRef.current\n if (!el) return\n const svgCx = vb.x + cx * vb.w\n const svgCy = vb.y + cy * vb.h\n el.setAttribute(\"cx\", String(svgCx))\n el.setAttribute(\"cy\", String(svgCy))\n }, [vb])\n\n // RAF loop for smooth follow\n useEffect(() => {\n if (duration <= 0) return\n\n // Lerp factor: higher = faster catch-up. Derived from duration.\n const speed = 1 - Math.pow(0.001, 1 / (duration * 60))\n\n const tick = () => {\n const cur = currentPos.current\n const tgt = targetPos.current\n cur.cx += (tgt.cx - cur.cx) * speed\n cur.cy += (tgt.cy - cur.cy) * speed\n applyGradientPos(cur.cx, cur.cy)\n rafId.current = requestAnimationFrame(tick)\n }\n\n rafId.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId.current)\n }, [duration, applyGradientPos])\n\n const updatePos = (e: React.MouseEvent<SVGSVGElement>) => {\n const svg = svgRef.current\n if (!svg) return\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n\n // If no smooth follow, apply instantly\n if (duration <= 0) {\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n }\n\n const handleMouseEnter = (e: React.MouseEvent<SVGSVGElement>) => {\n // Snap to entry point — no lerp on first frame\n const svg = svgRef.current\n if (svg) {\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n setHovered(true)\n }\n\n // Derived values\n const spotlightR = vb.h * spotlightSize\n const strokeW = strokeWidthPx ?? vb.h * 0.015\n const initCx = vb.x + 0.5 * vb.w\n const initCy = vb.y + 0.5 * vb.h\n\n // Unique SVG IDs\n const gradientId = `grad-${uid}`\n const maskId = `mask-${uid}`\n const revealId = `reveal-${uid}`\n\n // Evenly distribute color stops\n const stops = colors.map((color, i) => ({\n offset: `${(i / Math.max(colors.length - 1, 1)) * 100}%`,\n color,\n }))\n\n const textStyle = {\n fontSize: \"1em\",\n fontFamily,\n fill: \"none\",\n strokeWidth: strokeW,\n strokeLinejoin: \"round\" as const,\n strokeLinecap: \"round\" as const,\n paintOrder: \"stroke fill\" as const,\n }\n\n return (\n <svg\n ref={svgRef}\n data-slot=\"gradient-reveal-text\"\n width=\"100%\"\n viewBox={`${vb.x} ${vb.y} ${vb.w} ${vb.h}`}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={() => setHovered(false)}\n onMouseMove={updatePos}\n className={cn(\"select-none\", className)}\n style={{ opacity: measured ? 1 : 0 }}\n aria-hidden\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n {hovered &&\n stops.map((s) => (\n <stop key={s.offset} offset={s.offset} stopColor={s.color} />\n ))}\n </linearGradient>\n\n <radialGradient\n ref={gradientRef}\n id={revealId}\n gradientUnits=\"userSpaceOnUse\"\n r={spotlightR}\n cx={initCx}\n cy={initCy}\n >\n <stop offset=\"0%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </radialGradient>\n\n <mask id={maskId}>\n <rect\n x={vb.x - vb.w}\n y={vb.y - vb.h}\n width={vb.w * 3}\n height={vb.h * 3}\n fill={`url(#${revealId})`}\n />\n </mask>\n </defs>\n\n {/* Hidden text for measurement */}\n <text\n ref={textRef}\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold\"\n style={{ fontSize: \"1em\", fontFamily, visibility: \"hidden\" }}\n >\n {text}\n </text>\n\n {/* Base stroke — subtle outline */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className={baseColor ? \"font-bold\" : \"font-bold stroke-neutral-200 dark:stroke-neutral-800\"}\n style={{\n ...textStyle,\n ...(baseColor ? { stroke: baseColor } : {}),\n opacity: hovered ? hoverOpacity : baseOpacity,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {text}\n </text>\n\n {/* Gradient reveal on hover */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n mask={`url(#${maskId})`}\n className=\"font-bold\"\n style={{\n ...textStyle,\n stroke: `url(#${gradientId})`,\n }}\n >\n {text}\n </text>\n </svg>\n )\n}\n\nexport { GradientRevealText }\nexport type { GradientRevealTextProps }\n"],"mappings":"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"}
1
+ {"version":3,"file":"gradient-reveal-text.js","names":[],"sources":["../src/gradient-reveal-text.tsx"],"sourcesContent":["\"use client\"\n\nimport { useRef, useEffect, useState, useId, useCallback } from \"react\"\nimport { cn } from \"./lib/utils\"\n\ninterface GradientRevealTextProps {\n /** The text to display */\n text: string\n /** Spotlight follow speed in seconds. Default: 0 (instant) */\n duration?: number\n /** Gradient colors for the reveal effect. Default: rainbow */\n colors?: string[]\n /** Base stroke opacity when not hovered. Default: 0.3 */\n baseOpacity?: number\n /** Hovered stroke opacity. Default: 0.7 */\n hoverOpacity?: number\n /** Font family for SVG text. Default: Helvetica Neue */\n fontFamily?: string\n /** Spotlight radius multiplier relative to text height. Default: 0.6 */\n spotlightSize?: number\n /** Stroke width in px. Default: auto (1.5% of text height) */\n strokeWidth?: number\n /** Base stroke color. Default: neutral-200 (light) / neutral-800 (dark) via Tailwind */\n baseColor?: string\n className?: string\n}\n\nconst DEFAULT_COLORS = [\n \"#eab308\",\n \"#ef4444\",\n \"#3b82f6\",\n \"#06b6d4\",\n \"#8b5cf6\",\n]\n\n/**\n * Large decorative text with a gradient spotlight that follows the cursor.\n *\n * Renders as an SVG that auto-sizes to fit the text with zero padding.\n * The gradient reveal effect activates on hover — a circular spotlight\n * follows the mouse, revealing rainbow-colored strokes beneath.\n *\n * @example\n * ```tsx\n * <GradientRevealText text=\"HELLO\" />\n * <GradientRevealText text=\"BRAND\" colors={[\"#ff0000\", \"#00ff00\"]} />\n * ```\n */\nfunction GradientRevealText({\n text,\n duration = 0,\n colors = DEFAULT_COLORS,\n baseOpacity = 0.3,\n hoverOpacity = 0.7,\n fontFamily = \"Helvetica Neue, Helvetica, Arial, sans-serif\",\n spotlightSize = 0.6,\n strokeWidth: strokeWidthPx,\n baseColor,\n className,\n}: GradientRevealTextProps) {\n const uid = useId()\n const svgRef = useRef<SVGSVGElement>(null)\n const textRef = useRef<SVGTextElement>(null)\n const gradientRef = useRef<SVGRadialGradientElement>(null)\n\n const [vb, setVb] = useState({ x: 0, y: 0, w: 100, h: 20 })\n const [measured, setMeasured] = useState(false)\n const [hovered, setHovered] = useState(false)\n\n // Target position (where cursor is) and current animated position\n const targetPos = useRef({ cx: 0.5, cy: 0.5 })\n const currentPos = useRef({ cx: 0.5, cy: 0.5 })\n const rafId = useRef<number>(0)\n\n // Measure text bbox → set viewBox to fit exactly\n const measure = useCallback(() => {\n const el = textRef.current\n if (!el) return\n const bbox = el.getBBox()\n if (bbox.width === 0) return\n\n setVb({ x: bbox.x, y: bbox.y, w: bbox.width, h: bbox.height })\n setMeasured(true)\n }, [])\n\n useEffect(() => {\n measure()\n document.fonts?.ready?.then(measure)\n }, [text, measure])\n\n // Update the SVG gradient attributes directly (no React re-render)\n const applyGradientPos = useCallback((cx: number, cy: number) => {\n const el = gradientRef.current\n if (!el) return\n const svgCx = vb.x + cx * vb.w\n const svgCy = vb.y + cy * vb.h\n el.setAttribute(\"cx\", String(svgCx))\n el.setAttribute(\"cy\", String(svgCy))\n }, [vb])\n\n // RAF loop for smooth follow\n useEffect(() => {\n if (duration <= 0) return\n\n // Lerp factor: higher = faster catch-up. Derived from duration.\n const speed = 1 - Math.pow(0.001, 1 / (duration * 60))\n\n const tick = () => {\n const cur = currentPos.current\n const tgt = targetPos.current\n cur.cx += (tgt.cx - cur.cx) * speed\n cur.cy += (tgt.cy - cur.cy) * speed\n applyGradientPos(cur.cx, cur.cy)\n rafId.current = requestAnimationFrame(tick)\n }\n\n rafId.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId.current)\n }, [duration, applyGradientPos])\n\n const updatePos = (e: React.MouseEvent<SVGSVGElement>) => {\n const svg = svgRef.current\n if (!svg) return\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n\n // If no smooth follow, apply instantly\n if (duration <= 0) {\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n }\n\n const handleMouseEnter = (e: React.MouseEvent<SVGSVGElement>) => {\n // Snap to entry point — no lerp on first frame\n const svg = svgRef.current\n if (svg) {\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n setHovered(true)\n }\n\n // Derived values\n const spotlightR = vb.h * spotlightSize\n const strokeW = strokeWidthPx ?? vb.h * 0.015\n const initCx = vb.x + 0.5 * vb.w\n const initCy = vb.y + 0.5 * vb.h\n\n // Unique SVG IDs\n const gradientId = `grad-${uid}`\n const maskId = `mask-${uid}`\n const revealId = `reveal-${uid}`\n\n // Evenly distribute color stops\n const stops = colors.map((color, i) => ({\n offset: `${(i / Math.max(colors.length - 1, 1)) * 100}%`,\n color,\n }))\n\n const textStyle = {\n fontSize: \"1em\",\n fontFamily,\n fill: \"none\",\n strokeWidth: strokeW,\n strokeLinejoin: \"round\" as const,\n strokeLinecap: \"round\" as const,\n paintOrder: \"stroke fill\" as const,\n }\n\n return (\n <svg\n ref={svgRef}\n data-slot=\"gradient-reveal-text\"\n width=\"100%\"\n viewBox={`${vb.x} ${vb.y} ${vb.w} ${vb.h}`}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={() => setHovered(false)}\n onMouseMove={updatePos}\n className={cn(\"select-none\", className)}\n style={{ opacity: measured ? 1 : 0 }}\n role=\"img\"\n aria-label={text}\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n {hovered &&\n stops.map((s) => (\n <stop key={s.offset} offset={s.offset} stopColor={s.color} />\n ))}\n </linearGradient>\n\n <radialGradient\n ref={gradientRef}\n id={revealId}\n gradientUnits=\"userSpaceOnUse\"\n r={spotlightR}\n cx={initCx}\n cy={initCy}\n >\n <stop offset=\"0%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </radialGradient>\n\n <mask id={maskId}>\n <rect\n x={vb.x - vb.w}\n y={vb.y - vb.h}\n width={vb.w * 3}\n height={vb.h * 3}\n fill={`url(#${revealId})`}\n />\n </mask>\n </defs>\n\n {/* Hidden text for measurement */}\n <text\n ref={textRef}\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold\"\n style={{ fontSize: \"1em\", fontFamily, visibility: \"hidden\" }}\n >\n {text}\n </text>\n\n {/* Base stroke — subtle outline */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className={baseColor ? \"font-bold\" : \"font-bold stroke-neutral-200 dark:stroke-neutral-800\"}\n style={{\n ...textStyle,\n ...(baseColor ? { stroke: baseColor } : {}),\n opacity: hovered ? hoverOpacity : baseOpacity,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {text}\n </text>\n\n {/* Gradient reveal on hover */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n mask={`url(#${maskId})`}\n className=\"font-bold\"\n style={{\n ...textStyle,\n stroke: `url(#${gradientId})`,\n }}\n >\n {text}\n </text>\n </svg>\n )\n}\n\nexport { GradientRevealText }\nexport type { GradientRevealTextProps }\n"],"mappings":"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"}
@@ -6,23 +6,16 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/infinite-scroll.tsx
7
7
  function InfiniteScroll({ onLoadMore, hasMore, isLoading = false, direction = "down", root, rootMargin = "200px", threshold = 0, loader, endMessage, className, children }) {
8
8
  const sentinelRef = React.useRef(null);
9
- const loadingRef = React.useRef(false);
10
9
  const onLoadMoreRef = React.useRef(onLoadMore);
11
10
  React.useEffect(() => {
12
11
  onLoadMoreRef.current = onLoadMore;
13
12
  }, [onLoadMore]);
14
- React.useEffect(() => {
15
- if (!isLoading) loadingRef.current = false;
16
- }, [isLoading]);
17
13
  React.useEffect(() => {
18
14
  const sentinel = sentinelRef.current;
19
- if (!sentinel || !hasMore) return;
15
+ if (!sentinel || !hasMore || isLoading) return;
20
16
  const observer = new IntersectionObserver((entries) => {
21
17
  const [entry] = entries;
22
- if (entry?.isIntersecting && !loadingRef.current) {
23
- loadingRef.current = true;
24
- onLoadMoreRef.current();
25
- }
18
+ if (entry?.isIntersecting) onLoadMoreRef.current();
26
19
  }, {
27
20
  root: root?.current ?? null,
28
21
  rootMargin,
@@ -34,6 +27,7 @@ function InfiniteScroll({ onLoadMore, hasMore, isLoading = false, direction = "d
34
27
  };
35
28
  }, [
36
29
  hasMore,
30
+ isLoading,
37
31
  root,
38
32
  rootMargin,
39
33
  threshold
@@ -1 +1 @@
1
- {"version":3,"file":"infinite-scroll.js","names":[],"sources":["../src/infinite-scroll.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\nimport { Spinner } from \"./spinner\"\n\ntype InfiniteScrollProps = {\n onLoadMore: () => void\n hasMore: boolean\n isLoading?: boolean\n direction?: \"down\" | \"up\"\n root?: React.RefObject<Element | null>\n rootMargin?: string\n threshold?: number\n loader?: React.ReactNode\n endMessage?: React.ReactNode\n className?: string\n children?: React.ReactNode\n}\n\nfunction InfiniteScroll({\n onLoadMore,\n hasMore,\n isLoading = false,\n direction = \"down\",\n root,\n rootMargin = \"200px\",\n threshold = 0,\n loader,\n endMessage,\n className,\n children,\n}: InfiniteScrollProps) {\n const sentinelRef = React.useRef<HTMLDivElement>(null)\n const loadingRef = React.useRef(false)\n\n const onLoadMoreRef = React.useRef(onLoadMore)\n React.useEffect(() => {\n onLoadMoreRef.current = onLoadMore\n }, [onLoadMore])\n\n React.useEffect(() => {\n if (!isLoading) {\n loadingRef.current = false\n }\n }, [isLoading])\n\n React.useEffect(() => {\n const sentinel = sentinelRef.current\n if (!sentinel || !hasMore) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const [entry] = entries\n if (entry?.isIntersecting && !loadingRef.current) {\n loadingRef.current = true\n onLoadMoreRef.current()\n }\n },\n {\n root: root?.current ?? null,\n rootMargin,\n threshold,\n }\n )\n\n observer.observe(sentinel)\n\n return () => {\n observer.disconnect()\n }\n }, [hasMore, root, rootMargin, threshold])\n\n const loaderContent = isLoading && (\n <div\n data-slot=\"infinite-scroll-loader\"\n className=\"flex items-center justify-center py-6\"\n >\n {loader ?? <Spinner className=\"size-6 text-muted\" />}\n </div>\n )\n\n const endContent = !hasMore && !isLoading && endMessage && (\n <div\n data-slot=\"infinite-scroll-end\"\n className=\"flex items-center justify-center py-6 text-sm text-muted\"\n >\n {endMessage}\n </div>\n )\n\n const sentinel = (\n <div\n ref={sentinelRef}\n data-slot=\"infinite-scroll-sentinel\"\n aria-hidden=\"true\"\n className=\"h-px\"\n />\n )\n\n return (\n <div\n data-slot=\"infinite-scroll\"\n aria-busy={isLoading}\n className={cn(\"flex flex-col\", className)}\n >\n {direction === \"up\" && (\n <>\n {sentinel}\n {loaderContent}\n </>\n )}\n\n {children}\n\n {direction === \"down\" && (\n <>\n {sentinel}\n {loaderContent}\n </>\n )}\n\n {endContent}\n </div>\n )\n}\n\nexport { InfiniteScroll, type InfiniteScrollProps }\n"],"mappings":";;;;;;AAqBA,SAAS,eAAe,EACtB,YACA,SACA,YAAY,OACZ,YAAY,QACZ,MACA,aAAa,SACb,YAAY,GACZ,QACA,YACA,WACA,YACsB;CACtB,MAAM,cAAc,MAAM,OAAuB,KAAK;CACtD,MAAM,aAAa,MAAM,OAAO,MAAM;CAEtC,MAAM,gBAAgB,MAAM,OAAO,WAAW;AAC9C,OAAM,gBAAgB;AACpB,gBAAc,UAAU;IACvB,CAAC,WAAW,CAAC;AAEhB,OAAM,gBAAgB;AACpB,MAAI,CAAC,UACH,YAAW,UAAU;IAEtB,CAAC,UAAU,CAAC;AAEf,OAAM,gBAAgB;EACpB,MAAM,WAAW,YAAY;AAC7B,MAAI,CAAC,YAAY,CAAC,QAAS;EAE3B,MAAM,WAAW,IAAI,sBAClB,YAAY;GACX,MAAM,CAAC,SAAS;AAChB,OAAI,OAAO,kBAAkB,CAAC,WAAW,SAAS;AAChD,eAAW,UAAU;AACrB,kBAAc,SAAS;;KAG3B;GACE,MAAM,MAAM,WAAW;GACvB;GACA;GACD,CACF;AAED,WAAS,QAAQ,SAAS;AAE1B,eAAa;AACX,YAAS,YAAY;;IAEtB;EAAC;EAAS;EAAM;EAAY;EAAU,CAAC;CAE1C,MAAM,gBAAgB,aACpB,oBAAC,OAAD;EACE,aAAU;EACV,WAAU;YAET,UAAU,oBAAC,SAAD,EAAS,WAAU,qBAAsB,CAAA;EAChD,CAAA;CAGR,MAAM,aAAa,CAAC,WAAW,CAAC,aAAa,cAC3C,oBAAC,OAAD;EACE,aAAU;EACV,WAAU;YAET;EACG,CAAA;CAGR,MAAM,WACJ,oBAAC,OAAD;EACE,KAAK;EACL,aAAU;EACV,eAAY;EACZ,WAAU;EACV,CAAA;AAGJ,QACE,qBAAC,OAAD;EACE,aAAU;EACV,aAAW;EACX,WAAW,GAAG,iBAAiB,UAAU;YAH3C;GAKG,cAAc,QACb,qBAAA,UAAA,EAAA,UAAA,CACG,UACA,cACA,EAAA,CAAA;GAGJ;GAEA,cAAc,UACb,qBAAA,UAAA,EAAA,UAAA,CACG,UACA,cACA,EAAA,CAAA;GAGJ;GACG"}
1
+ {"version":3,"file":"infinite-scroll.js","names":[],"sources":["../src/infinite-scroll.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\nimport { Spinner } from \"./spinner\"\n\ntype InfiniteScrollProps = {\n onLoadMore: () => void\n hasMore: boolean\n isLoading?: boolean\n direction?: \"down\" | \"up\"\n root?: React.RefObject<Element | null>\n rootMargin?: string\n threshold?: number\n loader?: React.ReactNode\n endMessage?: React.ReactNode\n className?: string\n children?: React.ReactNode\n}\n\nfunction InfiniteScroll({\n onLoadMore,\n hasMore,\n isLoading = false,\n direction = \"down\",\n root,\n rootMargin = \"200px\",\n threshold = 0,\n loader,\n endMessage,\n className,\n children,\n}: InfiniteScrollProps) {\n const sentinelRef = React.useRef<HTMLDivElement>(null)\n\n const onLoadMoreRef = React.useRef(onLoadMore)\n React.useEffect(() => {\n onLoadMoreRef.current = onLoadMore\n }, [onLoadMore])\n\n React.useEffect(() => {\n const sentinel = sentinelRef.current\n // Don't observe while a load is in flight. Re-observing when `isLoading`\n // flips back to false re-checks the sentinel's CURRENT visibility (an\n // IntersectionObserver fires an initial callback on `observe`), so a\n // sentinel that stayed in view across the load triggers the next page.\n // Without this the observer only fires on intersection *transitions* and\n // stalls once the sentinel stops moving.\n if (!sentinel || !hasMore || isLoading) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const [entry] = entries\n if (entry?.isIntersecting) {\n onLoadMoreRef.current()\n }\n },\n {\n root: root?.current ?? null,\n rootMargin,\n threshold,\n }\n )\n\n observer.observe(sentinel)\n\n return () => {\n observer.disconnect()\n }\n }, [hasMore, isLoading, root, rootMargin, threshold])\n\n const loaderContent = isLoading && (\n <div\n data-slot=\"infinite-scroll-loader\"\n className=\"flex items-center justify-center py-6\"\n >\n {loader ?? <Spinner className=\"size-6 text-muted\" />}\n </div>\n )\n\n const endContent = !hasMore && !isLoading && endMessage && (\n <div\n data-slot=\"infinite-scroll-end\"\n className=\"flex items-center justify-center py-6 text-sm text-muted\"\n >\n {endMessage}\n </div>\n )\n\n const sentinel = (\n <div\n ref={sentinelRef}\n data-slot=\"infinite-scroll-sentinel\"\n aria-hidden=\"true\"\n className=\"h-px\"\n />\n )\n\n return (\n <div\n data-slot=\"infinite-scroll\"\n aria-busy={isLoading}\n className={cn(\"flex flex-col\", className)}\n >\n {direction === \"up\" && (\n <>\n {sentinel}\n {loaderContent}\n </>\n )}\n\n {children}\n\n {direction === \"down\" && (\n <>\n {sentinel}\n {loaderContent}\n </>\n )}\n\n {endContent}\n </div>\n )\n}\n\nexport { InfiniteScroll, type InfiniteScrollProps }\n"],"mappings":";;;;;;AAqBA,SAAS,eAAe,EACtB,YACA,SACA,YAAY,OACZ,YAAY,QACZ,MACA,aAAa,SACb,YAAY,GACZ,QACA,YACA,WACA,YACsB;CACtB,MAAM,cAAc,MAAM,OAAuB,KAAK;CAEtD,MAAM,gBAAgB,MAAM,OAAO,WAAW;AAC9C,OAAM,gBAAgB;AACpB,gBAAc,UAAU;IACvB,CAAC,WAAW,CAAC;AAEhB,OAAM,gBAAgB;EACpB,MAAM,WAAW,YAAY;AAO7B,MAAI,CAAC,YAAY,CAAC,WAAW,UAAW;EAExC,MAAM,WAAW,IAAI,sBAClB,YAAY;GACX,MAAM,CAAC,SAAS;AAChB,OAAI,OAAO,eACT,eAAc,SAAS;KAG3B;GACE,MAAM,MAAM,WAAW;GACvB;GACA;GACD,CACF;AAED,WAAS,QAAQ,SAAS;AAE1B,eAAa;AACX,YAAS,YAAY;;IAEtB;EAAC;EAAS;EAAW;EAAM;EAAY;EAAU,CAAC;CAErD,MAAM,gBAAgB,aACpB,oBAAC,OAAD;EACE,aAAU;EACV,WAAU;YAET,UAAU,oBAAC,SAAD,EAAS,WAAU,qBAAsB,CAAA;EAChD,CAAA;CAGR,MAAM,aAAa,CAAC,WAAW,CAAC,aAAa,cAC3C,oBAAC,OAAD;EACE,aAAU;EACV,WAAU;YAET;EACG,CAAA;CAGR,MAAM,WACJ,oBAAC,OAAD;EACE,KAAK;EACL,aAAU;EACV,eAAY;EACZ,WAAU;EACV,CAAA;AAGJ,QACE,qBAAC,OAAD;EACE,aAAU;EACV,aAAW;EACX,WAAW,GAAG,iBAAiB,UAAU;YAH3C;GAKG,cAAc,QACb,qBAAA,UAAA,EAAA,UAAA,CACG,UACA,cACA,EAAA,CAAA;GAGJ;GAEA,cAAc,UACb,qBAAA,UAAA,EAAA,UAAA,CACG,UACA,cACA,EAAA,CAAA;GAGJ;GACG"}
package/dist/item.d.ts CHANGED
@@ -11,7 +11,7 @@ declare const itemVariants: (props?: ({
11
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>;
package/dist/label.js CHANGED
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
6
6
  function Label({ className, ...props }) {
7
7
  return /* @__PURE__ */ jsx("label", {
8
8
  "data-slot": "label",
9
- className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
9
+ className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled]:pointer-events-none group-data-[disabled]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
10
10
  ...props
11
11
  });
12
12
  }
package/dist/label.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"label.js","names":[],"sources":["../src/label.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\n\ntype LabelProps = React.ComponentProps<\"label\">\n\nfunction Label({ className, ...props }: LabelProps) {\n return (\n <label\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Label }\n"],"mappings":";;;;;AAQA,SAAS,MAAM,EAAE,WAAW,GAAG,SAAqB;AAClD,QACE,oBAAC,SAAD;EACE,aAAU;EACV,WAAW,GACT,uNACA,UACD;EACD,GAAI;EACJ,CAAA"}
1
+ {"version":3,"file":"label.js","names":[],"sources":["../src/label.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\n\ntype LabelProps = React.ComponentProps<\"label\">\n\nfunction Label({ className, ...props }: LabelProps) {\n return (\n <label\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled]:pointer-events-none group-data-[disabled]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Label }\n"],"mappings":";;;;;AAQA,SAAS,MAAM,EAAE,WAAW,GAAG,SAAqB;AAClD,QACE,oBAAC,SAAD;EACE,aAAU;EACV,WAAW,GACT,6MACA,UACD;EACD,GAAI;EACJ,CAAA"}
@@ -5,7 +5,7 @@ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
5
5
  /**
6
6
  * Internal-only SVG icons used by wave-ui components.
7
7
  *
8
- * NOT a public entry point — bundled into shared chunks via tsup splitting.
8
+ * NOT a public entry point — imported by components via relative paths.
9
9
  */
10
10
  type IconProps = React.SVGProps<SVGSVGElement>;
11
11
  declare function ChevronDownIcon(props: IconProps): _$react_jsx_runtime0.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"internal-icons.d.ts","names":[],"sources":["../../src/lib/internal-icons.tsx"],"mappings":";;;;;;;;AAmIuB;KA3HlB,SAAA,GAAY,KAAA,CAAM,QAAA,CAAS,aAAA;AAAA,iBAkBhB,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQhC,aAAA,CAAc,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ9B,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAShC,gBAAA,CAAiB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAYjC,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ1B,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAS1B,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ1B,YAAA,CAAa,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU7B,oBAAA,CAAqB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUrC,kBAAA,CAAmB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAanC,gBAAA,CAAiB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;;cAUpC,UAAA,EAAU,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,SAAA,WAAA,OAAA,CAAA,aAAA,CAAA,aAAA;AAAA,iBAqBP,iBAAA,CAAkB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUlC,iBAAA,CAAkB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBASlC,cAAA,CAAe,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU/B,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAchC,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU1B,QAAA,CAAS,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"internal-icons.d.ts","names":[],"sources":["../../src/lib/internal-icons.tsx"],"mappings":";;;;;;;;AAwIuB;KAhIlB,SAAA,GAAY,KAAA,CAAM,QAAA,CAAS,aAAA;AAAA,iBAuBhB,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQhC,aAAA,CAAc,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ9B,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAShC,gBAAA,CAAiB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAYjC,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ1B,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAS1B,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ1B,YAAA,CAAa,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU7B,oBAAA,CAAqB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUrC,kBAAA,CAAmB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAanC,gBAAA,CAAiB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;;cAUpC,UAAA,EAAU,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,SAAA,WAAA,OAAA,CAAA,aAAA,CAAA,aAAA;AAAA,iBAqBP,iBAAA,CAAkB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAUlC,iBAAA,CAAkB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBASlC,cAAA,CAAe,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU/B,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAchC,SAAA,CAAU,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU1B,QAAA,CAAS,KAAA,EAAO,SAAA,GAAS,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -4,7 +4,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
4
4
  /**
5
5
  * Internal-only SVG icons used by wave-ui components.
6
6
  *
7
- * NOT a public entry point — bundled into shared chunks via tsup splitting.
7
+ * NOT a public entry point — imported by components via relative paths.
8
8
  */
9
9
  const SVG_BASE = {
10
10
  xmlns: "http://www.w3.org/2000/svg",
@@ -15,7 +15,9 @@ const SVG_BASE = {
15
15
  stroke: "currentColor",
16
16
  strokeWidth: 2,
17
17
  strokeLinecap: "round",
18
- strokeLinejoin: "round"
18
+ strokeLinejoin: "round",
19
+ "aria-hidden": true,
20
+ focusable: false
19
21
  };
20
22
  function ChevronDownIcon(props) {
21
23
  return /* @__PURE__ */ jsx("svg", {
@@ -1 +1 @@
1
- {"version":3,"file":"internal-icons.js","names":[],"sources":["../../src/lib/internal-icons.tsx"],"sourcesContent":["/**\n * Internal-only SVG icons used by wave-ui components.\n *\n * NOT a public entry point — bundled into shared chunks via tsup splitting.\n */\n\nimport { forwardRef } from 'react';\n\ntype IconProps = React.SVGProps<SVGSVGElement>;\n\nconst SVG_BASE = {\n xmlns: 'http://www.w3.org/2000/svg',\n width: 24,\n height: 24,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n} as const;\n\n// ---------------------------------------------------------------------------\n// Navigation chevrons\n// ---------------------------------------------------------------------------\n\nexport function ChevronDownIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n );\n}\n\nexport function ChevronUpIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n );\n}\n\nexport function ChevronLeftIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n );\n}\n\n\nexport function ChevronRightIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Actions\n// ---------------------------------------------------------------------------\n\nexport function CheckIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\nexport function CloseIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function MinusIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M5 12h14\" />\n </svg>\n );\n}\n\nexport function EllipsisIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n </svg>\n );\n}\n\nexport function EllipsisVerticalIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n\nexport function ChevronsUpDownIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m7 15 5 5 5-5\" />\n <path d=\"m7 9 5-5 5 5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// UI chrome\n// ---------------------------------------------------------------------------\n\nexport function SidebarPanelIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M9 3v18\" />\n </svg>\n );\n}\n\n/** `forwardRef` because `Spinner` exposes this as `React.ComponentProps<\"svg\">`. */\nexport const LoaderIcon = forwardRef<SVGSVGElement, IconProps>(\n function LoaderIcon(props, ref) {\n return (\n <svg {...SVG_BASE} ref={ref} {...props}>\n <path d=\"M12 2v4\" />\n <path d=\"m16.2 7.8 2.9-2.9\" />\n <path d=\"M18 12h4\" />\n <path d=\"m16.2 16.2 2.9 2.9\" />\n <path d=\"M12 18v4\" />\n <path d=\"m4.9 19.1 2.9-2.9\" />\n <path d=\"M2 12h4\" />\n <path d=\"m4.9 4.9 2.9 2.9\" />\n </svg>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Toast status icons\n// ---------------------------------------------------------------------------\n\nexport function AlertTriangleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n );\n}\n\nexport function SuccessCircleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n </svg>\n );\n}\n\nexport function InfoCircleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n );\n}\n\nexport function ErrorCircleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m15 9-6 6\" />\n <path d=\"m9 9 6 6\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Social icons\n// ---------------------------------------------------------------------------\n\nexport function TrashIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n );\n}\n\nexport function StarIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\" />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"internal-icons.js","names":[],"sources":["../../src/lib/internal-icons.tsx"],"sourcesContent":["/**\n * Internal-only SVG icons used by wave-ui components.\n *\n * NOT a public entry point — imported by components via relative paths.\n */\n\nimport { forwardRef } from 'react';\n\ntype IconProps = React.SVGProps<SVGSVGElement>;\n\nconst SVG_BASE = {\n xmlns: 'http://www.w3.org/2000/svg',\n width: 24,\n height: 24,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n // Decorative by default — the control rendering an icon provides the\n // accessible name (aria-label / sr-only text). A component using an icon\n // *meaningfully* overrides this via props (e.g. Spinner sets aria-hidden={false}).\n \"aria-hidden\": true,\n focusable: false,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Navigation chevrons\n// ---------------------------------------------------------------------------\n\nexport function ChevronDownIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n );\n}\n\nexport function ChevronUpIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n );\n}\n\nexport function ChevronLeftIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n );\n}\n\n\nexport function ChevronRightIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Actions\n// ---------------------------------------------------------------------------\n\nexport function CheckIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\nexport function CloseIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function MinusIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M5 12h14\" />\n </svg>\n );\n}\n\nexport function EllipsisIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n </svg>\n );\n}\n\nexport function EllipsisVerticalIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n\nexport function ChevronsUpDownIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m7 15 5 5 5-5\" />\n <path d=\"m7 9 5-5 5 5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// UI chrome\n// ---------------------------------------------------------------------------\n\nexport function SidebarPanelIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M9 3v18\" />\n </svg>\n );\n}\n\n/** `forwardRef` because `Spinner` exposes this as `React.ComponentProps<\"svg\">`. */\nexport const LoaderIcon = forwardRef<SVGSVGElement, IconProps>(\n function LoaderIcon(props, ref) {\n return (\n <svg {...SVG_BASE} ref={ref} {...props}>\n <path d=\"M12 2v4\" />\n <path d=\"m16.2 7.8 2.9-2.9\" />\n <path d=\"M18 12h4\" />\n <path d=\"m16.2 16.2 2.9 2.9\" />\n <path d=\"M12 18v4\" />\n <path d=\"m4.9 19.1 2.9-2.9\" />\n <path d=\"M2 12h4\" />\n <path d=\"m4.9 4.9 2.9 2.9\" />\n </svg>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Toast status icons\n// ---------------------------------------------------------------------------\n\nexport function AlertTriangleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n );\n}\n\nexport function SuccessCircleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n </svg>\n );\n}\n\nexport function InfoCircleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n );\n}\n\nexport function ErrorCircleIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m15 9-6 6\" />\n <path d=\"m9 9 6 6\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Social icons\n// ---------------------------------------------------------------------------\n\nexport function TrashIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n );\n}\n\nexport function StarIcon(props: IconProps) {\n return (\n <svg {...SVG_BASE} {...props}>\n <path d=\"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\" />\n </svg>\n );\n}\n"],"mappings":"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"}
package/dist/spinner.js CHANGED
@@ -4,8 +4,10 @@ import { jsx } from "react/jsx-runtime";
4
4
  //#region src/spinner.tsx
5
5
  function Spinner({ className, ...props }) {
6
6
  return /* @__PURE__ */ jsx(LoaderIcon, {
7
+ "data-slot": "spinner",
7
8
  role: "status",
8
9
  "aria-label": "Loading",
10
+ "aria-hidden": false,
9
11
  className: cn("size-4 animate-spin", className),
10
12
  ...props
11
13
  });
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.js","names":[],"sources":["../src/spinner.tsx"],"sourcesContent":["import { cn } from \"./lib/utils\"\nimport { LoaderIcon } from \"./lib/internal-icons\"\n\ntype SpinnerProps = React.ComponentProps<\"svg\">\n\nfunction Spinner({ className, ...props }: SpinnerProps) {\n return (\n <LoaderIcon role=\"status\" aria-label=\"Loading\" className={cn(\"size-4 animate-spin\", className)} {...props} />\n )\n}\n\nexport { Spinner }\n"],"mappings":";;;;AAKA,SAAS,QAAQ,EAAE,WAAW,GAAG,SAAuB;AACtD,QACE,oBAAC,YAAD;EAAY,MAAK;EAAS,cAAW;EAAU,WAAW,GAAG,uBAAuB,UAAU;EAAE,GAAI;EAAS,CAAA"}
1
+ {"version":3,"file":"spinner.js","names":[],"sources":["../src/spinner.tsx"],"sourcesContent":["import { cn } from \"./lib/utils\"\nimport { LoaderIcon } from \"./lib/internal-icons\"\n\ntype SpinnerProps = React.ComponentProps<\"svg\">\n\nfunction Spinner({ className, ...props }: SpinnerProps) {\n return (\n <LoaderIcon\n data-slot=\"spinner\"\n role=\"status\"\n aria-label=\"Loading\"\n // The spinner IS the accessible status, so it opts out of the\n // decorative-by-default aria-hidden that internal icons carry.\n aria-hidden={false}\n className={cn(\"size-4 animate-spin\", className)}\n {...props}\n />\n )\n}\n\nexport { Spinner }\n"],"mappings":";;;;AAKA,SAAS,QAAQ,EAAE,WAAW,GAAG,SAAuB;AACtD,QACE,oBAAC,YAAD;EACE,aAAU;EACV,MAAK;EACL,cAAW;EAGX,eAAa;EACb,WAAW,GAAG,uBAAuB,UAAU;EAC/C,GAAI;EACJ,CAAA"}