@a4ui/core 0.14.1 → 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/src/ui/Ripple.tsx CHANGED
@@ -1,15 +1,13 @@
1
- // Material-style click ripple: a wrapper that spawns an expanding, fading
2
- // circle from the pointer's down position on every `pointerdown` Motion's
3
- // `animate` drives the scale/opacity tween since each ripple is a one-shot
4
- // spawn-then-discard element, not a persistent CSS transition. `x`/`y` are
5
- // animated to a constant -50% alongside `scale` so Motion (which owns the
6
- // element's `transform` once it's animating any transform sub-property)
7
- // composes `translate(-50%,-50%) scale(...)` itself rather than clobbering a
8
- // translate we'd otherwise have set by hand via inline style.
9
- import { createSignal, For, onCleanup, type JSX } from 'solid-js'
1
+ // Material-style click ripple: an expanding, fading circle from the pointer's
2
+ // down position on every `pointerdown`. The tween is driven by the native Web
3
+ // Animations API (el.animate) each ripple is a one-shot spawn-then-discard
4
+ // element, so there's nothing for a JS animation engine to add. Being
5
+ // engine-free is deliberate: it lets <Button ripple> bake this in without
6
+ // pulling the `motion` package into every Button consumer's bundle.
7
+ import { type JSX } from 'solid-js'
10
8
 
11
9
  import { cn } from '../lib/cn'
12
- import { animate, motionReduced } from '../lib/motion'
10
+ import { motionReduced } from '../lib/motion'
13
11
 
