@photon-ai/pho-ui 2.5.0 → 2.7.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/dist/chunks/IconChevronDown-CZilB71T.js +11 -0
- package/dist/chunks/IconChevronDown-CZilB71T.js.map +1 -0
- package/dist/chunks/IconSearch-BKAHkLyX.js +14 -0
- package/dist/chunks/IconSearch-BKAHkLyX.js.map +1 -0
- package/dist/chunks/animated-height-CCO-Ocoz.js +48 -0
- package/dist/chunks/animated-height-CCO-Ocoz.js.map +1 -0
- package/dist/chunks/basic-page-DR5szOOs.js +1373 -0
- package/dist/chunks/basic-page-DR5szOOs.js.map +1 -0
- package/dist/chunks/{button-DNNs5RsT.js → button-CdqS_t5a.js} +62 -65
- package/dist/chunks/button-CdqS_t5a.js.map +1 -0
- package/dist/chunks/checkbox-Cdm08HWG.js +129 -0
- package/dist/chunks/checkbox-Cdm08HWG.js.map +1 -0
- package/dist/chunks/{choice-card-CunOnY9l.js → choice-card-BVNP1NB6.js} +2 -2
- package/dist/chunks/{choice-card-CunOnY9l.js.map → choice-card-BVNP1NB6.js.map} +1 -1
- package/dist/chunks/data-table-DwbPU0zt.js +2970 -0
- package/dist/chunks/data-table-DwbPU0zt.js.map +1 -0
- package/dist/chunks/{dialog-8SRNi_rv.js → dialog-BxKACOj5.js} +4 -4
- package/dist/chunks/{dialog-8SRNi_rv.js.map → dialog-BxKACOj5.js.map} +1 -1
- package/dist/chunks/{error-Crs-wqMC.js → error-D0yoFxCv.js} +2 -2
- package/dist/chunks/{error-Crs-wqMC.js.map → error-D0yoFxCv.js.map} +1 -1
- package/dist/chunks/is-react-component-DSnjtBmo.js +10 -0
- package/dist/chunks/is-react-component-DSnjtBmo.js.map +1 -0
- package/dist/chunks/link-provider-DXzDQ08N.js +24 -0
- package/dist/chunks/link-provider-DXzDQ08N.js.map +1 -0
- package/dist/chunks/rolldown-runtime-DG5F_Nuu.js +27 -0
- package/dist/chunks/{scroll-area-Bu7egArU.js → scroll-area-BO-9PMM7.js} +27 -26
- package/dist/chunks/scroll-area-BO-9PMM7.js.map +1 -0
- package/dist/chunks/sidebar-DVzZsCts.js +223 -0
- package/dist/chunks/sidebar-DVzZsCts.js.map +1 -0
- package/dist/chunks/skeleton-DwjSl4vC.js +18 -0
- package/dist/chunks/skeleton-DwjSl4vC.js.map +1 -0
- package/dist/chunks/{toast-DoXaRPIZ.js → toast-iSf6NuAS.js} +43 -45
- package/dist/chunks/toast-iSf6NuAS.js.map +1 -0
- package/dist/chunks/use-press-pulse-IbNstUT0.js +58 -0
- package/dist/chunks/use-press-pulse-IbNstUT0.js.map +1 -0
- package/dist/components/button.js +1 -1
- package/dist/components/checkbox.js +4 -126
- package/dist/components/command.js +54 -57
- package/dist/components/command.js.map +1 -1
- package/dist/components/data-table.js +11 -0
- package/dist/components/dialog.js +1 -1
- package/dist/components/error.js +1 -1
- package/dist/components/phone-input.js +609 -616
- package/dist/components/phone-input.js.map +1 -1
- package/dist/components/radio-group.js +2 -2
- package/dist/components/scroll-area.js +1 -1
- package/dist/components/select.js +35 -39
- package/dist/components/select.js.map +1 -1
- package/dist/components/skeleton.js +2 -15
- package/dist/components/toast.js +1 -1
- package/dist/index.js +94 -73
- package/dist/motion.js +89 -0
- package/dist/motion.js.map +1 -0
- package/dist/primitives/accordion.js +1 -1
- package/dist/primitives/alert-dialog.js +1 -1
- package/dist/primitives/autocomplete.js +1 -1
- package/dist/primitives/avatar.js +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/checkbox-group.js +1 -1
- package/dist/primitives/checkbox.js +1 -1
- package/dist/primitives/collapsible.js +1 -1
- package/dist/primitives/combobox.js +1 -1
- package/dist/primitives/context-menu.js +1 -1
- package/dist/primitives/csp-provider.js +1 -1
- package/dist/primitives/dialog.js +1 -1
- package/dist/primitives/direction-provider.js +1 -1
- package/dist/primitives/drawer.js +1 -1
- package/dist/primitives/field.js +1 -1
- package/dist/primitives/fieldset.js +1 -1
- package/dist/primitives/form.js +1 -1
- package/dist/primitives/input.js +1 -1
- package/dist/primitives/menu.js +1 -1
- package/dist/primitives/menubar.js +1 -1
- package/dist/primitives/meter.js +1 -1
- package/dist/primitives/navigation-menu.js +1 -1
- package/dist/primitives/number-field.js +1 -1
- package/dist/primitives/otp-field.js +1 -1
- package/dist/primitives/popover.js +1 -1
- package/dist/primitives/preview-card.js +1 -1
- package/dist/primitives/progress.js +1 -1
- package/dist/primitives/radio-group.js +1 -1
- package/dist/primitives/radio.js +1 -1
- package/dist/primitives/scroll-area.js +1 -1
- package/dist/primitives/select.js +1 -1
- package/dist/primitives/separator.js +1 -1
- package/dist/primitives/slider.js +1 -1
- package/dist/primitives/switch.js +1 -1
- package/dist/primitives/tabs.js +1 -1
- package/dist/primitives/toast.js +1 -1
- package/dist/primitives/toggle-group.js +1 -1
- package/dist/primitives/toggle.js +1 -1
- package/dist/primitives/toolbar.js +1 -1
- package/dist/primitives/tooltip.js +1 -1
- package/dist/primitives.js +3 -3
- package/dist/sections/basic-page.js +16 -14
- package/dist/sections/sidebar.js +1 -1
- package/dist/src/components/data-table/data-table.d.ts +227 -0
- package/dist/src/components/data-table/index.d.ts +2 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/motion/index.d.ts +149 -0
- package/dist/src/sections/basic-page/basic-page.d.ts +63 -14
- package/dist/src/sections/basic-page/index.d.ts +1 -0
- package/dist/utils.js +13 -12
- package/package.json +10 -1
- package/dist/chunks/animated-height-C2eQstGy.js +0 -51
- package/dist/chunks/animated-height-C2eQstGy.js.map +0 -1
- package/dist/chunks/basic-page-w6ftlo0h.js +0 -1284
- package/dist/chunks/basic-page-w6ftlo0h.js.map +0 -1
- package/dist/chunks/button-DNNs5RsT.js.map +0 -1
- package/dist/chunks/link-provider-9TFNyDqO.js +0 -28
- package/dist/chunks/link-provider-9TFNyDqO.js.map +0 -1
- package/dist/chunks/rolldown-runtime-wKSmTnsc.js +0 -22
- package/dist/chunks/scroll-area-Bu7egArU.js.map +0 -1
- package/dist/chunks/sidebar-DvB-G0BP.js +0 -231
- package/dist/chunks/sidebar-DvB-G0BP.js.map +0 -1
- package/dist/chunks/toast-DoXaRPIZ.js.map +0 -1
- package/dist/chunks/use-press-pulse-8iorQPsh.js +0 -62
- package/dist/chunks/use-press-pulse-8iorQPsh.js.map +0 -1
- package/dist/components/checkbox.js.map +0 -1
- package/dist/components/skeleton.js.map +0 -1
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as l } from "./cn-ChIgwEl3.js";
|
|
3
|
-
import {
|
|
3
|
+
import { t as A } from "./is-react-component-DSnjtBmo.js";
|
|
4
4
|
import { t as R } from "./resolve-variant-CcD8iG5l.js";
|
|
5
|
+
import { n as Z } from "./link-provider-DXzDQ08N.js";
|
|
6
|
+
import { SPRING_PRESS as Q } from "../motion.js";
|
|
5
7
|
import { n as C } from "./spinner-BzLUo4Xk.js";
|
|
6
|
-
import { isValidElement as I, useEffect as
|
|
7
|
-
import { Fragment as
|
|
8
|
-
import { motion as w, useReducedMotion as
|
|
9
|
-
var
|
|
8
|
+
import { isValidElement as I, useEffect as $, useMemo as J, useRef as X, useState as Y } from "react";
|
|
9
|
+
import { Fragment as z, jsx as s, jsxs as ee } from "react/jsx-runtime";
|
|
10
|
+
import { motion as w, useReducedMotion as oe } from "motion/react";
|
|
11
|
+
var ae = l("group relative inline-flex h-max cursor-pointer items-center justify-center whitespace-nowrap outline-pho-brand transition-[color,background-color,border-color,opacity,box-shadow,outline-color] duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2", "disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"), L = {
|
|
10
12
|
sm: {
|
|
11
13
|
classes: l("gap-1 px-3.5 py-1.5 text-base font-medium data-svg-only:p-2", "has-[[data-icon=prefix]]:pl-2 has-[[data-icon=loading]]:pl-2 has-[[data-icon=suffix]]:pr-2"),
|
|
12
14
|
description: "Small — compact rows, tables, and toolbars"
|
|
@@ -19,7 +21,7 @@ var oe = l("group relative inline-flex h-max cursor-pointer items-center justify
|
|
|
19
21
|
classes: l("gap-1.5 px-5 py-2.5 text-md font-medium data-svg-only:p-3", "has-[[data-icon=prefix]]:pl-3 has-[[data-icon=loading]]:pl-3 has-[[data-icon=suffix]]:pr-3"),
|
|
20
22
|
description: "Large — prominent and marketing actions"
|
|
21
23
|
}
|
|
22
|
-
},
|
|
24
|
+
}, re = {
|
|
23
25
|
rounded: {
|
|
24
26
|
classes: "rounded-full",
|
|
25
27
|
description: "Pill — the default; every button on photon.codes"
|
|
@@ -32,11 +34,11 @@ var oe = l("group relative inline-flex h-max cursor-pointer items-center justify
|
|
|
32
34
|
classes: "rounded-full",
|
|
33
35
|
description: "Circular — pair with svgOnly for round icon buttons"
|
|
34
36
|
}
|
|
35
|
-
},
|
|
37
|
+
}, ne = "squircle", te = {
|
|
36
38
|
sm: "py-[4.5px] data-svg-only:p-[6.5px]",
|
|
37
39
|
md: "py-[6.5px] data-svg-only:p-[8.5px]",
|
|
38
40
|
lg: "py-[8.5px] data-svg-only:p-[10.5px]"
|
|
39
|
-
},
|
|
41
|
+
}, Se = {
|
|
40
42
|
effect: {
|
|
41
43
|
classes: "",
|
|
42
44
|
description: "Default — marketing pill with same-hue outer rim and inset sheen"
|
|
@@ -53,7 +55,7 @@ var oe = l("group relative inline-flex h-max cursor-pointer items-center justify
|
|
|
53
55
|
classes: "",
|
|
54
56
|
description: "Borderless — quiet / inline action"
|
|
55
57
|
}
|
|
56
|
-
},
|
|
58
|
+
}, Te = {
|
|
57
59
|
default: {
|
|
58
60
|
classes: "",
|
|
59
61
|
description: "Neutral / brand contrast"
|
|
@@ -62,7 +64,7 @@ var oe = l("group relative inline-flex h-max cursor-pointer items-center justify
|
|
|
62
64
|
classes: "",
|
|
63
65
|
description: "Destructive intent (delete, discard)"
|
|
64
66
|
}
|
|
65
|
-
},
|
|
67
|
+
}, se = {
|
|
66
68
|
effect: {
|
|
67
69
|
default: l("squircle overflow-hidden bg-pho-brand-solid text-pho-on-brand transition-none", "hover:bg-pho-brand-solid data-loading:bg-pho-brand-solid", "[--pho-rim:color-mix(in_oklab,var(--background-color-pho-brand-solid)_62%,transparent)]", "[--pho-sheen:light-dark(rgba(255,255,255,0.5),rgba(0,0,0,0.12))]", "shadow-[0_0_0_1.5px_var(--pho-rim),inset_0_0_0_1px_var(--border-color-pho-on-brand),inset_0_var(--pho-sheen-y,0px)_var(--pho-sheen-blur,5px)_var(--pho-sheen-spread,2px)_var(--pho-sheen)]"),
|
|
68
70
|
destructive: l("squircle overflow-hidden bg-pho-error-solid text-white outline-pho-error transition-none", "hover:bg-pho-error-solid data-loading:bg-pho-error-solid", "[--pho-rim:color-mix(in_oklab,var(--background-color-pho-error-solid)_62%,transparent)]", "[--pho-sheen:light-dark(rgba(255,255,255,0.45),rgba(0,0,0,0.18))]", "shadow-[0_0_0_1.5px_var(--pho-rim),inset_0_0_0_1px_oklch(1_0_0/0.2),inset_0_var(--pho-sheen-y,0px)_var(--pho-sheen-blur,5px)_var(--pho-sheen-spread,2px)_var(--pho-sheen)]")
|
|
@@ -81,14 +83,14 @@ var oe = l("group relative inline-flex h-max cursor-pointer items-center justify
|
|
|
81
83
|
}
|
|
82
84
|
};
|
|
83
85
|
function F(e) {
|
|
84
|
-
const { variant: a = "effect", color: o = "default", size: r = "md", shape: n = "rounded", className: t } = e ?? {}, p = a === "effect" ? "rounded" : n, i =
|
|
85
|
-
return l(
|
|
86
|
+
const { variant: a = "effect", color: o = "default", size: r = "md", shape: n = "rounded", className: t } = e ?? {}, p = a === "effect" ? "rounded" : n, i = se[a]?.[o] ?? "";
|
|
87
|
+
return l(ae, R(re, p), p === "square" && r === "lg" && ne, R(L, r), a === "effect" && te[r], i, t);
|
|
86
88
|
}
|
|
87
|
-
var
|
|
89
|
+
var ie = "transition-inherit-all pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-[1.125em] [&>svg]:shrink-0";
|
|
88
90
|
function k({ position: e, children: a }) {
|
|
89
91
|
return /* @__PURE__ */ s("span", {
|
|
90
92
|
"data-icon": e,
|
|
91
|
-
className:
|
|
93
|
+
className: ie,
|
|
92
94
|
children: a
|
|
93
95
|
});
|
|
94
96
|
}
|
|
@@ -101,19 +103,14 @@ function B(e, a) {
|
|
|
101
103
|
children: e
|
|
102
104
|
}) : null;
|
|
103
105
|
}
|
|
104
|
-
function
|
|
106
|
+
function P(e, a) {
|
|
105
107
|
e && !a && typeof process < "u" && process.env.NODE_ENV !== "production" && console.warn("Button: `svgOnly` buttons require an `aria-label` that names the action.");
|
|
106
108
|
}
|
|
107
|
-
var
|
|
108
|
-
type: "spring",
|
|
109
|
-
stiffness: 200,
|
|
110
|
-
damping: 30,
|
|
111
|
-
mass: 0.1
|
|
112
|
-
}, ie = {
|
|
109
|
+
var U = Q, pe = {
|
|
113
110
|
"--pho-sheen-y": "0px",
|
|
114
111
|
"--pho-sheen-blur": "5px",
|
|
115
112
|
"--pho-sheen-spread": "2px"
|
|
116
|
-
},
|
|
113
|
+
}, le = {
|
|
117
114
|
sm: {
|
|
118
115
|
"--pho-sheen-y": "-3px",
|
|
119
116
|
"--pho-sheen-blur": "8px",
|
|
@@ -129,7 +126,7 @@ var V = {
|
|
|
129
126
|
"--pho-sheen-blur": "14px",
|
|
130
127
|
"--pho-sheen-spread": "1px"
|
|
131
128
|
}
|
|
132
|
-
},
|
|
129
|
+
}, he = {
|
|
133
130
|
sm: {
|
|
134
131
|
"--pho-sheen-y": "1.5px",
|
|
135
132
|
"--pho-sheen-blur": "4px",
|
|
@@ -145,7 +142,7 @@ var V = {
|
|
|
145
142
|
"--pho-sheen-blur": "7px",
|
|
146
143
|
"--pho-sheen-spread": "1px"
|
|
147
144
|
}
|
|
148
|
-
},
|
|
145
|
+
}, de = 0.97, ce = {
|
|
149
146
|
sm: {
|
|
150
147
|
"--pho-sheen-y": [
|
|
151
148
|
"1.5px",
|
|
@@ -197,7 +194,7 @@ var V = {
|
|
|
197
194
|
"2px"
|
|
198
195
|
]
|
|
199
196
|
}
|
|
200
|
-
},
|
|
197
|
+
}, ue = {
|
|
201
198
|
duration: 0.6,
|
|
202
199
|
delay: 0.05,
|
|
203
200
|
times: [
|
|
@@ -207,9 +204,9 @@ var V = {
|
|
|
207
204
|
],
|
|
208
205
|
ease: ["easeOut", "easeInOut"]
|
|
209
206
|
};
|
|
210
|
-
function
|
|
211
|
-
const [o, r] =
|
|
212
|
-
return
|
|
207
|
+
function V(e, a) {
|
|
208
|
+
const [o, r] = Y(!1), n = X(e), t = oe();
|
|
209
|
+
return $(() => {
|
|
213
210
|
n.current && !e && a && !t ? r(!0) : e && r(!1), n.current = e;
|
|
214
211
|
}, [
|
|
215
212
|
e,
|
|
@@ -222,7 +219,7 @@ function M(e, a) {
|
|
|
222
219
|
}
|
|
223
220
|
};
|
|
224
221
|
}
|
|
225
|
-
var
|
|
222
|
+
var fe = {
|
|
226
223
|
sm: {
|
|
227
224
|
rest: {
|
|
228
225
|
opacity: 0,
|
|
@@ -259,7 +256,7 @@ var ue = {
|
|
|
259
256
|
height: 21
|
|
260
257
|
}
|
|
261
258
|
}
|
|
262
|
-
},
|
|
259
|
+
}, M = {
|
|
263
260
|
sm: "has-[[data-icon=prefix]]:pl-3.5 has-[[data-icon=loading]]:pl-3.5 has-[[data-icon=suffix]]:pr-3.5",
|
|
264
261
|
md: "has-[[data-icon=prefix]]:pl-4 has-[[data-icon=loading]]:pl-4 has-[[data-icon=suffix]]:pr-4",
|
|
265
262
|
lg: "has-[[data-icon=prefix]]:pl-5 has-[[data-icon=loading]]:pl-5 has-[[data-icon=suffix]]:pr-5"
|
|
@@ -267,8 +264,8 @@ var ue = {
|
|
|
267
264
|
function N({ position: e, size: a, children: o }) {
|
|
268
265
|
return /* @__PURE__ */ s(w.span, {
|
|
269
266
|
"data-icon": e,
|
|
270
|
-
variants:
|
|
271
|
-
transition:
|
|
267
|
+
variants: fe[a],
|
|
268
|
+
transition: U,
|
|
272
269
|
style: {
|
|
273
270
|
display: "inline-flex",
|
|
274
271
|
flex: "none",
|
|
@@ -298,7 +295,7 @@ function O(e, a, o) {
|
|
|
298
295
|
function H({ svgOnly: e, loading: a, prefix: o, suffix: r, children: n, iconReveal: t, size: p }) {
|
|
299
296
|
if (e) return a ? /* @__PURE__ */ s(C, {}) : n;
|
|
300
297
|
const i = !!t;
|
|
301
|
-
return /* @__PURE__ */ z
|
|
298
|
+
return /* @__PURE__ */ ee(z, { children: [
|
|
302
299
|
a ? /* @__PURE__ */ s(k, {
|
|
303
300
|
position: "loading",
|
|
304
301
|
children: /* @__PURE__ */ s(C, {})
|
|
@@ -314,13 +311,13 @@ function H({ svgOnly: e, loading: a, prefix: o, suffix: r, children: n, iconReve
|
|
|
314
311
|
function W(e, a, o) {
|
|
315
312
|
const r = {
|
|
316
313
|
scale: 1,
|
|
317
|
-
...o.sheen ?
|
|
318
|
-
}, n = o.sheen ? { ...
|
|
319
|
-
scale:
|
|
320
|
-
...o.sheen ?
|
|
314
|
+
...o.sheen ? pe : {}
|
|
315
|
+
}, n = o.sheen ? { ...le[e] } : {}, t = {
|
|
316
|
+
scale: de,
|
|
317
|
+
...o.sheen ? he[e] : {}
|
|
321
318
|
}, p = o.sheen ? {
|
|
322
|
-
...
|
|
323
|
-
transition:
|
|
319
|
+
...ce[e],
|
|
320
|
+
transition: ue
|
|
324
321
|
} : {};
|
|
325
322
|
return o.iconReveal && (r.gap = 0, n.gap = e === "lg" ? 4 : 0), {
|
|
326
323
|
initial: !1,
|
|
@@ -333,7 +330,7 @@ function W(e, a, o) {
|
|
|
333
330
|
press: t,
|
|
334
331
|
wake: p
|
|
335
332
|
},
|
|
336
|
-
transition:
|
|
333
|
+
transition: U
|
|
337
334
|
};
|
|
338
335
|
}
|
|
339
336
|
function q({ variant: e, color: a, size: o, shape: r, loading: n, svgOnly: t, className: p }) {
|
|
@@ -345,15 +342,15 @@ function q({ variant: e, color: a, size: o, shape: r, loading: n, svgOnly: t, cl
|
|
|
345
342
|
}), n && "pointer-events-none", t && "[&>svg]:size-[1.25em] [&>svg]:shrink-0", p);
|
|
346
343
|
}
|
|
347
344
|
function D({ variant: e = "effect", color: a, size: o = "md", shape: r, prefix: n, suffix: t, iconReveal: p = !1, svgOnly: i, loading: h, children: g, className: b, ref: _, ...v }) {
|
|
348
|
-
|
|
349
|
-
const d = e === "effect", u = p && !i, x = !!(v.disabled || h), { waking: f, onWakeComplete: y } =
|
|
345
|
+
P(i, v["aria-label"]);
|
|
346
|
+
const d = e === "effect", u = p && !i, x = !!(v.disabled || h), { waking: f, onWakeComplete: y } = V(x, d), m = q({
|
|
350
347
|
variant: e,
|
|
351
348
|
color: a,
|
|
352
349
|
size: o,
|
|
353
350
|
shape: r,
|
|
354
351
|
loading: h,
|
|
355
352
|
svgOnly: i,
|
|
356
|
-
className: l(u &&
|
|
353
|
+
className: l(u && M[o], b)
|
|
357
354
|
}), E = H({
|
|
358
355
|
svgOnly: i,
|
|
359
356
|
loading: h,
|
|
@@ -382,8 +379,8 @@ function D({ variant: e = "effect", color: a, size: o = "md", shape: r, prefix:
|
|
|
382
379
|
});
|
|
383
380
|
}
|
|
384
381
|
D.displayName = "Button";
|
|
385
|
-
function
|
|
386
|
-
|
|
382
|
+
function G({ variant: e = "effect", color: a, size: o = "md", shape: r, prefix: n, suffix: t, iconReveal: p = !1, svgOnly: i, loading: h, disabled: g, href: b, children: _, className: v, ...d }) {
|
|
383
|
+
P(i, d["aria-label"]);
|
|
387
384
|
const u = Z(), x = e === "effect", f = p && !i, y = q({
|
|
388
385
|
variant: e,
|
|
389
386
|
color: a,
|
|
@@ -391,7 +388,7 @@ function j({ variant: e = "effect", color: a, size: o = "md", shape: r, prefix:
|
|
|
391
388
|
shape: r,
|
|
392
389
|
loading: h,
|
|
393
390
|
svgOnly: i,
|
|
394
|
-
className: l(f &&
|
|
391
|
+
className: l(f && M[o], v)
|
|
395
392
|
}), m = H({
|
|
396
393
|
svgOnly: i,
|
|
397
394
|
loading: h,
|
|
@@ -400,7 +397,7 @@ function j({ variant: e = "effect", color: a, size: o = "md", shape: r, prefix:
|
|
|
400
397
|
children: _,
|
|
401
398
|
iconReveal: f,
|
|
402
399
|
size: o
|
|
403
|
-
}), E =
|
|
400
|
+
}), E = J(() => w.create(u), [u]), c = !!(g || h), { waking: S, onWakeComplete: j } = V(c, x), T = {
|
|
404
401
|
...d,
|
|
405
402
|
...c ? {} : { href: b },
|
|
406
403
|
"aria-disabled": c || void 0,
|
|
@@ -422,15 +419,15 @@ function j({ variant: e = "effect", color: a, size: o = "md", shape: r, prefix:
|
|
|
422
419
|
iconReveal: f,
|
|
423
420
|
waking: S
|
|
424
421
|
}),
|
|
425
|
-
onAnimationComplete:
|
|
422
|
+
onAnimationComplete: j,
|
|
426
423
|
"data-waking": S || void 0,
|
|
427
424
|
...T,
|
|
428
425
|
children: m
|
|
429
426
|
});
|
|
430
427
|
}
|
|
431
|
-
|
|
432
|
-
var
|
|
433
|
-
function
|
|
428
|
+
G.displayName = "ButtonLink";
|
|
429
|
+
var Re = L;
|
|
430
|
+
function Ce(e) {
|
|
434
431
|
const { size: a = "md", fullWidth: o, className: r } = e ?? {};
|
|
435
432
|
return F({
|
|
436
433
|
variant: "effect",
|
|
@@ -438,7 +435,7 @@ function Se(e) {
|
|
|
438
435
|
className: l(o && "w-full", r)
|
|
439
436
|
});
|
|
440
437
|
}
|
|
441
|
-
function
|
|
438
|
+
function ve({ size: e = "md", fullWidth: a, animated: o, iconReveal: r, className: n, ...t }) {
|
|
442
439
|
return /* @__PURE__ */ s(D, {
|
|
443
440
|
variant: "effect",
|
|
444
441
|
size: e,
|
|
@@ -447,9 +444,9 @@ function fe({ size: e = "md", fullWidth: a, animated: o, iconReveal: r, classNam
|
|
|
447
444
|
...t
|
|
448
445
|
});
|
|
449
446
|
}
|
|
450
|
-
|
|
451
|
-
function
|
|
452
|
-
return /* @__PURE__ */ s(
|
|
447
|
+
ve.displayName = "EffectButton";
|
|
448
|
+
function xe({ size: e = "md", fullWidth: a, animated: o, iconReveal: r, className: n, ...t }) {
|
|
449
|
+
return /* @__PURE__ */ s(G, {
|
|
453
450
|
variant: "effect",
|
|
454
451
|
size: e,
|
|
455
452
|
iconReveal: r ?? o ?? !0,
|
|
@@ -457,19 +454,19 @@ function ve({ size: e = "md", fullWidth: a, animated: o, iconReveal: r, classNam
|
|
|
457
454
|
...t
|
|
458
455
|
});
|
|
459
456
|
}
|
|
460
|
-
|
|
457
|
+
xe.displayName = "EffectButtonLink";
|
|
461
458
|
export {
|
|
462
459
|
D as a,
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
460
|
+
ve as c,
|
|
461
|
+
Ce as d,
|
|
462
|
+
Se as i,
|
|
463
|
+
xe as l,
|
|
464
|
+
re as n,
|
|
465
|
+
G as o,
|
|
469
466
|
L as r,
|
|
470
|
-
|
|
471
|
-
|
|
467
|
+
Re as s,
|
|
468
|
+
Te as t,
|
|
472
469
|
F as u
|
|
473
470
|
};
|
|
474
471
|
|
|
475
|
-
//# sourceMappingURL=button-
|
|
472
|
+
//# sourceMappingURL=button-CdqS_t5a.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-CdqS_t5a.js","names":[],"sources":["../../src/components/button/button.tsx"],"sourcesContent":["import {\n isValidElement,\n useEffect,\n useMemo,\n useRef,\n useState,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type ComponentType,\n type FC,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { SPRING_PRESS } from \"../../motion\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\nimport { isReactComponent } from \"../../utils/is-react-component\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { Spinner } from \"../spinner/spinner\";\n\n/**\n * Design notes:\n * - TWO visual axes: `variant` is the surface (filled / outlined / ghost /\n * effect) and `color` is the semantic ink (default / destructive). Dialog\n * confirms use the default `effect`; danger-zone triggers are `ghost` +\n * `destructive`. `effect` is the marketing pill: same-hue 1.5px outer rim\n * plus inset sheen that springs on hover.\n * - `iconReveal` is a separate boolean: on hover, prefix/suffix icons spring\n * in from collapsed — works with any variant, independent of `effect`.\n * - Press scale (Motion `whileTap` → 0.97) is shared by every variant; only\n * `effect` also springs its inset sheen on hover/press, and replays a\n * one-shot sheen glint when it leaves `disabled`/`loading` (wake).\n * - THREE sizes (`sm` / `md` / `lg`, default `md`). No `xs` / `xl`.\n * - `prefix` / `suffix` are generic slots (icon, spinner, count…), not\n * icon-only props. `svgOnly` makes an icon button and *requires* an\n * `aria-label`. `loading` is declarative. Effect’s rim/sheen are\n * box-shadow layers (not layout `border`).\n * - Navigation belongs to `ButtonLink`; an inline text link is an anchor.\n */\n\nconst COMMON_ROOT = cn(\n // Transition colors/shadows in CSS; transform (press scale) is owned by Motion.\n \"group relative inline-flex h-max cursor-pointer items-center justify-center whitespace-nowrap outline-pho-brand transition-[color,background-color,border-color,opacity,box-shadow,outline-color] duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2\",\n // Disabled (native `disabled` on <button>, `aria-disabled` on links).\n \"disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none\",\n);\n\n/**\n * Size axis — padding, text size, and icon-only (svgOnly) padding.\n *\n * Icon-side tuck (LiftKit-derived optical correction): a side that carries an\n * icon gets its padding divided by the golden ratio — an icon's rounded form\n * brings its own whitespace, so the full text-edge padding reads as a hole.\n * LiftKit: `--button-padX-sideWithIcon: calc(font-size / 1.618)`. Applied to\n * Pho's paddings: sm 14px/φ ≈ 8px · md 16px/φ ≈ 10px · lg 20px/φ ≈ 12px,\n * selected structurally via `:has()` on the slot markers (`data-icon` is\n * `prefix`, `suffix`, or `loading` — the spinner is an icon too).\n */\nexport const BUTTON_SIZES = {\n sm: {\n classes: cn(\n \"gap-1 px-3.5 py-1.5 text-base font-medium data-svg-only:p-2\",\n \"has-[[data-icon=prefix]]:pl-2 has-[[data-icon=loading]]:pl-2 has-[[data-icon=suffix]]:pr-2\",\n ),\n description: \"Small — compact rows, tables, and toolbars\",\n },\n md: {\n classes: cn(\n \"gap-1 px-4 py-2 text-base font-medium data-svg-only:p-2.5\",\n \"has-[[data-icon=prefix]]:pl-2.5 has-[[data-icon=loading]]:pl-2.5 has-[[data-icon=suffix]]:pr-2.5\",\n ),\n description: \"Medium — the default\",\n },\n lg: {\n classes: cn(\n \"gap-1.5 px-5 py-2.5 text-md font-medium data-svg-only:p-3\",\n \"has-[[data-icon=prefix]]:pl-3 has-[[data-icon=loading]]:pl-3 has-[[data-icon=suffix]]:pr-3\",\n ),\n description: \"Large — prominent and marketing actions\",\n },\n} satisfies VariantMap;\n\n/** Shape axis — corner treatment. Pills are the photon.codes default. */\nexport const BUTTON_SHAPES = {\n rounded: {\n classes: \"rounded-full\",\n description: \"Pill — the default; every button on photon.codes\",\n },\n square: {\n classes: \"rounded-base\",\n description: \"Gently rounded corners for dense app chrome\",\n },\n circle: {\n classes: \"rounded-full\",\n description: \"Circular — pair with svgOnly for round icon buttons\",\n },\n} satisfies VariantMap;\n\n/**\n * At `lg`, square buttons add squircle smoothing on top of `rounded-base`\n * (12px) — the same treatment as Input `lg`, so 44px buttons and fields share\n * a corner language. 12/44 ≈ 0.272 — LiftKit's half-step decimal (√φ − 1).\n */\nconst SQUARE_LG_RADIUS = \"squircle\";\n\n/**\n * Optical pad for `effect`: the 1.5px outer rim is a box-shadow (no layout\n * cost), so without this the painted height reads ~3px taller than filled /\n * outlined / ghost. Subtract 1.5px from each side so fill+rim matches siblings.\n */\nconst EFFECT_OPTICAL_PAD: Record<ButtonSize, string> = {\n sm: \"py-[4.5px] data-svg-only:p-[6.5px]\",\n md: \"py-[6.5px] data-svg-only:p-[8.5px]\",\n lg: \"py-[8.5px] data-svg-only:p-[10.5px]\",\n};\n\n/** Surface axis — how the control is drawn. `effect` is the default. */\nexport const BUTTON_VARIANTS = {\n effect: {\n classes: \"\",\n description:\n \"Default — marketing pill with same-hue outer rim and inset sheen\",\n },\n filled: {\n classes: \"\",\n description: \"Solid fill without sheen\",\n },\n outlined: {\n classes: \"\",\n description: \"Hairline ring — supporting action\",\n },\n ghost: {\n classes: \"\",\n description: \"Borderless — quiet / inline action\",\n },\n} satisfies VariantMap;\n\n/** Color axis — semantic ink. `default` is the default. */\nexport const BUTTON_COLORS = {\n default: {\n classes: \"\",\n description: \"Neutral / brand contrast\",\n },\n destructive: {\n classes: \"\",\n description: \"Destructive intent (delete, discard)\",\n },\n} satisfies VariantMap;\n\n/**\n * Surface × color looks. Kept as a matrix so each cell can own its tokens\n * (filled destructive is solid red; ghost destructive is red text only).\n */\nconst BUTTON_LOOKS: Record<\n keyof typeof BUTTON_VARIANTS,\n Record<keyof typeof BUTTON_COLORS, string>\n> = {\n // Icons inherit the label ink (currentColor) — no separate opacity/tint.\n // The rim replicates photon.codes' Framer CTA border: 1.5px in the fill hue\n // at 62% alpha, reading as a soft same-hue edge (the site has NO outer\n // glow — verified against live computed styles). Sheen geometry is CSS\n // vars that Motion springs on hover (see Button). All edges are shadows —\n // never a layout `border` — so height stays paired with other variants.\n effect: {\n default: cn(\n \"squircle overflow-hidden bg-pho-brand-solid text-pho-on-brand transition-none\",\n \"hover:bg-pho-brand-solid data-loading:bg-pho-brand-solid\",\n \"[--pho-rim:color-mix(in_oklab,var(--background-color-pho-brand-solid)_62%,transparent)]\",\n \"[--pho-sheen:light-dark(rgba(255,255,255,0.5),rgba(0,0,0,0.12))]\",\n \"shadow-[0_0_0_1.5px_var(--pho-rim),inset_0_0_0_1px_var(--border-color-pho-on-brand),inset_0_var(--pho-sheen-y,0px)_var(--pho-sheen-blur,5px)_var(--pho-sheen-spread,2px)_var(--pho-sheen)]\",\n ),\n destructive: cn(\n \"squircle overflow-hidden bg-pho-error-solid text-white outline-pho-error transition-none\",\n \"hover:bg-pho-error-solid data-loading:bg-pho-error-solid\",\n \"[--pho-rim:color-mix(in_oklab,var(--background-color-pho-error-solid)_62%,transparent)]\",\n \"[--pho-sheen:light-dark(rgba(255,255,255,0.45),rgba(0,0,0,0.18))]\",\n \"shadow-[0_0_0_1.5px_var(--pho-rim),inset_0_0_0_1px_oklch(1_0_0/0.2),inset_0_var(--pho-sheen-y,0px)_var(--pho-sheen-blur,5px)_var(--pho-sheen-spread,2px)_var(--pho-sheen)]\",\n ),\n },\n filled: {\n default:\n \"bg-pho-brand-solid text-pho-on-brand hover:bg-pho-brand-solid-hover data-loading:bg-pho-brand-solid-hover\",\n destructive:\n \"bg-pho-error-solid text-white outline-pho-error hover:bg-pho-error-solid-hover data-loading:bg-pho-error-solid-hover\",\n },\n outlined: {\n default:\n // Rest hairline is the card stroke; hover climbs to primary ink so the\n // edge reads as black (white in dark), matching the label's hover lift.\n // The ring spans the full ladder, so ease it in gently — 200ms ease-out\n // approximates the effect variant's soft spring instead of base's\n // 100ms linear snap. Prefer the named `ring-pho-ink` token over an\n // arbitrary value so consumers' Tailwind scanners pick it up reliably.\n \"bg-pho-primary text-pho-secondary ring-1 ring-pho-secondary ring-inset duration-200 ease-out hover:bg-pho-primary-hover hover:text-pho-secondary-hover hover:ring-pho-ink data-loading:bg-pho-primary-hover\",\n destructive:\n \"bg-pho-primary text-pho-error outline-pho-error ring-1 ring-pho-error ring-inset duration-200 ease-out hover:bg-pho-error-primary hover:text-pho-error-hover data-loading:bg-pho-error-primary\",\n },\n ghost: {\n default:\n \"text-pho-secondary hover:bg-pho-ghost-hover hover:text-pho-secondary-hover data-loading:bg-pho-ghost-hover\",\n destructive:\n \"text-pho-error outline-pho-error hover:bg-pho-error-primary hover:text-pho-error-hover data-loading:bg-pho-error-primary\",\n },\n};\n\nexport type ButtonSize = keyof typeof BUTTON_SIZES;\nexport type ButtonShape = keyof typeof BUTTON_SHAPES;\nexport type ButtonVariant = keyof typeof BUTTON_VARIANTS;\nexport type ButtonColor = keyof typeof BUTTON_COLORS;\n\n/** Compose the full class string for a button — exported for reuse/testing. */\nexport function buttonVariants(opts?: {\n variant?: ButtonVariant;\n color?: ButtonColor;\n size?: ButtonSize;\n shape?: ButtonShape;\n className?: string;\n}): string {\n const {\n variant = \"effect\",\n color = \"default\",\n size = \"md\",\n shape: shapeOpt = \"rounded\",\n className,\n } = opts ?? {};\n // Effect pills are always fully rounded — shape is ignored.\n const shape = variant === \"effect\" ? \"rounded\" : shapeOpt;\n const look =\n BUTTON_LOOKS[variant as keyof typeof BUTTON_LOOKS]?.[\n color as keyof (typeof BUTTON_LOOKS)[\"effect\"]\n ] ?? \"\";\n return cn(\n COMMON_ROOT,\n resolveVariant(BUTTON_SHAPES, shape),\n shape === \"square\" && size === \"lg\" && SQUARE_LG_RADIUS,\n resolveVariant(BUTTON_SIZES, size),\n // Outer rim is a 1.5px box-shadow (no layout cost). Shrink padding by the\n // same amount so fill+rim paints at the same visual size as filled /\n // outlined / ghost siblings of the same `size`.\n variant === \"effect\" && EFFECT_OPTICAL_PAD[size],\n look,\n className,\n );\n}\n\n/** An icon/element slot rendered before or after the label. */\ntype Slottable = ReactNode | FC<{ className?: string }>;\n\ninterface ButtonBaseProps {\n /** Surface variant. @default \"effect\" */\n variant?: ButtonVariant;\n /** Semantic color. @default \"default\" */\n color?: ButtonColor;\n /** Size variant. @default \"md\" */\n size?: ButtonSize;\n /** Corner shape. @default \"rounded\" */\n shape?: ButtonShape;\n /** Slot before the label — a component (`Plus`) or element (`<Plus />`). */\n prefix?: Slottable;\n /** Slot after the label. */\n suffix?: Slottable;\n /**\n * Reveal prefix/suffix icons on hover — collapsed and invisible at rest,\n * spring in on hover. Independent of `variant` (including `effect`).\n * Ignored when `svgOnly`. @default false\n */\n iconReveal?: boolean;\n /** Render as an icon-only button. Requires an `aria-label`. */\n svgOnly?: boolean;\n /** Show a spinner and block interaction while staying readable. */\n loading?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\n/**\n * DOM event handlers whose React signatures clash with Motion's gesture\n * props of the same name (Motion re-types these on `motion.*` elements).\n * Excluded from the public API — Button renders through Motion when the\n * sheen or icon reveal is active, so these handlers would be intercepted.\n */\ntype MotionHandlerConflicts =\n | \"onAnimationStart\"\n | \"onAnimationEnd\"\n | \"onAnimationIteration\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onDragEnter\"\n | \"onDragExit\"\n | \"onDragLeave\"\n | \"onDragOver\"\n | \"onDrop\";\n\nexport interface ButtonProps\n extends\n ButtonBaseProps,\n Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n keyof ButtonBaseProps | MotionHandlerConflicts\n > {\n ref?: Ref<HTMLButtonElement>;\n}\n\nexport interface ButtonLinkProps\n extends\n ButtonBaseProps,\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof ButtonBaseProps | MotionHandlerConflicts\n > {\n /** Navigate to this URL (rendered via the host's `LinkProvider`). */\n href: string;\n /** Visually and semantically disable the link. */\n disabled?: boolean;\n}\n\nconst SLOT_CLASS =\n // Icons scale with the label: 1.125em tracks the button's font size\n // (16px icon beside 14px text, 18px beside 16px) so small buttons never\n // carry an oversized glyph.\n \"transition-inherit-all pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-[1.125em] [&>svg]:shrink-0\";\n\nfunction Slot({\n position,\n children,\n}: {\n position: \"prefix\" | \"suffix\" | \"loading\";\n children: ReactNode;\n}) {\n return (\n <span data-icon={position} className={SLOT_CLASS}>\n {children}\n </span>\n );\n}\n\nfunction renderSlot(icon: Slottable, position: \"prefix\" | \"suffix\") {\n if (icon == null || icon === false) return null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n return (\n <Slot position={position}>\n <Icon />\n </Slot>\n );\n }\n if (isValidElement(icon)) return <Slot position={position}>{icon}</Slot>;\n return null;\n}\n\nfunction warnMissingLabel(svgOnly: boolean | undefined, label: unknown) {\n if (\n svgOnly &&\n !label &&\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.warn(\n \"Button: `svgOnly` buttons require an `aria-label` that names the action.\",\n );\n }\n}\n\n/* ======================== Motion: sheen + icon reveal ======================== */\n\n/** Framer source transition: `spring-physics 200 30 0.1`. */\nconst BUTTON_SPRING = SPRING_PRESS;\n\nconst EFFECT_SHEEN_REST = {\n \"--pho-sheen-y\": \"0px\",\n \"--pho-sheen-blur\": \"5px\",\n \"--pho-sheen-spread\": \"2px\",\n} as const;\n\n/** Per-size sheen hover targets. */\nconst EFFECT_SHEEN_HOVER = {\n sm: {\n \"--pho-sheen-y\": \"-3px\",\n \"--pho-sheen-blur\": \"8px\",\n \"--pho-sheen-spread\": \"2px\",\n },\n md: {\n \"--pho-sheen-y\": \"-3px\",\n \"--pho-sheen-blur\": \"8px\",\n \"--pho-sheen-spread\": \"2px\",\n },\n lg: {\n \"--pho-sheen-y\": \"-6px\",\n \"--pho-sheen-blur\": \"14px\",\n \"--pho-sheen-spread\": \"1px\",\n },\n} as const;\n\n/**\n * Per-size sheen press targets — the inverse gesture of hover: the light\n * drops back below the rest line and tightens while the pill compresses\n * slightly, so hover → press reads as \"lift, then push in\".\n */\nconst EFFECT_SHEEN_PRESS = {\n sm: {\n \"--pho-sheen-y\": \"1.5px\",\n \"--pho-sheen-blur\": \"4px\",\n \"--pho-sheen-spread\": \"1px\",\n },\n md: {\n \"--pho-sheen-y\": \"1.5px\",\n \"--pho-sheen-blur\": \"4px\",\n \"--pho-sheen-spread\": \"1px\",\n },\n lg: {\n \"--pho-sheen-y\": \"3px\",\n \"--pho-sheen-blur\": \"7px\",\n \"--pho-sheen-spread\": \"1px\",\n },\n} as const;\n\n/** Pill compression while pressed — subtle, transform-only; every variant. */\nconst BUTTON_PRESS_SCALE = 0.97;\n\n/**\n * One-shot \"wake\" glint when an effect pill re-enables (disabled / loading →\n * interactive). The keyframes replay the pill's own gesture in reverse: the\n * sheen starts from its pressed-in position (low, tight — the dormant read),\n * springs up past the hover line, and settles at rest. Shadow-only, so the\n * pill never moves or resizes next to its neighbours.\n */\nconst EFFECT_SHEEN_WAKE = {\n sm: {\n \"--pho-sheen-y\": [\"1.5px\", \"-4px\", \"0px\"],\n \"--pho-sheen-blur\": [\"4px\", \"9px\", \"5px\"],\n \"--pho-sheen-spread\": [\"1px\", \"2px\", \"2px\"],\n },\n md: {\n \"--pho-sheen-y\": [\"1.5px\", \"-4px\", \"0px\"],\n \"--pho-sheen-blur\": [\"4px\", \"9px\", \"5px\"],\n \"--pho-sheen-spread\": [\"1px\", \"2px\", \"2px\"],\n },\n lg: {\n \"--pho-sheen-y\": [\"3px\", \"-8px\", \"0px\"],\n \"--pho-sheen-blur\": [\"7px\", \"16px\", \"5px\"],\n \"--pho-sheen-spread\": [\"1px\", \"1px\", \"2px\"],\n },\n} as const;\n\n/**\n * Wake timing: a short delay lets the 100ms opacity fade land first, then a\n * quick rise (feedback) and a relaxed settle. Keyframes need a tween — the\n * shared spring only animates between two values.\n */\nconst WAKE_TRANSITION = {\n duration: 0.6,\n delay: 0.05,\n times: [0, 0.4, 1],\n ease: [\"easeOut\", \"easeInOut\"],\n} as const;\n\n/**\n * Fire the wake glint on the disabled/loading → enabled edge (never on\n * mount), skipped under reduced motion. `data-waking` mirrors the window so\n * tests and styling can observe it.\n */\nfunction useWakeOnEnable(inert: boolean, sheen: boolean) {\n const [waking, setWaking] = useState(false);\n const prevInert = useRef(inert);\n const reduceMotion = useReducedMotion();\n\n useEffect(() => {\n if (prevInert.current && !inert && sheen && !reduceMotion) {\n setWaking(true);\n } else if (inert) {\n setWaking(false);\n }\n prevInert.current = inert;\n }, [inert, sheen, reduceMotion]);\n\n return {\n waking,\n onWakeComplete: (definition: unknown) => {\n if (definition === \"wake\") setWaking(false);\n },\n };\n}\n\n/**\n * Icon reveal sizes — collapsed at rest, full on hover. `lg` matches the\n * Framer 20×21 source; `sm`/`md` scale with the 14px label.\n */\nconst ICON_REVEAL_VARIANTS = {\n sm: {\n rest: { opacity: 0, width: 1, height: 9 },\n hover: { opacity: 1, width: 17, height: 18 },\n },\n md: {\n rest: { opacity: 0, width: 1, height: 9 },\n hover: { opacity: 1, width: 17, height: 18 },\n },\n lg: {\n rest: { opacity: 0, width: 1, height: 10 },\n hover: { opacity: 1, width: 20, height: 21 },\n },\n} as const;\n\n/**\n * When icons are hidden at rest, undo Button's icon-side padding tuck so the\n * pill doesn't look lopsided. Same `:has()` keys as the tuck (later wins).\n */\nconst ICON_REVEAL_PAD_RESTORE: Record<ButtonSize, string> = {\n sm: \"has-[[data-icon=prefix]]:pl-3.5 has-[[data-icon=loading]]:pl-3.5 has-[[data-icon=suffix]]:pr-3.5\",\n md: \"has-[[data-icon=prefix]]:pl-4 has-[[data-icon=loading]]:pl-4 has-[[data-icon=suffix]]:pr-4\",\n lg: \"has-[[data-icon=prefix]]:pl-5 has-[[data-icon=loading]]:pl-5 has-[[data-icon=suffix]]:pr-5\",\n};\n\nfunction RevealSlot({\n position,\n size,\n children,\n}: {\n position: \"prefix\" | \"suffix\";\n size: ButtonSize;\n children: ReactNode;\n}) {\n return (\n <motion.span\n data-icon={position}\n variants={ICON_REVEAL_VARIANTS[size]}\n transition={BUTTON_SPRING}\n style={{\n display: \"inline-flex\",\n flex: \"none\",\n alignItems: \"center\",\n overflow: \"hidden\",\n }}\n className=\"pointer-events-none [&>svg]:block [&>svg]:size-full\"\n >\n {children}\n </motion.span>\n );\n}\n\nfunction wrapRevealIcon(\n icon: Slottable,\n position: \"prefix\" | \"suffix\",\n size: ButtonSize,\n): ReactNode | undefined {\n if (icon == null || icon === false) return undefined;\n if (isReactComponent(icon)) {\n const Icon = icon;\n return (\n <RevealSlot position={position} size={size}>\n <Icon />\n </RevealSlot>\n );\n }\n if (isValidElement(icon)) {\n return (\n <RevealSlot position={position} size={size}>\n {icon}\n </RevealSlot>\n );\n }\n return (\n <RevealSlot position={position} size={size}>\n {icon}\n </RevealSlot>\n );\n}\n\nfunction buttonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n iconReveal,\n size,\n}: Pick<\n ButtonBaseProps,\n | \"svgOnly\"\n | \"loading\"\n | \"prefix\"\n | \"suffix\"\n | \"children\"\n | \"iconReveal\"\n | \"size\"\n> & { size: ButtonSize }) {\n if (svgOnly) {\n return loading ? <Spinner /> : children;\n }\n const reveal = Boolean(iconReveal);\n return (\n <>\n {loading ? (\n <Slot position=\"loading\">\n <Spinner />\n </Slot>\n ) : reveal ? (\n wrapRevealIcon(prefix, \"prefix\", size)\n ) : (\n renderSlot(prefix, \"prefix\")\n )}\n {children != null && children !== false && (\n <span data-text className=\"transition-inherit-all px-0.5\">\n {children}\n </span>\n )}\n {reveal\n ? wrapRevealIcon(suffix, \"suffix\", size)\n : renderSlot(suffix, \"suffix\")}\n </>\n );\n}\n\n/**\n * Root Motion props — press scale on every variant; sheen + icon-reveal gap\n * only when those features are on. Press composes over hover (`whileTap` >\n * `whileHover`): effect sheen inverts while the pill compresses; other\n * variants get the same scale with no sheen change. `waking` plays the\n * one-shot re-enable glint; a real hover mid-glint takes over seamlessly.\n */\nfunction buttonRootMotionProps(\n size: ButtonSize,\n inert: boolean | undefined,\n opts: { sheen: boolean; iconReveal: boolean; waking?: boolean },\n) {\n const rest: Record<string, string | number> = {\n scale: 1,\n ...(opts.sheen ? EFFECT_SHEEN_REST : {}),\n };\n const hover: Record<string, string | number> = opts.sheen\n ? { ...EFFECT_SHEEN_HOVER[size] }\n : {};\n const press: Record<string, string | number> = {\n scale: BUTTON_PRESS_SCALE,\n ...(opts.sheen ? EFFECT_SHEEN_PRESS[size] : {}),\n };\n const wake = opts.sheen\n ? { ...EFFECT_SHEEN_WAKE[size], transition: WAKE_TRANSITION }\n : {};\n if (opts.iconReveal) {\n // Collapse gap at rest so the hidden icon leaves no hole; lg eases open.\n rest.gap = 0;\n hover.gap = size === \"lg\" ? 4 : 0;\n }\n return {\n initial: false as const,\n animate: opts.waking && opts.sheen ? \"wake\" : \"rest\",\n whileHover: inert ? undefined : \"hover\",\n whileTap: inert ? undefined : \"press\",\n variants: { rest, hover, press, wake },\n transition: BUTTON_SPRING,\n };\n}\n\nfunction buttonClassName({\n variant,\n color,\n size,\n shape,\n loading,\n svgOnly,\n className,\n}: {\n variant?: ButtonVariant;\n color?: ButtonColor;\n size?: ButtonSize;\n shape?: ButtonShape;\n loading?: boolean;\n svgOnly?: boolean;\n className?: string;\n}) {\n return cn(\n buttonVariants({ variant, color, size, shape }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-[1.25em] [&>svg]:shrink-0\",\n className,\n );\n}\n\n/**\n * Button — triggers an action that mutates state (submit, save, delete).\n * For navigation that changes the URL, use {@link ButtonLink}.\n *\n * Default surface is `effect` (same-hue 1.5px outer rim + inset sheen). Use\n * `filled` for a solid fill without those layers. `iconReveal` springs\n * prefix/suffix icons in on hover — independent of variant.\n */\nexport function Button({\n variant = \"effect\",\n color,\n size = \"md\",\n shape,\n prefix,\n suffix,\n iconReveal = false,\n svgOnly,\n loading,\n children,\n className,\n ref,\n ...props\n}: ButtonProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n const sheen = variant === \"effect\";\n const reveal = iconReveal && !svgOnly;\n const inert = Boolean(props.disabled || loading);\n const { waking, onWakeComplete } = useWakeOnEnable(inert, sheen);\n const cls = buttonClassName({\n variant,\n color,\n size,\n shape,\n loading,\n svgOnly,\n className: cn(reveal && ICON_REVEAL_PAD_RESTORE[size], className),\n });\n const inner = buttonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n iconReveal: reveal,\n size,\n });\n\n return (\n <motion.button\n ref={ref}\n type=\"button\"\n {...buttonRootMotionProps(size, inert, {\n sheen,\n iconReveal: reveal,\n waking,\n })}\n onAnimationComplete={onWakeComplete}\n {...props}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n data-waking={waking || undefined}\n className={cls}\n >\n {inner}\n </motion.button>\n );\n}\n\nButton.displayName = \"Button\";\n\n/**\n * ButtonLink — a link styled as a button, for navigation that changes the URL.\n * Shares every visual prop with {@link Button}; renders the host router's link\n * via `LinkProvider`.\n */\nexport function ButtonLink({\n variant = \"effect\",\n color,\n size = \"md\",\n shape,\n prefix,\n suffix,\n iconReveal = false,\n svgOnly,\n loading,\n disabled,\n href,\n children,\n className,\n ...props\n}: ButtonLinkProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n const Link = useLinkComponent();\n const sheen = variant === \"effect\";\n const reveal = iconReveal && !svgOnly;\n const cls = buttonClassName({\n variant,\n color,\n size,\n shape,\n loading,\n svgOnly,\n className: cn(reveal && ICON_REVEAL_PAD_RESTORE[size], className),\n });\n const inner = buttonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n iconReveal: reveal,\n size,\n });\n // Hooks must run unconditionally — only used when Motion is needed.\n const MotionLink = useMemo(\n // LinkProvider requires `href`; motion.create needs an open prop record —\n // bridge the two through `unknown` (props are supplied at the call site).\n () =>\n motion.create(Link as unknown as ComponentType<Record<string, unknown>>),\n [Link],\n );\n\n const inert = Boolean(disabled || loading);\n const { waking, onWakeComplete } = useWakeOnEnable(inert, sheen);\n const shared = {\n ...props,\n ...(inert ? {} : { href }),\n \"aria-disabled\": inert || undefined,\n \"aria-busy\": loading || undefined,\n \"data-loading\": loading ? (\"true\" as const) : undefined,\n \"data-svg-only\": svgOnly ? (\"true\" as const) : undefined,\n className: cls,\n tabIndex: inert ? -1 : props.tabIndex,\n onClick: inert\n ? (event: ReactMouseEvent<HTMLAnchorElement>) => {\n event.preventDefault();\n }\n : props.onClick,\n };\n\n if (inert) {\n return <span {...shared}>{inner}</span>;\n }\n\n return (\n <MotionLink\n {...buttonRootMotionProps(size, inert, {\n sheen,\n iconReveal: reveal,\n waking,\n })}\n onAnimationComplete={onWakeComplete}\n data-waking={waking || undefined}\n {...shared}\n >\n {inner}\n </MotionLink>\n );\n}\n\nButtonLink.displayName = \"ButtonLink\";\n\n/* ======================= EffectButton (compat alias) ======================= */\n\nexport const EFFECT_BUTTON_SIZES = BUTTON_SIZES;\nexport type EffectButtonSize = ButtonSize;\n\n/** Compose classes for an effect pill — `Button` with `variant=\"effect\"`. */\nexport function effectButtonVariants(opts?: {\n size?: EffectButtonSize;\n fullWidth?: boolean;\n className?: string;\n}): string {\n const { size = \"md\", fullWidth, className } = opts ?? {};\n return buttonVariants({\n variant: \"effect\",\n size,\n className: cn(fullWidth && \"w-full\", className),\n });\n}\n\n/**\n * Legacy EffectButton also reserved `style` (sheen variables lived there) and\n * never exposed the HTML `color` attribute — Button's semantic `color` prop\n * now occupies that name.\n */\ntype MotionConflicts = MotionHandlerConflicts | \"style\" | \"color\";\n\ninterface EffectButtonBaseProps {\n /** Size variant — Button's scale (32 / 36 / 44px). @default \"md\" */\n size?: EffectButtonSize;\n /** Stretch to the container's full width (stacked login / OAuth pills). */\n fullWidth?: boolean;\n /**\n * @deprecated Use `iconReveal` on `Button` instead. Mapped to `iconReveal`\n * when set.\n */\n animated?: boolean;\n /** @see ButtonBaseProps.iconReveal */\n iconReveal?: boolean;\n prefix?: Slottable;\n suffix?: Slottable;\n svgOnly?: boolean;\n loading?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\nexport interface EffectButtonProps\n extends\n EffectButtonBaseProps,\n Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n keyof EffectButtonBaseProps | MotionConflicts\n > {\n ref?: Ref<HTMLButtonElement>;\n}\n\nexport interface EffectButtonLinkProps\n extends\n EffectButtonBaseProps,\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof EffectButtonBaseProps | MotionConflicts\n > {\n href: string;\n disabled?: boolean;\n}\n\n/**\n * @deprecated Prefer `<Button variant=\"effect\">`. Thin alias that forwards to\n * Button with the sheen surface (no icon reveal).\n */\nexport function EffectButton({\n size = \"md\",\n fullWidth,\n animated,\n iconReveal,\n className,\n ...props\n}: EffectButtonProps) {\n return (\n <Button\n variant=\"effect\"\n size={size}\n iconReveal={iconReveal ?? animated ?? true}\n className={cn(fullWidth && \"w-full\", className)}\n {...props}\n />\n );\n}\n\nEffectButton.displayName = \"EffectButton\";\n\n/**\n * @deprecated Prefer `<ButtonLink variant=\"effect\">`.\n */\nexport function EffectButtonLink({\n size = \"md\",\n fullWidth,\n animated,\n iconReveal,\n className,\n ...props\n}: EffectButtonLinkProps) {\n return (\n <ButtonLink\n variant=\"effect\"\n size={size}\n iconReveal={iconReveal ?? animated ?? true}\n className={cn(fullWidth && \"w-full\", className)}\n {...props}\n />\n );\n}\n\nEffectButtonLink.displayName = \"EffectButtonLink\";\n"],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t } from "./cn-ChIgwEl3.js";
|
|
3
|
+
import { r as b } from "./use-press-pulse-IbNstUT0.js";
|
|
4
|
+
import { n as v, r as f, t as x } from "./choice-card-BVNP1NB6.js";
|
|
5
|
+
import "react";
|
|
6
|
+
import { jsx as e, jsxs as p } from "react/jsx-runtime";
|
|
7
|
+
import { motion as u } from "motion/react";
|
|
8
|
+
import { Checkbox as h } from "@base-ui/react/checkbox";
|
|
9
|
+
import { CheckboxGroup as k } from "@base-ui/react/checkbox-group";
|
|
10
|
+
var C = "M5 12l5 5l10 -10", y = "M5 12l14 0", N = {
|
|
11
|
+
duration: 0.22,
|
|
12
|
+
ease: "easeOut"
|
|
13
|
+
};
|
|
14
|
+
function g({ indeterminate: r, className: o }) {
|
|
15
|
+
return /* @__PURE__ */ e("svg", {
|
|
16
|
+
viewBox: "0 0 24 24",
|
|
17
|
+
fill: "none",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeWidth: 2,
|
|
20
|
+
strokeLinecap: "round",
|
|
21
|
+
strokeLinejoin: "round",
|
|
22
|
+
className: o,
|
|
23
|
+
"aria-hidden": "true",
|
|
24
|
+
children: /* @__PURE__ */ e(u.path, {
|
|
25
|
+
d: r ? y : C,
|
|
26
|
+
initial: { pathLength: 0 },
|
|
27
|
+
animate: { pathLength: 1 },
|
|
28
|
+
transition: N
|
|
29
|
+
}, r ? "minus" : "check")
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
var I = {
|
|
33
|
+
sm: "size-4",
|
|
34
|
+
md: "size-5"
|
|
35
|
+
}, _ = {
|
|
36
|
+
sm: "size-3",
|
|
37
|
+
md: "size-3.5"
|
|
38
|
+
};
|
|
39
|
+
function A({ className: r, label: o, size: s = "md", disabled: i, indeterminate: a, ...d }) {
|
|
40
|
+
const { motionProps: l } = b({
|
|
41
|
+
scale: 0.94,
|
|
42
|
+
disabled: !!i
|
|
43
|
+
}), { onPointerDown: c, ...n } = l, m = /* @__PURE__ */ e(h.Root, {
|
|
44
|
+
disabled: i,
|
|
45
|
+
indeterminate: a,
|
|
46
|
+
render: /* @__PURE__ */ e(u.span, {
|
|
47
|
+
...n,
|
|
48
|
+
onPointerDown: o ? void 0 : c
|
|
49
|
+
}),
|
|
50
|
+
className: t("group/cb outline-pho-brand bg-pho-primary ring-pho-primary text-pho-on-brand flex shrink-0 cursor-pointer items-center justify-center rounded-sm ring-1 ring-inset focus-visible:outline-2 focus-visible:outline-offset-2", "transition-[background-color,box-shadow,color,outline-color] duration-150 ease-out", "hover:bg-pho-primary-hover hover:ring-pho-ink group-hover:bg-pho-primary-hover group-hover:ring-pho-ink", "data-[checked]:bg-pho-brand-solid data-[checked]:ring-transparent", "data-[indeterminate]:bg-pho-brand-solid data-[indeterminate]:ring-transparent", "data-[checked]:hover:bg-pho-brand-solid-hover data-[checked]:group-hover:bg-pho-brand-solid-hover", "data-[indeterminate]:hover:bg-pho-brand-solid-hover data-[indeterminate]:group-hover:bg-pho-brand-solid-hover", "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", I[s], r),
|
|
51
|
+
...d,
|
|
52
|
+
children: /* @__PURE__ */ e(h.Indicator, {
|
|
53
|
+
className: t("flex items-center justify-center transition-opacity duration-100 ease-out", "data-[ending-style]:opacity-0"),
|
|
54
|
+
children: /* @__PURE__ */ e(g, {
|
|
55
|
+
indeterminate: a,
|
|
56
|
+
className: _[s]
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
return o ? /* @__PURE__ */ p("label", {
|
|
61
|
+
className: "group flex cursor-pointer items-center gap-2 select-none",
|
|
62
|
+
onPointerDown: c,
|
|
63
|
+
children: [m, /* @__PURE__ */ e("span", {
|
|
64
|
+
className: "text-pho-secondary text-base",
|
|
65
|
+
children: o
|
|
66
|
+
})]
|
|
67
|
+
}) : m;
|
|
68
|
+
}
|
|
69
|
+
A.displayName = "Checkbox";
|
|
70
|
+
function P({ className: r, ...o }) {
|
|
71
|
+
return /* @__PURE__ */ e(k, {
|
|
72
|
+
className: t("flex flex-col gap-3", r),
|
|
73
|
+
...o
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
P.displayName = "CheckboxGroup";
|
|
77
|
+
function R({ title: r, description: o }) {
|
|
78
|
+
return /* @__PURE__ */ p("span", { children: [/* @__PURE__ */ e("span", {
|
|
79
|
+
className: "text-pho-primary block",
|
|
80
|
+
children: r
|
|
81
|
+
}), o ? /* @__PURE__ */ e("span", {
|
|
82
|
+
className: "text-pho-description block",
|
|
83
|
+
children: o
|
|
84
|
+
}) : null] });
|
|
85
|
+
}
|
|
86
|
+
function O({ className: r, title: o, description: s, icon: i, disabled: a, indeterminate: d, ...l }) {
|
|
87
|
+
const { motionProps: c } = b({
|
|
88
|
+
scale: v,
|
|
89
|
+
disabled: !!a,
|
|
90
|
+
transition: f
|
|
91
|
+
}), n = i != null;
|
|
92
|
+
return /* @__PURE__ */ p(u.label, {
|
|
93
|
+
...c,
|
|
94
|
+
className: t(x, n && "flex-col gap-1.5", r),
|
|
95
|
+
"data-disabled": a ? "" : void 0,
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ e(h.Root, {
|
|
98
|
+
disabled: a,
|
|
99
|
+
indeterminate: d,
|
|
100
|
+
className: n ? "sr-only" : t("bg-pho-primary ring-pho-primary text-pho-on-brand mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-sm ring-1 ring-inset", "group-hover:bg-pho-primary-hover group-hover:ring-pho-ink transition-[background-color,box-shadow,color] duration-150 ease-out", "data-[checked]:bg-pho-brand-solid data-[checked]:group-hover:bg-pho-brand-solid-hover data-[checked]:ring-transparent", "data-[indeterminate]:bg-pho-brand-solid data-[indeterminate]:group-hover:bg-pho-brand-solid-hover data-[indeterminate]:ring-transparent"),
|
|
101
|
+
...l,
|
|
102
|
+
children: n ? null : /* @__PURE__ */ e(h.Indicator, {
|
|
103
|
+
className: t("flex items-center justify-center transition-opacity duration-100 ease-out", "data-[ending-style]:opacity-0"),
|
|
104
|
+
children: /* @__PURE__ */ e(g, {
|
|
105
|
+
indeterminate: d,
|
|
106
|
+
className: "size-2.5"
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
}),
|
|
110
|
+
n ? /* @__PURE__ */ e("span", {
|
|
111
|
+
"aria-hidden": !0,
|
|
112
|
+
className: "text-pho-secondary flex size-6 shrink-0 items-center justify-center [&>svg]:size-6",
|
|
113
|
+
children: i
|
|
114
|
+
}) : null,
|
|
115
|
+
/* @__PURE__ */ e(R, {
|
|
116
|
+
title: o,
|
|
117
|
+
description: s
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
O.displayName = "CheckboxCard";
|
|
123
|
+
export {
|
|
124
|
+
P as n,
|
|
125
|
+
A as r,
|
|
126
|
+
O as t
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=checkbox-Cdm08HWG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox-Cdm08HWG.js","names":[],"sources":["../../src/components/checkbox/check-glyph.tsx","../../src/components/checkbox/checkbox.tsx","../../src/components/checkbox/checkbox-group.tsx","../../src/components/checkbox/checkbox-card.tsx"],"sourcesContent":["import { motion } from \"motion/react\";\n\n// Tabler's IconCheck / IconMinus paths, redrawn as a single animatable\n// `motion.path` — same 24×24 outline geometry (stroke 2, round caps/joins),\n// so the glyph matches every other Tabler-sourced icon at rest.\nconst CHECK_PATH = \"M5 12l5 5l10 -10\";\nconst MINUS_PATH = \"M5 12l14 0\";\n\nconst DRAW_TRANSITION = { duration: 0.22, ease: \"easeOut\" } as const;\n\n/**\n * The checkbox glyph, stroked on rather than popped in solid — same\n * considered-motion spirit as Button's press/wake effects. Re-keyed per\n * state (check vs. dash) so every appearance draws fresh from empty instead\n * of resuming a stroke left mid-way by whatever the glyph showed before.\n */\nexport function DrawnCheckGlyph({\n indeterminate,\n className,\n}: {\n indeterminate?: boolean;\n className?: string;\n}) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n aria-hidden=\"true\"\n >\n <motion.path\n key={indeterminate ? \"minus\" : \"check\"}\n d={indeterminate ? MINUS_PATH : CHECK_PATH}\n initial={{ pathLength: 0 }}\n animate={{ pathLength: 1 }}\n transition={DRAW_TRANSITION}\n />\n </svg>\n );\n}\n","import { type ComponentProps, type ReactNode } from \"react\";\nimport { Checkbox as BaseCheckbox } from \"@base-ui/react/checkbox\";\nimport { motion } from \"motion/react\";\nimport { DrawnCheckGlyph } from \"./check-glyph\";\nimport { cn } from \"../../utils/cn\";\nimport { usePressPulse } from \"../../utils/use-press-pulse\";\n\nexport type CheckboxSize = \"sm\" | \"md\";\n\nconst BOX: Record<CheckboxSize, string> = { sm: \"size-4\", md: \"size-5\" };\nconst ICON: Record<CheckboxSize, string> = { sm: \"size-3\", md: \"size-3.5\" };\n\nexport interface CheckboxProps extends Omit<\n ComponentProps<typeof BaseCheckbox.Root>,\n \"className\"\n> {\n className?: string;\n /** Text rendered beside the box; the whole row toggles the checkbox. */\n label?: ReactNode;\n /** Size variant. @default \"md\" */\n size?: CheckboxSize;\n}\n\n/**\n * Checkbox built on Base UI `Checkbox`. Supports checked, unchecked, and\n * `indeterminate` states; pass `label` for a clickable text row, or omit it\n * and provide an `aria-label`. For a set of related options that submit\n * together, wrap them in `CheckboxGroup`.\n *\n * Animation is the Effect Button family scaled to a toggle, kept restrained:\n * a quick shallow press pulse on pointer-down (always plays out), the\n * fill/stroke easing between states, and the glyph popping in.\n */\nexport function Checkbox({\n className,\n label,\n size = \"md\",\n disabled,\n indeterminate,\n ...props\n}: CheckboxProps) {\n const { motionProps } = usePressPulse({\n scale: 0.94,\n disabled: Boolean(disabled),\n });\n // With a label, the whole row is the hit target — press-trigger from there\n // (pointerdown bubbles up from the label text too) so the box still\n // animates when the text, not the box itself, is what's clicked.\n const { onPointerDown, ...boxMotionProps } = motionProps;\n\n const box = (\n <BaseCheckbox.Root\n disabled={disabled}\n indeterminate={indeterminate}\n render={\n <motion.span\n {...boxMotionProps}\n onPointerDown={label ? undefined : onPointerDown}\n />\n }\n className={cn(\n // Flat field surface with the input-strength ring; the glyph only shows\n // on the brand-solid checked fill, so it must be on-brand (not white —\n // brand-solid is white in dark mode).\n \"group/cb outline-pho-brand bg-pho-primary ring-pho-primary text-pho-on-brand flex shrink-0 cursor-pointer items-center justify-center rounded-sm ring-1 ring-inset focus-visible:outline-2 focus-visible:outline-offset-2\",\n // Fill and stroke ease between states (stroke dissolves into the\n // fill on tick). Transform stays out — Motion owns the press pulse.\n \"transition-[background-color,box-shadow,color,outline-color] duration-150 ease-out\",\n // group-hover covers hovering the label text, not just the box itself.\n \"hover:bg-pho-primary-hover hover:ring-pho-ink group-hover:bg-pho-primary-hover group-hover:ring-pho-ink\",\n \"data-[checked]:bg-pho-brand-solid data-[checked]:ring-transparent\",\n \"data-[indeterminate]:bg-pho-brand-solid data-[indeterminate]:ring-transparent\",\n \"data-[checked]:hover:bg-pho-brand-solid-hover data-[checked]:group-hover:bg-pho-brand-solid-hover\",\n \"data-[indeterminate]:hover:bg-pho-brand-solid-hover data-[indeterminate]:group-hover:bg-pho-brand-solid-hover\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n BOX[size],\n className,\n )}\n {...props}\n >\n {/* The glyph draws itself on (see DrawnCheckGlyph) — no separate\n pop-in needed. A quick fade covers the exit, since an unmount\n can't play the stroke backwards. */}\n <BaseCheckbox.Indicator\n className={cn(\n \"flex items-center justify-center transition-opacity duration-100 ease-out\",\n \"data-[ending-style]:opacity-0\",\n )}\n >\n <DrawnCheckGlyph indeterminate={indeterminate} className={ICON[size]} />\n </BaseCheckbox.Indicator>\n </BaseCheckbox.Root>\n );\n\n if (!label) return box;\n return (\n <label\n className=\"group flex cursor-pointer items-center gap-2 select-none\"\n onPointerDown={onPointerDown}\n >\n {box}\n <span className=\"text-pho-secondary text-base\">{label}</span>\n </label>\n );\n}\n\nCheckbox.displayName = \"Checkbox\";\n","import { type ComponentProps } from \"react\";\nimport { CheckboxGroup as BaseCheckboxGroup } from \"@base-ui/react/checkbox-group\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface CheckboxGroupProps extends Omit<\n ComponentProps<typeof BaseCheckboxGroup>,\n \"className\"\n> {\n className?: string;\n}\n\n/**\n * Groups related `Checkbox`es and tracks their values as one. Built on Base UI\n * `CheckboxGroup` — supports a parent \"select all\" checkbox via `allValues`.\n * Control with `value` / `onValueChange` or leave uncontrolled with\n * `defaultValue`.\n */\nexport function CheckboxGroup({ className, ...props }: CheckboxGroupProps) {\n return (\n <BaseCheckboxGroup\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n />\n );\n}\n\nCheckboxGroup.displayName = \"CheckboxGroup\";\n","import { type ComponentProps, type ReactNode } from \"react\";\nimport { Checkbox as BaseCheckbox } from \"@base-ui/react/checkbox\";\nimport { motion } from \"motion/react\";\nimport { DrawnCheckGlyph } from \"./check-glyph\";\nimport { cn } from \"../../utils/cn\";\nimport { usePressPulse } from \"../../utils/use-press-pulse\";\nimport {\n CHOICE_CARD_BASE,\n CHOICE_CARD_WITH_ICON,\n CHOICE_CARD_PRESS_SCALE,\n CHOICE_CARD_PRESS_TRANSITION,\n} from \"../../utils/choice-card\";\n\nexport interface CheckboxCardProps extends Omit<\n ComponentProps<typeof BaseCheckbox.Root>,\n \"className\" | \"title\"\n> {\n className?: string;\n /** Tile heading. */\n title: ReactNode;\n /** Supporting copy shown below the title. */\n description?: ReactNode;\n /** Glyph stacked above the title. When set, it replaces the checkbox box. */\n icon?: ReactNode;\n}\n\nfunction CardCopy({\n title,\n description,\n}: {\n title: ReactNode;\n description?: ReactNode;\n}) {\n return (\n <span>\n <span className=\"text-pho-primary block\">{title}</span>\n {description ? (\n <span className=\"text-pho-description block\">{description}</span>\n ) : null}\n </span>\n );\n}\n\n/**\n * A `Checkbox` styled as a bordered, selectable tile — title, optional\n * description, and either a stacked icon or the checkbox box. The tile is a\n * `<label>` around the control so clicks (including on the icon/title) are a\n * trusted activation of the hidden input Base UI renders beside the root.\n */\nexport function CheckboxCard({\n className,\n title,\n description,\n icon,\n disabled,\n indeterminate,\n ...props\n}: CheckboxCardProps) {\n const { motionProps } = usePressPulse({\n scale: CHOICE_CARD_PRESS_SCALE,\n disabled: Boolean(disabled),\n transition: CHOICE_CARD_PRESS_TRANSITION,\n });\n const hasIcon = icon != null;\n\n return (\n <motion.label\n {...motionProps}\n className={cn(\n CHOICE_CARD_BASE,\n hasIcon && CHOICE_CARD_WITH_ICON,\n className,\n )}\n data-disabled={disabled ? \"\" : undefined}\n >\n <BaseCheckbox.Root\n disabled={disabled}\n indeterminate={indeterminate}\n className={\n hasIcon\n ? \"sr-only\"\n : cn(\n \"bg-pho-primary ring-pho-primary text-pho-on-brand mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-sm ring-1 ring-inset\",\n \"group-hover:bg-pho-primary-hover group-hover:ring-pho-ink transition-[background-color,box-shadow,color] duration-150 ease-out\",\n \"data-[checked]:bg-pho-brand-solid data-[checked]:group-hover:bg-pho-brand-solid-hover data-[checked]:ring-transparent\",\n \"data-[indeterminate]:bg-pho-brand-solid data-[indeterminate]:group-hover:bg-pho-brand-solid-hover data-[indeterminate]:ring-transparent\",\n )\n }\n {...props}\n >\n {hasIcon ? null : (\n <BaseCheckbox.Indicator\n className={cn(\n \"flex items-center justify-center transition-opacity duration-100 ease-out\",\n \"data-[ending-style]:opacity-0\",\n )}\n >\n <DrawnCheckGlyph\n indeterminate={indeterminate}\n className=\"size-2.5\"\n />\n </BaseCheckbox.Indicator>\n )}\n </BaseCheckbox.Root>\n {hasIcon ? (\n <span\n aria-hidden\n className=\"text-pho-secondary flex size-6 shrink-0 items-center justify-center [&>svg]:size-6\"\n >\n {icon}\n </span>\n ) : null}\n <CardCopy title={title} description={description} />\n </motion.label>\n );\n}\n\nCheckboxCard.displayName = \"CheckboxCard\";\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { n as a } from "./use-press-pulse-
|
|
2
|
+
import { n as a } from "./use-press-pulse-IbNstUT0.js";
|
|
3
3
|
var s = "group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base p-3 text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2", o = "flex-col gap-1.5", r = 0.98, t = a, i = {
|
|
4
4
|
type: "spring",
|
|
5
5
|
stiffness: 500,
|
|
@@ -14,4 +14,4 @@ export {
|
|
|
14
14
|
s as t
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
//# sourceMappingURL=choice-card-
|
|
17
|
+
//# sourceMappingURL=choice-card-BVNP1NB6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice-card-
|
|
1
|
+
{"version":3,"file":"choice-card-BVNP1NB6.js","names":[],"sources":["../../src/utils/choice-card.ts"],"sourcesContent":["import type { Transition } from \"motion/react\";\nimport { CONTROL_PRESS_SPRING } from \"./use-press-pulse\";\n\n/**\n * Shared surface for `RadioCard` / `CheckboxCard` — a bordered, selectable\n * tile. Applied to the radio/checkbox root itself so the whole tile is the\n * hit target. Hover fills (`bg-pho-ghost-hover`); selected uses the brand\n * ring. Press feedback lives on this surface (see `usePressPulse`).\n */\nexport const CHOICE_CARD_BASE =\n \"group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base p-3 text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2\";\n\n/** Stacked icon above the copy — tighter than the checkbox/radio row gap. */\nexport const CHOICE_CARD_WITH_ICON = \"flex-col gap-1.5\";\n\n/** Same press as Select's default trigger — field-sized, not Button's whileTap. */\nexport const CHOICE_CARD_PRESS_SCALE = 0.98;\nexport const CHOICE_CARD_PRESS_TRANSITION: Transition = CONTROL_PRESS_SPRING;\n\n/** Selection pop for a radio dot / checkbox glyph — quick and slightly bouncy. */\nexport const CHOICE_INDICATOR_POP_TRANSITION: Transition = {\n type: \"spring\",\n stiffness: 500,\n damping: 30,\n mass: 0.5,\n};\n"],"mappings":";;AASA,IAAa,IACX,klBAGW,IAAwB,oBAGxB,IAA0B,MAC1B,IAA2C,GAG3C,IAA8C;AAAA,EACzD,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,MAAM;AACR"}
|