react-marketing-ui 0.0.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.
- package/README.md +34 -0
- package/dist/accordion.d.cts +21 -0
- package/dist/accordion.d.ts +21 -0
- package/dist/accordion.d.ts.map +1 -0
- package/dist/accordion.js +230 -0
- package/dist/accordion.js.map +1 -0
- package/dist/accordion.mjs +4 -0
- package/dist/accordion.mjs.map +1 -0
- package/dist/action-swap.d.cts +23 -0
- package/dist/action-swap.d.ts +23 -0
- package/dist/action-swap.d.ts.map +1 -0
- package/dist/action-swap.js +81 -0
- package/dist/action-swap.js.map +1 -0
- package/dist/action-swap.mjs +5 -0
- package/dist/action-swap.mjs.map +1 -0
- package/dist/animated-beam.d.cts +24 -0
- package/dist/animated-beam.d.ts +24 -0
- package/dist/animated-beam.d.ts.map +1 -0
- package/dist/animated-beam.js +130 -0
- package/dist/animated-beam.js.map +1 -0
- package/dist/animated-beam.mjs +4 -0
- package/dist/animated-beam.mjs.map +1 -0
- package/dist/button.d.cts +55 -0
- package/dist/button.d.ts +55 -0
- package/dist/button.d.ts.map +1 -0
- package/dist/button.js +119 -0
- package/dist/button.js.map +1 -0
- package/dist/button.mjs +4 -0
- package/dist/button.mjs.map +1 -0
- package/dist/card.d.cts +20 -0
- package/dist/card.d.ts +20 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +146 -0
- package/dist/card.js.map +1 -0
- package/dist/card.mjs +5 -0
- package/dist/card.mjs.map +1 -0
- package/dist/chunk-3SB6HUBA.mjs +31 -0
- package/dist/chunk-3SB6HUBA.mjs.map +1 -0
- package/dist/chunk-4PBVBXGY.mjs +84 -0
- package/dist/chunk-4PBVBXGY.mjs.map +1 -0
- package/dist/chunk-4VCFWVSJ.mjs +42 -0
- package/dist/chunk-4VCFWVSJ.mjs.map +1 -0
- package/dist/chunk-5QQAPGR2.mjs +109 -0
- package/dist/chunk-5QQAPGR2.mjs.map +1 -0
- package/dist/chunk-6MB4UKRX.mjs +19 -0
- package/dist/chunk-6MB4UKRX.mjs.map +1 -0
- package/dist/chunk-6T5LR34O.mjs +45 -0
- package/dist/chunk-6T5LR34O.mjs.map +1 -0
- package/dist/chunk-AYLCYDUM.mjs +275 -0
- package/dist/chunk-AYLCYDUM.mjs.map +1 -0
- package/dist/chunk-AYY7D2RJ.mjs +112 -0
- package/dist/chunk-AYY7D2RJ.mjs.map +1 -0
- package/dist/chunk-CTZEI2YS.mjs +324 -0
- package/dist/chunk-CTZEI2YS.mjs.map +1 -0
- package/dist/chunk-DA3I3Y5O.mjs +71 -0
- package/dist/chunk-DA3I3Y5O.mjs.map +1 -0
- package/dist/chunk-EYHT2EWJ.mjs +18 -0
- package/dist/chunk-EYHT2EWJ.mjs.map +1 -0
- package/dist/chunk-IHLGCS63.mjs +36 -0
- package/dist/chunk-IHLGCS63.mjs.map +1 -0
- package/dist/chunk-JVXJ6SFX.mjs +38 -0
- package/dist/chunk-JVXJ6SFX.mjs.map +1 -0
- package/dist/chunk-KBHYXLRG.mjs +13 -0
- package/dist/chunk-KBHYXLRG.mjs.map +1 -0
- package/dist/chunk-KMXUQYR3.mjs +74 -0
- package/dist/chunk-KMXUQYR3.mjs.map +1 -0
- package/dist/chunk-KNPOZ34H.mjs +88 -0
- package/dist/chunk-KNPOZ34H.mjs.map +1 -0
- package/dist/chunk-KRNWCJ4D.mjs +219 -0
- package/dist/chunk-KRNWCJ4D.mjs.map +1 -0
- package/dist/chunk-M5MESV26.mjs +124 -0
- package/dist/chunk-M5MESV26.mjs.map +1 -0
- package/dist/chunk-MJYBPJBA.mjs +115 -0
- package/dist/chunk-MJYBPJBA.mjs.map +1 -0
- package/dist/chunk-NNHPQ67J.mjs +10 -0
- package/dist/chunk-NNHPQ67J.mjs.map +1 -0
- package/dist/chunk-OCZFHVVD.mjs +71 -0
- package/dist/chunk-OCZFHVVD.mjs.map +1 -0
- package/dist/chunk-QAWSH567.mjs +19 -0
- package/dist/chunk-QAWSH567.mjs.map +1 -0
- package/dist/chunk-R2E2J42H.mjs +38 -0
- package/dist/chunk-R2E2J42H.mjs.map +1 -0
- package/dist/chunk-TPGLLSYV.mjs +65 -0
- package/dist/chunk-TPGLLSYV.mjs.map +1 -0
- package/dist/chunk-VJENJHXJ.mjs +72 -0
- package/dist/chunk-VJENJHXJ.mjs.map +1 -0
- package/dist/chunk-W22G7XHR.mjs +104 -0
- package/dist/chunk-W22G7XHR.mjs.map +1 -0
- package/dist/chunk-WDR5VPZJ.mjs +79 -0
- package/dist/chunk-WDR5VPZJ.mjs.map +1 -0
- package/dist/chunk-WLUGKBH7.mjs +37 -0
- package/dist/chunk-WLUGKBH7.mjs.map +1 -0
- package/dist/chunk-WYJYLDUA.mjs +84 -0
- package/dist/chunk-WYJYLDUA.mjs.map +1 -0
- package/dist/chunk-XZEDZVXT.mjs +38 -0
- package/dist/chunk-XZEDZVXT.mjs.map +1 -0
- package/dist/chunk-YKGP5JIL.mjs +328 -0
- package/dist/chunk-YKGP5JIL.mjs.map +1 -0
- package/dist/chunk-YM3U2OBE.mjs +99 -0
- package/dist/chunk-YM3U2OBE.mjs.map +1 -0
- package/dist/dia-text-reveal.css +18 -0
- package/dist/dia-text-reveal.css.map +1 -0
- package/dist/dia-text-reveal.d.cts +37 -0
- package/dist/dia-text-reveal.d.ts +37 -0
- package/dist/dia-text-reveal.d.ts.map +1 -0
- package/dist/dia-text-reveal.js +334 -0
- package/dist/dia-text-reveal.js.map +1 -0
- package/dist/dia-text-reveal.lines.d.cts +23 -0
- package/dist/dia-text-reveal.lines.d.ts +23 -0
- package/dist/dia-text-reveal.lines.d.ts.map +1 -0
- package/dist/dia-text-reveal.mjs +4 -0
- package/dist/dia-text-reveal.mjs.map +1 -0
- package/dist/dia-text-reveal.sweep.d.cts +49 -0
- package/dist/dia-text-reveal.sweep.d.ts +49 -0
- package/dist/dia-text-reveal.sweep.d.ts.map +1 -0
- package/dist/dia-text-reveal.utils.d.cts +3 -0
- package/dist/dia-text-reveal.utils.d.ts +3 -0
- package/dist/dia-text-reveal.utils.d.ts.map +1 -0
- package/dist/elevated-input.d.cts +11 -0
- package/dist/elevated-input.d.ts +11 -0
- package/dist/elevated-input.d.ts.map +1 -0
- package/dist/elevated-input.js +52 -0
- package/dist/elevated-input.js.map +1 -0
- package/dist/elevated-input.mjs +4 -0
- package/dist/elevated-input.mjs.map +1 -0
- package/dist/fade-in.d.cts +43 -0
- package/dist/fade-in.d.ts +43 -0
- package/dist/fade-in.d.ts.map +1 -0
- package/dist/fade-in.js +89 -0
- package/dist/fade-in.js.map +1 -0
- package/dist/fade-in.mjs +4 -0
- package/dist/fade-in.mjs.map +1 -0
- package/dist/feature-card.d.cts +23 -0
- package/dist/feature-card.d.ts +23 -0
- package/dist/feature-card.d.ts.map +1 -0
- package/dist/feature-card.js +38 -0
- package/dist/feature-card.js.map +1 -0
- package/dist/feature-card.mjs +4 -0
- package/dist/feature-card.mjs.map +1 -0
- package/dist/flowchart-parts.d.cts +61 -0
- package/dist/flowchart-parts.d.ts +61 -0
- package/dist/flowchart-parts.d.ts.map +1 -0
- package/dist/flowchart-parts.js +102 -0
- package/dist/flowchart-parts.js.map +1 -0
- package/dist/flowchart-parts.mjs +4 -0
- package/dist/flowchart-parts.mjs.map +1 -0
- package/dist/glossy-button.d.cts +21 -0
- package/dist/glossy-button.d.ts +21 -0
- package/dist/glossy-button.d.ts.map +1 -0
- package/dist/glossy-button.js +87 -0
- package/dist/glossy-button.js.map +1 -0
- package/dist/glossy-button.mjs +4 -0
- package/dist/glossy-button.mjs.map +1 -0
- package/dist/grainient.css +9 -0
- package/dist/grainient.css.map +1 -0
- package/dist/grainient.d.cts +5 -0
- package/dist/grainient.d.ts +5 -0
- package/dist/grainient.d.ts.map +1 -0
- package/dist/grainient.js +330 -0
- package/dist/grainient.js.map +1 -0
- package/dist/grainient.mjs +4 -0
- package/dist/grainient.mjs.map +1 -0
- package/dist/grainient.shader.d.cts +9 -0
- package/dist/grainient.shader.d.ts +9 -0
- package/dist/grainient.shader.d.ts.map +1 -0
- package/dist/grainient.types.d.cts +30 -0
- package/dist/grainient.types.d.ts +30 -0
- package/dist/grainient.types.d.ts.map +1 -0
- package/dist/highlighter.d.cts +47 -0
- package/dist/highlighter.d.ts +47 -0
- package/dist/highlighter.d.ts.map +1 -0
- package/dist/highlighter.js +125 -0
- package/dist/highlighter.js.map +1 -0
- package/dist/highlighter.mjs +5 -0
- package/dist/highlighter.mjs.map +1 -0
- package/dist/index.css +27 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +56 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2723 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +34 -0
- package/dist/index.mjs.map +1 -0
- package/dist/input.d.cts +15 -0
- package/dist/input.d.ts +15 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +110 -0
- package/dist/input.js.map +1 -0
- package/dist/input.mjs +4 -0
- package/dist/input.mjs.map +1 -0
- package/dist/lib/breakpoints.d.cts +36 -0
- package/dist/lib/breakpoints.d.ts +36 -0
- package/dist/lib/breakpoints.d.ts.map +1 -0
- package/dist/lib/breakpoints.js +41 -0
- package/dist/lib/breakpoints.js.map +1 -0
- package/dist/lib/breakpoints.mjs +3 -0
- package/dist/lib/breakpoints.mjs.map +1 -0
- package/dist/lib/cn.js +24 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/cn.mjs +3 -0
- package/dist/lib/cn.mjs.map +1 -0
- package/dist/lib/ease.d.cts +19 -0
- package/dist/lib/ease.d.ts +19 -0
- package/dist/lib/ease.d.ts.map +1 -0
- package/dist/lib/ease.js +16 -0
- package/dist/lib/ease.js.map +1 -0
- package/dist/lib/ease.mjs +3 -0
- package/dist/lib/ease.mjs.map +1 -0
- package/dist/lib/surface.d.cts +14 -0
- package/dist/lib/surface.d.ts +14 -0
- package/dist/lib/surface.d.ts.map +1 -0
- package/dist/lib/surface.js +40 -0
- package/dist/lib/surface.js.map +1 -0
- package/dist/lib/surface.mjs +3 -0
- package/dist/lib/surface.mjs.map +1 -0
- package/dist/lib/use-media-query.d.cts +9 -0
- package/dist/lib/use-media-query.d.ts +9 -0
- package/dist/lib/use-media-query.d.ts.map +1 -0
- package/dist/lib/use-media-query.js +19 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lib/use-media-query.mjs +3 -0
- package/dist/lib/use-media-query.mjs.map +1 -0
- package/dist/lib/utils.d.cts +25 -0
- package/dist/lib/utils.d.ts +25 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/liquid-metal.d.cts +24 -0
- package/dist/liquid-metal.d.ts +24 -0
- package/dist/liquid-metal.d.ts.map +1 -0
- package/dist/liquid-metal.js +43 -0
- package/dist/liquid-metal.js.map +1 -0
- package/dist/liquid-metal.mjs +4 -0
- package/dist/liquid-metal.mjs.map +1 -0
- package/dist/navigation-menu-icons.d.cts +5 -0
- package/dist/navigation-menu-icons.d.ts +5 -0
- package/dist/navigation-menu-icons.d.ts.map +1 -0
- package/dist/navigation-menu-icons.js +42 -0
- package/dist/navigation-menu-icons.js.map +1 -0
- package/dist/navigation-menu-icons.mjs +3 -0
- package/dist/navigation-menu-icons.mjs.map +1 -0
- package/dist/navigation-menu-styles.d.cts +45 -0
- package/dist/navigation-menu-styles.d.ts +45 -0
- package/dist/navigation-menu-styles.d.ts.map +1 -0
- package/dist/navigation-menu-styles.js +16 -0
- package/dist/navigation-menu-styles.js.map +1 -0
- package/dist/navigation-menu-styles.mjs +3 -0
- package/dist/navigation-menu-styles.mjs.map +1 -0
- package/dist/navigation-menu.d.cts +18 -0
- package/dist/navigation-menu.d.ts +18 -0
- package/dist/navigation-menu.d.ts.map +1 -0
- package/dist/navigation-menu.js +367 -0
- package/dist/navigation-menu.js.map +1 -0
- package/dist/navigation-menu.mjs +7 -0
- package/dist/navigation-menu.mjs.map +1 -0
- package/dist/password-input.d.cts +6 -0
- package/dist/password-input.d.ts +6 -0
- package/dist/password-input.d.ts.map +1 -0
- package/dist/password-input.js +174 -0
- package/dist/password-input.js.map +1 -0
- package/dist/password-input.mjs +5 -0
- package/dist/password-input.mjs.map +1 -0
- package/dist/rainbow-button.d.cts +16 -0
- package/dist/rainbow-button.d.ts +16 -0
- package/dist/rainbow-button.d.ts.map +1 -0
- package/dist/rainbow-button.js +49 -0
- package/dist/rainbow-button.js.map +1 -0
- package/dist/rainbow-button.mjs +4 -0
- package/dist/rainbow-button.mjs.map +1 -0
- package/dist/range-slider.d.cts +20 -0
- package/dist/range-slider.d.ts +20 -0
- package/dist/range-slider.d.ts.map +1 -0
- package/dist/range-slider.js +85 -0
- package/dist/range-slider.js.map +1 -0
- package/dist/range-slider.mjs +3 -0
- package/dist/range-slider.mjs.map +1 -0
- package/dist/rolling-badge.d.cts +11 -0
- package/dist/rolling-badge.d.ts +11 -0
- package/dist/rolling-badge.d.ts.map +1 -0
- package/dist/rolling-badge.js +71 -0
- package/dist/rolling-badge.js.map +1 -0
- package/dist/rolling-badge.mjs +4 -0
- package/dist/rolling-badge.mjs.map +1 -0
- package/dist/savings-badge.d.cts +10 -0
- package/dist/savings-badge.d.ts +10 -0
- package/dist/savings-badge.d.ts.map +1 -0
- package/dist/savings-badge.js +26 -0
- package/dist/savings-badge.js.map +1 -0
- package/dist/savings-badge.mjs +4 -0
- package/dist/savings-badge.mjs.map +1 -0
- package/dist/shine-border.d.cts +15 -0
- package/dist/shine-border.d.ts +15 -0
- package/dist/shine-border.d.ts.map +1 -0
- package/dist/shine-border.js +47 -0
- package/dist/shine-border.js.map +1 -0
- package/dist/shine-border.mjs +4 -0
- package/dist/shine-border.mjs.map +1 -0
- package/dist/sparkles-text.d.cts +22 -0
- package/dist/sparkles-text.d.ts +22 -0
- package/dist/sparkles-text.d.ts.map +1 -0
- package/dist/sparkles-text.js +87 -0
- package/dist/sparkles-text.js.map +1 -0
- package/dist/sparkles-text.mjs +5 -0
- package/dist/sparkles-text.mjs.map +1 -0
- package/dist/tabs.d.cts +16 -0
- package/dist/tabs.d.ts +16 -0
- package/dist/tabs.d.ts.map +1 -0
- package/dist/tabs.js +121 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tabs.mjs +4 -0
- package/dist/tabs.mjs.map +1 -0
- package/dist/theme-toggle.d.cts +10 -0
- package/dist/theme-toggle.d.ts +10 -0
- package/dist/theme-toggle.d.ts.map +1 -0
- package/dist/theme-toggle.js +251 -0
- package/dist/theme-toggle.js.map +1 -0
- package/dist/theme-toggle.mjs +7 -0
- package/dist/theme-toggle.mjs.map +1 -0
- package/package.json +428 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { cn } from './chunk-QAWSH567.mjs';
|
|
2
|
+
import { useReducedMotion, useSpring, useTransform, motion } from 'framer-motion';
|
|
3
|
+
import { useRef, useState, useCallback, useEffect } from 'react';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var PULL = 0.035;
|
|
7
|
+
function pillTarget(activeIdx, hoverIdx, rects, pull) {
|
|
8
|
+
const active = rects[activeIdx];
|
|
9
|
+
if (!active) throw new Error(`No rect at index ${activeIdx}`);
|
|
10
|
+
if (hoverIdx === null || hoverIdx === activeIdx) return active;
|
|
11
|
+
const hover = rects[hoverIdx];
|
|
12
|
+
if (!hover) return active;
|
|
13
|
+
const activeRight = active.left + active.width;
|
|
14
|
+
const hoverRight = hover.left + hover.width;
|
|
15
|
+
const left = Math.min(active.left, active.left + (hover.left - active.left) * pull);
|
|
16
|
+
const right = Math.max(activeRight, activeRight + (hoverRight - activeRight) * pull);
|
|
17
|
+
return { left, width: right - left };
|
|
18
|
+
}
|
|
19
|
+
var labelBox = "flex items-center gap-2.5 px-5 py-1.5 font-semibold text-[13px]";
|
|
20
|
+
var badgeBox = "font-bold text-(--color-accent-brand-soft) text-[11px] whitespace-nowrap";
|
|
21
|
+
function Tabs({ tabs, value, onChange, label, className }) {
|
|
22
|
+
const reduced = useReducedMotion();
|
|
23
|
+
const pull = reduced ? 0 : PULL;
|
|
24
|
+
const trackRef = useRef(null);
|
|
25
|
+
const [rects, setRects] = useState([]);
|
|
26
|
+
const [trackWidth, setTrackWidth] = useState(0);
|
|
27
|
+
const [hovered, setHovered] = useState(null);
|
|
28
|
+
const [ready, setReady] = useState(false);
|
|
29
|
+
const foundIdx = tabs.findIndex((t) => t.id === value);
|
|
30
|
+
const activeIdx = foundIdx === -1 ? 0 : foundIdx;
|
|
31
|
+
const springConfig = reduced ? { stiffness: 700, damping: 60 } : { stiffness: 420, damping: 34, mass: 0.7 };
|
|
32
|
+
const pillLeft = useSpring(0, springConfig);
|
|
33
|
+
const pillWidth = useSpring(0, springConfig);
|
|
34
|
+
const innerX = useTransform(pillLeft, (v) => -v);
|
|
35
|
+
const measure = useCallback(() => {
|
|
36
|
+
const track = trackRef.current;
|
|
37
|
+
if (!track) return;
|
|
38
|
+
setTrackWidth(track.offsetWidth);
|
|
39
|
+
const btns = track.querySelectorAll("button[data-index]");
|
|
40
|
+
setRects(
|
|
41
|
+
Array.from(btns, (el) => ({
|
|
42
|
+
left: el.offsetLeft,
|
|
43
|
+
width: el.offsetWidth
|
|
44
|
+
}))
|
|
45
|
+
);
|
|
46
|
+
}, []);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
measure();
|
|
49
|
+
const track = trackRef.current;
|
|
50
|
+
if (!track) return;
|
|
51
|
+
const ro = new ResizeObserver(measure);
|
|
52
|
+
ro.observe(track);
|
|
53
|
+
return () => ro.disconnect();
|
|
54
|
+
}, [measure]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (rects.length !== tabs.length) return;
|
|
57
|
+
const target = pillTarget(activeIdx, hovered, rects, pull);
|
|
58
|
+
if (ready) {
|
|
59
|
+
pillLeft.set(target.left);
|
|
60
|
+
pillWidth.set(target.width);
|
|
61
|
+
} else {
|
|
62
|
+
pillLeft.jump(target.left);
|
|
63
|
+
pillWidth.jump(target.width);
|
|
64
|
+
setReady(true);
|
|
65
|
+
}
|
|
66
|
+
}, [rects, tabs.length, activeIdx, hovered, pull, ready, pillLeft, pillWidth]);
|
|
67
|
+
const handleClick = useCallback(
|
|
68
|
+
(e) => onChange(tabs[Number(e.currentTarget.dataset.index)].id),
|
|
69
|
+
[onChange, tabs]
|
|
70
|
+
);
|
|
71
|
+
const handleEnter = useCallback((e) => setHovered(Number(e.currentTarget.dataset.index)), []);
|
|
72
|
+
const handleLeave = useCallback(() => setHovered(null), []);
|
|
73
|
+
return /* @__PURE__ */ jsx(
|
|
74
|
+
"fieldset",
|
|
75
|
+
{
|
|
76
|
+
"aria-label": label,
|
|
77
|
+
className: cn("inline-flex items-center rounded-full border border-(--color-border) bg-(--color-surface) p-1", className),
|
|
78
|
+
children: /* @__PURE__ */ jsxs("div", { ref: trackRef, className: "relative inline-flex items-center", children: [
|
|
79
|
+
tabs.map((tab, i) => /* @__PURE__ */ jsxs(
|
|
80
|
+
"button",
|
|
81
|
+
{
|
|
82
|
+
type: "button",
|
|
83
|
+
"data-index": i,
|
|
84
|
+
onClick: handleClick,
|
|
85
|
+
onMouseEnter: handleEnter,
|
|
86
|
+
onMouseLeave: handleLeave,
|
|
87
|
+
"aria-pressed": value === tab.id,
|
|
88
|
+
className: cn(labelBox, "text-(--color-muted-foreground) hover:text-(--color-foreground)"),
|
|
89
|
+
children: [
|
|
90
|
+
tab.label,
|
|
91
|
+
tab.badge ? /* @__PURE__ */ jsx("span", { className: badgeBox, children: tab.badge }) : null
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
tab.id
|
|
95
|
+
)),
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
motion.div,
|
|
98
|
+
{
|
|
99
|
+
"aria-hidden": true,
|
|
100
|
+
className: "pointer-events-none absolute inset-y-0 select-none overflow-hidden rounded-full bg-(--color-foreground)",
|
|
101
|
+
style: { left: pillLeft, width: pillWidth, opacity: ready ? 1 : 0 },
|
|
102
|
+
children: /* @__PURE__ */ jsx(motion.div, { className: "absolute inset-y-0 left-0 flex items-center", style: { width: trackWidth, x: innerX }, children: tabs.map((tab) => /* @__PURE__ */ jsxs("span", { className: cn(labelBox, "text-(--color-surface)"), children: [
|
|
103
|
+
tab.label,
|
|
104
|
+
tab.badge ? /* @__PURE__ */ jsx("span", { className: badgeBox, children: tab.badge }) : null
|
|
105
|
+
] }, tab.id)) })
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
] })
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { Tabs };
|
|
114
|
+
//# sourceMappingURL=chunk-MJYBPJBA.mjs.map
|
|
115
|
+
//# sourceMappingURL=chunk-MJYBPJBA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/tabs.tsx"],"names":[],"mappings":"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","file":"chunk-MJYBPJBA.mjs","sourcesContent":["'use client';\n\nimport { motion, useReducedMotion, useSpring, useTransform } from 'framer-motion';\nimport { type MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/* ── Tabs ───────────────────────────────────────────────────────────────\n * A segmented control whose active pill slides between tabs and, while an\n * inactive tab is hovered, stretches (\"pulls\") toward the cursor for a\n * magnetic feel. A clipped, inverted duplicate of the labels stays glued to\n * the base labels underneath, so text flips colour exactly as the pill\n * passes over it — including the partial reveal during the pull.\n *\n * Single-select only: it switches one value, so the buttons carry\n * `aria-pressed` rather than the tab/tabpanel roles, which would promise\n * associated panels and arrow-key navigation this control doesn't provide.\n */\n\n/** One segment. `id` is the value handed back to `onChange`. */\nexport type Tab<T extends string = string> = {\n id: T;\n label: string;\n badge?: string;\n};\n\n// How far the pill reaches toward the hovered tab (fraction of the gap).\nconst PULL = 0.035;\n\ntype Rect = { left: number; width: number };\n\n// Target pill rect: the active tab at rest, or stretched toward a hovered\n// neighbour so its leading edge reaches partway across the gap.\nfunction pillTarget(activeIdx: number, hoverIdx: number | null, rects: Rect[], pull: number): Rect {\n const active = rects[activeIdx];\n if (!active) throw new Error(`No rect at index ${activeIdx}`);\n if (hoverIdx === null || hoverIdx === activeIdx) return active;\n\n const hover = rects[hoverIdx];\n if (!hover) return active;\n const activeRight = active.left + active.width;\n const hoverRight = hover.left + hover.width;\n\n const left = Math.min(active.left, active.left + (hover.left - active.left) * pull);\n const right = Math.max(activeRight, activeRight + (hoverRight - activeRight) * pull);\n return { left, width: right - left };\n}\n\n// Shared box so the base labels and the inverted duplicate measure identically.\nconst labelBox = 'flex items-center gap-2.5 px-5 py-1.5 font-semibold text-[13px]';\nconst badgeBox = 'font-bold text-(--color-accent-brand-soft) text-[11px] whitespace-nowrap';\n\nexport type TabsProps<T extends string> = {\n tabs: readonly Tab<T>[];\n value: T;\n onChange: (v: T) => void;\n /** Accessible name for the group, e.g. \"Billing period\". */\n label: string;\n className?: string;\n};\n\nexport function Tabs<T extends string>({ tabs, value, onChange, label, className }: TabsProps<T>) {\n const reduced = useReducedMotion();\n const pull = reduced ? 0 : PULL;\n\n const trackRef = useRef<HTMLDivElement>(null);\n\n const [rects, setRects] = useState<Rect[]>([]);\n const [trackWidth, setTrackWidth] = useState(0);\n const [hovered, setHovered] = useState<number | null>(null);\n const [ready, setReady] = useState(false);\n\n const foundIdx = tabs.findIndex((t) => t.id === value);\n const activeIdx = foundIdx === -1 ? 0 : foundIdx;\n\n const springConfig = reduced ? { stiffness: 700, damping: 60 } : { stiffness: 420, damping: 34, mass: 0.7 };\n const pillLeft = useSpring(0, springConfig);\n const pillWidth = useSpring(0, springConfig);\n const innerX = useTransform(pillLeft, (v) => -v);\n\n const measure = useCallback(() => {\n const track = trackRef.current;\n if (!track) return;\n setTrackWidth(track.offsetWidth);\n const btns = track.querySelectorAll<HTMLButtonElement>('button[data-index]');\n setRects(\n Array.from(btns, (el) => ({\n left: el.offsetLeft,\n width: el.offsetWidth,\n })),\n );\n }, []);\n\n // biome-ignore lint/plugin: measures live DOM layout under a ResizeObserver — post-render measurement, no render-time equivalent.\n useEffect(() => {\n measure();\n const track = trackRef.current;\n if (!track) return;\n const ro = new ResizeObserver(measure);\n ro.observe(track);\n return () => ro.disconnect();\n }, [measure]);\n\n // biome-ignore lint/plugin: imperatively drives the pill's spring motion values toward a layout-derived target.\n useEffect(() => {\n if (rects.length !== tabs.length) return;\n const target = pillTarget(activeIdx, hovered, rects, pull);\n if (ready) {\n pillLeft.set(target.left);\n pillWidth.set(target.width);\n } else {\n pillLeft.jump(target.left);\n pillWidth.jump(target.width);\n setReady(true);\n }\n }, [rects, tabs.length, activeIdx, hovered, pull, ready, pillLeft, pillWidth]);\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLButtonElement>) => onChange(tabs[Number(e.currentTarget.dataset.index)]!.id),\n [onChange, tabs],\n );\n const handleEnter = useCallback((e: MouseEvent<HTMLButtonElement>) => setHovered(Number(e.currentTarget.dataset.index)), []);\n const handleLeave = useCallback(() => setHovered(null), []);\n\n return (\n <fieldset\n aria-label={label}\n className={cn('inline-flex items-center rounded-full border border-(--color-border) bg-(--color-surface) p-1', className)}\n >\n <div ref={trackRef} className=\"relative inline-flex items-center\">\n {/* Base labels — muted at rest; hidden wherever the opaque pill sits over them. */}\n {tabs.map((tab, i) => (\n <button\n key={tab.id}\n type=\"button\"\n data-index={i}\n onClick={handleClick}\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n aria-pressed={value === tab.id}\n className={cn(labelBox, 'text-(--color-muted-foreground) hover:text-(--color-foreground)')}\n >\n {tab.label}\n {tab.badge ? <span className={badgeBox}>{tab.badge}</span> : null}\n </button>\n ))}\n\n {/* Sliding, pulling pill carrying a clipped inverted copy of the labels. */}\n <motion.div\n aria-hidden={true}\n className=\"pointer-events-none absolute inset-y-0 select-none overflow-hidden rounded-full bg-(--color-foreground)\"\n style={{ left: pillLeft, width: pillWidth, opacity: ready ? 1 : 0 }}\n >\n <motion.div className=\"absolute inset-y-0 left-0 flex items-center\" style={{ width: trackWidth, x: innerX }}>\n {tabs.map((tab) => (\n <span key={tab.id} className={cn(labelBox, 'text-(--color-surface)')}>\n {tab.label}\n {tab.badge ? <span className={badgeBox}>{tab.badge}</span> : null}\n </span>\n ))}\n </motion.div>\n </motion.div>\n </div>\n </fieldset>\n );\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/lib/ease.ts
|
|
2
|
+
var easeOut = [0.22, 1, 0.36, 1];
|
|
3
|
+
var easeOutBack = [0.34, 1.56, 0.64, 1];
|
|
4
|
+
var EASE_OUT = [0.16, 1, 0.3, 1];
|
|
5
|
+
var EASE_OUT_CSS = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
6
|
+
var SPRING_SWAP = { type: "spring", stiffness: 460, damping: 30, mass: 0.55 };
|
|
7
|
+
|
|
8
|
+
export { EASE_OUT, EASE_OUT_CSS, SPRING_SWAP, easeOut, easeOutBack };
|
|
9
|
+
//# sourceMappingURL=chunk-NNHPQ67J.mjs.map
|
|
10
|
+
//# sourceMappingURL=chunk-NNHPQ67J.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/ease.ts"],"names":[],"mappings":";AAKO,IAAM,OAAA,GAAU,CAAC,IAAA,EAAM,CAAA,EAAG,MAAM,CAAC;AAGjC,IAAM,WAAA,GAAc,CAAC,IAAA,EAAM,IAAA,EAAM,MAAM,CAAC;AAOxC,IAAM,QAAA,GAAW,CAAC,IAAA,EAAM,CAAA,EAAG,KAAK,CAAC;AAGjC,IAAM,YAAA,GAAe;AAGrB,IAAM,WAAA,GAAc,EAAE,IAAA,EAAM,QAAA,EAAU,WAAW,GAAA,EAAK,OAAA,EAAS,EAAA,EAAI,IAAA,EAAM,IAAA","file":"chunk-NNHPQ67J.mjs","sourcesContent":["/**\n * Easing curves shared across landing-ui components.\n */\n\n/** Smooth deceleration — matches the former CSS `ease-out-expo`. */\nexport const easeOut = [0.22, 1, 0.36, 1] as const;\n\n/** Gentle overshoot — bounce-like settle for spring alternatives. */\nexport const easeOutBack = [0.34, 1.56, 0.64, 1] as const;\n\n// ── Content-swap tokens (action-swap) ─────────────────────────────────────\n// Values mirror beui.dev's `lib/ease.ts` so vendored action-swap primitives\n// keep their upstream timing.\n\n/** Strong ease-out — the default `ease-out` reads weak at these durations. */\nexport const EASE_OUT = [0.16, 1, 0.3, 1] as const;\n\n/** CSS string form of {@link EASE_OUT} for inline style transitions. */\nexport const EASE_OUT_CSS = 'cubic-bezier(0.16, 1, 0.3, 1)';\n\n/** Content swaps — label/icon slots trading places inside a control. */\nexport const SPRING_SWAP = { type: 'spring', stiffness: 460, damping: 30, mass: 0.55 } as const;\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useMediaQuery } from './chunk-EYHT2EWJ.mjs';
|
|
2
|
+
import { cn } from './chunk-QAWSH567.mjs';
|
|
3
|
+
import { motion } from 'framer-motion';
|
|
4
|
+
import { useState, useEffect } from 'react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var STAR_PATH = "M9.82531 0.843845C10.0553 0.215178 10.9446 0.215178 11.1746 0.843845L11.8618 2.72026C12.4006 4.19229 12.3916 6.39157 13.5 7.5C14.6084 8.60843 16.8077 8.59935 18.2797 9.13822L20.1561 9.82534C20.7858 10.0553 20.7858 10.9447 20.1561 11.1747L18.2797 11.8618C16.8077 12.4007 14.6084 12.3916 13.5 13.5C12.3916 14.6084 12.4006 16.8077 11.8618 18.2798L11.1746 20.1562C10.9446 20.7858 10.0553 20.7858 9.82531 20.1562L9.13819 18.2798C8.59932 16.8077 8.60843 14.6084 7.5 13.5C6.39157 12.3916 4.19225 12.4007 2.72023 11.8618L0.843814 11.1747C0.215148 10.9447 0.215148 10.0553 0.843814 9.82534L2.72023 9.13822C4.19225 8.59935 6.39157 8.60843 7.5 7.5C8.60843 6.39157 8.59932 4.19229 9.13819 2.72026L9.82531 0.843845Z";
|
|
8
|
+
var DEFAULT_COLORS = {
|
|
9
|
+
first: "var(--color-accent-brand)",
|
|
10
|
+
second: "var(--color-accent-brand-soft)"
|
|
11
|
+
};
|
|
12
|
+
function SparkleStar({ x, y, color, delay, scale }) {
|
|
13
|
+
return /* @__PURE__ */ jsx(
|
|
14
|
+
motion.svg,
|
|
15
|
+
{
|
|
16
|
+
className: "pointer-events-none absolute z-20",
|
|
17
|
+
initial: { opacity: 0, left: x, top: y },
|
|
18
|
+
animate: {
|
|
19
|
+
opacity: [0, 1, 0],
|
|
20
|
+
scale: [0, scale, 0],
|
|
21
|
+
rotate: [75, 120, 150]
|
|
22
|
+
},
|
|
23
|
+
transition: {
|
|
24
|
+
duration: 0.8,
|
|
25
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
26
|
+
delay
|
|
27
|
+
},
|
|
28
|
+
width: "21",
|
|
29
|
+
height: "21",
|
|
30
|
+
viewBox: "0 0 21 21",
|
|
31
|
+
"aria-hidden": true,
|
|
32
|
+
children: /* @__PURE__ */ jsx("path", { d: STAR_PATH, fill: color })
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
function SparklesText({ children, className, sparklesCount = 10, colors = DEFAULT_COLORS }) {
|
|
37
|
+
const reducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
|
|
38
|
+
const [sparkles, setSparkles] = useState([]);
|
|
39
|
+
const { first, second } = colors;
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (reducedMotion) {
|
|
42
|
+
setSparkles([]);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const spawn = () => ({
|
|
46
|
+
x: `${Math.random() * 100}%`,
|
|
47
|
+
y: `${Math.random() * 100}%`,
|
|
48
|
+
color: Math.random() > 0.5 ? first : second,
|
|
49
|
+
delay: Math.random() * 2,
|
|
50
|
+
scale: Math.random() + 0.3,
|
|
51
|
+
expiresAt: performance.now() + (Math.random() * 10 + 5) * 1e3
|
|
52
|
+
});
|
|
53
|
+
setSparkles(Array.from({ length: sparklesCount }, spawn));
|
|
54
|
+
const interval = setInterval(() => {
|
|
55
|
+
setSparkles((current) => {
|
|
56
|
+
const now = performance.now();
|
|
57
|
+
if (!current.some((sparkle) => sparkle.expiresAt <= now)) return current;
|
|
58
|
+
return current.map((sparkle) => sparkle.expiresAt <= now ? spawn() : sparkle);
|
|
59
|
+
});
|
|
60
|
+
}, 500);
|
|
61
|
+
return () => clearInterval(interval);
|
|
62
|
+
}, [first, second, sparklesCount, reducedMotion]);
|
|
63
|
+
return /* @__PURE__ */ jsxs("span", { className: cn("relative inline-block", className), children: [
|
|
64
|
+
sparkles.map((sparkle) => /* @__PURE__ */ jsx(SparkleStar, { ...sparkle }, `${sparkle.x}-${sparkle.y}-${sparkle.expiresAt}`)),
|
|
65
|
+
children
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { SparklesText };
|
|
70
|
+
//# sourceMappingURL=chunk-OCZFHVVD.mjs.map
|
|
71
|
+
//# sourceMappingURL=chunk-OCZFHVVD.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/sparkles-text.tsx"],"names":[],"mappings":"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","file":"chunk-OCZFHVVD.mjs","sourcesContent":["'use client';\n\nimport { motion } from 'framer-motion';\nimport { type ReactNode, useEffect, useState } from 'react';\nimport { useMediaQuery } from '../lib/use-media-query.js';\nimport { cn } from '../lib/utils.js';\n\n/** Four-pointed star, drawn once and reused by every sparkle. */\nconst STAR_PATH =\n 'M9.82531 0.843845C10.0553 0.215178 10.9446 0.215178 11.1746 0.843845L11.8618 2.72026C12.4006 4.19229 12.3916 6.39157 13.5 7.5C14.6084 8.60843 16.8077 8.59935 18.2797 9.13822L20.1561 9.82534C20.7858 10.0553 20.7858 10.9447 20.1561 11.1747L18.2797 11.8618C16.8077 12.4007 14.6084 12.3916 13.5 13.5C12.3916 14.6084 12.4006 16.8077 11.8618 18.2798L11.1746 20.1562C10.9446 20.7858 10.0553 20.7858 9.82531 20.1562L9.13819 18.2798C8.59932 16.8077 8.60843 14.6084 7.5 13.5C6.39157 12.3916 4.19225 12.4007 2.72023 11.8618L0.843814 11.1747C0.215148 10.9447 0.215148 10.0553 0.843814 9.82534L2.72023 9.13822C4.19225 8.59935 6.39157 8.60843 7.5 7.5C8.60843 6.39157 8.59932 4.19229 9.13819 2.72026L9.82531 0.843845Z';\n\nconst DEFAULT_COLORS = {\n first: 'var(--color-accent-brand)',\n second: 'var(--color-accent-brand-soft)',\n};\n\ntype Sparkle = {\n /** Position within the text's box, as percentages. */\n x: string;\n y: string;\n color: string;\n /** Offsets the twinkle so the group never pulses in unison. */\n delay: number;\n scale: number;\n /** `performance.now()` timestamp after which this sparkle is replaced by a fresh one. */\n expiresAt: number;\n};\n\nfunction SparkleStar({ x, y, color, delay, scale }: Omit<Sparkle, 'expiresAt'>) {\n return (\n <motion.svg\n className=\"pointer-events-none absolute z-20\"\n initial={{ opacity: 0, left: x, top: y }}\n animate={{\n opacity: [0, 1, 0],\n scale: [0, scale, 0],\n rotate: [75, 120, 150],\n }}\n transition={{\n duration: 0.8,\n repeat: Number.POSITIVE_INFINITY,\n delay,\n }}\n width=\"21\"\n height=\"21\"\n viewBox=\"0 0 21 21\"\n aria-hidden={true}\n >\n <path d={STAR_PATH} fill={color} />\n </motion.svg>\n );\n}\n\nexport type SparklesTextProps = {\n /** The text to sparkle. Rendered inline, so it inherits the surrounding type. */\n children: ReactNode;\n className?: string;\n /** How many sparkles orbit the text at once. @default 10 */\n sparklesCount?: number;\n /** The two colors sparkles alternate between. */\n colors?: { first: string; second: string };\n};\n\n/**\n * Wraps a word or phrase in continuously respawning sparkles.\n *\n * Sparkles are generated on the client only — the exported HTML ships the bare\n * text, so nothing about the layout depends on JS having run. Readers who ask\n * for reduced motion get that same bare text.\n */\nexport function SparklesText({ children, className, sparklesCount = 10, colors = DEFAULT_COLORS }: SparklesTextProps) {\n const reducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');\n const [sparkles, setSparkles] = useState<Sparkle[]>([]);\n const { first, second } = colors;\n\n // biome-ignore lint/plugin: spawns and retires sparkles on a timer — an imperative animation loop with no derived-state equivalent.\n useEffect(() => {\n if (reducedMotion) {\n setSparkles([]);\n return;\n }\n\n const spawn = (): Sparkle => ({\n x: `${Math.random() * 100}%`,\n y: `${Math.random() * 100}%`,\n color: Math.random() > 0.5 ? first : second,\n delay: Math.random() * 2,\n scale: Math.random() + 0.3,\n expiresAt: performance.now() + (Math.random() * 10 + 5) * 1000,\n });\n\n setSparkles(Array.from({ length: sparklesCount }, spawn));\n\n const interval = setInterval(() => {\n setSparkles((current) => {\n const now = performance.now();\n if (!current.some((sparkle) => sparkle.expiresAt <= now)) return current;\n return current.map((sparkle) => (sparkle.expiresAt <= now ? spawn() : sparkle));\n });\n }, 500);\n\n return () => clearInterval(interval);\n }, [first, second, sparklesCount, reducedMotion]);\n\n return (\n <span className={cn('relative inline-block', className)}>\n {sparkles.map((sparkle) => (\n <SparkleStar key={`${sparkle.x}-${sparkle.y}-${sparkle.expiresAt}`} {...sparkle} />\n ))}\n {children}\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
// src/lib/utils.ts
|
|
5
|
+
function cn(...inputs) {
|
|
6
|
+
return twMerge(clsx(inputs));
|
|
7
|
+
}
|
|
8
|
+
function validCssVars(style) {
|
|
9
|
+
return style;
|
|
10
|
+
}
|
|
11
|
+
function hasKey(key, obj) {
|
|
12
|
+
return obj !== null && typeof obj === "object" && Object.hasOwn(obj, key);
|
|
13
|
+
}
|
|
14
|
+
function noop() {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { cn, hasKey, noop, validCssVars };
|
|
18
|
+
//# sourceMappingURL=chunk-QAWSH567.mjs.map
|
|
19
|
+
//# sourceMappingURL=chunk-QAWSH567.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts"],"names":[],"mappings":";;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;AAiBO,SAAS,aAAa,KAAA,EAA6C;AACxE,EAAA,OAAO,KAAA;AACT;AAMO,SAAS,MAAA,CAA8B,KAAQ,GAAA,EAAyC;AAC7F,EAAA,OAAO,GAAA,KAAQ,QAAQ,OAAO,GAAA,KAAQ,YAAY,MAAA,CAAO,MAAA,CAAO,KAAK,GAAG,CAAA;AAC1E;AAEO,SAAS,IAAA,GAAa;AAE7B","file":"chunk-QAWSH567.mjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { cn, validCssVars } from './chunk-QAWSH567.mjs';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
function ShineBorder({
|
|
5
|
+
borderWidth = 1,
|
|
6
|
+
duration = 14,
|
|
7
|
+
shineColor = "#000000",
|
|
8
|
+
className,
|
|
9
|
+
style,
|
|
10
|
+
...props
|
|
11
|
+
}) {
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
"div",
|
|
14
|
+
{
|
|
15
|
+
style: validCssVars({
|
|
16
|
+
"--border-width": `${borderWidth}px`,
|
|
17
|
+
"--duration": `${duration}s`,
|
|
18
|
+
backgroundImage: `radial-gradient(transparent,transparent, ${Array.isArray(shineColor) ? shineColor.join(",") : shineColor},transparent,transparent)`,
|
|
19
|
+
backgroundSize: "300% 300%",
|
|
20
|
+
mask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
|
|
21
|
+
WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
|
|
22
|
+
WebkitMaskComposite: "xor",
|
|
23
|
+
maskComposite: "exclude",
|
|
24
|
+
padding: "var(--border-width)",
|
|
25
|
+
...style
|
|
26
|
+
}),
|
|
27
|
+
className: cn(
|
|
28
|
+
"pointer-events-none absolute inset-0 size-full rounded-[inherit] will-change-[background-position] motion-safe:animate-shine",
|
|
29
|
+
className
|
|
30
|
+
),
|
|
31
|
+
...props
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { ShineBorder };
|
|
37
|
+
//# sourceMappingURL=chunk-R2E2J42H.mjs.map
|
|
38
|
+
//# sourceMappingURL=chunk-R2E2J42H.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/shine-border.tsx"],"names":[],"mappings":";;;AAkBO,SAAS,WAAA,CAAY;AAAA,EAC1B,WAAA,GAAc,CAAA;AAAA,EACd,QAAA,GAAW,EAAA;AAAA,EACX,UAAA,GAAa,SAAA;AAAA,EACb,SAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAqB;AACnB,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,OAAO,YAAA,CAAa;AAAA,QAClB,gBAAA,EAAkB,GAAG,WAAW,CAAA,EAAA,CAAA;AAAA,QAChC,YAAA,EAAc,GAAG,QAAQ,CAAA,CAAA,CAAA;AAAA,QACzB,eAAA,EAAiB,CAAA,yCAAA,EACf,KAAA,CAAM,OAAA,CAAQ,UAAU,IAAI,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,GAAI,UACrD,CAAA,yBAAA,CAAA;AAAA,QACA,cAAA,EAAgB,WAAA;AAAA,QAChB,IAAA,EAAM,kEAAA;AAAA,QACN,UAAA,EAAY,kEAAA;AAAA,QACZ,mBAAA,EAAqB,KAAA;AAAA,QACrB,aAAA,EAAe,SAAA;AAAA,QACf,OAAA,EAAS,qBAAA;AAAA,QACT,GAAG;AAAA,OACJ,CAAA;AAAA,MACD,SAAA,EAAW,EAAA;AAAA,QACT,8HAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ","file":"chunk-R2E2J42H.mjs","sourcesContent":["'use client';\n\nimport type { HTMLAttributes } from 'react';\nimport { cn, validCssVars } from '../lib/utils.js';\n\nexport interface ShineBorderProps extends HTMLAttributes<HTMLDivElement> {\n /** Width of the border in pixels. @default 1 */\n borderWidth?: number;\n /** Duration of the animation in seconds. @default 14 */\n duration?: number;\n /** Color of the border — single color or array of colors. @default \"#000000\" */\n shineColor?: string | string[];\n}\n\n/**\n * An animated background-border effect that sits absolutely on top of\n * its positioned parent. Add `relative` to the parent container.\n */\nexport function ShineBorder({\n borderWidth = 1,\n duration = 14,\n shineColor = '#000000',\n className,\n style,\n ...props\n}: ShineBorderProps) {\n return (\n <div\n style={validCssVars({\n '--border-width': `${borderWidth}px`,\n '--duration': `${duration}s`,\n backgroundImage: `radial-gradient(transparent,transparent, ${\n Array.isArray(shineColor) ? shineColor.join(',') : shineColor\n },transparent,transparent)`,\n backgroundSize: '300% 300%',\n mask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',\n WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',\n WebkitMaskComposite: 'xor',\n maskComposite: 'exclude',\n padding: 'var(--border-width)',\n ...style,\n })}\n className={cn(\n 'pointer-events-none absolute inset-0 size-full rounded-[inherit] will-change-[background-position] motion-safe:animate-shine',\n className,\n )}\n {...props}\n />\n );\n}\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { cn } from './chunk-QAWSH567.mjs';
|
|
2
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
3
|
+
import { useSyncExternalStore } from 'react';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var tick = 0;
|
|
7
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
8
|
+
var timer = null;
|
|
9
|
+
function subscribe(onChange) {
|
|
10
|
+
listeners.add(onChange);
|
|
11
|
+
if (timer === null)
|
|
12
|
+
timer = setInterval(() => {
|
|
13
|
+
tick += 1;
|
|
14
|
+
for (const l of listeners) l();
|
|
15
|
+
}, ROTATE_MS);
|
|
16
|
+
return () => {
|
|
17
|
+
listeners.delete(onChange);
|
|
18
|
+
if (listeners.size === 0 && timer !== null) {
|
|
19
|
+
clearInterval(timer);
|
|
20
|
+
timer = null;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
var getSnapshot = () => tick;
|
|
25
|
+
var getServerSnapshot = () => 0;
|
|
26
|
+
var ROTATE_MS = 4e3;
|
|
27
|
+
function RollingBadge({ badges, className }) {
|
|
28
|
+
const index = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) % badges.length;
|
|
29
|
+
const badge = badges[index];
|
|
30
|
+
if (badges.length === 0 || !badge) return null;
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
motion.div,
|
|
33
|
+
{
|
|
34
|
+
layout: true,
|
|
35
|
+
className: cn(
|
|
36
|
+
"relative inline-flex h-8 items-center overflow-hidden rounded-full border border-(--color-border) bg-background px-3.5 shadow-sm",
|
|
37
|
+
className
|
|
38
|
+
),
|
|
39
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "popLayout", children: /* @__PURE__ */ jsxs(
|
|
40
|
+
motion.span,
|
|
41
|
+
{
|
|
42
|
+
layout: "position",
|
|
43
|
+
initial: { y: "120%", opacity: 0 },
|
|
44
|
+
animate: { y: "0%", opacity: 1 },
|
|
45
|
+
exit: { y: "-120%", opacity: 0 },
|
|
46
|
+
transition: {
|
|
47
|
+
type: "spring",
|
|
48
|
+
stiffness: 320,
|
|
49
|
+
damping: 32
|
|
50
|
+
},
|
|
51
|
+
className: "flex items-center gap-1.5 whitespace-nowrap font-medium text-[12.5px]",
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx("span", { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": true, children: badge.icon }),
|
|
54
|
+
badge.label
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
index
|
|
58
|
+
) })
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { RollingBadge };
|
|
64
|
+
//# sourceMappingURL=chunk-TPGLLSYV.mjs.map
|
|
65
|
+
//# sourceMappingURL=chunk-TPGLLSYV.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/rolling-badge.tsx"],"names":[],"mappings":";;;;;AAQA,IAAI,IAAA,GAAO,CAAA;AACX,IAAM,SAAA,uBAAgB,GAAA,EAAgB;AACtC,IAAI,KAAA,GAA+C,IAAA;AAEnD,SAAS,UAAU,QAAA,EAAkC;AACnD,EAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,EAAA,IAAI,KAAA,KAAU,IAAA;AACZ,IAAA,KAAA,GAAQ,YAAY,MAAM;AACxB,MAAA,IAAA,IAAQ,CAAA;AACR,MAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,IAC/B,GAAG,SAAS,CAAA;AACd,EAAA,OAAO,MAAM;AACX,IAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AACzB,IAAA,IAAI,SAAA,CAAU,IAAA,KAAS,CAAA,IAAK,KAAA,KAAU,IAAA,EAAM;AAC1C,MAAA,aAAA,CAAc,KAAK,CAAA;AACnB,MAAA,KAAA,GAAQ,IAAA;AAAA,IACV;AAAA,EACF,CAAA;AACF;AAEA,IAAM,cAAc,MAAM,IAAA;AAC1B,IAAM,oBAAoB,MAAM,CAAA;AAIhC,IAAM,SAAA,GAAY,GAAA;AAYX,SAAS,YAAA,CAAa,EAAE,MAAA,EAAQ,SAAA,EAAU,EAAsB;AACrE,EAAA,MAAM,QAAQ,oBAAA,CAAqB,SAAA,EAAW,WAAA,EAAa,iBAAiB,IAAI,MAAA,CAAO,MAAA;AACvF,EAAA,MAAM,KAAA,GAAQ,OAAO,KAAK,CAAA;AAE1B,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,IAAK,CAAC,OAAO,OAAO,IAAA;AAE1C,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA,CAAO,GAAA;AAAA,IAAP;AAAA,MACC,MAAA,EAAQ,IAAA;AAAA,MACR,SAAA,EAAW,EAAA;AAAA,QACT,kIAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,kBAAA,GAAA,CAAC,eAAA,EAAA,EAAgB,OAAA,EAAS,KAAA,EAAO,MAAK,WAAA,EACpC,QAAA,kBAAA,IAAA;AAAA,QAAC,MAAA,CAAO,IAAA;AAAA,QAAP;AAAA,UAEC,MAAA,EAAO,UAAA;AAAA,UACP,OAAA,EAAS,EAAE,CAAA,EAAG,MAAA,EAAQ,SAAS,CAAA,EAAE;AAAA,UACjC,OAAA,EAAS,EAAE,CAAA,EAAG,IAAA,EAAM,SAAS,CAAA,EAAE;AAAA,UAC/B,IAAA,EAAM,EAAE,CAAA,EAAG,OAAA,EAAS,SAAS,CAAA,EAAE;AAAA,UAC/B,UAAA,EAAY;AAAA,YACV,IAAA,EAAM,QAAA;AAAA,YACN,SAAA,EAAW,GAAA;AAAA,YACX,OAAA,EAAS;AAAA,WACX;AAAA,UACA,SAAA,EAAU,uEAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,UAAK,SAAA,EAAU,sBAAA,EAAuB,aAAA,EAAa,IAAA,EACjD,gBAAM,IAAA,EACT,CAAA;AAAA,YACC,KAAA,CAAM;AAAA;AAAA,SAAA;AAAA,QAfF;AAAA,OAgBP,EACF;AAAA;AAAA,GACF;AAEJ","file":"chunk-TPGLLSYV.mjs","sourcesContent":["'use client';\n\nimport { AnimatePresence, motion } from 'framer-motion';\nimport { type ReactNode, useSyncExternalStore } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/* ── One-shot ticking store ─────────────────────────────── */\n\nlet tick = 0;\nconst listeners = new Set<() => void>();\nlet timer: ReturnType<typeof setInterval> | null = null;\n\nfunction subscribe(onChange: () => void): () => void {\n listeners.add(onChange);\n if (timer === null)\n timer = setInterval(() => {\n tick += 1;\n for (const l of listeners) l();\n }, ROTATE_MS);\n return () => {\n listeners.delete(onChange);\n if (listeners.size === 0 && timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n };\n}\n\nconst getSnapshot = () => tick;\nconst getServerSnapshot = () => 0;\n\n/* ── Component ──────────────────────────────────────────── */\n\nconst ROTATE_MS = 4000;\n\nexport type BadgeEntry = {\n icon: ReactNode;\n label: string;\n};\n\nexport type RollingBadgeProps = {\n badges: BadgeEntry[];\n className?: string;\n};\n\nexport function RollingBadge({ badges, className }: RollingBadgeProps) {\n const index = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) % badges.length;\n const badge = badges[index];\n\n if (badges.length === 0 || !badge) return null;\n\n return (\n <motion.div\n layout={true}\n className={cn(\n 'relative inline-flex h-8 items-center overflow-hidden rounded-full border border-(--color-border) bg-background px-3.5 shadow-sm',\n className,\n )}\n >\n <AnimatePresence initial={false} mode=\"popLayout\">\n <motion.span\n key={index}\n layout=\"position\"\n initial={{ y: '120%', opacity: 0 }}\n animate={{ y: '0%', opacity: 1 }}\n exit={{ y: '-120%', opacity: 0 }}\n transition={{\n type: 'spring',\n stiffness: 320,\n damping: 32,\n }}\n className=\"flex items-center gap-1.5 whitespace-nowrap font-medium text-[12.5px]\"\n >\n <span className=\"h-3.5 w-3.5 shrink-0\" aria-hidden={true}>\n {badge.icon}\n </span>\n {badge.label}\n </motion.span>\n </AnimatePresence>\n </motion.div>\n );\n}\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Input } from './chunk-W22G7XHR.mjs';
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
function PasswordInput({ inputType = "password", ...props }) {
|
|
6
|
+
const [visible, setVisible] = useState(false);
|
|
7
|
+
const toggle = useCallback(() => setVisible((v) => !v), []);
|
|
8
|
+
const eye = /* @__PURE__ */ jsx(
|
|
9
|
+
"button",
|
|
10
|
+
{
|
|
11
|
+
type: "button",
|
|
12
|
+
onClick: toggle,
|
|
13
|
+
className: "pointer-events-auto cursor-pointer text-(--color-muted-foreground) hover:text-(--color-foreground)",
|
|
14
|
+
"aria-label": visible ? "Hide password" : "Show password",
|
|
15
|
+
tabIndex: -1,
|
|
16
|
+
children: visible ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "size-5" }) : /* @__PURE__ */ jsx(EyeIcon, { className: "size-5" })
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
return /* @__PURE__ */ jsx(
|
|
20
|
+
Input,
|
|
21
|
+
{
|
|
22
|
+
...props,
|
|
23
|
+
inputType: visible ? "text" : "password",
|
|
24
|
+
rightAdornment: eye,
|
|
25
|
+
autoComplete: inputType === "new-password" ? "new-password" : "current-password"
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function EyeIcon(props) {
|
|
30
|
+
return /* @__PURE__ */ jsxs(
|
|
31
|
+
"svg",
|
|
32
|
+
{
|
|
33
|
+
"aria-hidden": "true",
|
|
34
|
+
viewBox: "0 0 24 24",
|
|
35
|
+
fill: "none",
|
|
36
|
+
stroke: "currentColor",
|
|
37
|
+
strokeWidth: "2",
|
|
38
|
+
strokeLinecap: "round",
|
|
39
|
+
strokeLinejoin: "round",
|
|
40
|
+
...props,
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
|
|
43
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" })
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
function EyeOffIcon(props) {
|
|
49
|
+
return /* @__PURE__ */ jsxs(
|
|
50
|
+
"svg",
|
|
51
|
+
{
|
|
52
|
+
"aria-hidden": "true",
|
|
53
|
+
viewBox: "0 0 24 24",
|
|
54
|
+
fill: "none",
|
|
55
|
+
stroke: "currentColor",
|
|
56
|
+
strokeWidth: "2",
|
|
57
|
+
strokeLinecap: "round",
|
|
58
|
+
strokeLinejoin: "round",
|
|
59
|
+
...props,
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsx("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
|
|
62
|
+
/* @__PURE__ */ jsx("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
|
|
63
|
+
/* @__PURE__ */ jsx("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
|
|
64
|
+
/* @__PURE__ */ jsx("path", { d: "m2 2 20 20" })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { PasswordInput };
|
|
71
|
+
//# sourceMappingURL=chunk-VJENJHXJ.mjs.map
|
|
72
|
+
//# sourceMappingURL=chunk-VJENJHXJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/password-input.tsx"],"names":[],"mappings":";;;;AASO,SAAS,cAAc,EAAE,SAAA,GAAY,UAAA,EAAY,GAAG,OAAM,EAAuB;AACtF,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAE5C,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAM,UAAA,CAAW,CAAC,MAAM,CAAC,CAAC,CAAA,EAAG,EAAE,CAAA;AAE1D,EAAA,MAAM,GAAA,mBACJ,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,MAAA;AAAA,MACT,SAAA,EAAU,oGAAA;AAAA,MACV,YAAA,EAAY,UAAU,eAAA,GAAkB,eAAA;AAAA,MACxC,QAAA,EAAU,EAAA;AAAA,MAET,QAAA,EAAA,OAAA,uBAAW,UAAA,EAAA,EAAW,SAAA,EAAU,UAAS,CAAA,mBAAK,GAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAU,QAAA,EAAS;AAAA;AAAA,GAC7E;AAGF,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,UAAU,MAAA,GAAS,UAAA;AAAA,MAC9B,cAAA,EAAgB,GAAA;AAAA,MAChB,YAAA,EAAc,SAAA,KAAc,cAAA,GAAiB,cAAA,GAAiB;AAAA;AAAA,GAChE;AAEJ;AAEA,SAAS,QAAQ,KAAA,EAAoC;AACnD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,MAAA;AAAA,MACZ,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,MAAA,EAAO,cAAA;AAAA,MACP,WAAA,EAAY,GAAA;AAAA,MACZ,aAAA,EAAc,OAAA;AAAA,MACd,cAAA,EAAe,OAAA;AAAA,MACd,GAAG,KAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,uGAAA,EAAwG,CAAA;AAAA,4BAC/G,QAAA,EAAA,EAAO,EAAA,EAAG,MAAK,EAAA,EAAG,IAAA,EAAK,GAAE,GAAA,EAAI;AAAA;AAAA;AAAA,GAChC;AAEJ;AAEA,SAAS,WAAW,KAAA,EAAoC;AACtD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,MAAA;AAAA,MACZ,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,MAAA,EAAO,cAAA;AAAA,MACP,WAAA,EAAY,GAAA;AAAA,MACZ,aAAA,EAAc,OAAA;AAAA,MACd,cAAA,EAAe,OAAA;AAAA,MACd,GAAG,KAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,gGAAA,EAAiG,CAAA;AAAA,wBACzG,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,sCAAA,EAAuC,CAAA;AAAA,wBAC/C,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,8FAAA,EAA+F,CAAA;AAAA,wBACvG,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,YAAA,EAAa;AAAA;AAAA;AAAA,GACvB;AAEJ","file":"chunk-VJENJHXJ.mjs","sourcesContent":["'use client';\n\nimport { useCallback, useState } from 'react';\nimport { Input, type InputProps } from './input.js';\n\nexport type PasswordInputProps = Omit<InputProps, 'rightAdornment' | 'inputType'> & {\n inputType?: 'password' | 'new-password';\n};\n\nexport function PasswordInput({ inputType = 'password', ...props }: PasswordInputProps) {\n const [visible, setVisible] = useState(false);\n\n const toggle = useCallback(() => setVisible((v) => !v), []);\n\n const eye = (\n <button\n type=\"button\"\n onClick={toggle}\n className=\"pointer-events-auto cursor-pointer text-(--color-muted-foreground) hover:text-(--color-foreground)\"\n aria-label={visible ? 'Hide password' : 'Show password'}\n tabIndex={-1}\n >\n {visible ? <EyeOffIcon className=\"size-5\" /> : <EyeIcon className=\"size-5\" />}\n </button>\n );\n\n return (\n <Input\n {...props}\n inputType={visible ? 'text' : 'password'}\n rightAdornment={eye}\n autoComplete={inputType === 'new-password' ? 'new-password' : 'current-password'}\n />\n );\n}\n\nfunction EyeIcon(props: React.ComponentProps<'svg'>) {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n );\n}\n\nfunction EyeOffIcon(props: React.ComponentProps<'svg'>) {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { cn } from './chunk-QAWSH567.mjs';
|
|
2
|
+
import { useId, useState } from 'react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var FIELD_BORDER = {
|
|
6
|
+
idle: "border-(--color-border)",
|
|
7
|
+
focused: "border-(--color-foreground)/40",
|
|
8
|
+
error: "border-(--color-destructive)"
|
|
9
|
+
};
|
|
10
|
+
var FIELD_HEIGHT = {
|
|
11
|
+
sm: "h-8",
|
|
12
|
+
md: "h-9",
|
|
13
|
+
lg: "h-11"
|
|
14
|
+
};
|
|
15
|
+
var FIELD_SHAPE = {
|
|
16
|
+
rounded: "rounded-lg",
|
|
17
|
+
pill: "rounded-full"
|
|
18
|
+
};
|
|
19
|
+
var INPUT_SIZE = {
|
|
20
|
+
sm: "text-xs",
|
|
21
|
+
md: "text-sm",
|
|
22
|
+
lg: "text-base"
|
|
23
|
+
};
|
|
24
|
+
var INPUT_PAD = {
|
|
25
|
+
sm: "px-2.5",
|
|
26
|
+
md: "px-3",
|
|
27
|
+
lg: "px-3.5"
|
|
28
|
+
};
|
|
29
|
+
function Input({
|
|
30
|
+
label,
|
|
31
|
+
error,
|
|
32
|
+
hint,
|
|
33
|
+
leftAdornment,
|
|
34
|
+
rightAdornment,
|
|
35
|
+
size = "md",
|
|
36
|
+
shape = "rounded",
|
|
37
|
+
className,
|
|
38
|
+
inputClassName,
|
|
39
|
+
inputType = "text",
|
|
40
|
+
id: idProp,
|
|
41
|
+
onFocus,
|
|
42
|
+
onBlur,
|
|
43
|
+
disabled,
|
|
44
|
+
autoFocus,
|
|
45
|
+
...inputProps
|
|
46
|
+
}) {
|
|
47
|
+
const autoId = useId();
|
|
48
|
+
const id = idProp ?? autoId;
|
|
49
|
+
const [focused, setFocused] = useState(false);
|
|
50
|
+
const hasError = Boolean(error);
|
|
51
|
+
const errorMessage = typeof error === "string" ? error : null;
|
|
52
|
+
const state = hasError ? "error" : focused ? "focused" : "idle";
|
|
53
|
+
const hasLeft = Boolean(leftAdornment);
|
|
54
|
+
const hasRight = Boolean(rightAdornment);
|
|
55
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
|
|
56
|
+
label ? /* @__PURE__ */ jsx("label", { htmlFor: id, className: "px-1 font-medium text-(--color-foreground) text-sm", children: label }) : null,
|
|
57
|
+
/* @__PURE__ */ jsxs(
|
|
58
|
+
"div",
|
|
59
|
+
{
|
|
60
|
+
className: cn(
|
|
61
|
+
"relative flex flex-row items-center overflow-hidden border",
|
|
62
|
+
FIELD_BORDER[state],
|
|
63
|
+
FIELD_HEIGHT[size],
|
|
64
|
+
FIELD_SHAPE[shape],
|
|
65
|
+
disabled && "opacity-60"
|
|
66
|
+
),
|
|
67
|
+
children: [
|
|
68
|
+
hasLeft ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute top-0 bottom-0 left-3 z-10 flex items-center justify-center", children: leftAdornment }) : null,
|
|
69
|
+
/* @__PURE__ */ jsx(
|
|
70
|
+
"input",
|
|
71
|
+
{
|
|
72
|
+
id,
|
|
73
|
+
type: inputType,
|
|
74
|
+
disabled,
|
|
75
|
+
autoFocus,
|
|
76
|
+
onFocus: (event_) => {
|
|
77
|
+
setFocused(true);
|
|
78
|
+
onFocus?.(event_);
|
|
79
|
+
},
|
|
80
|
+
onBlur: (event_) => {
|
|
81
|
+
setFocused(false);
|
|
82
|
+
onBlur?.(event_);
|
|
83
|
+
},
|
|
84
|
+
className: cn(
|
|
85
|
+
"h-full min-w-0 flex-1 bg-transparent text-(--color-foreground) outline-none",
|
|
86
|
+
INPUT_SIZE[size],
|
|
87
|
+
hasLeft ? "pl-10" : INPUT_PAD[size],
|
|
88
|
+
hasRight ? "pr-10" : INPUT_PAD[size],
|
|
89
|
+
inputClassName
|
|
90
|
+
),
|
|
91
|
+
...inputProps
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
hasRight ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute top-0 right-3 bottom-0 z-10 flex items-center justify-center", children: rightAdornment }) : null
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
),
|
|
98
|
+
errorMessage ? /* @__PURE__ */ jsx("p", { role: "alert", className: "px-1 text-(--color-destructive) text-xs", children: errorMessage }) : hint ? /* @__PURE__ */ jsx("p", { className: "px-1 text-(--color-muted-foreground) text-xs", children: hint }) : null
|
|
99
|
+
] });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { Input };
|
|
103
|
+
//# sourceMappingURL=chunk-W22G7XHR.mjs.map
|
|
104
|
+
//# sourceMappingURL=chunk-W22G7XHR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/input.tsx"],"names":[],"mappings":"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","file":"chunk-W22G7XHR.mjs","sourcesContent":["'use client';\n\nimport { type InputHTMLAttributes, type ReactNode, useId, useState } from 'react';\nimport { cn } from '../lib/utils.js';\n\nconst FIELD_BORDER: Record<string, string> = {\n idle: 'border-(--color-border)',\n focused: 'border-(--color-foreground)/40',\n error: 'border-(--color-destructive)',\n};\n\nconst FIELD_HEIGHT: Record<string, string> = {\n sm: 'h-8',\n md: 'h-9',\n lg: 'h-11',\n};\n\nconst FIELD_SHAPE: Record<string, string> = {\n rounded: 'rounded-lg',\n pill: 'rounded-full',\n};\n\nconst INPUT_SIZE: Record<string, string> = {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n};\n\nconst INPUT_PAD: Record<string, string> = {\n sm: 'px-2.5',\n md: 'px-3',\n lg: 'px-3.5',\n};\n\nexport type InputProps = {\n label?: string;\n error?: string | boolean;\n hint?: string;\n leftAdornment?: ReactNode;\n rightAdornment?: ReactNode;\n size?: 'sm' | 'md' | 'lg';\n shape?: 'rounded' | 'pill';\n className?: string;\n inputClassName?: string;\n inputType?: InputHTMLAttributes<HTMLInputElement>['type'];\n} & Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'>;\n\nexport function Input({\n label,\n error,\n hint,\n leftAdornment,\n rightAdornment,\n size = 'md',\n shape = 'rounded',\n className,\n inputClassName,\n inputType = 'text',\n id: idProp,\n onFocus,\n onBlur,\n disabled,\n autoFocus,\n ...inputProps\n}: InputProps) {\n const autoId = useId();\n const id = idProp ?? autoId;\n const [focused, setFocused] = useState(false);\n const hasError = Boolean(error);\n const errorMessage = typeof error === 'string' ? error : null;\n const state = hasError ? 'error' : focused ? 'focused' : 'idle';\n const hasLeft = Boolean(leftAdornment);\n const hasRight = Boolean(rightAdornment);\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)}>\n {label ? (\n <label htmlFor={id} className=\"px-1 font-medium text-(--color-foreground) text-sm\">\n {label}\n </label>\n ) : null}\n\n <div\n className={cn(\n 'relative flex flex-row items-center overflow-hidden border',\n FIELD_BORDER[state],\n FIELD_HEIGHT[size],\n FIELD_SHAPE[shape],\n disabled && 'opacity-60',\n )}\n >\n {hasLeft ? (\n <div className=\"pointer-events-none absolute top-0 bottom-0 left-3 z-10 flex items-center justify-center\">\n {leftAdornment}\n </div>\n ) : null}\n\n <input\n id={id}\n type={inputType}\n disabled={disabled}\n // biome-ignore lint/a11y/noAutofocus: forwarded HTML attribute — callers decide whether to autofocus\n autoFocus={autoFocus}\n onFocus={(event_) => {\n setFocused(true);\n onFocus?.(event_);\n }}\n onBlur={(event_) => {\n setFocused(false);\n onBlur?.(event_);\n }}\n className={cn(\n 'h-full min-w-0 flex-1 bg-transparent text-(--color-foreground) outline-none',\n INPUT_SIZE[size],\n hasLeft ? 'pl-10' : INPUT_PAD[size],\n hasRight ? 'pr-10' : INPUT_PAD[size],\n inputClassName,\n )}\n {...inputProps}\n />\n\n {hasRight ? (\n <div className=\"pointer-events-none absolute top-0 right-3 bottom-0 z-10 flex items-center justify-center\">\n {rightAdornment}\n </div>\n ) : null}\n </div>\n\n {errorMessage ? (\n <p role=\"alert\" className=\"px-1 text-(--color-destructive) text-xs\">\n {errorMessage}\n </p>\n ) : hint ? (\n <p className=\"px-1 text-(--color-muted-foreground) text-xs\">{hint}</p>\n ) : null}\n </div>\n );\n}\n"]}
|