@kanzo-tech/ui 0.1.0 → 0.3.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/analytics.d.ts +1 -0
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +43 -41
- package/dist/charts/chart-marks.d.ts +22 -3
- package/dist/charts/chart-marks.d.ts.map +1 -1
- package/dist/charts/chart-marks.js.map +1 -1
- package/dist/composites/sidebar.d.ts.map +1 -1
- package/dist/composites/sidebar.js +6 -0
- package/dist/composites/sidebar.js.map +1 -1
- package/dist/guard-corpus.d.ts.map +1 -1
- package/dist/simples/button.d.ts +25 -18
- package/dist/simples/button.d.ts.map +1 -1
- package/dist/simples/button.js +74 -32
- package/dist/simples/button.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
package/dist/simples/button.js
CHANGED
|
@@ -1,17 +1,58 @@
|
|
|
1
|
-
import { jsx as e, jsxs as
|
|
1
|
+
import { jsx as e, jsxs as b, Fragment as v } from "react/jsx-runtime";
|
|
2
2
|
import { ark as p } from "@ark-ui/react/factory";
|
|
3
3
|
import { tv as f } from "tailwind-variants";
|
|
4
|
-
import { cn as
|
|
5
|
-
import { Spinner as
|
|
4
|
+
import { cn as g } from "../lib/cn.js";
|
|
5
|
+
import { Spinner as u } from "./spinner.js";
|
|
6
6
|
const m = f({
|
|
7
7
|
base: [
|
|
8
8
|
"relative",
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// attribute this library lets a caller rename, and a renamed part silently lost its height:
|
|
12
|
-
// `ConversationScrollButton` measured 16×16 against a 24×24 floor. daisyUI's `.btn` does it
|
|
13
|
-
// this way for the same reason, and `no-measurement-on-a-renameable-slot.test.ts` holds it.
|
|
9
|
+
// Nothing below may be keyed on `data-slot`. See the docblock: `--size` was moved here first,
|
|
10
|
+
// in `05f3a0a`, and the paint followed it once the same rename was measured against the colour.
|
|
14
11
|
"h-(--size)",
|
|
12
|
+
// The only one of the three locals a variant may leave unset — `outline` is the sole variant
|
|
13
|
+
// that assigns `--btn-bd`, while all six assign the fill and the ink. A default for those two
|
|
14
|
+
// would be a line that is overwritten every single render.
|
|
15
|
+
"[--btn-bd:transparent]",
|
|
16
|
+
// Derived, never assigned by a variant. `--depth: 0` collapses the edge and the lift to
|
|
17
|
+
// nothing, which is what the library looks like today; `1` gives it relief. Same classes.
|
|
18
|
+
//
|
|
19
|
+
// daisyUI darkens a fill with `color-mix(in oklab, var(--btn-bg), #000 5%)`. Mixing toward
|
|
20
|
+
// `--foreground` instead is a divergence taken on a reason: `black` is only "darker" in a light
|
|
21
|
+
// theme, and on a dark one the hover of a pale button should move toward white. One formula
|
|
22
|
+
// reads as "push this fill away from the page and toward the ink" in both, and it follows a
|
|
23
|
+
// tenant's document instead of a constant — which is also why `--depth` can be a single number.
|
|
24
|
+
// Their half-pixel inset gloss needs a colour that is toward the light side in both modes and
|
|
25
|
+
// neither `--foreground` nor `--background` is that, so it waits for a reason to exist.
|
|
26
|
+
"[--btn-edge:color-mix(in_oklab,var(--btn-bd),var(--foreground)_calc(var(--depth)*8%))]",
|
|
27
|
+
"[--btn-lift:color-mix(in_oklab,var(--btn-bg)_calc(var(--depth)*30%),transparent)]",
|
|
28
|
+
"bg-(--btn-bg) text-(--btn-fg)",
|
|
29
|
+
// The grain, and the whole of the conditional that switches it off: at `--noise: 0` the layer
|
|
30
|
+
// is sized to zero and never painted, at `1` it tiles. No variant — which is the property that
|
|
31
|
+
// lets it be a value a tenant sets rather than a look somebody has to write. It defaults to `0`
|
|
32
|
+
// here rather than in every theme, because a theme that wants no texture is saying nothing.
|
|
33
|
+
"bg-(image:--fx-noise) bg-size-[calc(var(--noise,0)*100%)]",
|
|
34
|
+
// `rounded-[var(--radius-field)]` and not `rounded-field`, which is the same radius and the
|
|
35
|
+
// spelling every other recipe here uses: `tailwind-merge` knows nothing about a theme key it
|
|
36
|
+
// was never configured with, so `rounded-field` and a caller's `rounded-full` both survive the
|
|
37
|
+
// merge and the winner is whichever Tailwind happened to emit last. The `pill` variant is that
|
|
38
|
+
// caller. An arbitrary value is in a group the merge does know.
|
|
39
|
+
"border-[length:var(--stroke)] border-(--btn-edge) rounded-[var(--radius-field)]",
|
|
40
|
+
// As `shadow-*` rather than a raw `box-shadow`, so it composes with `focus-visible:ring-[3px]`
|
|
41
|
+
// through Tailwind's shadow chain instead of being replaced by it. At `--depth: 0` the lift is
|
|
42
|
+
// transparent and nothing is drawn either way, which is why that was invisible before.
|
|
43
|
+
"shadow-[0_3px_2px_-2px_var(--btn-lift),0_4px_3px_-2px_var(--btn-lift)]",
|
|
44
|
+
// One hover and one active for every variant, solid and transparent alike — and the transparent
|
|
45
|
+
// case is the tell that the formula is right. Mixing `transparent` with the foreground at 10%
|
|
46
|
+
// IS the foreground at 10% alpha, which is exactly the wash a ghost button wants.
|
|
47
|
+
//
|
|
48
|
+
// The CSS rule guarded these with `:not(:disabled, [aria-disabled="true"], [data-disabled])`.
|
|
49
|
+
// All three spellings already carry `pointer-events-none` on this same base and an element with
|
|
50
|
+
// `pointer-events: none` can match neither `:hover` nor `:active`, so the guard was
|
|
51
|
+
// belt-and-braces. Dropping it is not tidiness: with the plain modifier, `tailwind-merge` can
|
|
52
|
+
// see a variant's own `hover:bg-*` as the same utility and let it win — which is how `link`
|
|
53
|
+
// opts out in one class, instead of losing to a longer selector on specificity.
|
|
54
|
+
"hover:bg-[color-mix(in_oklab,var(--btn-bg),var(--foreground)_10%)]",
|
|
55
|
+
"active:bg-[color-mix(in_oklab,var(--btn-bg),var(--foreground)_16%)]",
|
|
15
56
|
"inline-flex shrink-0 items-center justify-center gap-2",
|
|
16
57
|
"whitespace-nowrap font-medium text-sm",
|
|
17
58
|
"border-solid",
|
|
@@ -56,8 +97,9 @@ const m = f({
|
|
|
56
97
|
"focus-visible:border-primary"
|
|
57
98
|
],
|
|
58
99
|
// The one variant that opts OUT of the shared hover, because a link's hover is an underline
|
|
59
|
-
// and not a wash.
|
|
60
|
-
//
|
|
100
|
+
// and not a wash. Same modifier and same utility group as the base's wash, so
|
|
101
|
+
// `tailwind-variants` merges the two and the variant wins — which is what makes opting out
|
|
102
|
+
// one class rather than an exception somewhere else.
|
|
61
103
|
link: [
|
|
62
104
|
"[--btn-bg:transparent]",
|
|
63
105
|
"[--btn-fg:var(--primary)]",
|
|
@@ -67,9 +109,9 @@ const m = f({
|
|
|
67
109
|
]
|
|
68
110
|
},
|
|
69
111
|
/**
|
|
70
|
-
* Padding, gaps and icon sizes.
|
|
71
|
-
*
|
|
72
|
-
*
|
|
112
|
+
* Padding, gaps and icon sizes. A size variant only **moves `--size`** — the height that reads
|
|
113
|
+
* it is on the `base` — so a tenant can ask for compact controls, through `--size-field`,
|
|
114
|
+
* without asking for tighter text.
|
|
73
115
|
*
|
|
74
116
|
* The floor is still measured rather than chosen. `xs` and `icon-xs` were both `1.5rem`, and
|
|
75
117
|
* every size is a `rem` against a root the density axis sets — 16px default, 14px compact, 18px
|
|
@@ -115,43 +157,43 @@ const m = f({
|
|
|
115
157
|
clickEffect: !0,
|
|
116
158
|
pill: !1
|
|
117
159
|
}
|
|
118
|
-
}),
|
|
160
|
+
}), k = (s) => {
|
|
119
161
|
const {
|
|
120
|
-
variant:
|
|
121
|
-
size:
|
|
162
|
+
variant: r = "default",
|
|
163
|
+
size: t = "md",
|
|
122
164
|
clickEffect: n = !0,
|
|
123
165
|
pill: o = !1,
|
|
124
|
-
isLoading:
|
|
166
|
+
isLoading: a = !1,
|
|
125
167
|
className: l,
|
|
126
|
-
children:
|
|
168
|
+
children: i,
|
|
127
169
|
slot: d,
|
|
128
170
|
...c
|
|
129
|
-
} =
|
|
171
|
+
} = s;
|
|
130
172
|
return /* @__PURE__ */ e(
|
|
131
173
|
p.button,
|
|
132
174
|
{
|
|
133
|
-
className:
|
|
134
|
-
m({ variant:
|
|
175
|
+
className: g(
|
|
176
|
+
m({ variant: r, size: t, clickEffect: n, pill: o }),
|
|
135
177
|
l
|
|
136
178
|
),
|
|
137
|
-
"data-size":
|
|
138
|
-
"data-state":
|
|
139
|
-
"data-variant":
|
|
179
|
+
"data-size": t,
|
|
180
|
+
"data-state": a ? "loading" : "idle",
|
|
181
|
+
"data-variant": r,
|
|
140
182
|
type: "button",
|
|
141
183
|
...c,
|
|
142
184
|
"data-slot": d ?? "button",
|
|
143
|
-
"aria-busy":
|
|
144
|
-
"aria-disabled":
|
|
145
|
-
children:
|
|
146
|
-
/* @__PURE__ */ e("span", { "aria-hidden": !0, className: "invisible", children:
|
|
147
|
-
/* @__PURE__ */ e("span", { className: "sr-only", children:
|
|
148
|
-
/* @__PURE__ */ e("span", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ e(
|
|
149
|
-
] }) :
|
|
185
|
+
"aria-busy": a,
|
|
186
|
+
"aria-disabled": a,
|
|
187
|
+
children: a ? /* @__PURE__ */ b(v, { children: [
|
|
188
|
+
/* @__PURE__ */ e("span", { "aria-hidden": !0, className: "invisible", children: i }),
|
|
189
|
+
/* @__PURE__ */ e("span", { className: "sr-only", children: i }),
|
|
190
|
+
/* @__PURE__ */ e("span", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ e(u, { "aria-hidden": !0 }) })
|
|
191
|
+
] }) : i
|
|
150
192
|
}
|
|
151
193
|
);
|
|
152
194
|
};
|
|
153
195
|
export {
|
|
154
|
-
|
|
196
|
+
k as Button,
|
|
155
197
|
m as buttonVariants
|
|
156
198
|
};
|
|
157
199
|
//# sourceMappingURL=button.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sources":["../../src/simples/button.tsx"],"sourcesContent":["import { ark } from \"@ark-ui/react/factory\";\nimport type React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\nimport { cn } from \"../lib/cn\";\nimport { Spinner } from \"./spinner\";\n\n/**\n * Everything a class list can say. The rest — the fill, the ink, the edge, the lift, the hover, the\n * active and the height — is one block of real CSS in `styles.css`, written once in terms of three\n * locals, and this file assigns those three.\n *\n * **That is the whole shape of the change, and it is daisyUI's.** Their `.btn-primary` is two\n * custom-property assignments over a `.btn` that derives every state; ours was six variants of five\n * to six utilities each, naming eight different tokens between them, with the hover of each written\n * separately. A hover rule that lives in six places is a hover rule that drifts in six places, and\n * three of the comments this file used to carry were measurements taken to settle one of those\n * drifts.\n *\n * What a variant may set: `--btn-bg`, `--btn-fg`, `--btn-bd`. Nothing else here paints.\n */\nexport const buttonVariants = tv({\n base: [\n \"relative\",\n // The height is HERE, on the base, and every size variant only moves `--size`. Keyed off the\n // part's own name instead — `[data-slot=\"button\"][data-size=\"sm\"]` — it was keyed off the one\n // attribute this library lets a caller rename, and a renamed part silently lost its height:\n // `ConversationScrollButton` measured 16×16 against a 24×24 floor. daisyUI's `.btn` does it\n // this way for the same reason, and `no-measurement-on-a-renameable-slot.test.ts` holds it.\n \"h-(--size)\",\n \"inline-flex shrink-0 items-center justify-center gap-2\",\n \"whitespace-nowrap font-medium text-sm\",\n \"border-solid\",\n \"transition-all\",\n \"outline-none focus-visible:ring-[3px] focus-visible:ring-ring\",\n \"disabled:pointer-events-none disabled:opacity-64\",\n \"data-disabled:pointer-events-none data-disabled:opacity-64\",\n \"aria-disabled:pointer-events-none aria-disabled:opacity-64\",\n \"data-[state=loading]:pointer-events-none\",\n \"aria-invalid:border-destructive aria-invalid:ring-destructive/24\",\n \"[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n \"motion-reduce:transition-none!\",\n ],\n variants: {\n variant: {\n default: [\n \"[--btn-bg:var(--primary)]\",\n \"[--btn-fg:var(--primary-foreground)]\",\n \"focus-visible:border-background\",\n ],\n outline: [\n \"[--btn-bg:transparent]\",\n \"[--btn-fg:var(--foreground)]\",\n \"[--btn-bd:var(--input)]\",\n \"focus-visible:border-primary\",\n ],\n destructive: [\n \"[--btn-bg:var(--destructive)]\",\n // Was `text-white` at 3.81 on red-500. The fill moved to `-600` and the ink became a token,\n // because no choice of ink rescued red-500: white 3.81, near-black 4.15, AA needs 4.5.\n \"[--btn-fg:var(--destructive-content)]\",\n \"focus-visible:border-background focus-visible:ring-destructive-foreground/32\",\n ],\n secondary: [\n \"[--btn-bg:var(--secondary)]\",\n \"[--btn-fg:var(--secondary-foreground)]\",\n \"focus-visible:border-primary\",\n ],\n ghost: [\n \"[--btn-bg:transparent]\",\n \"[--btn-fg:var(--foreground)]\",\n \"focus-visible:border-primary\",\n ],\n // The one variant that opts OUT of the shared hover, because a link's hover is an underline\n // and not a wash. A utility beats the recipe base by cascade layer, which is what makes\n // opting out one class rather than an exception in the CSS.\n link: [\n \"[--btn-bg:transparent]\",\n \"[--btn-fg:var(--primary)]\",\n \"underline-offset-4\",\n \"hover:bg-transparent hover:underline active:bg-transparent\",\n \"focus-visible:border-primary\",\n ],\n },\n /**\n * Padding, gaps and icon sizes. **The heights are not here** — they are `--size-field` in\n * `styles.css`, keyed off the `data-size` this recipe already writes, so a tenant can ask for\n * compact controls without asking for tighter text.\n *\n * The floor is still measured rather than chosen. `xs` and `icon-xs` were both `1.5rem`, and\n * every size is a `rem` against a root the density axis sets — 16px default, 14px compact, 18px\n * comfortable — so they measured **21px in compact**, under the 24×24 WCAG 2.5.8 states in CSS\n * pixels. `sm` is the smallest size that clears the bar in all three densities. No call site was\n * failing: the spacing exception saves a clustered control, and every measured `xs` was in a\n * cluster. The variant went because its NAME promised a size it could not deliver at one\n * density, and nothing was published to break.\n */\n size: {\n sm: [\"[--size:calc(var(--size-field)*7)]\", \"px-2.5\", \"gap-1.5\", \"[&_svg:not([class*='size-'])]:size-3.5\"],\n md: [\"[--size:calc(var(--size-field)*8)]\", \"px-3\", \"py-2\"],\n lg: [\"[--size:calc(var(--size-field)*9)]\", \"px-3.5\"],\n xl: [\"[--size:calc(var(--size-field)*10)]\", \"text-base\", \"px-4\"],\n // Square, and the width is stated rather than left to `aspect-ratio`: a caller who writes\n // `w-fit` on top of an aspect ratio gets the icon's own width and a control twice as tall.\n \"icon-sm\": [\"[--size:calc(var(--size-field)*7)]\", \"w-(--size)\", \"px-0\"],\n \"icon-md\": [\"[--size:calc(var(--size-field)*8)]\", \"w-(--size)\", \"px-0\"],\n \"icon-lg\": [\"[--size:calc(var(--size-field)*9)]\", \"w-(--size)\", \"px-0\"],\n \"icon-xl\": [\n \"[--size:calc(var(--size-field)*10)]\",\n \"w-(--size)\",\n \"px-0\",\n \"[&_svg:not([class*='size-'])]:size-5\",\n ],\n },\n clickEffect: {\n true: \"active:not-aria-[haspopup]:scale-[0.98]\",\n },\n pill: {\n true: [\n \"rounded-full\",\n \"has-[>svg]:data-[size=sm]:pe-3.5\",\n \"has-[>svg]:data-[size=md]:pe-4\",\n \"has-[>svg]:data-[size=lg]:pe-4.5\",\n \"has-[>svg]:data-[size=xl]:pe-5\",\n ],\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n clickEffect: true,\n pill: false,\n },\n});\n\nexport interface ButtonProps\n extends React.ComponentProps<typeof ark.button>,\n VariantProps<typeof buttonVariants> {\n /**\n * Apply a click effect to the button\n *\n * @default true\n */\n clickEffect?: boolean;\n /**\n * Show a loading indicator\n *\n * @default false\n */\n isLoading?: boolean;\n}\n\nexport const Button = (props: ButtonProps) => {\n const {\n variant = \"default\",\n size = \"md\",\n clickEffect = true,\n pill = false,\n isLoading = false,\n className,\n children,\n slot,\n ...rest\n } = props;\n\n return (\n <ark.button\n className={cn(\n buttonVariants({ variant, size, clickEffect, pill }),\n className\n )}\n data-size={size}\n data-state={isLoading ? \"loading\" : \"idle\"}\n data-variant={variant}\n type=\"button\"\n {...rest}\n data-slot={slot ?? \"button\"}\n aria-busy={isLoading}\n aria-disabled={isLoading}\n >\n {isLoading ? (\n <>\n <span aria-hidden className=\"invisible\">\n {children}\n </span>\n\n <span className=\"sr-only\">{children}</span>\n\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner aria-hidden />\n </span>\n </>\n ) : (\n children\n )}\n </ark.button>\n );\n};\n"],"names":["buttonVariants","tv","Button","props","variant","size","clickEffect","pill","isLoading","className","children","slot","rest","jsx","ark","cn","jsxs","Fragment","Spinner"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"button.js","sources":["../../src/simples/button.tsx"],"sourcesContent":["import { ark } from \"@ark-ui/react/factory\";\nimport type React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\nimport { cn } from \"../lib/cn\";\nimport { Spinner } from \"./spinner\";\n\n/**\n * The whole control: the fill, the ink, the edge, the lift, both washes and the height, all on the\n * `base` and all written once in terms of three locals a variant assigns.\n *\n * **The shape is daisyUI's.** Their `.btn-primary` is two custom-property assignments over a `.btn`\n * that derives every state; ours was six variants of five to six utilities each, naming eight\n * different tokens between them, with the hover of each written separately. A hover rule that lives\n * in six places is a hover rule that drifts in six places.\n *\n * **The placement is daisyUI's too, and that half arrived late.** The derivations sat in\n * `styles.css` under `[data-slot=\"button\"]`, which is the one attribute this library invites a\n * caller to RENAME — every part takes `slot?: string`. So every component of ours that renames a\n * `Button` got the variant's three assignments and no rule that read them: `AlertDialogAction` and\n * `AlertDialogCancel` reported their `data-variant` correctly and `background-color:\n * rgba(0, 0, 0, 0)` in a live document, and twenty-nine more call sites sat on the same fault.\n * `05f3a0a` had already moved the *height* here for exactly this reason and left the colour behind,\n * on the argument that losing a colour on a rename is a caller asking for a different look — which\n * is true of a caller and was never true of us. `no-paint-on-a-renameable-slot.test.ts` holds it.\n *\n * What a variant may set: `--btn-bg`, `--btn-fg`, `--btn-bd`. Nothing else here paints.\n */\nexport const buttonVariants = tv({\n base: [\n \"relative\",\n // Nothing below may be keyed on `data-slot`. See the docblock: `--size` was moved here first,\n // in `05f3a0a`, and the paint followed it once the same rename was measured against the colour.\n \"h-(--size)\",\n // The only one of the three locals a variant may leave unset — `outline` is the sole variant\n // that assigns `--btn-bd`, while all six assign the fill and the ink. A default for those two\n // would be a line that is overwritten every single render.\n \"[--btn-bd:transparent]\",\n // Derived, never assigned by a variant. `--depth: 0` collapses the edge and the lift to\n // nothing, which is what the library looks like today; `1` gives it relief. Same classes.\n //\n // daisyUI darkens a fill with `color-mix(in oklab, var(--btn-bg), #000 5%)`. Mixing toward\n // `--foreground` instead is a divergence taken on a reason: `black` is only \"darker\" in a light\n // theme, and on a dark one the hover of a pale button should move toward white. One formula\n // reads as \"push this fill away from the page and toward the ink\" in both, and it follows a\n // tenant's document instead of a constant — which is also why `--depth` can be a single number.\n // Their half-pixel inset gloss needs a colour that is toward the light side in both modes and\n // neither `--foreground` nor `--background` is that, so it waits for a reason to exist.\n \"[--btn-edge:color-mix(in_oklab,var(--btn-bd),var(--foreground)_calc(var(--depth)*8%))]\",\n \"[--btn-lift:color-mix(in_oklab,var(--btn-bg)_calc(var(--depth)*30%),transparent)]\",\n \"bg-(--btn-bg) text-(--btn-fg)\",\n // The grain, and the whole of the conditional that switches it off: at `--noise: 0` the layer\n // is sized to zero and never painted, at `1` it tiles. No variant — which is the property that\n // lets it be a value a tenant sets rather than a look somebody has to write. It defaults to `0`\n // here rather than in every theme, because a theme that wants no texture is saying nothing.\n \"bg-(image:--fx-noise) bg-size-[calc(var(--noise,0)*100%)]\",\n // `rounded-[var(--radius-field)]` and not `rounded-field`, which is the same radius and the\n // spelling every other recipe here uses: `tailwind-merge` knows nothing about a theme key it\n // was never configured with, so `rounded-field` and a caller's `rounded-full` both survive the\n // merge and the winner is whichever Tailwind happened to emit last. The `pill` variant is that\n // caller. An arbitrary value is in a group the merge does know.\n \"border-[length:var(--stroke)] border-(--btn-edge) rounded-[var(--radius-field)]\",\n // As `shadow-*` rather than a raw `box-shadow`, so it composes with `focus-visible:ring-[3px]`\n // through Tailwind's shadow chain instead of being replaced by it. At `--depth: 0` the lift is\n // transparent and nothing is drawn either way, which is why that was invisible before.\n \"shadow-[0_3px_2px_-2px_var(--btn-lift),0_4px_3px_-2px_var(--btn-lift)]\",\n // One hover and one active for every variant, solid and transparent alike — and the transparent\n // case is the tell that the formula is right. Mixing `transparent` with the foreground at 10%\n // IS the foreground at 10% alpha, which is exactly the wash a ghost button wants.\n //\n // The CSS rule guarded these with `:not(:disabled, [aria-disabled=\"true\"], [data-disabled])`.\n // All three spellings already carry `pointer-events-none` on this same base and an element with\n // `pointer-events: none` can match neither `:hover` nor `:active`, so the guard was\n // belt-and-braces. Dropping it is not tidiness: with the plain modifier, `tailwind-merge` can\n // see a variant's own `hover:bg-*` as the same utility and let it win — which is how `link`\n // opts out in one class, instead of losing to a longer selector on specificity.\n \"hover:bg-[color-mix(in_oklab,var(--btn-bg),var(--foreground)_10%)]\",\n \"active:bg-[color-mix(in_oklab,var(--btn-bg),var(--foreground)_16%)]\",\n \"inline-flex shrink-0 items-center justify-center gap-2\",\n \"whitespace-nowrap font-medium text-sm\",\n \"border-solid\",\n \"transition-all\",\n \"outline-none focus-visible:ring-[3px] focus-visible:ring-ring\",\n \"disabled:pointer-events-none disabled:opacity-64\",\n \"data-disabled:pointer-events-none data-disabled:opacity-64\",\n \"aria-disabled:pointer-events-none aria-disabled:opacity-64\",\n \"data-[state=loading]:pointer-events-none\",\n \"aria-invalid:border-destructive aria-invalid:ring-destructive/24\",\n \"[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n \"motion-reduce:transition-none!\",\n ],\n variants: {\n variant: {\n default: [\n \"[--btn-bg:var(--primary)]\",\n \"[--btn-fg:var(--primary-foreground)]\",\n \"focus-visible:border-background\",\n ],\n outline: [\n \"[--btn-bg:transparent]\",\n \"[--btn-fg:var(--foreground)]\",\n \"[--btn-bd:var(--input)]\",\n \"focus-visible:border-primary\",\n ],\n destructive: [\n \"[--btn-bg:var(--destructive)]\",\n // Was `text-white` at 3.81 on red-500. The fill moved to `-600` and the ink became a token,\n // because no choice of ink rescued red-500: white 3.81, near-black 4.15, AA needs 4.5.\n \"[--btn-fg:var(--destructive-content)]\",\n \"focus-visible:border-background focus-visible:ring-destructive-foreground/32\",\n ],\n secondary: [\n \"[--btn-bg:var(--secondary)]\",\n \"[--btn-fg:var(--secondary-foreground)]\",\n \"focus-visible:border-primary\",\n ],\n ghost: [\n \"[--btn-bg:transparent]\",\n \"[--btn-fg:var(--foreground)]\",\n \"focus-visible:border-primary\",\n ],\n // The one variant that opts OUT of the shared hover, because a link's hover is an underline\n // and not a wash. Same modifier and same utility group as the base's wash, so\n // `tailwind-variants` merges the two and the variant wins — which is what makes opting out\n // one class rather than an exception somewhere else.\n link: [\n \"[--btn-bg:transparent]\",\n \"[--btn-fg:var(--primary)]\",\n \"underline-offset-4\",\n \"hover:bg-transparent hover:underline active:bg-transparent\",\n \"focus-visible:border-primary\",\n ],\n },\n /**\n * Padding, gaps and icon sizes. A size variant only **moves `--size`** — the height that reads\n * it is on the `base` — so a tenant can ask for compact controls, through `--size-field`,\n * without asking for tighter text.\n *\n * The floor is still measured rather than chosen. `xs` and `icon-xs` were both `1.5rem`, and\n * every size is a `rem` against a root the density axis sets — 16px default, 14px compact, 18px\n * comfortable — so they measured **21px in compact**, under the 24×24 WCAG 2.5.8 states in CSS\n * pixels. `sm` is the smallest size that clears the bar in all three densities. No call site was\n * failing: the spacing exception saves a clustered control, and every measured `xs` was in a\n * cluster. The variant went because its NAME promised a size it could not deliver at one\n * density, and nothing was published to break.\n */\n size: {\n sm: [\"[--size:calc(var(--size-field)*7)]\", \"px-2.5\", \"gap-1.5\", \"[&_svg:not([class*='size-'])]:size-3.5\"],\n md: [\"[--size:calc(var(--size-field)*8)]\", \"px-3\", \"py-2\"],\n lg: [\"[--size:calc(var(--size-field)*9)]\", \"px-3.5\"],\n xl: [\"[--size:calc(var(--size-field)*10)]\", \"text-base\", \"px-4\"],\n // Square, and the width is stated rather than left to `aspect-ratio`: a caller who writes\n // `w-fit` on top of an aspect ratio gets the icon's own width and a control twice as tall.\n \"icon-sm\": [\"[--size:calc(var(--size-field)*7)]\", \"w-(--size)\", \"px-0\"],\n \"icon-md\": [\"[--size:calc(var(--size-field)*8)]\", \"w-(--size)\", \"px-0\"],\n \"icon-lg\": [\"[--size:calc(var(--size-field)*9)]\", \"w-(--size)\", \"px-0\"],\n \"icon-xl\": [\n \"[--size:calc(var(--size-field)*10)]\",\n \"w-(--size)\",\n \"px-0\",\n \"[&_svg:not([class*='size-'])]:size-5\",\n ],\n },\n clickEffect: {\n true: \"active:not-aria-[haspopup]:scale-[0.98]\",\n },\n pill: {\n true: [\n \"rounded-full\",\n \"has-[>svg]:data-[size=sm]:pe-3.5\",\n \"has-[>svg]:data-[size=md]:pe-4\",\n \"has-[>svg]:data-[size=lg]:pe-4.5\",\n \"has-[>svg]:data-[size=xl]:pe-5\",\n ],\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n clickEffect: true,\n pill: false,\n },\n});\n\nexport interface ButtonProps\n extends React.ComponentProps<typeof ark.button>,\n VariantProps<typeof buttonVariants> {\n /**\n * Apply a click effect to the button\n *\n * @default true\n */\n clickEffect?: boolean;\n /**\n * Show a loading indicator\n *\n * @default false\n */\n isLoading?: boolean;\n}\n\nexport const Button = (props: ButtonProps) => {\n const {\n variant = \"default\",\n size = \"md\",\n clickEffect = true,\n pill = false,\n isLoading = false,\n className,\n children,\n slot,\n ...rest\n } = props;\n\n return (\n <ark.button\n className={cn(\n buttonVariants({ variant, size, clickEffect, pill }),\n className\n )}\n data-size={size}\n data-state={isLoading ? \"loading\" : \"idle\"}\n data-variant={variant}\n type=\"button\"\n {...rest}\n data-slot={slot ?? \"button\"}\n aria-busy={isLoading}\n aria-disabled={isLoading}\n >\n {isLoading ? (\n <>\n <span aria-hidden className=\"invisible\">\n {children}\n </span>\n\n <span className=\"sr-only\">{children}</span>\n\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner aria-hidden />\n </span>\n </>\n ) : (\n children\n )}\n </ark.button>\n );\n};\n"],"names":["buttonVariants","tv","Button","props","variant","size","clickEffect","pill","isLoading","className","children","slot","rest","jsx","ark","cn","jsxs","Fragment","Spinner"],"mappings":"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"}
|