@photon-ai/pho-ui 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,7 +3,7 @@ import { t as p } from "./cn-D6jQqeRj.js";
|
|
|
3
3
|
import { n as T, r as S } from "./link-provider-9TFNyDqO.js";
|
|
4
4
|
import { t as m } from "./resolve-variant-CcD8iG5l.js";
|
|
5
5
|
import { isValidElement as B, useMemo as R } from "react";
|
|
6
|
-
import { Fragment as _, jsx as
|
|
6
|
+
import { Fragment as _, jsx as a, jsxs as g } from "react/jsx-runtime";
|
|
7
7
|
import { motion as y } from "motion/react";
|
|
8
8
|
var q = p("group relative inline-flex h-max cursor-pointer items-center justify-center whitespace-nowrap outline-pho-brand transition duration-100 ease-linear before:absolute 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"), M = {
|
|
9
9
|
sm: {
|
|
@@ -50,12 +50,12 @@ var q = p("group relative inline-flex h-max cursor-pointer items-center justify-
|
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
function C(e) {
|
|
53
|
-
const { variant: r = "primary", size: i = "md", shape: n = "square", shadow:
|
|
54
|
-
return p(q, m(O, n), m(M, i), m(z, r),
|
|
53
|
+
const { variant: r = "primary", size: i = "md", shape: n = "square", shadow: o, className: s } = e ?? {};
|
|
54
|
+
return p(q, m(O, n), m(M, i), m(z, r), o && "shadow-pho-md", s);
|
|
55
55
|
}
|
|
56
56
|
var D = "transition-inherit-all pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-5 [&>svg]:shrink-0";
|
|
57
57
|
function b({ position: e, children: r }) {
|
|
58
|
-
return /* @__PURE__ */
|
|
58
|
+
return /* @__PURE__ */ a("span", {
|
|
59
59
|
"data-icon": e,
|
|
60
60
|
className: D,
|
|
61
61
|
children: r
|
|
@@ -66,14 +66,14 @@ function v() {
|
|
|
66
66
|
fill: "none",
|
|
67
67
|
viewBox: "0 0 20 20",
|
|
68
68
|
"aria-hidden": "true",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ a("circle", {
|
|
70
70
|
className: "stroke-current opacity-30",
|
|
71
71
|
cx: "10",
|
|
72
72
|
cy: "10",
|
|
73
73
|
r: "8",
|
|
74
74
|
fill: "none",
|
|
75
75
|
strokeWidth: "2"
|
|
76
|
-
}), /* @__PURE__ */
|
|
76
|
+
}), /* @__PURE__ */ a("circle", {
|
|
77
77
|
className: "origin-center animate-spin stroke-current",
|
|
78
78
|
cx: "10",
|
|
79
79
|
cy: "10",
|
|
@@ -86,24 +86,24 @@ function v() {
|
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
function w(e, r) {
|
|
89
|
-
return e == null || e === !1 ? null : S(e) ? /* @__PURE__ */
|
|
89
|
+
return e == null || e === !1 ? null : S(e) ? /* @__PURE__ */ a(b, {
|
|
90
90
|
position: r,
|
|
91
|
-
children: /* @__PURE__ */
|
|
92
|
-
}) : B(e) ? /* @__PURE__ */
|
|
91
|
+
children: /* @__PURE__ */ a(e, {})
|
|
92
|
+
}) : B(e) ? /* @__PURE__ */ a(b, {
|
|
93
93
|
position: r,
|
|
94
94
|
children: e
|
|
95
95
|
}) : null;
|
|
96
96
|
}
|
|
97
|
-
function F({ svgOnly: e, loading: r, prefix: i, suffix: n, children:
|
|
98
|
-
return e ? r ? /* @__PURE__ */
|
|
99
|
-
r ? /* @__PURE__ */
|
|
97
|
+
function F({ svgOnly: e, loading: r, prefix: i, suffix: n, children: o }) {
|
|
98
|
+
return e ? r ? /* @__PURE__ */ a(v, {}) : o : /* @__PURE__ */ g(_, { children: [
|
|
99
|
+
r ? /* @__PURE__ */ a(b, {
|
|
100
100
|
position: "loading",
|
|
101
|
-
children: /* @__PURE__ */
|
|
101
|
+
children: /* @__PURE__ */ a(v, {})
|
|
102
102
|
}) : w(i, "prefix"),
|
|
103
|
-
|
|
103
|
+
o != null && o !== !1 && /* @__PURE__ */ a("span", {
|
|
104
104
|
"data-text": !0,
|
|
105
105
|
className: "transition-inherit-all px-0.5",
|
|
106
|
-
children:
|
|
106
|
+
children: o
|
|
107
107
|
}),
|
|
108
108
|
w(n, "suffix")
|
|
109
109
|
] });
|
|
@@ -111,48 +111,48 @@ function F({ svgOnly: e, loading: r, prefix: i, suffix: n, children: a }) {
|
|
|
111
111
|
function x(e, r) {
|
|
112
112
|
e && !r && typeof process < "u" && process.env.NODE_ENV !== "production" && console.warn("Button: `svgOnly` buttons require an `aria-label` that names the action.");
|
|
113
113
|
}
|
|
114
|
-
function H({ variant: e, size: r, shape: i, shadow: n, prefix:
|
|
115
|
-
return x(
|
|
114
|
+
function H({ variant: e, size: r, shape: i, shadow: n, prefix: o, suffix: s, svgOnly: t, loading: d, children: u, className: c, ref: l, ...h }) {
|
|
115
|
+
return x(t, h["aria-label"]), /* @__PURE__ */ a("button", {
|
|
116
116
|
ref: l,
|
|
117
117
|
type: "button",
|
|
118
118
|
...h,
|
|
119
119
|
"aria-busy": d || void 0,
|
|
120
120
|
"data-loading": d ? "true" : void 0,
|
|
121
|
-
"data-svg-only":
|
|
121
|
+
"data-svg-only": t ? "true" : void 0,
|
|
122
122
|
className: p(C({
|
|
123
123
|
variant: e,
|
|
124
124
|
size: r,
|
|
125
125
|
shape: i,
|
|
126
126
|
shadow: n
|
|
127
|
-
}), d && "pointer-events-none",
|
|
127
|
+
}), d && "pointer-events-none", t && "[&>svg]:size-5 [&>svg]:shrink-0", c),
|
|
128
128
|
children: F({
|
|
129
|
-
svgOnly:
|
|
129
|
+
svgOnly: t,
|
|
130
130
|
loading: d,
|
|
131
|
-
prefix:
|
|
131
|
+
prefix: o,
|
|
132
132
|
suffix: s,
|
|
133
133
|
children: u
|
|
134
134
|
})
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
H.displayName = "Button";
|
|
138
|
-
function U({ variant: e, size: r, shape: i, shadow: n, prefix:
|
|
139
|
-
return x(
|
|
138
|
+
function U({ variant: e, size: r, shape: i, shadow: n, prefix: o, suffix: s, svgOnly: t, loading: d, disabled: u, href: c, children: l, className: h, ...f }) {
|
|
139
|
+
return x(t, f["aria-label"]), /* @__PURE__ */ a(T(), {
|
|
140
140
|
href: c,
|
|
141
141
|
...f,
|
|
142
142
|
"aria-disabled": u || d || void 0,
|
|
143
143
|
"aria-busy": d || void 0,
|
|
144
144
|
"data-loading": d ? "true" : void 0,
|
|
145
|
-
"data-svg-only":
|
|
145
|
+
"data-svg-only": t ? "true" : void 0,
|
|
146
146
|
className: p(C({
|
|
147
147
|
variant: e,
|
|
148
148
|
size: r,
|
|
149
149
|
shape: i,
|
|
150
150
|
shadow: n
|
|
151
|
-
}), d && "pointer-events-none",
|
|
151
|
+
}), d && "pointer-events-none", t && "[&>svg]:size-5 [&>svg]:shrink-0", h),
|
|
152
152
|
children: F({
|
|
153
|
-
svgOnly:
|
|
153
|
+
svgOnly: t,
|
|
154
154
|
loading: d,
|
|
155
|
-
prefix:
|
|
155
|
+
prefix: o,
|
|
156
156
|
suffix: s,
|
|
157
157
|
children: l
|
|
158
158
|
})
|
|
@@ -188,13 +188,13 @@ var j = p("squircle relative inline-flex h-max cursor-pointer items-center justi
|
|
|
188
188
|
description: "Brand fill with the glossy inset sheen (default)"
|
|
189
189
|
},
|
|
190
190
|
secondary: {
|
|
191
|
-
classes: "border-transparent bg-pho-primary text-pho-secondary shadow-pho-skeuo-xs ring-1 ring-pho-primary ring-inset transition-colors duration-100 ease-linear hover:bg-pho-primary-hover hover:text-pho-secondary-hover data-loading:bg-pho-primary-hover",
|
|
191
|
+
classes: "border-transparent bg-pho-primary text-pho-secondary shadow-pho-skeuo-xs ring-1 ring-pho-primary ring-inset transition-colors duration-100 ease-linear not-disabled:hover:bg-pho-primary-hover not-disabled:hover:text-pho-secondary-hover data-loading:bg-pho-primary-hover",
|
|
192
192
|
description: "Neutral white-card pill (OAuth / supporting CTA), no sheen"
|
|
193
193
|
}
|
|
194
194
|
};
|
|
195
195
|
function L(e) {
|
|
196
|
-
const { variant: r = "primary", size: i = "md", fullWidth: n, className:
|
|
197
|
-
return p(j, m(W, i), m(Z, r), n && "w-full",
|
|
196
|
+
const { variant: r = "primary", size: i = "md", fullWidth: n, className: o } = e ?? {};
|
|
197
|
+
return p(j, m(W, i), m(Z, r), n && "w-full", o);
|
|
198
198
|
}
|
|
199
199
|
function G(e, r) {
|
|
200
200
|
return r === "secondary" ? {
|
|
@@ -221,7 +221,7 @@ var J = {
|
|
|
221
221
|
}
|
|
222
222
|
};
|
|
223
223
|
function E({ position: e, children: r }) {
|
|
224
|
-
return /* @__PURE__ */
|
|
224
|
+
return /* @__PURE__ */ a(y.span, {
|
|
225
225
|
"data-icon": e,
|
|
226
226
|
variants: J,
|
|
227
227
|
transition: A,
|
|
@@ -236,82 +236,82 @@ function E({ position: e, children: r }) {
|
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
function k(e, r) {
|
|
239
|
-
return e == null || e === !1 ? null : S(e) ? /* @__PURE__ */
|
|
239
|
+
return e == null || e === !1 ? null : S(e) ? /* @__PURE__ */ a(E, {
|
|
240
240
|
position: r,
|
|
241
|
-
children: /* @__PURE__ */
|
|
242
|
-
}) : B(e) ? /* @__PURE__ */
|
|
241
|
+
children: /* @__PURE__ */ a(e, {})
|
|
242
|
+
}) : B(e) ? /* @__PURE__ */ a(E, {
|
|
243
243
|
position: r,
|
|
244
244
|
children: e
|
|
245
245
|
}) : null;
|
|
246
246
|
}
|
|
247
|
-
function V({ svgOnly: e, loading: r, prefix: i, suffix: n, children:
|
|
248
|
-
return e ? r ? /* @__PURE__ */
|
|
249
|
-
r ? /* @__PURE__ */
|
|
247
|
+
function V({ svgOnly: e, loading: r, prefix: i, suffix: n, children: o }) {
|
|
248
|
+
return e ? r ? /* @__PURE__ */ a(v, {}) : o : /* @__PURE__ */ g(_, { children: [
|
|
249
|
+
r ? /* @__PURE__ */ a(b, {
|
|
250
250
|
position: "loading",
|
|
251
|
-
children: /* @__PURE__ */
|
|
251
|
+
children: /* @__PURE__ */ a(v, {})
|
|
252
252
|
}) : k(i, "prefix"),
|
|
253
|
-
|
|
253
|
+
o != null && o !== !1 && /* @__PURE__ */ a("span", {
|
|
254
254
|
"data-text": !0,
|
|
255
255
|
className: "px-0.5",
|
|
256
|
-
children:
|
|
256
|
+
children: o
|
|
257
257
|
}),
|
|
258
258
|
k(n, "suffix")
|
|
259
259
|
] });
|
|
260
260
|
}
|
|
261
|
-
function I(e, r) {
|
|
261
|
+
function I(e, r, i) {
|
|
262
262
|
return {
|
|
263
263
|
initial: !1,
|
|
264
264
|
animate: "rest",
|
|
265
|
-
whileHover: "hover",
|
|
265
|
+
whileHover: i ? void 0 : "hover",
|
|
266
266
|
variants: G(e, r),
|
|
267
267
|
transition: A
|
|
268
268
|
};
|
|
269
269
|
}
|
|
270
|
-
function K({ variant: e = "primary", size: r = "md", fullWidth: i, prefix: n, suffix:
|
|
271
|
-
return x(s, l["aria-label"]), /* @__PURE__ */
|
|
270
|
+
function K({ variant: e = "primary", size: r = "md", fullWidth: i, prefix: n, suffix: o, svgOnly: s, loading: t, children: d, className: u, ref: c, ...l }) {
|
|
271
|
+
return x(s, l["aria-label"]), /* @__PURE__ */ a(y.button, {
|
|
272
272
|
ref: c,
|
|
273
273
|
type: "button",
|
|
274
|
-
...I(r, e),
|
|
274
|
+
...I(r, e, l.disabled || t),
|
|
275
275
|
...l,
|
|
276
|
-
"aria-busy":
|
|
277
|
-
"data-loading":
|
|
276
|
+
"aria-busy": t || void 0,
|
|
277
|
+
"data-loading": t ? "true" : void 0,
|
|
278
278
|
"data-svg-only": s ? "true" : void 0,
|
|
279
279
|
className: p(L({
|
|
280
280
|
variant: e,
|
|
281
281
|
size: r,
|
|
282
282
|
fullWidth: i
|
|
283
|
-
}),
|
|
283
|
+
}), t && "pointer-events-none", s && "[&>svg]:size-5 [&>svg]:shrink-0", u),
|
|
284
284
|
children: V({
|
|
285
285
|
svgOnly: s,
|
|
286
|
-
loading:
|
|
286
|
+
loading: t,
|
|
287
287
|
prefix: n,
|
|
288
|
-
suffix:
|
|
288
|
+
suffix: o,
|
|
289
289
|
children: d
|
|
290
290
|
})
|
|
291
291
|
});
|
|
292
292
|
}
|
|
293
293
|
K.displayName = "EffectButton";
|
|
294
|
-
function Q({ variant: e = "primary", size: r = "md", fullWidth: i, prefix: n, suffix:
|
|
294
|
+
function Q({ variant: e = "primary", size: r = "md", fullWidth: i, prefix: n, suffix: o, svgOnly: s, loading: t, disabled: d, href: u, children: c, className: l, ...h }) {
|
|
295
295
|
x(s, h["aria-label"]);
|
|
296
296
|
const f = T();
|
|
297
|
-
return /* @__PURE__ */
|
|
297
|
+
return /* @__PURE__ */ a(R(() => y.create(f), [f]), {
|
|
298
298
|
href: u,
|
|
299
|
-
...I(r, e),
|
|
299
|
+
...I(r, e, d || t),
|
|
300
300
|
...h,
|
|
301
|
-
"aria-disabled": d ||
|
|
302
|
-
"aria-busy":
|
|
303
|
-
"data-loading":
|
|
301
|
+
"aria-disabled": d || t || void 0,
|
|
302
|
+
"aria-busy": t || void 0,
|
|
303
|
+
"data-loading": t ? "true" : void 0,
|
|
304
304
|
"data-svg-only": s ? "true" : void 0,
|
|
305
305
|
className: p(L({
|
|
306
306
|
variant: e,
|
|
307
307
|
size: r,
|
|
308
308
|
fullWidth: i
|
|
309
|
-
}),
|
|
309
|
+
}), t && "pointer-events-none", s && "[&>svg]:size-5 [&>svg]:shrink-0", l),
|
|
310
310
|
children: V({
|
|
311
311
|
svgOnly: s,
|
|
312
|
-
loading:
|
|
312
|
+
loading: t,
|
|
313
313
|
prefix: n,
|
|
314
|
-
suffix:
|
|
314
|
+
suffix: o,
|
|
315
315
|
children: c
|
|
316
316
|
})
|
|
317
317
|
});
|
|
@@ -331,4 +331,4 @@ export {
|
|
|
331
331
|
C as u
|
|
332
332
|
};
|
|
333
333
|
|
|
334
|
-
//# sourceMappingURL=button-
|
|
334
|
+
//# sourceMappingURL=button-DjjSiLYz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-DjjSiLYz.js","names":[],"sources":["../../src/components/button/button.tsx"],"sourcesContent":["import {\n isValidElement,\n useMemo,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type FC,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { motion, type HTMLMotionProps } from \"motion/react\";\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\";\n\n/**\n * Design notes (Geist-aligned):\n * - ONE emphasis axis, kept deliberately small. `variant` is a closed,\n * semantic set — a single high-emphasis default plus the supporting and\n * intent variants you actually reach for. There is no `ghost`, no `link`,\n * and no second destructive: navigation belongs to `ButtonLink`, and an\n * inline text link is an anchor, not a button.\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`. Boolean flags (`loading`, `shadow`) are declarative.\n */\n\nconst COMMON_ROOT = cn(\n \"group relative inline-flex h-max cursor-pointer items-center justify-center whitespace-nowrap outline-pho-brand transition duration-100 ease-linear before:absolute 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/** Size axis — padding, text size, and icon-only (svgOnly) padding. */\nexport const BUTTON_SIZES = {\n sm: {\n classes: \"gap-1 px-3 py-2 text-sm font-semibold data-svg-only:p-2\",\n description: \"Small — compact rows, tables, and toolbars\",\n },\n md: {\n classes: \"gap-1 px-3.5 py-2.5 text-sm font-semibold data-svg-only:p-2.5\",\n description: \"Medium — the default\",\n },\n lg: {\n classes: \"gap-1.5 px-4 py-2.5 text-md font-semibold data-svg-only:p-3\",\n description: \"Large — prominent and marketing actions\",\n },\n} satisfies VariantMap;\n\n/** Shape axis — corner treatment. `square` is the default text-button shape. */\nexport const BUTTON_SHAPES = {\n square: {\n classes: \"rounded-lg before:rounded-[7px]\",\n description: \"Default — gently rounded corners\",\n },\n circle: {\n classes: \"rounded-full before:rounded-full\",\n description: \"Circular — pair with svgOnly for round icon buttons\",\n },\n rounded: {\n classes: \"rounded-full before:rounded-full\",\n description: \"Pill — marketing CTAs, often with shadow\",\n },\n} satisfies VariantMap;\n\n/** Emphasis axis — a tight, semantic set. `primary` is the default. */\nexport const BUTTON_VARIANTS = {\n primary: {\n classes:\n \"bg-pho-brand-solid text-white shadow-pho-skeuo-xs ring-1 ring-transparent ring-inset hover:bg-pho-brand-solid-hover data-loading:bg-pho-brand-solid-hover before:absolute before:inset-px before:border before:border-white/12 before:mask-b-from-0% *:data-icon:text-white/60 hover:*:data-icon:text-white/70\",\n description: \"High-emphasis primary action (default)\",\n },\n secondary: {\n classes:\n \"bg-pho-primary text-pho-secondary shadow-pho-skeuo-xs ring-1 ring-pho-primary ring-inset hover:bg-pho-primary-hover hover:text-pho-secondary-hover data-loading:bg-pho-primary-hover *:data-icon:text-fg-pho-quaternary hover:*:data-icon:text-fg-pho-quaternary-hover\",\n description: \"Neutral, supporting action\",\n },\n tertiary: {\n classes:\n \"text-pho-tertiary hover:bg-pho-primary-hover hover:text-pho-tertiary-hover data-loading:bg-pho-primary-hover *:data-icon:text-fg-pho-quaternary hover:*:data-icon:text-fg-pho-quaternary-hover\",\n description: \"Low-emphasis, borderless action\",\n },\n error: {\n classes:\n \"bg-pho-error-solid text-white shadow-pho-skeuo-xs ring-1 ring-transparent outline-pho-error ring-inset hover:bg-pho-error-solid-hover data-loading:bg-pho-error-solid-hover before:absolute before:inset-px before:border before:border-white/12 before:mask-b-from-0% *:data-icon:text-white/60 hover:*:data-icon:text-white/70\",\n description: \"Destructive confirmation\",\n },\n} satisfies VariantMap;\n\nexport type ButtonSize = keyof typeof BUTTON_SIZES;\nexport type ButtonShape = keyof typeof BUTTON_SHAPES;\nexport type ButtonVariant = keyof typeof BUTTON_VARIANTS;\n\n/** Compose the full class string for a button — exported for reuse/testing. */\nexport function buttonVariants(opts?: {\n variant?: ButtonVariant;\n size?: ButtonSize;\n shape?: ButtonShape;\n shadow?: boolean;\n className?: string;\n}): string {\n const {\n variant = \"primary\",\n size = \"md\",\n shape = \"square\",\n shadow,\n className,\n } = opts ?? {};\n return cn(\n COMMON_ROOT,\n resolveVariant(BUTTON_SHAPES, shape),\n resolveVariant(BUTTON_SIZES, size),\n resolveVariant(BUTTON_VARIANTS, variant),\n shadow && \"shadow-pho-md\",\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 /** Emphasis variant. @default \"primary\" */\n variant?: ButtonVariant;\n /** Size variant. @default \"md\" */\n size?: ButtonSize;\n /** Corner shape. @default \"square\" */\n shape?: ButtonShape;\n /** Add an elevation shadow (marketing / `rounded`). */\n shadow?: boolean;\n /** Slot before the label — a component (`Plus`) or element (`<Plus />`). */\n prefix?: Slottable;\n /** Slot after the label. */\n suffix?: Slottable;\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\nexport interface ButtonProps\n extends\n ButtonBaseProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonBaseProps> {\n ref?: Ref<HTMLButtonElement>;\n}\n\nexport interface ButtonLinkProps\n extends\n ButtonBaseProps,\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ButtonBaseProps> {\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 \"transition-inherit-all pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-5 [&>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 Spinner() {\n return (\n <svg fill=\"none\" viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <circle\n className=\"stroke-current opacity-30\"\n cx=\"10\"\n cy=\"10\"\n r=\"8\"\n fill=\"none\"\n strokeWidth=\"2\"\n />\n <circle\n className=\"origin-center animate-spin stroke-current\"\n cx=\"10\"\n cy=\"10\"\n r=\"8\"\n fill=\"none\"\n strokeWidth=\"2\"\n strokeDasharray=\"12.5 50\"\n strokeLinecap=\"round\"\n />\n </svg>\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 buttonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n}: Pick<\n ButtonBaseProps,\n \"svgOnly\" | \"loading\" | \"prefix\" | \"suffix\" | \"children\"\n>) {\n if (svgOnly) {\n return loading ? <Spinner /> : children;\n }\n return (\n <>\n {loading ? (\n <Slot position=\"loading\">\n <Spinner />\n </Slot>\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 {renderSlot(suffix, \"suffix\")}\n </>\n );\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/**\n * Button — triggers an action that mutates state (submit, save, delete).\n * For navigation that changes the URL, use {@link ButtonLink}.\n */\nexport function Button({\n variant,\n size,\n shape,\n shadow,\n prefix,\n suffix,\n svgOnly,\n loading,\n children,\n className,\n ref,\n ...props\n}: ButtonProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n return (\n <button\n ref={ref}\n type=\"button\"\n {...props}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n buttonVariants({ variant, size, shape, shadow }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {buttonInner({ svgOnly, loading, prefix, suffix, children })}\n </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,\n size,\n shape,\n shadow,\n prefix,\n suffix,\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 return (\n <Link\n href={href}\n {...props}\n aria-disabled={disabled || loading || undefined}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n buttonVariants({ variant, size, shape, shadow }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {buttonInner({ svgOnly, loading, prefix, suffix, children })}\n </Link>\n );\n}\n\nButtonLink.displayName = \"ButtonLink\";\n\n/* ============================= Effect button ============================= */\n\n/**\n * A frame-exact port of Photon's Framer \"Button - Effect\", driven by Motion\n * (the same engine Framer renders with) so every frame matches the source — not\n * a CSS approximation. On hover, three things spring together on the *identical*\n * transition (`spring-physics 200 30 0.1` → stiffness 200 / damping 30 / mass\n * 0.1): a glossy inset white sheen reshapes toward the bottom edge, the gap\n * eases open (md), and any icon grows and fades in from nothing.\n *\n * Because it's a real spring — not a fixed-duration tween — it's also velocity-\n * correct: hovering out mid-animation continues from the current velocity,\n * exactly like Framer.\n *\n * Fill and stroke are STATIC (the source keeps them identical between the base\n * and hover variants); `variant` picks the treatment — `primary` is the source\n * brand pill with the glossy sheen, `secondary` the neutral white-card pill\n * (Button's secondary surface tokens) with the sheen omitted. The gap + icon\n * reveal springs are shared. `size` maps to the two source variants: `md` =\n * \"Variant 1\" (16px label, 12×16 padding), `sm` = \"Variant 2\" (14px label,\n * 8px padding).\n */\nconst EFFECT_ROOT = cn(\n // Every variant keeps the 1px border so the pill geometry never shifts.\n \"squircle relative inline-flex h-max cursor-pointer items-center justify-center overflow-hidden rounded-full border font-medium whitespace-nowrap\",\n \"outline-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2\",\n \"disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:cursor-not-allowed aria-disabled:opacity-50\",\n);\n\n/** The exact source transition: `spring-physics 200 30 0.1` (stiffness/damping/mass). */\nconst EFFECT_SPRING = {\n type: \"spring\",\n stiffness: 200,\n damping: 30,\n mass: 0.1,\n} as const;\n\n/** Resting inset sheen — identical across both sizes (source base variants). */\nconst EFFECT_REST_SHADOW = \"inset 0px 0px 5px 2px rgba(255, 255, 255, 0.5)\";\n\n/** Per-size hover targets, sampled 1:1 from the source hover (gesture) variants. */\nconst EFFECT_HOVER = {\n sm: { boxShadow: \"inset 0px -3px 8px 2px rgba(255, 255, 255, 0.5)\", gap: 0 },\n md: { boxShadow: \"inset 0px -6px 14px 1px rgba(255, 255, 255, 0.5)\", gap: 4 },\n} as const;\n\n/** Size axis for {@link EffectButton} — padding + label size per source variant. */\nexport const EFFECT_BUTTON_SIZES = {\n sm: {\n classes: \"p-2 text-sm data-svg-only:p-2\",\n description: \"Small — the compact 'Variant 2' (14px label, 8px padding)\",\n },\n md: {\n classes: \"px-4 py-3 text-md data-svg-only:p-3\",\n description: \"Medium — the 'Variant 1' (16px label, 12×16 padding)\",\n },\n} satisfies VariantMap;\n\n/**\n * Emphasis axis for {@link EffectButton} — the static fill + edge treatment.\n * `secondary` reuses the white-card surface tokens of Button's `secondary`\n * (white card, hairline ring, quiet hover) and skips the glossy sheen — that\n * inset shine is the brand-fill treatment.\n */\nexport const EFFECT_BUTTON_VARIANTS = {\n primary: {\n classes: \"border-white/15 bg-pho-brand-solid text-white\",\n description: \"Brand fill with the glossy inset sheen (default)\",\n },\n secondary: {\n // The colors-only hover is gated with `not-disabled:` — CSS `:hover` still\n // matches a disabled <button> (only pointer *events* are suppressed), and\n // `enabled:` would never match the <a> rendered by EffectButtonLink. A\n // disabled link is already inert via `aria-disabled:pointer-events-none`.\n classes:\n \"border-transparent bg-pho-primary text-pho-secondary shadow-pho-skeuo-xs ring-1 ring-pho-primary ring-inset transition-colors duration-100 ease-linear not-disabled:hover:bg-pho-primary-hover not-disabled:hover:text-pho-secondary-hover data-loading:bg-pho-primary-hover\",\n description: \"Neutral white-card pill (OAuth / supporting CTA), no sheen\",\n },\n} satisfies VariantMap;\n\nexport type EffectButtonSize = keyof typeof EFFECT_BUTTON_SIZES;\nexport type EffectButtonVariant = keyof typeof EFFECT_BUTTON_VARIANTS;\n\n/** Compose the static class string for an effect button — exported for reuse. */\nexport function effectButtonVariants(opts?: {\n variant?: EffectButtonVariant;\n size?: EffectButtonSize;\n fullWidth?: boolean;\n className?: string;\n}): string {\n const { variant = \"primary\", size = \"md\", fullWidth, className } = opts ?? {};\n return cn(\n EFFECT_ROOT,\n resolveVariant(EFFECT_BUTTON_SIZES, size),\n resolveVariant(EFFECT_BUTTON_VARIANTS, variant),\n fullWidth && \"w-full\",\n className,\n );\n}\n\n/**\n * Motion variants for the pill root — the sheen (+ gap on md) spring on hover.\n * `secondary` springs only the gap: its box-shadow stays with the CSS classes\n * (ring + skeuomorphic shadow), so Motion must never write an inline one.\n */\nfunction effectRootVariants(\n size: EffectButtonSize,\n variant: EffectButtonVariant,\n) {\n if (variant === \"secondary\") {\n return {\n rest: { gap: 0 },\n hover: { gap: EFFECT_HOVER[size].gap },\n };\n }\n return {\n rest: { boxShadow: EFFECT_REST_SHADOW, gap: 0 },\n hover: EFFECT_HOVER[size],\n };\n}\n\n/**\n * Icon reveal — a 1:1 port of the source \"Arrow Right\" instance: collapsed and\n * invisible at rest (opacity 0, 1×10px), grown to full size on hover (opacity 1,\n * 20×21px). The child inherits the pill's `rest`/`hover` variant label, so it\n * springs in perfect lockstep with the sheen and gap.\n */\nconst EFFECT_ICON_VARIANTS = {\n rest: { opacity: 0, width: 1, height: 10 },\n hover: { opacity: 1, width: 20, height: 21 },\n} as const;\n\nfunction EffectSlot({\n position,\n children,\n}: {\n position: \"prefix\" | \"suffix\";\n children: ReactNode;\n}) {\n return (\n <motion.span\n data-icon={position}\n variants={EFFECT_ICON_VARIANTS}\n transition={EFFECT_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 renderEffectSlot(icon: Slottable, position: \"prefix\" | \"suffix\") {\n if (icon == null || icon === false) return null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n return (\n <EffectSlot position={position}>\n <Icon />\n </EffectSlot>\n );\n }\n if (isValidElement(icon))\n return <EffectSlot position={position}>{icon}</EffectSlot>;\n return null;\n}\n\nfunction effectButtonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n}: Pick<\n EffectButtonBaseProps,\n \"svgOnly\" | \"loading\" | \"prefix\" | \"suffix\" | \"children\"\n>) {\n // An icon-only button keeps its icon always visible (nothing to reveal).\n if (svgOnly) return loading ? <Spinner /> : children;\n return (\n <>\n {loading ? (\n <Slot position=\"loading\">\n <Spinner />\n </Slot>\n ) : (\n renderEffectSlot(prefix, \"prefix\")\n )}\n {children != null && children !== false && (\n <span data-text className=\"px-0.5\">\n {children}\n </span>\n )}\n {renderEffectSlot(suffix, \"suffix\")}\n </>\n );\n}\n\n/** Motion props (initial/animate/hover/variants/transition) shared by both roots. */\nfunction effectMotionProps(\n size: EffectButtonSize,\n variant: EffectButtonVariant,\n inert: boolean | undefined,\n) {\n return {\n initial: false as const,\n animate: \"rest\",\n // Browsers still dispatch pointerenter on a disabled <button>, so Motion's\n // hover gesture would run the sheen / gap / icon-reveal springs on a pill\n // that must read as inert. Omitting `whileHover` while disabled or loading\n // is Motion's intended off-switch: the gesture never engages (no inline\n // styles mutate), an in-flight hover springs back to `rest`, and restoring\n // the prop re-arms hover in place — no remount, no rest-state change.\n whileHover: inert ? undefined : \"hover\",\n variants: effectRootVariants(size, variant),\n transition: EFFECT_SPRING,\n };\n}\n\n// Motion redefines these DOM handlers; drop them from our public props so\n// spreading onto a motion element type-checks cleanly.\ntype MotionConflicts =\n | \"onAnimationStart\"\n | \"onAnimationEnd\"\n | \"onAnimationIteration\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onDragEnter\"\n | \"onDragExit\"\n | \"onDragLeave\"\n | \"onDragOver\"\n | \"onDrop\"\n | \"style\";\n\ninterface EffectButtonBaseProps {\n /** Emphasis variant. @default \"primary\" */\n variant?: EffectButtonVariant;\n /** Size variant. @default \"md\" */\n size?: EffectButtonSize;\n /** Stretch to the container's full width (stacked login / OAuth pills). */\n fullWidth?: boolean;\n /** Slot before the label — a component (`Plus`) or element (`<Plus />`). */\n prefix?: Slottable;\n /** Slot after the label. */\n suffix?: Slottable;\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\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 /** 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\n/**\n * EffectButton — the glossy, springy pill ported frame-for-frame from Photon's\n * Framer \"Button - Effect\", driven by Motion. `variant=\"secondary\"` swaps the\n * brand fill for the neutral white-card surface without the sheen (the login /\n * OAuth pill), and `fullWidth` stretches the pill across its container.\n * Triggers an action; for navigation use {@link EffectButtonLink}.\n */\nexport function EffectButton({\n variant = \"primary\",\n size = \"md\",\n fullWidth,\n prefix,\n suffix,\n svgOnly,\n loading,\n children,\n className,\n ref,\n ...props\n}: EffectButtonProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n return (\n <motion.button\n ref={ref}\n type=\"button\"\n {...effectMotionProps(size, variant, props.disabled || loading)}\n {...props}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n effectButtonVariants({ variant, size, fullWidth }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {effectButtonInner({ svgOnly, loading, prefix, suffix, children })}\n </motion.button>\n );\n}\n\nEffectButton.displayName = \"EffectButton\";\n\n/**\n * EffectButtonLink — {@link EffectButton} as a link, for navigation that changes\n * the URL. Renders the host router's link (via `LinkProvider`) wrapped by Motion,\n * so the pill animates identically to the button.\n */\nexport function EffectButtonLink({\n variant = \"primary\",\n size = \"md\",\n fullWidth,\n prefix,\n suffix,\n svgOnly,\n loading,\n disabled,\n href,\n children,\n className,\n ...props\n}: EffectButtonLinkProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n const Link = useLinkComponent();\n // Wrap the host link once per link identity so Motion can drive the DOM node.\n const MotionLink = useMemo(() => motion.create(Link), [Link]);\n return (\n <MotionLink\n href={href}\n {...effectMotionProps(size, variant, disabled || loading)}\n {...(props as HTMLMotionProps<\"a\">)}\n aria-disabled={disabled || loading || undefined}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n effectButtonVariants({ variant, size, fullWidth }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {effectButtonInner({ svgOnly, loading, prefix, suffix, children })}\n </MotionLink>\n );\n}\n\nEffectButtonLink.displayName = \"EffectButtonLink\";\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { a, c as s, d as o, i as T, l as n, n as B, o as u, r as E, s as e, t as f, u as i } from "../chunks/button-
|
|
2
|
+
import { a, c as s, d as o, i as T, l as n, n as B, o as u, r as E, s as e, t as f, u as i } from "../chunks/button-DjjSiLYz.js";
|
|
3
3
|
import { t as S } from "../chunks/close-button-CbQNfpxU.js";
|
|
4
4
|
export {
|
|
5
5
|
f as BUTTON_SHAPES,
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { t as o } from "./chunks/cn-D6jQqeRj.js";
|
|
|
3
3
|
import { n as s, r, t as n } from "./chunks/link-provider-9TFNyDqO.js";
|
|
4
4
|
import { t as m } from "./chunks/resolve-variant-CcD8iG5l.js";
|
|
5
5
|
import "./utils.js";
|
|
6
|
-
import { a as f, c as p, d as u, i as B, l as E, n as S, o as c, r as N, s as _, t as l, u as A } from "./chunks/button-
|
|
6
|
+
import { a as f, c as p, d as u, i as B, l as E, n as S, o as c, r as N, s as _, t as l, u as A } from "./chunks/button-DjjSiLYz.js";
|
|
7
7
|
import { t as I } from "./chunks/close-button-CbQNfpxU.js";
|
|
8
8
|
import { t as U } from "./chunks/input-aZqjjV_m.js";
|
|
9
9
|
import { t as k } from "./chunks/dialog-BSBF1Wyq.js";
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"button-9pp4g7en.js","names":[],"sources":["../../src/components/button/button.tsx"],"sourcesContent":["import {\n isValidElement,\n useMemo,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type FC,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { motion, type HTMLMotionProps } from \"motion/react\";\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\";\n\n/**\n * Design notes (Geist-aligned):\n * - ONE emphasis axis, kept deliberately small. `variant` is a closed,\n * semantic set — a single high-emphasis default plus the supporting and\n * intent variants you actually reach for. There is no `ghost`, no `link`,\n * and no second destructive: navigation belongs to `ButtonLink`, and an\n * inline text link is an anchor, not a button.\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`. Boolean flags (`loading`, `shadow`) are declarative.\n */\n\nconst COMMON_ROOT = cn(\n \"group relative inline-flex h-max cursor-pointer items-center justify-center whitespace-nowrap outline-pho-brand transition duration-100 ease-linear before:absolute 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/** Size axis — padding, text size, and icon-only (svgOnly) padding. */\nexport const BUTTON_SIZES = {\n sm: {\n classes: \"gap-1 px-3 py-2 text-sm font-semibold data-svg-only:p-2\",\n description: \"Small — compact rows, tables, and toolbars\",\n },\n md: {\n classes: \"gap-1 px-3.5 py-2.5 text-sm font-semibold data-svg-only:p-2.5\",\n description: \"Medium — the default\",\n },\n lg: {\n classes: \"gap-1.5 px-4 py-2.5 text-md font-semibold data-svg-only:p-3\",\n description: \"Large — prominent and marketing actions\",\n },\n} satisfies VariantMap;\n\n/** Shape axis — corner treatment. `square` is the default text-button shape. */\nexport const BUTTON_SHAPES = {\n square: {\n classes: \"rounded-lg before:rounded-[7px]\",\n description: \"Default — gently rounded corners\",\n },\n circle: {\n classes: \"rounded-full before:rounded-full\",\n description: \"Circular — pair with svgOnly for round icon buttons\",\n },\n rounded: {\n classes: \"rounded-full before:rounded-full\",\n description: \"Pill — marketing CTAs, often with shadow\",\n },\n} satisfies VariantMap;\n\n/** Emphasis axis — a tight, semantic set. `primary` is the default. */\nexport const BUTTON_VARIANTS = {\n primary: {\n classes:\n \"bg-pho-brand-solid text-white shadow-pho-skeuo-xs ring-1 ring-transparent ring-inset hover:bg-pho-brand-solid-hover data-loading:bg-pho-brand-solid-hover before:absolute before:inset-px before:border before:border-white/12 before:mask-b-from-0% *:data-icon:text-white/60 hover:*:data-icon:text-white/70\",\n description: \"High-emphasis primary action (default)\",\n },\n secondary: {\n classes:\n \"bg-pho-primary text-pho-secondary shadow-pho-skeuo-xs ring-1 ring-pho-primary ring-inset hover:bg-pho-primary-hover hover:text-pho-secondary-hover data-loading:bg-pho-primary-hover *:data-icon:text-fg-pho-quaternary hover:*:data-icon:text-fg-pho-quaternary-hover\",\n description: \"Neutral, supporting action\",\n },\n tertiary: {\n classes:\n \"text-pho-tertiary hover:bg-pho-primary-hover hover:text-pho-tertiary-hover data-loading:bg-pho-primary-hover *:data-icon:text-fg-pho-quaternary hover:*:data-icon:text-fg-pho-quaternary-hover\",\n description: \"Low-emphasis, borderless action\",\n },\n error: {\n classes:\n \"bg-pho-error-solid text-white shadow-pho-skeuo-xs ring-1 ring-transparent outline-pho-error ring-inset hover:bg-pho-error-solid-hover data-loading:bg-pho-error-solid-hover before:absolute before:inset-px before:border before:border-white/12 before:mask-b-from-0% *:data-icon:text-white/60 hover:*:data-icon:text-white/70\",\n description: \"Destructive confirmation\",\n },\n} satisfies VariantMap;\n\nexport type ButtonSize = keyof typeof BUTTON_SIZES;\nexport type ButtonShape = keyof typeof BUTTON_SHAPES;\nexport type ButtonVariant = keyof typeof BUTTON_VARIANTS;\n\n/** Compose the full class string for a button — exported for reuse/testing. */\nexport function buttonVariants(opts?: {\n variant?: ButtonVariant;\n size?: ButtonSize;\n shape?: ButtonShape;\n shadow?: boolean;\n className?: string;\n}): string {\n const {\n variant = \"primary\",\n size = \"md\",\n shape = \"square\",\n shadow,\n className,\n } = opts ?? {};\n return cn(\n COMMON_ROOT,\n resolveVariant(BUTTON_SHAPES, shape),\n resolveVariant(BUTTON_SIZES, size),\n resolveVariant(BUTTON_VARIANTS, variant),\n shadow && \"shadow-pho-md\",\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 /** Emphasis variant. @default \"primary\" */\n variant?: ButtonVariant;\n /** Size variant. @default \"md\" */\n size?: ButtonSize;\n /** Corner shape. @default \"square\" */\n shape?: ButtonShape;\n /** Add an elevation shadow (marketing / `rounded`). */\n shadow?: boolean;\n /** Slot before the label — a component (`Plus`) or element (`<Plus />`). */\n prefix?: Slottable;\n /** Slot after the label. */\n suffix?: Slottable;\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\nexport interface ButtonProps\n extends\n ButtonBaseProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonBaseProps> {\n ref?: Ref<HTMLButtonElement>;\n}\n\nexport interface ButtonLinkProps\n extends\n ButtonBaseProps,\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ButtonBaseProps> {\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 \"transition-inherit-all pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-5 [&>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 Spinner() {\n return (\n <svg fill=\"none\" viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <circle\n className=\"stroke-current opacity-30\"\n cx=\"10\"\n cy=\"10\"\n r=\"8\"\n fill=\"none\"\n strokeWidth=\"2\"\n />\n <circle\n className=\"origin-center animate-spin stroke-current\"\n cx=\"10\"\n cy=\"10\"\n r=\"8\"\n fill=\"none\"\n strokeWidth=\"2\"\n strokeDasharray=\"12.5 50\"\n strokeLinecap=\"round\"\n />\n </svg>\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 buttonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n}: Pick<\n ButtonBaseProps,\n \"svgOnly\" | \"loading\" | \"prefix\" | \"suffix\" | \"children\"\n>) {\n if (svgOnly) {\n return loading ? <Spinner /> : children;\n }\n return (\n <>\n {loading ? (\n <Slot position=\"loading\">\n <Spinner />\n </Slot>\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 {renderSlot(suffix, \"suffix\")}\n </>\n );\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/**\n * Button — triggers an action that mutates state (submit, save, delete).\n * For navigation that changes the URL, use {@link ButtonLink}.\n */\nexport function Button({\n variant,\n size,\n shape,\n shadow,\n prefix,\n suffix,\n svgOnly,\n loading,\n children,\n className,\n ref,\n ...props\n}: ButtonProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n return (\n <button\n ref={ref}\n type=\"button\"\n {...props}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n buttonVariants({ variant, size, shape, shadow }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {buttonInner({ svgOnly, loading, prefix, suffix, children })}\n </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,\n size,\n shape,\n shadow,\n prefix,\n suffix,\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 return (\n <Link\n href={href}\n {...props}\n aria-disabled={disabled || loading || undefined}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n buttonVariants({ variant, size, shape, shadow }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {buttonInner({ svgOnly, loading, prefix, suffix, children })}\n </Link>\n );\n}\n\nButtonLink.displayName = \"ButtonLink\";\n\n/* ============================= Effect button ============================= */\n\n/**\n * A frame-exact port of Photon's Framer \"Button - Effect\", driven by Motion\n * (the same engine Framer renders with) so every frame matches the source — not\n * a CSS approximation. On hover, three things spring together on the *identical*\n * transition (`spring-physics 200 30 0.1` → stiffness 200 / damping 30 / mass\n * 0.1): a glossy inset white sheen reshapes toward the bottom edge, the gap\n * eases open (md), and any icon grows and fades in from nothing.\n *\n * Because it's a real spring — not a fixed-duration tween — it's also velocity-\n * correct: hovering out mid-animation continues from the current velocity,\n * exactly like Framer.\n *\n * Fill and stroke are STATIC (the source keeps them identical between the base\n * and hover variants); `variant` picks the treatment — `primary` is the source\n * brand pill with the glossy sheen, `secondary` the neutral white-card pill\n * (Button's secondary surface tokens) with the sheen omitted. The gap + icon\n * reveal springs are shared. `size` maps to the two source variants: `md` =\n * \"Variant 1\" (16px label, 12×16 padding), `sm` = \"Variant 2\" (14px label,\n * 8px padding).\n */\nconst EFFECT_ROOT = cn(\n // Every variant keeps the 1px border so the pill geometry never shifts.\n \"squircle relative inline-flex h-max cursor-pointer items-center justify-center overflow-hidden rounded-full border font-medium whitespace-nowrap\",\n \"outline-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2\",\n \"disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:cursor-not-allowed aria-disabled:opacity-50\",\n);\n\n/** The exact source transition: `spring-physics 200 30 0.1` (stiffness/damping/mass). */\nconst EFFECT_SPRING = {\n type: \"spring\",\n stiffness: 200,\n damping: 30,\n mass: 0.1,\n} as const;\n\n/** Resting inset sheen — identical across both sizes (source base variants). */\nconst EFFECT_REST_SHADOW = \"inset 0px 0px 5px 2px rgba(255, 255, 255, 0.5)\";\n\n/** Per-size hover targets, sampled 1:1 from the source hover (gesture) variants. */\nconst EFFECT_HOVER = {\n sm: { boxShadow: \"inset 0px -3px 8px 2px rgba(255, 255, 255, 0.5)\", gap: 0 },\n md: { boxShadow: \"inset 0px -6px 14px 1px rgba(255, 255, 255, 0.5)\", gap: 4 },\n} as const;\n\n/** Size axis for {@link EffectButton} — padding + label size per source variant. */\nexport const EFFECT_BUTTON_SIZES = {\n sm: {\n classes: \"p-2 text-sm data-svg-only:p-2\",\n description: \"Small — the compact 'Variant 2' (14px label, 8px padding)\",\n },\n md: {\n classes: \"px-4 py-3 text-md data-svg-only:p-3\",\n description: \"Medium — the 'Variant 1' (16px label, 12×16 padding)\",\n },\n} satisfies VariantMap;\n\n/**\n * Emphasis axis for {@link EffectButton} — the static fill + edge treatment.\n * `secondary` reuses the white-card surface tokens of Button's `secondary`\n * (white card, hairline ring, quiet hover) and skips the glossy sheen — that\n * inset shine is the brand-fill treatment.\n */\nexport const EFFECT_BUTTON_VARIANTS = {\n primary: {\n classes: \"border-white/15 bg-pho-brand-solid text-white\",\n description: \"Brand fill with the glossy inset sheen (default)\",\n },\n secondary: {\n classes:\n \"border-transparent bg-pho-primary text-pho-secondary shadow-pho-skeuo-xs ring-1 ring-pho-primary ring-inset transition-colors duration-100 ease-linear hover:bg-pho-primary-hover hover:text-pho-secondary-hover data-loading:bg-pho-primary-hover\",\n description: \"Neutral white-card pill (OAuth / supporting CTA), no sheen\",\n },\n} satisfies VariantMap;\n\nexport type EffectButtonSize = keyof typeof EFFECT_BUTTON_SIZES;\nexport type EffectButtonVariant = keyof typeof EFFECT_BUTTON_VARIANTS;\n\n/** Compose the static class string for an effect button — exported for reuse. */\nexport function effectButtonVariants(opts?: {\n variant?: EffectButtonVariant;\n size?: EffectButtonSize;\n fullWidth?: boolean;\n className?: string;\n}): string {\n const { variant = \"primary\", size = \"md\", fullWidth, className } = opts ?? {};\n return cn(\n EFFECT_ROOT,\n resolveVariant(EFFECT_BUTTON_SIZES, size),\n resolveVariant(EFFECT_BUTTON_VARIANTS, variant),\n fullWidth && \"w-full\",\n className,\n );\n}\n\n/**\n * Motion variants for the pill root — the sheen (+ gap on md) spring on hover.\n * `secondary` springs only the gap: its box-shadow stays with the CSS classes\n * (ring + skeuomorphic shadow), so Motion must never write an inline one.\n */\nfunction effectRootVariants(\n size: EffectButtonSize,\n variant: EffectButtonVariant,\n) {\n if (variant === \"secondary\") {\n return {\n rest: { gap: 0 },\n hover: { gap: EFFECT_HOVER[size].gap },\n };\n }\n return {\n rest: { boxShadow: EFFECT_REST_SHADOW, gap: 0 },\n hover: EFFECT_HOVER[size],\n };\n}\n\n/**\n * Icon reveal — a 1:1 port of the source \"Arrow Right\" instance: collapsed and\n * invisible at rest (opacity 0, 1×10px), grown to full size on hover (opacity 1,\n * 20×21px). The child inherits the pill's `rest`/`hover` variant label, so it\n * springs in perfect lockstep with the sheen and gap.\n */\nconst EFFECT_ICON_VARIANTS = {\n rest: { opacity: 0, width: 1, height: 10 },\n hover: { opacity: 1, width: 20, height: 21 },\n} as const;\n\nfunction EffectSlot({\n position,\n children,\n}: {\n position: \"prefix\" | \"suffix\";\n children: ReactNode;\n}) {\n return (\n <motion.span\n data-icon={position}\n variants={EFFECT_ICON_VARIANTS}\n transition={EFFECT_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 renderEffectSlot(icon: Slottable, position: \"prefix\" | \"suffix\") {\n if (icon == null || icon === false) return null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n return (\n <EffectSlot position={position}>\n <Icon />\n </EffectSlot>\n );\n }\n if (isValidElement(icon))\n return <EffectSlot position={position}>{icon}</EffectSlot>;\n return null;\n}\n\nfunction effectButtonInner({\n svgOnly,\n loading,\n prefix,\n suffix,\n children,\n}: Pick<\n EffectButtonBaseProps,\n \"svgOnly\" | \"loading\" | \"prefix\" | \"suffix\" | \"children\"\n>) {\n // An icon-only button keeps its icon always visible (nothing to reveal).\n if (svgOnly) return loading ? <Spinner /> : children;\n return (\n <>\n {loading ? (\n <Slot position=\"loading\">\n <Spinner />\n </Slot>\n ) : (\n renderEffectSlot(prefix, \"prefix\")\n )}\n {children != null && children !== false && (\n <span data-text className=\"px-0.5\">\n {children}\n </span>\n )}\n {renderEffectSlot(suffix, \"suffix\")}\n </>\n );\n}\n\n/** Motion props (initial/animate/hover/variants/transition) shared by both roots. */\nfunction effectMotionProps(\n size: EffectButtonSize,\n variant: EffectButtonVariant,\n) {\n return {\n initial: false as const,\n animate: \"rest\",\n whileHover: \"hover\",\n variants: effectRootVariants(size, variant),\n transition: EFFECT_SPRING,\n };\n}\n\n// Motion redefines these DOM handlers; drop them from our public props so\n// spreading onto a motion element type-checks cleanly.\ntype MotionConflicts =\n | \"onAnimationStart\"\n | \"onAnimationEnd\"\n | \"onAnimationIteration\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onDragEnter\"\n | \"onDragExit\"\n | \"onDragLeave\"\n | \"onDragOver\"\n | \"onDrop\"\n | \"style\";\n\ninterface EffectButtonBaseProps {\n /** Emphasis variant. @default \"primary\" */\n variant?: EffectButtonVariant;\n /** Size variant. @default \"md\" */\n size?: EffectButtonSize;\n /** Stretch to the container's full width (stacked login / OAuth pills). */\n fullWidth?: boolean;\n /** Slot before the label — a component (`Plus`) or element (`<Plus />`). */\n prefix?: Slottable;\n /** Slot after the label. */\n suffix?: Slottable;\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\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 /** 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\n/**\n * EffectButton — the glossy, springy pill ported frame-for-frame from Photon's\n * Framer \"Button - Effect\", driven by Motion. `variant=\"secondary\"` swaps the\n * brand fill for the neutral white-card surface without the sheen (the login /\n * OAuth pill), and `fullWidth` stretches the pill across its container.\n * Triggers an action; for navigation use {@link EffectButtonLink}.\n */\nexport function EffectButton({\n variant = \"primary\",\n size = \"md\",\n fullWidth,\n prefix,\n suffix,\n svgOnly,\n loading,\n children,\n className,\n ref,\n ...props\n}: EffectButtonProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n return (\n <motion.button\n ref={ref}\n type=\"button\"\n {...effectMotionProps(size, variant)}\n {...props}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n effectButtonVariants({ variant, size, fullWidth }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {effectButtonInner({ svgOnly, loading, prefix, suffix, children })}\n </motion.button>\n );\n}\n\nEffectButton.displayName = \"EffectButton\";\n\n/**\n * EffectButtonLink — {@link EffectButton} as a link, for navigation that changes\n * the URL. Renders the host router's link (via `LinkProvider`) wrapped by Motion,\n * so the pill animates identically to the button.\n */\nexport function EffectButtonLink({\n variant = \"primary\",\n size = \"md\",\n fullWidth,\n prefix,\n suffix,\n svgOnly,\n loading,\n disabled,\n href,\n children,\n className,\n ...props\n}: EffectButtonLinkProps) {\n warnMissingLabel(svgOnly, props[\"aria-label\"]);\n const Link = useLinkComponent();\n // Wrap the host link once per link identity so Motion can drive the DOM node.\n const MotionLink = useMemo(() => motion.create(Link), [Link]);\n return (\n <MotionLink\n href={href}\n {...effectMotionProps(size, variant)}\n {...(props as HTMLMotionProps<\"a\">)}\n aria-disabled={disabled || loading || undefined}\n aria-busy={loading || undefined}\n data-loading={loading ? \"true\" : undefined}\n data-svg-only={svgOnly ? \"true\" : undefined}\n className={cn(\n effectButtonVariants({ variant, size, fullWidth }),\n loading && \"pointer-events-none\",\n svgOnly && \"[&>svg]:size-5 [&>svg]:shrink-0\",\n className,\n )}\n >\n {effectButtonInner({ svgOnly, loading, prefix, suffix, children })}\n </MotionLink>\n );\n}\n\nEffectButtonLink.displayName = \"EffectButtonLink\";\n"],"mappings":"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"}
|