@stackone/malachite 2.47.1 → 2.48.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/COMPONENTS.md +1 -0
- package/dist/components/Button.js +64 -87
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Dropdown.js +304 -302
- package/dist/components/Dropdown.js.map +1 -1
- package/dist/components/IconIndicator.js +27 -0
- package/dist/components/IconIndicator.js.map +1 -0
- package/dist/components/MultiSelect.js +138 -134
- package/dist/components/MultiSelect.js.map +1 -1
- package/dist/components/buttonSizing.js +30 -0
- package/dist/components/buttonSizing.js.map +1 -0
- package/dist/components/dropdownTriggerStyle.js +50 -21
- package/dist/components/dropdownTriggerStyle.js.map +1 -1
- package/dist/components/focusRing.js +6 -7
- package/dist/components/focusRing.js.map +1 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +351 -349
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
package/COMPONENTS.md
CHANGED
|
@@ -35,6 +35,7 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
|
|
|
35
35
|
|
|
36
36
|
- **`ChangeReview`** — Reviewing changes a machine made. `ChangeReview.Item` attaches to one changed thing: it names what changed with an `assistant` Tag, shows the value it displaced struck through, and offers approve and deny as two equally reachable icon buttons — a review affordance that made keeping easier than rejecting would not be one. Given `children`, it wraps the field the change is annotating: the tag/label/actions become a header band above it and the before/after line moves below, so "Was …" reads next to the value it describes instead of stacked with the header; without children it renders as the standalone card it always has. `ChangeReview.Summary` counts what is still undecided across the whole form, which is what a per-item control cannot do and what a caller gates a save on; at zero it either says so or collapses to nothing. `ChangeReview.Removed` is for something the assistant took out: a dashed, tinted card listing what would be lost, because a removal that simply vanished would leave nothing to reject. `ChangeReview.Jump` is a chip an assistant turn carries to point at a field it touched. _Key props:_ `Item`: `label`, `before`, `after`, `kind` (`changed` | `added` | `removed`), `origin`, `children`, `onApprove`, `onDeny`, `disabled`, `className`. `Summary`: `count`, `origin`, `onApproveAll`, `onDenyAll`, `disabled`, `settledMessage`, `className`. `Removed`: `title`, `details` (`{label, value}[]`), `onRestore`, `onDiscard`, `restoreLabel`, `discardLabel`, `origin`, `disabled`, `className`. `Jump`: `label`, `onClick`, `disabled`, `className`. `Item` also takes `onPreviewRevert(previewing)`, fired on hover and on focus.
|
|
37
37
|
- **`Alert`** — Inline alert/callout. Four severities (info, success, warning, error) plus `assistant` — a violet, sparkle-marked ground that says a machine wrote the message rather than that anything is wrong, so provenance never has to borrow a severity colour. `action` puts a control at the end — the link or button that resolves what the alert reports — and `icon` replaces the status icon; an svg that paints with `currentColor` (a CustomIcon) is drawn in the colour and size of the built-in one. _Key props:_ `type`, `message`, `action`, `icon`, `hasMargin`, `children` (expandable body), `isExpanded`, `onToggle`, `className`.
|
|
38
|
+
- **`IconIndicator`** — A non-interactive icon that carries a meaning, such as a capability shown on a page that cannot switch it on. Same square as an icon-only `Button` at each `size`, so it lines up where a sibling view shows the button. Renders `role="img"`, named by `aria-label`; with a `tooltip` it takes focus so the tooltip is reachable by keyboard. Reach for it instead of a hand-sized `<span>` around an icon. _Key props:_ `icon`, `aria-label`, `tooltip`, `size`.
|
|
38
39
|
- **`StatusBadge`** — Large status indicator (e.g. success checkmark) for terminal/confirmation screens. _Key props:_ `type`.
|
|
39
40
|
- **`StatBadge`** — Pill showing a numeric value with a label (e.g. "3 accounts selected"). _Key props:_ `count`, `label`.
|
|
40
41
|
- **`Tag`** — Small status/label tag. Types: success, error, warning, default. _Key props:_ `value`, `type`, `paddingSize`, `textTransform`, `WidthSize`.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { forwardRef as
|
|
1
|
+
import { jsx as s, jsxs as o, Fragment as p } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as z } from "react";
|
|
3
3
|
import B from "./Tooltip.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { getIconOnlySizeClasses as R, getIconSizeClass as F } from "./buttonSizing.js";
|
|
5
|
+
import { resolveRel as L } from "./linkRel.js";
|
|
6
|
+
const O = (a) => {
|
|
7
|
+
switch (a) {
|
|
7
8
|
// Figma has no text X-Small button, only the icon-only square — nothing to align to.
|
|
8
9
|
case "xsmall":
|
|
9
10
|
return "px-2 py-1 text-xs";
|
|
@@ -16,22 +17,11 @@ const F = (t) => {
|
|
|
16
17
|
default:
|
|
17
18
|
return "min-h-[var(--malachite-control-height-large,42px)] px-[12px] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap";
|
|
18
19
|
}
|
|
19
|
-
},
|
|
20
|
-
switch (
|
|
21
|
-
case "xsmall":
|
|
22
|
-
return "size-[20px] shrink-0";
|
|
23
|
-
case "small":
|
|
24
|
-
return "size-[28px] shrink-0";
|
|
25
|
-
case "medium":
|
|
26
|
-
return "size-[32px] shrink-0";
|
|
27
|
-
default:
|
|
28
|
-
return "size-[42px] shrink-0";
|
|
29
|
-
}
|
|
30
|
-
}, O = (t, s) => {
|
|
31
|
-
switch (t) {
|
|
20
|
+
}, T = (a, t) => {
|
|
21
|
+
switch (a) {
|
|
32
22
|
// Only the square rounds at 8px — text buttons at this size keep their 6px corner.
|
|
33
23
|
case "xsmall":
|
|
34
|
-
return
|
|
24
|
+
return t ? "rounded-lg" : "rounded-md";
|
|
35
25
|
case "small":
|
|
36
26
|
return "rounded-[var(--malachite-radius-10,10px)]";
|
|
37
27
|
case "medium":
|
|
@@ -41,30 +31,17 @@ const F = (t) => {
|
|
|
41
31
|
default:
|
|
42
32
|
return "rounded-[var(--malachite-radius-xxl,14px)]";
|
|
43
33
|
}
|
|
44
|
-
}, _ = (
|
|
45
|
-
const e =
|
|
46
|
-
switch (
|
|
34
|
+
}, _ = (a, t) => {
|
|
35
|
+
const e = t === "start";
|
|
36
|
+
switch (a) {
|
|
47
37
|
case "small":
|
|
48
38
|
case "medium":
|
|
49
39
|
return e ? "mr-[6px]" : "ml-[6px]";
|
|
50
40
|
default:
|
|
51
41
|
return e ? "mr-2" : "ml-2";
|
|
52
42
|
}
|
|
53
|
-
},
|
|
54
|
-
switch (
|
|
55
|
-
case "xsmall":
|
|
56
|
-
return "[&_svg]:size-[var(--malachite-icon-size-xsmall)]!";
|
|
57
|
-
case "small":
|
|
58
|
-
return "[&_svg]:size-[var(--malachite-icon-size-small)]!";
|
|
59
|
-
case "medium":
|
|
60
|
-
return "[&_svg]:size-[var(--malachite-icon-size-medium)]!";
|
|
61
|
-
case "large":
|
|
62
|
-
return "[&_svg]:size-[var(--malachite-icon-size-large)]!";
|
|
63
|
-
default:
|
|
64
|
-
return "[&_svg]:size-[var(--malachite-icon-size-large)]!";
|
|
65
|
-
}
|
|
66
|
-
}, U = (t) => {
|
|
67
|
-
switch (t) {
|
|
43
|
+
}, U = (a) => {
|
|
44
|
+
switch (a) {
|
|
68
45
|
case "md":
|
|
69
46
|
return "rounded-md";
|
|
70
47
|
case "lg":
|
|
@@ -74,40 +51,40 @@ const F = (t) => {
|
|
|
74
51
|
default:
|
|
75
52
|
return "rounded-xl";
|
|
76
53
|
}
|
|
77
|
-
},
|
|
54
|
+
}, r = {
|
|
78
55
|
neutral: "focus-visible:[outline:2px_solid_var(--malachite-text-primary)]",
|
|
79
56
|
destructive: "focus-visible:[outline:2px_solid_var(--malachite-text-destructive)]",
|
|
80
57
|
success: "focus-visible:[outline:2px_solid_var(--malachite-text-success)]",
|
|
81
58
|
warning: "focus-visible:[outline:2px_solid_var(--malachite-text-warning)]",
|
|
82
59
|
error: "focus-visible:[outline:2px_solid_var(--malachite-text-error)]",
|
|
83
60
|
assistant: "focus-visible:[outline:2px_solid_var(--malachite-assistant-foreground)]"
|
|
84
|
-
}, V = (
|
|
85
|
-
const e = `font-medium transition-[color,background-color,border-color,opacity,box-shadow] duration-200 ease-in-out outline-none focus-visible:outline-offset-2 border border-solid ${
|
|
86
|
-
switch (
|
|
61
|
+
}, V = (a, t) => {
|
|
62
|
+
const e = `font-medium transition-[color,background-color,border-color,opacity,box-shadow] duration-200 ease-in-out outline-none focus-visible:outline-offset-2 border border-solid ${t} cursor-pointer`;
|
|
63
|
+
switch (a) {
|
|
87
64
|
case "filled":
|
|
88
|
-
return `${e} ${
|
|
65
|
+
return `${e} ${r.neutral} btn-filled shadow-default`;
|
|
89
66
|
case "outline":
|
|
90
|
-
return `${e} ${
|
|
67
|
+
return `${e} ${r.neutral} btn-outline shadow-default`;
|
|
91
68
|
case "surface":
|
|
92
|
-
return `${e} ${
|
|
69
|
+
return `${e} ${r.neutral} btn-surface shadow-default`;
|
|
93
70
|
case "assistant":
|
|
94
|
-
return `${e} ${
|
|
71
|
+
return `${e} ${r.assistant} btn-assistant shadow-default`;
|
|
95
72
|
case "destructive":
|
|
96
|
-
return `${e} ${
|
|
73
|
+
return `${e} ${r.destructive} btn-destructive`;
|
|
97
74
|
case "success":
|
|
98
|
-
return `${e} ${
|
|
75
|
+
return `${e} ${r.success} btn-glass-success`;
|
|
99
76
|
case "warning":
|
|
100
|
-
return `${e} ${
|
|
77
|
+
return `${e} ${r.warning} btn-glass-warning`;
|
|
101
78
|
case "error":
|
|
102
|
-
return `${e} ${
|
|
79
|
+
return `${e} ${r.error} btn-glass-error`;
|
|
103
80
|
case "ghost":
|
|
104
|
-
return `${e} ${
|
|
81
|
+
return `${e} ${r.neutral} btn-ghost`;
|
|
105
82
|
case "no-style":
|
|
106
|
-
return `${e} ${
|
|
83
|
+
return `${e} ${r.neutral} btn-no-style border-none`;
|
|
107
84
|
default:
|
|
108
|
-
return `${e} ${
|
|
85
|
+
return `${e} ${r.neutral} btn-filled shadow-default`;
|
|
109
86
|
}
|
|
110
|
-
}, W = () => /* @__PURE__ */
|
|
87
|
+
}, W = () => /* @__PURE__ */ o(
|
|
111
88
|
"svg",
|
|
112
89
|
{
|
|
113
90
|
className: "animate-spin -ml-1 mr-2 h-4 w-4",
|
|
@@ -115,7 +92,7 @@ const F = (t) => {
|
|
|
115
92
|
fill: "none",
|
|
116
93
|
viewBox: "0 0 24 24",
|
|
117
94
|
children: [
|
|
118
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ s(
|
|
119
96
|
"circle",
|
|
120
97
|
{
|
|
121
98
|
className: "opacity-25",
|
|
@@ -126,7 +103,7 @@ const F = (t) => {
|
|
|
126
103
|
strokeWidth: "4"
|
|
127
104
|
}
|
|
128
105
|
),
|
|
129
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ s(
|
|
130
107
|
"path",
|
|
131
108
|
{
|
|
132
109
|
className: "opacity-75",
|
|
@@ -136,84 +113,84 @@ const F = (t) => {
|
|
|
136
113
|
)
|
|
137
114
|
]
|
|
138
115
|
}
|
|
139
|
-
), A =
|
|
116
|
+
), A = z(
|
|
140
117
|
({
|
|
141
|
-
variant:
|
|
142
|
-
size:
|
|
118
|
+
variant: a,
|
|
119
|
+
size: t = "large",
|
|
143
120
|
radius: e,
|
|
144
121
|
loading: x = !1,
|
|
145
|
-
disabled:
|
|
122
|
+
disabled: y = !1,
|
|
146
123
|
icon: i,
|
|
147
|
-
iconPosition:
|
|
148
|
-
flexGrow:
|
|
149
|
-
fill:
|
|
124
|
+
iconPosition: h = "start",
|
|
125
|
+
flexGrow: c = !1,
|
|
126
|
+
fill: N = !1,
|
|
150
127
|
tooltip: u,
|
|
151
|
-
tooltipPlacement:
|
|
128
|
+
tooltipPlacement: I = "top",
|
|
152
129
|
iconOnly: f = !1,
|
|
153
130
|
children: n,
|
|
154
|
-
className:
|
|
131
|
+
className: S = "",
|
|
155
132
|
href: g,
|
|
156
133
|
target: v,
|
|
157
|
-
rel:
|
|
134
|
+
rel: j,
|
|
158
135
|
...w
|
|
159
136
|
}, $) => {
|
|
160
|
-
const
|
|
137
|
+
const k = e ? U(e) : T(t, f), l = y || x, b = [
|
|
161
138
|
"flex items-center justify-center",
|
|
162
|
-
f ? `p-0 ${
|
|
163
|
-
V(
|
|
164
|
-
|
|
165
|
-
|
|
139
|
+
f ? `p-0 ${R(t)}` : O(t),
|
|
140
|
+
V(a, k),
|
|
141
|
+
c ? "w-full" : "",
|
|
142
|
+
N ? "max-w-full" : "",
|
|
166
143
|
l ? "cursor-not-allowed" : "",
|
|
167
144
|
u && l ? "pointer-events-none" : "",
|
|
168
|
-
|
|
169
|
-
].filter(Boolean).join(" "),
|
|
145
|
+
S
|
|
146
|
+
].filter(Boolean).join(" "), C = () => {
|
|
170
147
|
if (x)
|
|
171
|
-
return /* @__PURE__ */
|
|
172
|
-
/* @__PURE__ */
|
|
148
|
+
return /* @__PURE__ */ o(p, { children: [
|
|
149
|
+
/* @__PURE__ */ s(W, {}),
|
|
173
150
|
n
|
|
174
151
|
] });
|
|
175
|
-
const m = `inline-flex items-center shrink-0 ${
|
|
176
|
-
return i &&
|
|
177
|
-
/* @__PURE__ */
|
|
152
|
+
const m = `inline-flex items-center shrink-0 ${F(t)}`;
|
|
153
|
+
return i && h === "start" ? /* @__PURE__ */ o(p, { children: [
|
|
154
|
+
/* @__PURE__ */ s(
|
|
178
155
|
"span",
|
|
179
156
|
{
|
|
180
|
-
className: `${m}${n ? ` ${_(
|
|
157
|
+
className: `${m}${n ? ` ${_(t, "start")}` : ""}`,
|
|
181
158
|
children: i
|
|
182
159
|
}
|
|
183
160
|
),
|
|
184
161
|
n
|
|
185
|
-
] }) : i &&
|
|
162
|
+
] }) : i && h === "end" ? /* @__PURE__ */ o(p, { children: [
|
|
186
163
|
n,
|
|
187
|
-
/* @__PURE__ */
|
|
164
|
+
/* @__PURE__ */ s(
|
|
188
165
|
"span",
|
|
189
166
|
{
|
|
190
|
-
className: `${m}${n ? ` ${_(
|
|
167
|
+
className: `${m}${n ? ` ${_(t, "end")}` : ""}`,
|
|
191
168
|
children: i
|
|
192
169
|
}
|
|
193
170
|
)
|
|
194
171
|
] }) : n;
|
|
195
|
-
}, d = g && !l ? /* @__PURE__ */
|
|
172
|
+
}, d = g && !l ? /* @__PURE__ */ s(
|
|
196
173
|
"a",
|
|
197
174
|
{
|
|
198
175
|
ref: $,
|
|
199
176
|
href: g,
|
|
200
177
|
target: v,
|
|
201
|
-
rel:
|
|
178
|
+
rel: L(j, v),
|
|
202
179
|
className: b,
|
|
203
180
|
...w,
|
|
204
|
-
children:
|
|
181
|
+
children: C()
|
|
205
182
|
}
|
|
206
|
-
) : /* @__PURE__ */
|
|
183
|
+
) : /* @__PURE__ */ s(
|
|
207
184
|
"button",
|
|
208
185
|
{
|
|
209
186
|
ref: $,
|
|
210
187
|
disabled: l,
|
|
211
188
|
className: b,
|
|
212
189
|
...w,
|
|
213
|
-
children:
|
|
190
|
+
children: C()
|
|
214
191
|
}
|
|
215
192
|
);
|
|
216
|
-
return u ? /* @__PURE__ */
|
|
193
|
+
return u ? /* @__PURE__ */ s(B, { text: u, placement: I, fill: c, children: l ? /* @__PURE__ */ s("span", { className: `inline-flex cursor-not-allowed${c ? " w-full" : ""}`, children: d }) : d }) : d;
|
|
217
194
|
}
|
|
218
195
|
);
|
|
219
196
|
A.displayName = "Button";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sources":["../../src/components/Button.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport Tooltip from './Tooltip';\nimport { resolveRel } from './linkRel';\n\n// Button variant types matching the old component\nexport type ButtonVariant =\n | 'filled'\n | 'outline'\n /**\n * `outline`'s geometry on a ground of its own. For a button sitting on a tinted or\n * patterned surface, where `outline`'s transparent background lets that surface through\n * and the control stops reading as a button.\n */\n | 'surface'\n /**\n * The violet the assistant is named in elsewhere — for a control that hands work to it, or\n * acts on what it produced. Provenance, not a severity: it says who is being asked, not\n * that anything is wrong.\n */\n | 'assistant'\n | 'destructive'\n | 'success'\n | 'warning'\n | 'error'\n | 'ghost'\n | 'no-style';\n\nexport type ButtonSize = 'xsmall' | 'small' | 'medium' | 'large';\n\nexport type ButtonRadius = 'md' | 'lg' | 'xl';\n\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant: ButtonVariant;\n size?: ButtonSize;\n radius?: ButtonRadius;\n loading?: boolean;\n disabled?: boolean;\n icon?: React.ReactNode;\n iconPosition?: 'start' | 'end';\n flexGrow?: boolean;\n fill?: boolean;\n tooltip?: string;\n tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';\n iconOnly?: boolean;\n children?: React.ReactNode;\n onClick?: React.MouseEventHandler<HTMLButtonElement & HTMLAnchorElement>;\n /** Renders the button as a real anchor, so a link action is never an <a> nested in a <button>. */\n href?: string;\n target?: React.HTMLAttributeAnchorTarget;\n rel?: string;\n}\n\n// Geometry from the Figma component library, which is variant-independent.\n// `min-h` not `h`: Tailwind emits `h-*` after `min-h-*`, so a hard height would beat a\n// consumer's own `h-*`. Paired with `whitespace-nowrap` (as Figma has it) so a long label\n// cannot wrap into a line the height would clip.\nconst getSizeClasses = (size: ButtonSize) => {\n switch (size) {\n // Figma has no text X-Small button, only the icon-only square — nothing to align to.\n case 'xsmall':\n return 'px-2 py-1 text-xs';\n case 'small':\n return 'min-h-[var(--malachite-control-height-small,28px)] px-[10px] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap';\n case 'medium':\n return 'min-h-[var(--malachite-control-height-medium,32px)] px-[10px] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap';\n case 'large':\n return 'min-h-[var(--malachite-control-height-large,42px)] px-[12px] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap';\n default:\n return 'min-h-[var(--malachite-control-height-large,42px)] px-[12px] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap';\n }\n};\n\n/** An icon-only button is a square on the control ladder; without this it collapses to the\n * glyph plus its border. */\nconst getIconOnlySizeClasses = (size: ButtonSize): string => {\n switch (size) {\n case 'xsmall':\n return 'size-[20px] shrink-0';\n case 'small':\n return 'size-[28px] shrink-0';\n case 'medium':\n return 'size-[32px] shrink-0';\n default:\n return 'size-[42px] shrink-0';\n }\n};\n\n// `rounded-*` reads the malachite radius tokens via `@theme`, so these follow the theme.\n// An explicit `radius` prop still wins, via getRadiusClass.\nconst getDefaultRadiusClass = (size: ButtonSize, iconOnly: boolean): string => {\n switch (size) {\n // Only the square rounds at 8px — text buttons at this size keep their 6px corner.\n case 'xsmall':\n return iconOnly ? 'rounded-lg' : 'rounded-md';\n case 'small':\n return 'rounded-[var(--malachite-radius-10,10px)]';\n case 'medium':\n return 'rounded-xl';\n case 'large':\n return 'rounded-[var(--malachite-radius-xxl,14px)]';\n default:\n return 'rounded-[var(--malachite-radius-xxl,14px)]';\n }\n};\n\n// Figma pairs a 6px icon gap with the 13px tiers and 8px with the 15px tier.\nconst getIconGapClass = (size: ButtonSize, position: 'start' | 'end'): string => {\n const start = position === 'start';\n switch (size) {\n case 'small':\n case 'medium':\n return start ? 'mr-[6px]' : 'ml-[6px]';\n default:\n return start ? 'mr-2' : 'ml-2';\n }\n};\n\nconst getIconSizeClass = (size: ButtonSize): string => {\n switch (size) {\n case 'xsmall':\n return '[&_svg]:size-[var(--malachite-icon-size-xsmall)]!';\n case 'small':\n return '[&_svg]:size-[var(--malachite-icon-size-small)]!';\n case 'medium':\n return '[&_svg]:size-[var(--malachite-icon-size-medium)]!';\n case 'large':\n return '[&_svg]:size-[var(--malachite-icon-size-large)]!';\n default:\n return '[&_svg]:size-[var(--malachite-icon-size-large)]!';\n }\n};\n\nconst getRadiusClass = (radius: ButtonRadius): string => {\n switch (radius) {\n case 'md':\n return 'rounded-md';\n case 'lg':\n return 'rounded-lg';\n case 'xl':\n return 'rounded-xl';\n default:\n return 'rounded-xl';\n }\n};\n\n// Focus ring: a `focus-visible` outline (keyboard only), coloured to match the variant.\n// Uses `outline` rather than Tailwind's `ring-*` because ring composes `--tw-ring-*`\n// custom properties via box-shadow that rely on document-level @property registration\n// and silently don't paint inside a shadow root (same class of issue as transform\n// utilities). The classes are full literals so Tailwind's JIT can generate them.\nconst FOCUS_OUTLINE = {\n neutral: 'focus-visible:[outline:2px_solid_var(--malachite-text-primary)]',\n destructive: 'focus-visible:[outline:2px_solid_var(--malachite-text-destructive)]',\n success: 'focus-visible:[outline:2px_solid_var(--malachite-text-success)]',\n warning: 'focus-visible:[outline:2px_solid_var(--malachite-text-warning)]',\n error: 'focus-visible:[outline:2px_solid_var(--malachite-text-error)]',\n assistant: 'focus-visible:[outline:2px_solid_var(--malachite-assistant-foreground)]',\n};\n\nconst getVariantClasses = (variant: ButtonVariant, radiusClass: string): string => {\n const baseClasses = `font-medium transition-[color,background-color,border-color,opacity,box-shadow] duration-200 ease-in-out outline-none focus-visible:outline-offset-2 border border-solid ${radiusClass} cursor-pointer`;\n\n switch (variant) {\n case 'filled':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-filled shadow-default`;\n\n case 'outline':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-outline shadow-default`;\n\n case 'surface':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-surface shadow-default`;\n\n case 'assistant':\n return `${baseClasses} ${FOCUS_OUTLINE.assistant} btn-assistant shadow-default`;\n\n case 'destructive':\n return `${baseClasses} ${FOCUS_OUTLINE.destructive} btn-destructive`;\n\n case 'success':\n return `${baseClasses} ${FOCUS_OUTLINE.success} btn-glass-success`;\n\n case 'warning':\n return `${baseClasses} ${FOCUS_OUTLINE.warning} btn-glass-warning`;\n\n case 'error':\n return `${baseClasses} ${FOCUS_OUTLINE.error} btn-glass-error`;\n\n case 'ghost':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-ghost`;\n\n case 'no-style':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-no-style border-none`;\n\n default:\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-filled shadow-default`;\n }\n};\n\nconst LoadingSpinner = () => (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n);\n\nexport const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(\n (\n {\n variant,\n size = 'large',\n radius,\n loading = false,\n disabled = false,\n icon,\n iconPosition = 'start',\n flexGrow = false,\n fill = false,\n tooltip,\n tooltipPlacement = 'top',\n iconOnly = false,\n children,\n className = '',\n href,\n target,\n rel,\n ...props\n },\n ref,\n ) => {\n const radiusClass = radius ? getRadiusClass(radius) : getDefaultRadiusClass(size, iconOnly);\n const isInactive = disabled || loading;\n const baseClasses = [\n 'flex items-center justify-center',\n iconOnly ? `p-0 ${getIconOnlySizeClasses(size)}` : getSizeClasses(size),\n getVariantClasses(variant, radiusClass),\n flexGrow ? 'w-full' : '',\n fill ? 'max-w-full' : '',\n isInactive ? 'cursor-not-allowed' : '',\n tooltip && isInactive ? 'pointer-events-none' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const renderContent = () => {\n if (loading) {\n return (\n <>\n <LoadingSpinner />\n {children}\n </>\n );\n }\n\n const iconWrapperClasses = `inline-flex items-center shrink-0 ${getIconSizeClass(size)}`;\n\n if (icon && iconPosition === 'start') {\n return (\n <>\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'start')}` : ''}`}\n >\n {icon}\n </span>\n {children}\n </>\n );\n }\n\n if (icon && iconPosition === 'end') {\n return (\n <>\n {children}\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'end')}` : ''}`}\n >\n {icon}\n </span>\n </>\n );\n }\n\n return children;\n };\n\n // An anchor cannot be disabled, so an inactive link still renders as a <button>.\n const button =\n href && !isInactive ? (\n <a\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n target={target}\n rel={resolveRel(rel, target)}\n className={baseClasses}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n {renderContent()}\n </a>\n ) : (\n <button\n ref={ref as React.Ref<HTMLButtonElement>}\n disabled={isInactive}\n className={baseClasses}\n {...props}\n >\n {renderContent()}\n </button>\n );\n\n if (tooltip) {\n const trigger = isInactive ? (\n <span className={`inline-flex cursor-not-allowed${flexGrow ? ' w-full' : ''}`}>\n {button}\n </span>\n ) : (\n button\n );\n return (\n <Tooltip text={tooltip} placement={tooltipPlacement} fill={flexGrow}>\n {trigger}\n </Tooltip>\n );\n }\n\n return button;\n },\n);\n\nButton.displayName = 'Button';\n\nexport default Button;\n"],"names":["getSizeClasses","size","getIconOnlySizeClasses","getDefaultRadiusClass","iconOnly","getIconGapClass","position","start","getIconSizeClass","getRadiusClass","radius","FOCUS_OUTLINE","getVariantClasses","variant","radiusClass","baseClasses","LoadingSpinner","jsxs","jsx","Button","forwardRef","loading","disabled","icon","iconPosition","flexGrow","fill","tooltip","tooltipPlacement","children","className","href","target","rel","props","ref","isInactive","renderContent","Fragment","iconWrapperClasses","button","resolveRel","Tooltip"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Button.js","sources":["../../src/components/Button.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport Tooltip from './Tooltip';\nimport { getIconOnlySizeClasses, getIconSizeClass } from './buttonSizing';\nimport { resolveRel } from './linkRel';\n\n// Button variant types matching the old component\nexport type ButtonVariant =\n | 'filled'\n | 'outline'\n /**\n * `outline`'s geometry on a ground of its own. For a button sitting on a tinted or\n * patterned surface, where `outline`'s transparent background lets that surface through\n * and the control stops reading as a button.\n */\n | 'surface'\n /**\n * The violet the assistant is named in elsewhere — for a control that hands work to it, or\n * acts on what it produced. Provenance, not a severity: it says who is being asked, not\n * that anything is wrong.\n */\n | 'assistant'\n | 'destructive'\n | 'success'\n | 'warning'\n | 'error'\n | 'ghost'\n | 'no-style';\n\nexport type ButtonSize = 'xsmall' | 'small' | 'medium' | 'large';\n\nexport type ButtonRadius = 'md' | 'lg' | 'xl';\n\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant: ButtonVariant;\n size?: ButtonSize;\n radius?: ButtonRadius;\n loading?: boolean;\n disabled?: boolean;\n icon?: React.ReactNode;\n iconPosition?: 'start' | 'end';\n flexGrow?: boolean;\n fill?: boolean;\n tooltip?: string;\n tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';\n iconOnly?: boolean;\n children?: React.ReactNode;\n onClick?: React.MouseEventHandler<HTMLButtonElement & HTMLAnchorElement>;\n /** Renders the button as a real anchor, so a link action is never an <a> nested in a <button>. */\n href?: string;\n target?: React.HTMLAttributeAnchorTarget;\n rel?: string;\n}\n\n// Geometry from the Figma component library, which is variant-independent.\n// `min-h` not `h`: Tailwind emits `h-*` after `min-h-*`, so a hard height would beat a\n// consumer's own `h-*`. Paired with `whitespace-nowrap` (as Figma has it) so a long label\n// cannot wrap into a line the height would clip.\nconst getSizeClasses = (size: ButtonSize) => {\n switch (size) {\n // Figma has no text X-Small button, only the icon-only square — nothing to align to.\n case 'xsmall':\n return 'px-2 py-1 text-xs';\n case 'small':\n return 'min-h-[var(--malachite-control-height-small,28px)] px-[10px] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap';\n case 'medium':\n return 'min-h-[var(--malachite-control-height-medium,32px)] px-[10px] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap';\n case 'large':\n return 'min-h-[var(--malachite-control-height-large,42px)] px-[12px] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap';\n default:\n return 'min-h-[var(--malachite-control-height-large,42px)] px-[12px] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap';\n }\n};\n\n// `rounded-*` reads the malachite radius tokens via `@theme`, so these follow the theme.\n// An explicit `radius` prop still wins, via getRadiusClass.\nconst getDefaultRadiusClass = (size: ButtonSize, iconOnly: boolean): string => {\n switch (size) {\n // Only the square rounds at 8px — text buttons at this size keep their 6px corner.\n case 'xsmall':\n return iconOnly ? 'rounded-lg' : 'rounded-md';\n case 'small':\n return 'rounded-[var(--malachite-radius-10,10px)]';\n case 'medium':\n return 'rounded-xl';\n case 'large':\n return 'rounded-[var(--malachite-radius-xxl,14px)]';\n default:\n return 'rounded-[var(--malachite-radius-xxl,14px)]';\n }\n};\n\n// Figma pairs a 6px icon gap with the 13px tiers and 8px with the 15px tier.\nconst getIconGapClass = (size: ButtonSize, position: 'start' | 'end'): string => {\n const start = position === 'start';\n switch (size) {\n case 'small':\n case 'medium':\n return start ? 'mr-[6px]' : 'ml-[6px]';\n default:\n return start ? 'mr-2' : 'ml-2';\n }\n};\n\nconst getRadiusClass = (radius: ButtonRadius): string => {\n switch (radius) {\n case 'md':\n return 'rounded-md';\n case 'lg':\n return 'rounded-lg';\n case 'xl':\n return 'rounded-xl';\n default:\n return 'rounded-xl';\n }\n};\n\n// Focus ring: a `focus-visible` outline (keyboard only), coloured to match the variant.\n// Uses `outline` rather than Tailwind's `ring-*` because ring composes `--tw-ring-*`\n// custom properties via box-shadow that rely on document-level @property registration\n// and silently don't paint inside a shadow root (same class of issue as transform\n// utilities). The classes are full literals so Tailwind's JIT can generate them.\nconst FOCUS_OUTLINE = {\n neutral: 'focus-visible:[outline:2px_solid_var(--malachite-text-primary)]',\n destructive: 'focus-visible:[outline:2px_solid_var(--malachite-text-destructive)]',\n success: 'focus-visible:[outline:2px_solid_var(--malachite-text-success)]',\n warning: 'focus-visible:[outline:2px_solid_var(--malachite-text-warning)]',\n error: 'focus-visible:[outline:2px_solid_var(--malachite-text-error)]',\n assistant: 'focus-visible:[outline:2px_solid_var(--malachite-assistant-foreground)]',\n};\n\nconst getVariantClasses = (variant: ButtonVariant, radiusClass: string): string => {\n const baseClasses = `font-medium transition-[color,background-color,border-color,opacity,box-shadow] duration-200 ease-in-out outline-none focus-visible:outline-offset-2 border border-solid ${radiusClass} cursor-pointer`;\n\n switch (variant) {\n case 'filled':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-filled shadow-default`;\n\n case 'outline':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-outline shadow-default`;\n\n case 'surface':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-surface shadow-default`;\n\n case 'assistant':\n return `${baseClasses} ${FOCUS_OUTLINE.assistant} btn-assistant shadow-default`;\n\n case 'destructive':\n return `${baseClasses} ${FOCUS_OUTLINE.destructive} btn-destructive`;\n\n case 'success':\n return `${baseClasses} ${FOCUS_OUTLINE.success} btn-glass-success`;\n\n case 'warning':\n return `${baseClasses} ${FOCUS_OUTLINE.warning} btn-glass-warning`;\n\n case 'error':\n return `${baseClasses} ${FOCUS_OUTLINE.error} btn-glass-error`;\n\n case 'ghost':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-ghost`;\n\n case 'no-style':\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-no-style border-none`;\n\n default:\n return `${baseClasses} ${FOCUS_OUTLINE.neutral} btn-filled shadow-default`;\n }\n};\n\nconst LoadingSpinner = () => (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n);\n\nexport const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(\n (\n {\n variant,\n size = 'large',\n radius,\n loading = false,\n disabled = false,\n icon,\n iconPosition = 'start',\n flexGrow = false,\n fill = false,\n tooltip,\n tooltipPlacement = 'top',\n iconOnly = false,\n children,\n className = '',\n href,\n target,\n rel,\n ...props\n },\n ref,\n ) => {\n const radiusClass = radius ? getRadiusClass(radius) : getDefaultRadiusClass(size, iconOnly);\n const isInactive = disabled || loading;\n const baseClasses = [\n 'flex items-center justify-center',\n iconOnly ? `p-0 ${getIconOnlySizeClasses(size)}` : getSizeClasses(size),\n getVariantClasses(variant, radiusClass),\n flexGrow ? 'w-full' : '',\n fill ? 'max-w-full' : '',\n isInactive ? 'cursor-not-allowed' : '',\n tooltip && isInactive ? 'pointer-events-none' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const renderContent = () => {\n if (loading) {\n return (\n <>\n <LoadingSpinner />\n {children}\n </>\n );\n }\n\n const iconWrapperClasses = `inline-flex items-center shrink-0 ${getIconSizeClass(size)}`;\n\n if (icon && iconPosition === 'start') {\n return (\n <>\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'start')}` : ''}`}\n >\n {icon}\n </span>\n {children}\n </>\n );\n }\n\n if (icon && iconPosition === 'end') {\n return (\n <>\n {children}\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'end')}` : ''}`}\n >\n {icon}\n </span>\n </>\n );\n }\n\n return children;\n };\n\n // An anchor cannot be disabled, so an inactive link still renders as a <button>.\n const button =\n href && !isInactive ? (\n <a\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n target={target}\n rel={resolveRel(rel, target)}\n className={baseClasses}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n {renderContent()}\n </a>\n ) : (\n <button\n ref={ref as React.Ref<HTMLButtonElement>}\n disabled={isInactive}\n className={baseClasses}\n {...props}\n >\n {renderContent()}\n </button>\n );\n\n if (tooltip) {\n const trigger = isInactive ? (\n <span className={`inline-flex cursor-not-allowed${flexGrow ? ' w-full' : ''}`}>\n {button}\n </span>\n ) : (\n button\n );\n return (\n <Tooltip text={tooltip} placement={tooltipPlacement} fill={flexGrow}>\n {trigger}\n </Tooltip>\n );\n }\n\n return button;\n },\n);\n\nButton.displayName = 'Button';\n\nexport default Button;\n"],"names":["getSizeClasses","size","getDefaultRadiusClass","iconOnly","getIconGapClass","position","start","getRadiusClass","radius","FOCUS_OUTLINE","getVariantClasses","variant","radiusClass","baseClasses","LoadingSpinner","jsxs","jsx","Button","forwardRef","loading","disabled","icon","iconPosition","flexGrow","fill","tooltip","tooltipPlacement","children","className","href","target","rel","props","ref","isInactive","getIconOnlySizeClasses","renderContent","Fragment","iconWrapperClasses","getIconSizeClass","button","resolveRel","Tooltip"],"mappings":"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"}
|