@a4ui/core 0.15.0 → 0.16.0
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 +12 -12
- package/dist/Checkbox-B5Gb3h5J.js +400 -0
- package/dist/commerce.js +1 -1
- package/dist/elements.iife.js +2 -2
- package/dist/elements.js +2919 -2848
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2132 -2349
- package/dist/ui/Button.d.ts +7 -0
- package/dist/ui/Card.d.ts +15 -1
- package/dist/ui/Ripple.d.ts +14 -1
- package/dist/ui/Spotlight.d.ts +15 -2
- package/dist/ui/TiltCard.d.ts +14 -1
- package/package.json +1 -1
- package/src/index.ts +4 -4
- package/src/ui/Button.tsx +24 -2
- package/src/ui/Card.tsx +32 -3
- package/src/ui/Ripple.tsx +64 -75
- package/src/ui/Spotlight.tsx +51 -40
- package/src/ui/TiltCard.tsx +51 -42
- package/dist/Checkbox-DQcDOBLd.js +0 -168
package/src/ui/TiltCard.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// TiltCard — tilts its wrapped content in 3D toward the cursor on hover, like
|
|
2
|
-
// a card catching the light. The
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
2
|
+
// a card catching the light. The tilt is a direct transform smoothed by a CSS
|
|
3
|
+
// transition (engine-free — no `motion` dependency), which keeps it cheap
|
|
4
|
+
// enough for <Card tilt> to bake in without growing every Card consumer's
|
|
5
|
+
// bundle. No-op (static) under reduced motion.
|
|
6
6
|
import { onCleanup, onMount, type JSX } from 'solid-js'
|
|
7
7
|
|
|
8
8
|
import { cn } from '../lib/cn'
|
|
9
|
-
import {
|
|
9
|
+
import { motionReduced } from '../lib/motion'
|
|
10
10
|
|
|
11
11
|
export interface TiltCardProps {
|
|
12
12
|
children: JSX.Element
|
|
@@ -15,12 +15,54 @@ export interface TiltCardProps {
|
|
|
15
15
|
class?: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Binds a cursor-following 3D tilt: pointer moves over `listenEl` rotate
|
|
20
|
+
* `animEl` toward the cursor (clamped to `max` degrees) with a slight lift,
|
|
21
|
+
* easing back flat on pointerleave. Returns a cleanup that unbinds and clears
|
|
22
|
+
* the transform. Engine-free (CSS transitions); no-op under reduced motion.
|
|
23
|
+
* This is the primitive behind {@link TiltCard} and `<Card tilt>` — pass the
|
|
24
|
+
* same element twice to tilt the element the pointer is over.
|
|
25
|
+
*/
|
|
26
|
+
export function attachTilt(
|
|
27
|
+
listenEl: HTMLElement,
|
|
28
|
+
animEl: HTMLElement,
|
|
29
|
+
opts: { max?: number } = {},
|
|
30
|
+
): () => void {
|
|
31
|
+
if (motionReduced()) return () => {}
|
|
32
|
+
animEl.style.willChange = 'transform'
|
|
33
|
+
|
|
34
|
+
const move = (event: PointerEvent): void => {
|
|
35
|
+
const rect = listenEl.getBoundingClientRect()
|
|
36
|
+
const nx = (event.clientX - rect.left) / rect.width - 0.5
|
|
37
|
+
const ny = (event.clientY - rect.top) / rect.height - 0.5
|
|
38
|
+
const max = opts.max ?? 10
|
|
39
|
+
animEl.style.transition = 'transform 0.15s ease-out'
|
|
40
|
+
animEl.style.transform = `perspective(800px) rotateX(${(ny * -2 * max).toFixed(2)}deg) rotateY(${(nx * 2 * max).toFixed(2)}deg) scale(1.02)`
|
|
41
|
+
}
|
|
42
|
+
const leave = (): void => {
|
|
43
|
+
animEl.style.transition = 'transform 0.4s ease'
|
|
44
|
+
animEl.style.transform = 'perspective(800px) rotateX(0deg) rotateY(0deg) scale(1)'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
listenEl.addEventListener('pointermove', move)
|
|
48
|
+
listenEl.addEventListener('pointerleave', leave)
|
|
49
|
+
return () => {
|
|
50
|
+
listenEl.removeEventListener('pointermove', move)
|
|
51
|
+
listenEl.removeEventListener('pointerleave', leave)
|
|
52
|
+
animEl.style.transform = ''
|
|
53
|
+
animEl.style.transition = ''
|
|
54
|
+
animEl.style.willChange = ''
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
18
58
|
/**
|
|
19
59
|
* Wraps `children` in a card that tilts in 3D toward the cursor: as the
|
|
20
60
|
* pointer moves within its bounds, the card rotates on both axes (clamped to
|
|
21
|
-
* `max` degrees) and lifts slightly,
|
|
61
|
+
* `max` degrees) and lifts slightly, easing back flat on pointerleave.
|
|
22
62
|
* Respects `prefers-reduced-motion` (renders static).
|
|
23
63
|
*
|
|
64
|
+
* A4ui's own `Card` can do this without the wrapper — `<Card tilt>`.
|
|
65
|
+
*
|
|
24
66
|
* @example
|
|
25
67
|
* ```tsx
|
|
26
68
|
* <TiltCard max={12}>
|
|
@@ -33,46 +75,13 @@ export function TiltCard(props: TiltCardProps): JSX.Element {
|
|
|
33
75
|
let inner!: HTMLDivElement
|
|
34
76
|
|
|
35
77
|
onMount(() => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
let controls: ReturnType<typeof animate> | undefined
|
|
39
|
-
|
|
40
|
-
const handlePointerMove = (event: PointerEvent): void => {
|
|
41
|
-
const rect = root.getBoundingClientRect()
|
|
42
|
-
const nx = (event.clientX - rect.left) / rect.width - 0.5
|
|
43
|
-
const ny = (event.clientY - rect.top) / rect.height - 0.5
|
|
44
|
-
const max = props.max ?? 10
|
|
45
|
-
|
|
46
|
-
controls?.stop()
|
|
47
|
-
controls = animate(
|
|
48
|
-
inner,
|
|
49
|
-
{ rotateX: ny * -2 * max, rotateY: nx * 2 * max, scale: 1.02 },
|
|
50
|
-
{ type: 'spring', stiffness: 300, damping: 20 },
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const handlePointerLeave = (): void => {
|
|
55
|
-
controls?.stop()
|
|
56
|
-
controls = animate(
|
|
57
|
-
inner,
|
|
58
|
-
{ rotateX: 0, rotateY: 0, scale: 1 },
|
|
59
|
-
{ type: 'spring', stiffness: 300, damping: 20 },
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
root.addEventListener('pointermove', handlePointerMove)
|
|
64
|
-
root.addEventListener('pointerleave', handlePointerLeave)
|
|
65
|
-
|
|
66
|
-
onCleanup(() => {
|
|
67
|
-
root.removeEventListener('pointermove', handlePointerMove)
|
|
68
|
-
root.removeEventListener('pointerleave', handlePointerLeave)
|
|
69
|
-
controls?.stop()
|
|
70
|
-
})
|
|
78
|
+
const cleanup = attachTilt(root, inner, { max: props.max })
|
|
79
|
+
onCleanup(cleanup)
|
|
71
80
|
})
|
|
72
81
|
|
|
73
82
|
return (
|
|
74
83
|
<div ref={root} class={cn('inline-block', props.class)} style={{ perspective: '800px' }}>
|
|
75
|
-
<div ref={inner}
|
|
84
|
+
<div ref={inner} style={{ 'transform-style': 'preserve-3d' }}>
|
|
76
85
|
{props.children}
|
|
77
86
|
</div>
|
|
78
87
|
</div>
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { spread as g, mergeProps as m, insert as i, template as d, createComponent as v, effect as h, setAttribute as x, className as y, delegateEvents as E } from "solid-js/web";
|
|
2
|
-
import { splitProps as f, createSignal as S, Show as L, For as p } from "solid-js";
|
|
3
|
-
import { c } from "./cn-B6yFEsav.js";
|
|
4
|
-
import { Star as C } from "lucide-solid";
|
|
5
|
-
var B = /* @__PURE__ */ d("<span>");
|
|
6
|
-
const R = {
|
|
7
|
-
neutral: "bg-muted text-muted-foreground ring-border",
|
|
8
|
-
success: "bg-emerald-500/15 text-emerald-600 ring-emerald-500/30",
|
|
9
|
-
warning: "bg-amber-500/15 text-amber-600 ring-amber-500/30",
|
|
10
|
-
danger: "bg-rose-500/15 text-rose-600 ring-rose-500/30",
|
|
11
|
-
info: "bg-sky-500/15 text-sky-600 ring-sky-500/30"
|
|
12
|
-
}, T = "badge inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-semibold ring-1 ring-inset whitespace-nowrap";
|
|
13
|
-
function q(r) {
|
|
14
|
-
const [e, n] = f(r, ["tone", "class", "children"]);
|
|
15
|
-
return (() => {
|
|
16
|
-
var t = B();
|
|
17
|
-
return g(t, m({
|
|
18
|
-
get class() {
|
|
19
|
-
return c(T, R[e.tone ?? "neutral"], e.class);
|
|
20
|
-
}
|
|
21
|
-
}, n), !1, !0), i(t, () => e.children), t;
|
|
22
|
-
})();
|
|
23
|
-
}
|
|
24
|
-
var D = /* @__PURE__ */ d("<button>");
|
|
25
|
-
const N = {
|
|
26
|
-
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
27
|
-
secondary: "bg-muted text-foreground hover:bg-muted/70",
|
|
28
|
-
outline: "border border-border bg-transparent text-foreground hover:bg-muted",
|
|
29
|
-
ghost: "bg-transparent text-foreground hover:bg-muted"
|
|
30
|
-
}, G = "inline-flex items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-[color,background-color,transform] duration-150 active:scale-[0.97] focus:outline-none focus:ring-2 focus:ring-ring disabled:pointer-events-none disabled:opacity-50";
|
|
31
|
-
function z(r) {
|
|
32
|
-
const [e, n] = f(r, ["variant", "class", "type", "children"]);
|
|
33
|
-
return (() => {
|
|
34
|
-
var t = D();
|
|
35
|
-
return g(t, m({
|
|
36
|
-
get type() {
|
|
37
|
-
return e.type ?? "button";
|
|
38
|
-
},
|
|
39
|
-
get class() {
|
|
40
|
-
return c(G, N[e.variant ?? "primary"], e.class);
|
|
41
|
-
}
|
|
42
|
-
}, n), !1, !0), i(t, () => e.children), t;
|
|
43
|
-
})();
|
|
44
|
-
}
|
|
45
|
-
var $ = /* @__PURE__ */ d("<div>"), H = /* @__PURE__ */ d("<h2>");
|
|
46
|
-
function J(r) {
|
|
47
|
-
const [e, n] = f(r, ["class", "children", "glass", "glow"]), t = () => (e.glow ?? e.glass) === !0;
|
|
48
|
-
return (() => {
|
|
49
|
-
var u = $();
|
|
50
|
-
return g(u, m({
|
|
51
|
-
get class() {
|
|
52
|
-
return c(e.glass ? "card rounded-xl text-card-foreground" : "rounded-xl border border-border bg-card text-card-foreground shadow-sm", t() && "glow-edge", e.class);
|
|
53
|
-
}
|
|
54
|
-
}, n), !1, !0), i(u, () => e.children), u;
|
|
55
|
-
})();
|
|
56
|
-
}
|
|
57
|
-
function K(r) {
|
|
58
|
-
const [e, n] = f(r, ["class", "children"]);
|
|
59
|
-
return (() => {
|
|
60
|
-
var t = $();
|
|
61
|
-
return g(t, m({
|
|
62
|
-
get class() {
|
|
63
|
-
return c("flex flex-col space-y-1.5 p-6", e.class);
|
|
64
|
-
}
|
|
65
|
-
}, n), !1, !0), i(t, () => e.children), t;
|
|
66
|
-
})();
|
|
67
|
-
}
|
|
68
|
-
function Q(r) {
|
|
69
|
-
const [e, n] = f(r, ["class", "children"]);
|
|
70
|
-
return (() => {
|
|
71
|
-
var t = H();
|
|
72
|
-
return g(t, m({
|
|
73
|
-
get class() {
|
|
74
|
-
return c("text-lg font-semibold leading-none tracking-tight", e.class);
|
|
75
|
-
}
|
|
76
|
-
}, n), !1, !0), i(t, () => e.children), t;
|
|
77
|
-
})();
|
|
78
|
-
}
|
|
79
|
-
function W(r) {
|
|
80
|
-
const [e, n] = f(r, ["class", "children"]);
|
|
81
|
-
return (() => {
|
|
82
|
-
var t = $();
|
|
83
|
-
return g(t, m({
|
|
84
|
-
get class() {
|
|
85
|
-
return c("p-6 pt-0", e.class);
|
|
86
|
-
}
|
|
87
|
-
}, n), !1, !0), i(t, () => e.children), t;
|
|
88
|
-
})();
|
|
89
|
-
}
|
|
90
|
-
var M = /* @__PURE__ */ d("<div role=radiogroup>"), O = /* @__PURE__ */ d("<div role=img>"), P = /* @__PURE__ */ d('<button type=button role=radio class="rounded outline-none focus-visible:ring-2 focus-visible:ring-ring/40">');
|
|
91
|
-
function X(r) {
|
|
92
|
-
const [e, n] = S(0), t = () => r.max ?? 5, u = () => Array.from({
|
|
93
|
-
length: t()
|
|
94
|
-
}, (s, a) => a + 1), A = () => e() > 0 ? e() : r.value, b = (s) => {
|
|
95
|
-
var a;
|
|
96
|
-
r.readonly || (a = r.onChange) == null || a.call(r, s);
|
|
97
|
-
}, k = (s) => c("h-5 w-5 transition-colors", s <= A() ? "fill-primary text-primary" : "fill-transparent text-muted-foreground");
|
|
98
|
-
return v(L, {
|
|
99
|
-
get when() {
|
|
100
|
-
return !r.readonly;
|
|
101
|
-
},
|
|
102
|
-
get fallback() {
|
|
103
|
-
return (() => {
|
|
104
|
-
var s = O();
|
|
105
|
-
return i(s, v(p, {
|
|
106
|
-
get each() {
|
|
107
|
-
return u();
|
|
108
|
-
},
|
|
109
|
-
children: (a) => v(C, {
|
|
110
|
-
get class() {
|
|
111
|
-
return k(a);
|
|
112
|
-
},
|
|
113
|
-
"aria-hidden": "true"
|
|
114
|
-
})
|
|
115
|
-
})), h((a) => {
|
|
116
|
-
var o = c("inline-flex items-center gap-1", r.class), l = `Rating ${r.value} of ${t()}`;
|
|
117
|
-
return o !== a.e && y(s, a.e = o), l !== a.t && x(s, "aria-label", a.t = l), a;
|
|
118
|
-
}, {
|
|
119
|
-
e: void 0,
|
|
120
|
-
t: void 0
|
|
121
|
-
}), s;
|
|
122
|
-
})();
|
|
123
|
-
},
|
|
124
|
-
get children() {
|
|
125
|
-
var s = M();
|
|
126
|
-
return s.addEventListener("mouseleave", () => n(0)), i(s, v(p, {
|
|
127
|
-
get each() {
|
|
128
|
-
return u();
|
|
129
|
-
},
|
|
130
|
-
children: (a) => (() => {
|
|
131
|
-
var o = P();
|
|
132
|
-
return o.$$keydown = (l) => {
|
|
133
|
-
l.key === "ArrowRight" || l.key === "ArrowUp" ? (l.preventDefault(), b(Math.min(r.value + 1, t()))) : (l.key === "ArrowLeft" || l.key === "ArrowDown") && (l.preventDefault(), b(Math.max(r.value - 1, 0)));
|
|
134
|
-
}, o.$$click = () => b(a), o.addEventListener("blur", () => n(0)), o.addEventListener("focus", () => n(a)), o.addEventListener("mouseenter", () => n(a)), i(o, v(C, {
|
|
135
|
-
get class() {
|
|
136
|
-
return k(a);
|
|
137
|
-
},
|
|
138
|
-
"aria-hidden": "true"
|
|
139
|
-
})), h((l) => {
|
|
140
|
-
var w = r.value === a, _ = `Rate ${a} of ${t()}`;
|
|
141
|
-
return w !== l.e && x(o, "aria-checked", l.e = w), _ !== l.t && x(o, "aria-label", l.t = _), l;
|
|
142
|
-
}, {
|
|
143
|
-
e: void 0,
|
|
144
|
-
t: void 0
|
|
145
|
-
}), o;
|
|
146
|
-
})()
|
|
147
|
-
})), h(() => y(s, c("inline-flex items-center gap-1", r.class))), s;
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
E(["click", "keydown"]);
|
|
152
|
-
var U = /* @__PURE__ */ d('<label><input type=checkbox class="h-4 w-4 rounded border-input accent-primary">');
|
|
153
|
-
function Y(r) {
|
|
154
|
-
return (() => {
|
|
155
|
-
var e = U(), n = e.firstChild;
|
|
156
|
-
return n.addEventListener("change", (t) => r.onChange(t.currentTarget.checked)), i(e, () => r.label, null), h(() => y(e, c("inline-flex items-center gap-2 text-sm text-foreground", r.class))), h(() => n.checked = r.checked), e;
|
|
157
|
-
})();
|
|
158
|
-
}
|
|
159
|
-
export {
|
|
160
|
-
q as B,
|
|
161
|
-
J as C,
|
|
162
|
-
X as R,
|
|
163
|
-
z as a,
|
|
164
|
-
Y as b,
|
|
165
|
-
W as c,
|
|
166
|
-
K as d,
|
|
167
|
-
Q as e
|
|
168
|
-
};
|