14
12
  export interface RippleProps {
15
13
  children: JSX.Element
@@ -20,14 +18,58 @@ export interface RippleProps {
20
18
  class?: string
21
19
  }
22
20
 
23
- interface RippleInstance {
24
- id: number
25
- x: number
26
- y: number
27
- size: number
28
- }
21
+ /**
22
+ * Spawns one Material-style ripple inside `container` at the pointer's
23
+ * position, expanding to cover the container and fading out, then removes
24
+ * itself. The container must be `position: relative; overflow: hidden`.
25
+ * Engine-free (Web Animations API); no-op under reduced motion. This is the
26
+ * primitive behind {@link Ripple} and `<Button ripple>`.
27
+ */
28
+ export function spawnRipple(
29
+ container: HTMLElement,
30
+ event: PointerEvent,
31
+ opts: { color?: string; opacity?: number } = {},
32
+ ): void {
33
+ if (motionReduced()) return
34
+ const rect = container.getBoundingClientRect()
35
+ const x = event.clientX - rect.left
36
+ const y = event.clientY - rect.top
37
+ // Diameter = 2× the distance to the farthest corner, so the circle always
38
+ // covers the whole container from wherever the press landed.
39
+ const size =
40
+ 2 *
41
+ Math.max(
42
+ Math.hypot(x, y),
43
+ Math.hypot(rect.width - x, y),
44
+ Math.hypot(x, rect.height - y),
45
+ Math.hypot(rect.width - x, rect.height - y),
46
+ )
29
47
 
30
- let nextRippleId = 0
48
+ const el = document.createElement('span')
49
+ el.setAttribute('aria-hidden', 'true')
50
+ Object.assign(el.style, {
51
+ position: 'absolute',
52
+ left: `${x}px`,
53
+ top: `${y}px`,
54
+ width: `${size}px`,
55
+ height: `${size}px`,
56
+ borderRadius: '9999px',
57
+ background: opts.color ?? 'currentColor',
58
+ pointerEvents: 'none',
59
+ transform: 'translate(-50%,-50%) scale(0)',
60
+ })
61
+ container.appendChild(el)
62
+
63
+ const animation = el.animate(
64
+ [
65
+ { transform: 'translate(-50%,-50%) scale(0)', opacity: String(opts.opacity ?? 0.3) },
66
+ { transform: 'translate(-50%,-50%) scale(1)', opacity: '0' },
67
+ ],
68
+ { duration: 600, easing: 'ease-out' },
69
+ )
70
+ const done = (): void => el.remove()
71
+ animation.finished.then(done).catch(done)
72
+ }
31
73
 
32
74
  /**
33
75
  * Wraps `children` in a `position: relative; overflow: hidden` layer that
@@ -37,59 +79,23 @@ let nextRippleId = 0
37
79
  * itself once its animation finishes. A no-op under reduced motion: children
38
80
  * still render, but no ripple ever spawns.
39
81
  *
82
+ * Buttons don't need the wrapper — use `<Button ripple>` instead.
83
+ *
40
84
  * @example
41
85
  * ```tsx
42
86
  * <Ripple color="white" opacity={0.25}>
43
- * <button class="rounded-lg bg-primary px-4 py-2 text-primary-foreground">Save</button>
87
+ * <div class="rounded-lg bg-primary px-4 py-2 text-primary-foreground">Save</div>
44
88
  * </Ripple>
45
89
  * ```
46
90
  */
47
91
  export function Ripple(props: RippleProps): JSX.Element {
48
- const [ripples, setRipples] = createSignal<RippleInstance[]>([])
49
- const active = new Set<ReturnType<typeof animate>>()
50
-
51
92
  let containerEl: HTMLSpanElement | undefined
52
93
 
53
- const remove = (id: number): void => {
54
- setRipples((current) => current.filter((ripple) => ripple.id !== id))
55
- }
56
-
57
- const spawnAnimation = (el: HTMLSpanElement, id: number, opacity: number): void => {
58
- const controls = animate(
59
- el,
60
- { x: ['-50%', '-50%'], y: ['-50%', '-50%'], scale: [0, 1], opacity: [opacity, 0] },
61
- { duration: 0.6, ease: 'easeOut' },
62
- )
63
- active.add(controls)
64
- controls.finished
65
- .then(() => {
66
- active.delete(controls)
67
- remove(id)
68
- })
69
- .catch(() => {})
70
- }
71
-
72
94
  const handlePointerDown = (event: PointerEvent): void => {
73
- if (motionReduced() || !containerEl) return
74
-
75
- const rect = containerEl.getBoundingClientRect()
76
- const x = event.clientX - rect.left
77
- const y = event.clientY - rect.top
78
- const maxDist = Math.max(
79
- Math.hypot(x, y),
80
- Math.hypot(rect.width - x, y),
81
- Math.hypot(x, rect.height - y),
82
- Math.hypot(rect.width - x, rect.height - y),
83
- )
84
-
85
- setRipples((current) => [...current, { id: nextRippleId++, x, y, size: maxDist * 2 }])
95
+ if (!containerEl) return
96
+ spawnRipple(containerEl, event, { color: props.color, opacity: props.opacity })
86
97
  }
87
98
 
88
- onCleanup(() => {
89
- active.forEach((controls) => controls.stop())
90
- active.clear()
91
- })
92
-
93
99
  return (
94
100
  <span
95
101
  ref={containerEl}
@@ -97,23 +103,6 @@ export function Ripple(props: RippleProps): JSX.Element {
97
103
  onPointerDown={handlePointerDown}
98
104
  >
99
105
  {props.children}
100
- <span aria-hidden="true" class="pointer-events-none absolute inset-0">
101
- <For each={ripples()}>
102
- {(ripple) => (
103
- <span
104
- ref={(el) => spawnAnimation(el, ripple.id, props.opacity ?? 0.3)}
105
- class="absolute rounded-full"
106
- style={{
107
- left: `${ripple.x}px`,
108
- top: `${ripple.y}px`,
109
- width: `${ripple.size}px`,
110
- height: `${ripple.size}px`,
111
- background: props.color ?? 'currentColor',
112
- }}
113
- />
114
- )}
115
- </For>
116
- </span>
117
106
  </span>
118
107
  )
119
108
  }
@@ -0,0 +1,61 @@
1
+ // ScrollProgress — a thin bar pinned to the top of the viewport that fills
2
+ // left-to-right as the page scrolls, a common reading-progress indicator.
3
+ // Driven by Motion's `scroll` progress callback (0..1). Renders a static,
4
+ // unfilled bar under reduced motion (no scroll subscription).
5
+ import { onCleanup, onMount, type JSX } from 'solid-js'
6
+
7
+ import { cn } from '../lib/cn'
8
+ import { motionReduced, scroll } from '../lib/motion'
9
+
10
+ export interface ScrollProgressProps {
11
+ /** Bar height in px. @default 3 */
12
+ height?: number
13
+ /** Bar color (CSS color). @default 'hsl(var(--primary))' */
14
+ color?: string
15
+ class?: string
16
+ }
17
+
18
+ /**
19
+ * Renders a fixed bar at the top of the viewport whose fill tracks how far
20
+ * the page has been scrolled. Subscribes to Motion's `scroll` on mount and
21
+ * scales the inner bar horizontally; respects `prefers-reduced-motion`
22
+ * (renders a static, empty bar instead).
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <ScrollProgress height={4} color="hsl(var(--accent))" />
27
+ * ```
28
+ */
29
+ export function ScrollProgress(props: ScrollProgressProps): JSX.Element {
30
+ let bar!: HTMLDivElement
31
+
32
+ onMount(() => {
33
+ bar.style.transform = 'scaleX(0)'
34
+
35
+ if (motionReduced()) return
36
+
37
+ const stop = scroll((progress: number) => {
38
+ bar.style.transform = `scaleX(${progress})`
39
+ })
40
+
41
+ onCleanup(() => stop())
42
+ })
43
+
44
+ return (
45
+ <div
46
+ aria-hidden="true"
47
+ class={cn('fixed top-0 left-0 z-[9999] w-full', props.class)}
48
+ style={{ height: `${props.height ?? 3}px` }}
49
+ >
50
+ <div
51
+ ref={bar}
52
+ class="origin-left will-change-transform"
53
+ style={{
54
+ height: '100%',
55
+ width: '100%',
56
+ 'background-color': props.color ?? 'hsl(var(--primary))',
57
+ }}
58
+ />
59
+ </div>
60
+ )
61
+ }
@@ -0,0 +1,94 @@
1
+ // Spotlight — a soft radial glow that follows the cursor inside the wrapped
2
+ // element, like a light hovering over the surface. This is a plain CSS
3
+ // follow (the overlay's `background` is written directly on pointermove)
4
+ // rather than a Motion tween: a radial-gradient position update has no
5
+ // transform to spring, so there's nothing for an animation engine to add.
6
+ // Engine-free, which lets <Card spotlight> bake it in for free. Only the
7
+ // fade in/out on enter/leave uses a CSS `transition: opacity`. No-op (no
8
+ // glow, children still render) under reduced motion.
9
+ import { onCleanup, onMount, type JSX } from 'solid-js'
10
+
11
+ import { cn } from '../lib/cn'
12
+ import { motionReduced } from '../lib/motion'
13
+
14
+ export interface SpotlightProps {
15
+ children: JSX.Element
16
+ /** Glow color (CSS color). @default 'hsl(var(--primary))' */
17
+ color?: string
18
+ /** Glow radius in px. @default 180 */
19
+ size?: number
20
+ class?: string
21
+ }
22
+
23
+ /**
24
+ * Appends a cursor-following radial-glow overlay inside `el` (which must be
25
+ * `position: relative; overflow: hidden`) and binds the pointer handlers.
26
+ * Returns a cleanup that unbinds and removes the overlay. Engine-free; no-op
27
+ * under reduced motion. This is the primitive behind {@link Spotlight} and
28
+ * `<Card spotlight>`.
29
+ */
30
+ export function attachSpotlight(el: HTMLElement, opts: { color?: string; size?: number } = {}): () => void {
31
+ if (motionReduced()) return () => {}
32
+
33
+ const overlay = document.createElement('span')
34
+ overlay.setAttribute('aria-hidden', 'true')
35
+ overlay.className = 'pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300'
36
+ el.appendChild(overlay)
37
+
38
+ const size = opts.size ?? 180
39
+ const color = opts.color ?? 'hsl(var(--primary))'
40
+
41
+ const paint = (x: number, y: number): void => {
42
+ overlay.style.background = `radial-gradient(${size}px circle at ${x}px ${y}px, color-mix(in srgb, ${color} 30%, transparent), transparent 70%)`
43
+ }
44
+ const handlePointerMove = (event: PointerEvent): void => {
45
+ const rect = el.getBoundingClientRect()
46
+ paint(event.clientX - rect.left, event.clientY - rect.top)
47
+ }
48
+ const handlePointerEnter = (): void => {
49
+ overlay.style.opacity = '1'
50
+ }
51
+ const handlePointerLeave = (): void => {
52
+ overlay.style.opacity = '0'
53
+ }
54
+
55
+ el.addEventListener('pointermove', handlePointerMove)
56
+ el.addEventListener('pointerenter', handlePointerEnter)
57
+ el.addEventListener('pointerleave', handlePointerLeave)
58
+ return () => {
59
+ el.removeEventListener('pointermove', handlePointerMove)
60
+ el.removeEventListener('pointerenter', handlePointerEnter)
61
+ el.removeEventListener('pointerleave', handlePointerLeave)
62
+ overlay.remove()
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Wraps `children` in a `position: relative; overflow: hidden` layer with a
68
+ * radial glow that tracks the cursor, fading in on pointerenter and out on
69
+ * pointerleave. Children render below the (pointer-transparent) glow.
70
+ * Respects `prefers-reduced-motion` (renders children with no glow at all).
71
+ *
72
+ * A4ui's own `Card` can do this without the wrapper — `<Card spotlight>`.
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * <Spotlight color="hsl(var(--primary))" size={220}>
77
+ * <div class="rounded-2xl border border-border p-8">Hover for glow</div>
78
+ * </Spotlight>
79
+ * ```
80
+ */
81
+ export function Spotlight(props: SpotlightProps): JSX.Element {
82
+ let root!: HTMLDivElement
83
+
84
+ onMount(() => {
85
+ const cleanup = attachSpotlight(root, { color: props.color, size: props.size })
86
+ onCleanup(cleanup)
87
+ })
88
+
89
+ return (
90
+ <div ref={root} class={cn('relative overflow-hidden', props.class)}>
91
+ {props.children}
92
+ </div>
93
+ )
94
+ }
@@ -0,0 +1,89 @@
1
+ // TiltCard — tilts its wrapped content in 3D toward the cursor on hover, like
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
+ import { onCleanup, onMount, type JSX } from 'solid-js'
7
+
8
+ import { cn } from '../lib/cn'
9
+ import { motionReduced } from '../lib/motion'
10
+
11
+ export interface TiltCardProps {
12
+ children: JSX.Element
13
+ /** Max tilt in degrees. @default 10 */
14
+ max?: number
15
+ class?: string
16
+ }
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
+
58
+ /**
59
+ * Wraps `children` in a card that tilts in 3D toward the cursor: as the
60
+ * pointer moves within its bounds, the card rotates on both axes (clamped to
61
+ * `max` degrees) and lifts slightly, easing back flat on pointerleave.
62
+ * Respects `prefers-reduced-motion` (renders static).
63
+ *
64
+ * A4ui's own `Card` can do this without the wrapper — `<Card tilt>`.
65
+ *
66
+ * @example
67
+ * ```tsx
68
+ * <TiltCard max={12}>
69
+ * <div class="rounded-2xl border border-border bg-card p-6">Card content</div>
70
+ * </TiltCard>
71
+ * ```
72
+ */
73
+ export function TiltCard(props: TiltCardProps): JSX.Element {
74
+ let root!: HTMLDivElement
75
+ let inner!: HTMLDivElement
76
+
77
+ onMount(() => {
78
+ const cleanup = attachTilt(root, inner, { max: props.max })
79
+ onCleanup(cleanup)
80
+ })
81
+
82
+ return (
83
+ <div ref={root} class={cn('inline-block', props.class)} style={{ perspective: '800px' }}>
84
+ <div ref={inner} style={{ 'transform-style': 'preserve-3d' }}>
85
+ {props.children}
86
+ </div>
87
+ </div>
88
+ )
89
+ }
@@ -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
- };