liquidify-react
Version:
🚀 Production-ready React component library inspired by Apple's new design language post-WWDC 2025. Built with Panda CSS and React, using Bun as runtime (npm compatible). Helps developers maintain design consistency for Apple platform apps. 47+ components
383 lines (382 loc) • 10.7 kB
JavaScript
import { jsxs as me, jsx as R } from "react/jsx-runtime";
import { useSpring as P, useMotionValue as N, useTransform as D, motion as fe } from "framer-motion";
import { useCallback as h, useState as Y, useEffect as F, useRef as ge, forwardRef as he, useMemo as _e } from "react";
import { d as j, u as q, s as K, b as be, e as Me, c as U, f as ve, h as ye, i as we, w as Ee, m as Ce } from "./cva-CMV13orU.mjs";
import { c as T } from "./cx-DSqNu2Ai.mjs";
const Se = (e, o, n) => {
const i = (t) => ({
[e]: "__ignore__",
...o,
...be(t)
});
return {
recipeFn: (t, a = !0) => {
const m = Me({
conditions: {
shift: ye,
finalize: ve,
breakpoints: { keys: ["base"] }
},
utility: {
toHash: (c, l) => l(c.join(":")),
transform: (c, l) => (we(e, n, t, c), l === "__ignore__" ? { className: e } : (l = Ee(l), { className: `${e}--${c}_${l}` }))
}
}), u = i(t);
if (a) {
const c = j(
n,
u
);
return T(m(u), U(c));
}
return m(u);
},
getVariantProps: i,
__getCompoundVariantCss__: (t) => j(n, i(t))
};
}, Pe = (e, o) => {
if (e && !o) return e;
if (!e && o) return o;
const n = (...t) => T(e(...t), o(...t)), i = q(e.variantKeys, o.variantKeys), s = i.reduce((t, a) => (t[a] = q(e.variantMap[a], o.variantMap[a]), t), {});
return Object.assign(n, {
__recipe__: !0,
__name__: `${e.__name__} ${o.__name__}`,
raw: (t) => t,
variantKeys: i,
variantMap: s,
splitVariantProps(t) {
return K(t, i);
}
});
}, L = /* @__PURE__ */ Se(
"liquid-button",
{
variant: "primary",
size: "md"
},
[]
), B = {
variant: ["primary", "secondary", "ghost", "danger", "success", "warning"],
size: ["sm", "md", "lg", "xl"]
}, I = Object.keys(B), Re = /* @__PURE__ */ Object.assign(Ce(L.recipeFn), {
__recipe__: !0,
__name__: "button",
__getCompoundVariantCss__: L.__getCompoundVariantCss__,
raw: (e) => e,
variantKeys: I,
variantMap: B,
merge(e) {
return Pe(this, e);
},
splitVariantProps(e) {
return K(e, I);
},
getVariantProps: L.getVariantProps
});
function Ve(e = !0) {
return e ? U({
_focusVisible: {
outline: "none",
boxShadow: "0 0 0 3px color-mix(in oklch, var(--colors-accent-dynamic) 35%, transparent)",
borderColor: "token(colors.accent.dynamic)"
}
}) : "";
}
function X(e = "hover") {
return {
hover: "liquid-flow",
active: "liquid-pressed",
focus: "liquid-flow"
}[e];
}
Object.assign(X, {
gentle: X("hover"),
interactive: "liquid-flow",
smooth: "liquid-flow"
});
const xe = (e = {}) => {
const {
stiffness: o = 350,
// Enhanced for more Apple-like responsiveness
damping: n = 22,
// Optimized for smooth settle
rippleColor: i = "rgba(255,255,255,0.3)",
onTap: s
} = e, t = Ne(), a = P(1, {
stiffness: t ? 0 : o,
damping: t ? 0 : n,
mass: t ? 0 : 0.9,
// Add mass for more realistic physics feel
restDelta: 1e-3
// Fine-tuned settling threshold
}), r = P(0, {
stiffness: t ? 0 : o * 0.8,
damping: t ? 0 : n * 1.1,
mass: t ? 0 : 0.8
}), m = N(0), u = N(0), c = N(1), l = D(c, [0, 1], ["0%", "200%"]), M = D(c, [0, 1], [0, 1]), _ = h(
(b) => {
if (t || !s) return;
const f = b.currentTarget.getBoundingClientRect(), v = "touches" in b ? b.touches[0]?.clientX ?? 0 : b.clientX, g = "touches" in b ? b.touches[0]?.clientY ?? 0 : b.clientY;
m.set(v - f.left), u.set(g - f.top), c.set(1), c.set(0), s();
},
[t, s, m, u, c]
), E = h(() => {
t || (a.set(1.025), r.set(-1.5));
}, [a, r, t]), C = h(() => {
t || (a.set(1), r.set(0));
}, [a, r, t]), S = h(() => {
t || (a.set(0.955), r.set(0.5));
}, [a, r, t]), d = h(() => {
t || (a.set(1.025), r.set(-1.5));
}, [a, r, t]);
return {
scale: a,
// Use in motion.div style={{ scale }}
y: r,
// Use in motion.div style={{ y }}
ripple: {
createRippleProps: () => ({
style: {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background: `radial-gradient(circle, ${i} 0%, transparent 70%)`,
scale: M,
opacity: c,
borderRadius: "inherit",
pointerEvents: "none"
},
initial: { scale: 0, opacity: 0 },
transition: { duration: 0.3, ease: "easeOut" }
}),
handleTap: _,
// Motion values for direct use
x: m,
y: u,
opacity: c,
size: l,
scale: M
},
interactions: {
onHoverStart: E,
onHoverEnd: C,
onPressStart: S,
onPressEnd: d
},
reducedMotion: t
};
}, Ne = () => {
const [e, o] = Y(!1);
return F(() => {
const n = window.matchMedia("(prefers-reduced-motion: reduce)");
o(n.matches);
const i = (s) => o(s.matches);
return n.addEventListener("change", i), () => n.removeEventListener("change", i);
}, []), e;
}, Le = () => {
const [e, o] = Y(!1);
return F(() => {
const n = window.matchMedia("(prefers-reduced-motion: reduce)");
o(n.matches);
const i = (s) => o(s.matches);
return n.addEventListener("change", i), () => n.removeEventListener("change", i);
}, []), e;
}, Te = (e = {}) => {
const { strength: o = 0.3, disabled: n = !1 } = e, i = ge(null), s = Le(), t = P(0, { stiffness: 150, damping: 15 }), a = P(0, { stiffness: 150, damping: 15 }), r = P(1, { stiffness: 300, damping: 20 }), m = h(
(l) => {
if (n || !i.current || s) return;
const _ = i.current.getBoundingClientRect(), E = _.left + _.width / 2, C = _.top + _.height / 2, S = (l.clientX - E) * o, d = (l.clientY - C) * o;
t.set(S), a.set(d), r.set(1.05);
},
[n, o, t, a, r, s]
), u = h(() => {
n || s || (t.set(0), a.set(0), r.set(1));
}, [n, t, a, r, s]), c = h(() => {
n || s || r.set(1.02);
}, [n, r, s]);
return {
ref: i,
style: { x: t, y: a, scale: r },
handlers: {
onMouseMove: m,
onMouseLeave: u,
onMouseEnter: c
}
};
};
function He(e) {
switch (e) {
case "compact":
return "sm";
case "regular":
return "md";
case "large":
return "lg";
case "sm":
case "md":
case "lg":
case "xl":
return e;
default:
return "md";
}
}
function Q(e) {
return e === "primary" || e === "secondary" || e === "ghost" || e === "danger" || e === "success" || e === "warning";
}
function ze(e, o = "accent") {
if (Q(e)) return e;
switch (e) {
case "filled":
case "tinted":
case "plain":
return e;
default:
return "filled";
}
}
function V(e) {
return e === "button";
}
const Oe = he(function(o, n) {
const {
as: i,
variant: s = "filled",
tone: t = "accent",
size: a = "regular",
icon: r,
iconPosition: m = "start",
loading: u = !1,
disabled: c = !1,
className: l,
children: M,
"aria-label": _,
onClick: E,
role: C,
tabIndex: S,
magneticHover: d = !0,
magneticStrength: H = 0.3,
...b
} = o, f = i || "button", v = !!c || !!u, g = xe({
stiffness: 350,
damping: 22,
onTap: E ? () => {
} : void 0
// Enable tap effects when clickable
}), y = Te({
strength: H,
disabled: v || !d
}), G = h(
(p) => {
y.ref.current !== p && (y.ref.current = p), typeof n == "function" ? n(p) : n && "current" in n && (n.current = p);
},
[n, y.ref]
);
Q(s) && typeof process < "u" && process.env?.NODE_ENV !== "production" && console.warn(
`[Button] Legacy variant value "${s}" is deprecated. Use ${s === "primary" ? 'variant="filled" tone="accent"' : s === "secondary" ? 'variant="tinted" tone="neutral"' : s === "ghost" ? 'variant="plain" tone="neutral"' : s === "danger" ? 'variant="filled" tone="destructive"' : s === "success" ? 'variant="filled" tone="accent"' : s === "warning" ? 'variant="tinted" tone="accent"' : ""}.`
);
const W = ze(s, t), J = He(a), z = !M && !!r;
z && !_ && typeof process < "u" && process.env?.NODE_ENV !== "production" && console.warn(
"[Button] Icon-only buttons must include an accessible name via `aria-label`."
);
const Z = {
"aria-busy": u || void 0,
"aria-disabled": !V(f) && v ? !0 : void 0,
"data-loading": u ? "" : void 0,
"data-icon-only": z ? "" : void 0,
"data-tone": t
}, A = (p) => {
if (v) {
p.preventDefault(), p.stopPropagation();
return;
}
E?.(p);
}, ee = !V(f) && !C ? "button" : C, te = !V(f) && S == null ? v ? -1 : 0 : S, ne = _e(
() => d ? fe(f) : f,
[d, f]
), w = h(
(p, $, k) => p || $ || k ? (x) => {
p?.(x), $?.(x), k?.(x);
} : void 0,
[]
), {
onMouseMove: O,
onMouseEnter: se,
onMouseLeave: oe,
onMouseDown: re,
onMouseUp: ae,
onTouchStart: ie,
onTouchEnd: ce,
style: ue,
...le
} = b, de = {
// Magnetic hover handlers (if enabled)
onMouseMove: d ? w(O, y.handlers.onMouseMove) : O,
onMouseEnter: w(
se,
d ? y.handlers.onMouseEnter : void 0,
g.interactions.onHoverStart
),
onMouseLeave: w(
oe,
d ? y.handlers.onMouseLeave : void 0,
g.interactions.onHoverEnd
),
// Enhanced spring physics for press interactions
onMouseDown: w(
re,
g.interactions.onPressStart
),
onMouseUp: w(
ae,
g.interactions.onPressEnd
),
onTouchStart: w(
ie,
g.interactions.onPressStart
),
onTouchEnd: w(
ce,
g.interactions.onPressEnd
)
}, pe = {
...ue,
...d ? y.style : {},
// Add enhanced spring physics to all buttons
scale: g.scale,
y: g.y
};
return /* @__PURE__ */ me(
ne,
{
ref: d ? G : n,
style: pe,
className: T(
Re({ variant: W, tone: t, size: J }),
Ve(!0),
l
),
disabled: V(f) ? v : void 0,
onClick: A,
role: ee,
tabIndex: te,
"aria-label": _,
...Z,
...le,
...de,
children: [
r && m === "start" ? /* @__PURE__ */ R("span", { "aria-hidden": "true", className: "btn__icon btn__icon--start", children: r }) : null,
M ? /* @__PURE__ */ R("span", { className: "btn__label", children: M }) : null,
r && m === "end" ? /* @__PURE__ */ R("span", { "aria-hidden": "true", className: "btn__icon btn__icon--end", children: r }) : null,
u ? /* @__PURE__ */ R("span", { "aria-hidden": "true", className: "btn__spinner" }) : null
]
}
);
});
Oe.displayName = "Button";
export {
Oe as B
};
//# sourceMappingURL=button-Cxh3vJQ6.mjs.map