@stackone/malachite 2.70.0 → 2.71.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.
@@ -1,27 +1,27 @@
1
1
  import { jsx as r, jsxs as i, Fragment as d } from "react/jsx-runtime";
2
- import { forwardRef as O } from "react";
3
- import T from "./Tooltip.js";
4
- import { getIconOnlySizeClasses as U, getIconSizeClass as V } from "./buttonSizing.js";
5
- import { resolveRel as W } from "./linkRel.js";
6
- const A = (s) => {
7
- switch (s) {
2
+ import { forwardRef as A } from "react";
3
+ import E from "./Tooltip.js";
4
+ import { getIconOnlySizeClasses as H, getIconSizeClass as M } from "./buttonSizing.js";
5
+ import { resolveRel as D } from "./linkRel.js";
6
+ const O = (t) => {
7
+ switch (t) {
8
8
  // Figma has no text X-Small button, only the icon-only square — nothing to align to.
9
9
  case "xsmall":
10
- return "px-2 py-1 text-xs";
10
+ return "[--btn-px:calc(var(--spacing)*2)] px-[var(--btn-px)] py-1 text-xs";
11
11
  case "small":
12
- return "min-h-[var(--malachite-control-height-small,28px)] px-[10px] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap";
12
+ return "min-h-[var(--malachite-control-height-small,28px)] [--btn-px:10px] px-[var(--btn-px)] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap";
13
13
  case "medium":
14
- return "min-h-[var(--malachite-control-height-medium,32px)] px-[10px] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap";
14
+ return "min-h-[var(--malachite-control-height-medium,32px)] [--btn-px:10px] px-[var(--btn-px)] text-[length:var(--malachite-font-size-small,13px)] leading-[16px] whitespace-nowrap";
15
15
  case "large":
16
- return "min-h-[var(--malachite-control-height-large,42px)] px-[12px] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap";
16
+ return "min-h-[var(--malachite-control-height-large,42px)] [--btn-px:12px] px-[var(--btn-px)] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap";
17
17
  default:
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
+ return "min-h-[var(--malachite-control-height-large,42px)] [--btn-px:12px] px-[var(--btn-px)] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap";
19
19
  }
20
- }, D = (s, t) => {
21
- switch (s) {
20
+ }, T = "-mx-[calc(var(--btn-px)+1px)]", V = "-mx-[var(--btn-px)]", W = (t, a) => {
21
+ switch (t) {
22
22
  // Only the square rounds at 8px — text buttons at this size keep their 6px corner.
23
23
  case "xsmall":
24
- return t ? "rounded-lg" : "rounded-md";
24
+ return a ? "rounded-lg" : "rounded-md";
25
25
  case "small":
26
26
  return "rounded-[var(--malachite-radius-10,10px)]";
27
27
  case "medium":
@@ -31,17 +31,17 @@ const A = (s) => {
31
31
  default:
32
32
  return "rounded-[var(--malachite-radius-xxl,14px)]";
33
33
  }
34
- }, k = (s, t) => {
35
- const e = t === "start";
36
- switch (s) {
34
+ }, R = (t, a) => {
35
+ const e = a === "start";
36
+ switch (t) {
37
37
  case "small":
38
38
  case "medium":
39
39
  return e ? "mr-[6px]" : "ml-[6px]";
40
40
  default:
41
41
  return e ? "mr-2" : "ml-2";
42
42
  }
43
- }, E = (s) => {
44
- switch (s) {
43
+ }, G = (t) => {
44
+ switch (t) {
45
45
  case "md":
46
46
  return "rounded-md";
47
47
  case "lg":
@@ -51,40 +51,40 @@ const A = (s) => {
51
51
  default:
52
52
  return "rounded-xl";
53
53
  }
54
- }, a = {
54
+ }, s = {
55
55
  neutral: "focus-visible:[outline:2px_solid_var(--malachite-text-primary)]",
56
56
  destructive: "focus-visible:[outline:2px_solid_var(--malachite-text-destructive)]",
57
57
  success: "focus-visible:[outline:2px_solid_var(--malachite-text-success)]",
58
58
  warning: "focus-visible:[outline:2px_solid_var(--malachite-text-warning)]",
59
59
  error: "focus-visible:[outline:2px_solid_var(--malachite-text-error)]",
60
60
  assistant: "focus-visible:[outline:2px_solid_var(--malachite-assistant-foreground)]"
61
- }, H = (s, 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 (s) {
61
+ }, q = (t, a) => {
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 ${a} cursor-pointer`;
63
+ switch (t) {
64
64
  case "filled":
65
- return `${e} ${a.neutral} btn-filled shadow-default`;
65
+ return `${e} ${s.neutral} btn-filled shadow-default`;
66
66
  case "outline":
67
- return `${e} ${a.neutral} btn-outline shadow-default`;
67
+ return `${e} ${s.neutral} btn-outline shadow-default`;
68
68
  case "surface":
69
- return `${e} ${a.neutral} btn-surface shadow-default`;
69
+ return `${e} ${s.neutral} btn-surface shadow-default`;
70
70
  case "assistant":
71
- return `${e} ${a.assistant} btn-assistant shadow-default`;
71
+ return `${e} ${s.assistant} btn-assistant shadow-default`;
72
72
  case "destructive":
73
- return `${e} ${a.destructive} btn-destructive`;
73
+ return `${e} ${s.destructive} btn-destructive`;
74
74
  case "success":
75
- return `${e} ${a.success} btn-glass-success`;
75
+ return `${e} ${s.success} btn-glass-success`;
76
76
  case "warning":
77
- return `${e} ${a.warning} btn-glass-warning`;
77
+ return `${e} ${s.warning} btn-glass-warning`;
78
78
  case "error":
79
- return `${e} ${a.error} btn-glass-error`;
79
+ return `${e} ${s.error} btn-glass-error`;
80
80
  case "ghost":
81
- return `${e} ${a.neutral} btn-ghost`;
81
+ return `${e} ${s.neutral} btn-ghost`;
82
82
  case "no-style":
83
- return `${e} ${a.neutral} btn-no-style border-none`;
83
+ return `${e} ${s.neutral} btn-no-style border-none`;
84
84
  default:
85
- return `${e} ${a.neutral} btn-filled shadow-default`;
85
+ return `${e} ${s.neutral} btn-filled shadow-default`;
86
86
  }
87
- }, M = () => /* @__PURE__ */ i(
87
+ }, J = () => /* @__PURE__ */ i(
88
88
  "svg",
89
89
  {
90
90
  className: "animate-spin -ml-1 mr-2 h-4 w-4",
@@ -113,83 +113,85 @@ const A = (s) => {
113
113
  )
114
114
  ]
115
115
  }
116
- ), q = O(
116
+ ), K = A(
117
117
  ({
118
- variant: s,
119
- size: t = "large",
118
+ variant: t,
119
+ size: a = "large",
120
120
  radius: e,
121
- loading: f = !1,
122
- disabled: j = !1,
123
- icon: o,
124
- iconPosition: g = "start",
121
+ loading: g = !1,
122
+ disabled: I = !1,
123
+ icon: c,
124
+ iconPosition: b = "start",
125
125
  leading: v,
126
- contentAlign: I = "center",
126
+ contentAlign: k = "center",
127
127
  flexGrow: m = !1,
128
- fill: z = !1,
128
+ fill: j = !1,
129
129
  tooltip: x,
130
130
  tooltipPlacement: B = "top",
131
- iconOnly: w = !1,
131
+ iconOnly: p = !1,
132
+ flush: L = !1,
132
133
  children: n,
133
- className: R = "",
134
- href: b,
134
+ className: z = "",
135
+ href: w,
135
136
  target: $,
136
137
  rel: F,
137
138
  ...C
138
139
  }, _) => {
139
- const L = e ? E(e) : D(t, w), l = j || f, N = I === "start", y = [
140
+ const U = e ? G(e) : W(a, p), l = I || g, N = k === "start", y = [
140
141
  N ? "flex items-center justify-start text-left" : "flex items-center justify-center",
141
- w ? `p-0 ${U(t)}` : A(t),
142
- H(s, L),
142
+ p ? `p-0 ${H(a)}` : O(a),
143
+ q(t, U),
143
144
  m ? "w-full" : "",
144
- z ? "max-w-full" : "",
145
+ j ? "max-w-full" : "",
145
146
  l ? "cursor-not-allowed" : "",
146
147
  x && l ? "pointer-events-none" : "",
147
- R
148
- ].filter(Boolean).join(" "), c = N ? /* @__PURE__ */ r("span", { className: "flex min-w-0 flex-1 items-center", children: n }) : n, u = v ? /* @__PURE__ */ r(
148
+ L && !p ? t === "no-style" ? V : T : "",
149
+ z
150
+ ].filter(Boolean).join(" "), o = N ? /* @__PURE__ */ r("span", { className: "flex min-w-0 flex-1 items-center", children: n }) : n, u = v ? /* @__PURE__ */ r(
149
151
  "span",
150
152
  {
151
153
  className: n ? "btn-leading inline-flex shrink-0 items-center me-2" : "btn-leading inline-flex shrink-0 items-center",
152
154
  children: v
153
155
  }
154
156
  ) : null, S = () => {
155
- if (f)
157
+ if (g)
156
158
  return /* @__PURE__ */ i(d, { children: [
157
159
  u,
158
- /* @__PURE__ */ r(M, {}),
159
- c
160
+ /* @__PURE__ */ r(J, {}),
161
+ o
160
162
  ] });
161
- const h = `inline-flex items-center shrink-0 ${V(t)}`;
162
- return o && g === "start" ? /* @__PURE__ */ i(d, { children: [
163
+ const f = `inline-flex items-center shrink-0 ${M(a)}`;
164
+ return c && b === "start" ? /* @__PURE__ */ i(d, { children: [
163
165
  u,
164
166
  /* @__PURE__ */ r(
165
167
  "span",
166
168
  {
167
- className: `${h}${n ? ` ${k(t, "start")}` : ""}`,
168
- children: o
169
+ className: `${f}${n ? ` ${R(a, "start")}` : ""}`,
170
+ children: c
169
171
  }
170
172
  ),
171
- c
172
- ] }) : o && g === "end" ? /* @__PURE__ */ i(d, { children: [
173
+ o
174
+ ] }) : c && b === "end" ? /* @__PURE__ */ i(d, { children: [
173
175
  u,
174
- c,
176
+ o,
175
177
  /* @__PURE__ */ r(
176
178
  "span",
177
179
  {
178
- className: `${h}${n ? ` ${k(t, "end")}` : ""}`,
179
- children: o
180
+ className: `${f}${n ? ` ${R(a, "end")}` : ""}`,
181
+ children: c
180
182
  }
181
183
  )
182
184
  ] }) : /* @__PURE__ */ i(d, { children: [
183
185
  u,
184
- c
186
+ o
185
187
  ] });
186
- }, p = b && !l ? /* @__PURE__ */ r(
188
+ }, h = w && !l ? /* @__PURE__ */ r(
187
189
  "a",
188
190
  {
189
191
  ref: _,
190
- href: b,
192
+ href: w,
191
193
  target: $,
192
- rel: W(F, $),
194
+ rel: D(F, $),
193
195
  className: y,
194
196
  ...C,
195
197
  children: S()
@@ -204,12 +206,12 @@ const A = (s) => {
204
206
  children: S()
205
207
  }
206
208
  );
207
- return x ? /* @__PURE__ */ r(T, { text: x, placement: B, fill: m, children: l ? /* @__PURE__ */ r("span", { className: `inline-flex cursor-not-allowed${m ? " w-full" : ""}`, children: p }) : p }) : p;
209
+ return x ? /* @__PURE__ */ r(E, { text: x, placement: B, fill: m, children: l ? /* @__PURE__ */ r("span", { className: `inline-flex cursor-not-allowed${m ? " w-full" : ""}`, children: h }) : h }) : h;
208
210
  }
209
211
  );
210
- q.displayName = "Button";
212
+ K.displayName = "Button";
211
213
  export {
212
- q as Button,
213
- q as default
214
+ K as Button,
215
+ K as default
214
216
  };
215
217
  //# sourceMappingURL=Button.js.map
@@ -1 +1 @@
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 /** Before the label at its own size, never squeezed (an avatar); pairs with an end `icon`. */\n leading?: React.ReactNode;\n /** `start` aligns the label to the leading edge and pins an end `icon` to the far edge. */\n contentAlign?: 'center' | 'start';\n /** Fills the container's width. */\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 leading,\n contentAlign = 'center',\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 alignStart = contentAlign === 'start';\n const baseClasses = [\n alignStart\n ? 'flex items-center justify-start text-left'\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 label = alignStart ? (\n <span className=\"flex min-w-0 flex-1 items-center\">{children}</span>\n ) : (\n children\n );\n\n const leadingSlot = leading ? (\n <span\n className={\n children\n ? 'btn-leading inline-flex shrink-0 items-center me-2'\n : 'btn-leading inline-flex shrink-0 items-center'\n }\n >\n {leading}\n </span>\n ) : null;\n\n const renderContent = () => {\n if (loading) {\n return (\n <>\n {leadingSlot}\n <LoadingSpinner />\n {label}\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 {leadingSlot}\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'start')}` : ''}`}\n >\n {icon}\n </span>\n {label}\n </>\n );\n }\n\n if (icon && iconPosition === 'end') {\n return (\n <>\n {leadingSlot}\n {label}\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'end')}` : ''}`}\n >\n {icon}\n </span>\n </>\n );\n }\n\n return (\n <>\n {leadingSlot}\n {label}\n </>\n );\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","leading","contentAlign","flexGrow","fill","tooltip","tooltipPlacement","children","className","href","target","rel","props","ref","isInactive","alignStart","getIconOnlySizeClasses","label","leadingSlot","renderContent","Fragment","iconWrapperClasses","getIconSizeClass","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 /** Before the label at its own size, never squeezed (an avatar); pairs with an end `icon`. */\n leading?: React.ReactNode;\n /** `start` aligns the label to the leading edge and pins an end `icon` to the far edge. */\n contentAlign?: 'center' | 'start';\n /** Fills the container's width. */\n flexGrow?: boolean;\n fill?: boolean;\n tooltip?: string;\n tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';\n iconOnly?: boolean;\n /** Pulls a borderless button out by its own padding, so its label lines up with the text around it. */\n flush?: 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 '[--btn-px:calc(var(--spacing)*2)] px-[var(--btn-px)] py-1 text-xs';\n case 'small':\n return 'min-h-[var(--malachite-control-height-small,28px)] [--btn-px:10px] px-[var(--btn-px)] 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)] [--btn-px:10px] px-[var(--btn-px)] 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)] [--btn-px:12px] px-[var(--btn-px)] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap';\n default:\n return 'min-h-[var(--malachite-control-height-large,42px)] [--btn-px:12px] px-[var(--btn-px)] text-[length:var(--malachite-font-size-15,15px)] leading-[18px] whitespace-nowrap';\n }\n};\n\n// The 1px is the transparent border, which `no-style` drops.\nconst FLUSH_MARGIN = '-mx-[calc(var(--btn-px)+1px)]';\nconst FLUSH_MARGIN_BORDERLESS = '-mx-[var(--btn-px)]';\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 leading,\n contentAlign = 'center',\n flexGrow = false,\n fill = false,\n tooltip,\n tooltipPlacement = 'top',\n iconOnly = false,\n flush = 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 alignStart = contentAlign === 'start';\n const baseClasses = [\n alignStart\n ? 'flex items-center justify-start text-left'\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 flush && !iconOnly\n ? variant === 'no-style'\n ? FLUSH_MARGIN_BORDERLESS\n : FLUSH_MARGIN\n : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const label = alignStart ? (\n <span className=\"flex min-w-0 flex-1 items-center\">{children}</span>\n ) : (\n children\n );\n\n const leadingSlot = leading ? (\n <span\n className={\n children\n ? 'btn-leading inline-flex shrink-0 items-center me-2'\n : 'btn-leading inline-flex shrink-0 items-center'\n }\n >\n {leading}\n </span>\n ) : null;\n\n const renderContent = () => {\n if (loading) {\n return (\n <>\n {leadingSlot}\n <LoadingSpinner />\n {label}\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 {leadingSlot}\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'start')}` : ''}`}\n >\n {icon}\n </span>\n {label}\n </>\n );\n }\n\n if (icon && iconPosition === 'end') {\n return (\n <>\n {leadingSlot}\n {label}\n <span\n className={`${iconWrapperClasses}${children ? ` ${getIconGapClass(size, 'end')}` : ''}`}\n >\n {icon}\n </span>\n </>\n );\n }\n\n return (\n <>\n {leadingSlot}\n {label}\n </>\n );\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","FLUSH_MARGIN","FLUSH_MARGIN_BORDERLESS","getDefaultRadiusClass","iconOnly","getIconGapClass","position","start","getRadiusClass","radius","FOCUS_OUTLINE","getVariantClasses","variant","radiusClass","baseClasses","LoadingSpinner","jsxs","jsx","Button","forwardRef","loading","disabled","icon","iconPosition","leading","contentAlign","flexGrow","fill","tooltip","tooltipPlacement","flush","children","className","href","target","rel","props","ref","isInactive","alignStart","getIconOnlySizeClasses","label","leadingSlot","renderContent","Fragment","iconWrapperClasses","getIconSizeClass","button","resolveRel","Tooltip"],"mappings":"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"}
@@ -1,19 +1,19 @@
1
- import { jsx as r, jsxs as l, Fragment as P } from "react/jsx-runtime";
2
- import { useId as V, useState as h, useRef as n, useEffect as Y, useCallback as B } from "react";
3
- import { createPortal as ae } from "react-dom";
4
- import { ShadowRootWrapper as le } from "../ShadowRootWrapper.js";
5
- import te from "./CalloutStrip.js";
6
- import ie from "./CustomIcons/DismissIcon.js";
7
- import { getDeepActiveElement as ne } from "./activeElement.js";
8
- import { GLASS_SURFACE_STYLE as oe } from "./glassSurface.js";
9
- import { MODAL_TRAY_BACKGROUND as se, MODAL_TRAY_CAPTION_COLOR as ce } from "./modalTray.js";
10
- import { useOverlayBehaviour as de, OVERLAY_ICON_BUTTON_CLASSES as me } from "./overlayBehaviour.js";
11
- import { OVERLAY_ELEVATED_ATTR as ue, overlayIdentity as F } from "./portalOverlay.js";
1
+ import { jsx as r, jsxs as l, Fragment as j } from "react/jsx-runtime";
2
+ import { useId as B, useState as h, useRef as n, useEffect as P, useCallback as V } from "react";
3
+ import { createPortal as le } from "react-dom";
4
+ import { ShadowRootWrapper as te } from "../ShadowRootWrapper.js";
5
+ import ie from "./CalloutStrip.js";
6
+ import ne from "./CustomIcons/DismissIcon.js";
7
+ import { getDeepActiveElement as oe } from "./activeElement.js";
8
+ import { GLASS_SURFACE_STYLE as se } from "./glassSurface.js";
9
+ import { MODAL_TRAY_BACKGROUND as ce, MODAL_TRAY_CAPTION_COLOR as de } from "./modalTray.js";
10
+ import { useOverlayBehaviour as me, OVERLAY_ICON_BUTTON_CLASSES as ue } from "./overlayBehaviour.js";
11
+ import { OVERLAY_ELEVATED_ATTR as pe, overlayIdentity as F } from "./portalOverlay.js";
12
12
  const U = {
13
13
  small: "420px",
14
14
  medium: "612px",
15
15
  large: "760px"
16
- }, v = 200, Te = ({
16
+ }, v = 200, xe = "flex-[0_1_auto] h-[min(600px,calc(100dvh-160px))]", Ie = ({
17
17
  open: c,
18
18
  onClose: d,
19
19
  title: u,
@@ -24,64 +24,65 @@ const U = {
24
24
  tray: e,
25
25
  headerDivider: w = !1,
26
26
  footer: R,
27
- size: A = "medium",
27
+ size: _ = "medium",
28
28
  showCloseButton: W = !0,
29
29
  closeOnOverlayClick: z = !0,
30
- bodyPadding: T = !0,
31
- callouts: f,
32
- renderLink: G,
33
- role: q = "dialog",
34
- "aria-label": H,
35
- "aria-labelledby": I,
36
- "aria-describedby": K,
30
+ bodyPadding: A = !0,
31
+ bodyHeight: G = "auto",
32
+ callouts: x,
33
+ renderLink: q,
34
+ role: H = "dialog",
35
+ "aria-label": K,
36
+ "aria-labelledby": T,
37
+ "aria-describedby": X,
37
38
  busy: o = !1,
38
- children: _
39
+ children: I
39
40
  }) => {
40
- const k = V(), S = V(), m = (f == null ? void 0 : f.filter((a) => a.message.trim())) ?? [], [x, $] = h(!1), [X, E] = h(!1), [Z, O] = h(!1), C = n(null), s = n(null), t = n(null), L = n(o), M = n(d);
41
- Y(() => {
42
- L.current = o, M.current = d;
41
+ const k = B(), S = B(), m = (x == null ? void 0 : x.filter((a) => a.message.trim())) ?? [], [f, $] = h(!1), [Z, O] = h(!1), [J, E] = h(!1), C = n(null), s = n(null), t = n(null), L = n(o), D = n(d);
42
+ P(() => {
43
+ L.current = o, D.current = d;
43
44
  }, [o, d]);
44
- const y = B(() => {
45
- L.current || M.current();
46
- }, []), D = n(null), {
47
- ref: j,
48
- isTopmost: J,
49
- zIndex: Q,
50
- elevated: ee
51
- } = de({
45
+ const M = V(() => {
46
+ L.current || D.current();
47
+ }, []), y = n(null), {
48
+ ref: Y,
49
+ isTopmost: Q,
50
+ zIndex: ee,
51
+ elevated: re
52
+ } = me({
52
53
  open: c,
53
54
  onClose: d,
54
- hostRef: D
55
- }), re = B(
55
+ hostRef: y
56
+ }), ae = V(
56
57
  (a) => {
57
- C.current = a, j(a);
58
+ C.current = a, Y(a);
58
59
  },
59
- [j]
60
+ [Y]
60
61
  );
61
- return Y(() => {
62
+ return P(() => {
62
63
  var a;
63
64
  if (c)
64
- E(!0), O(!1), t.current && (clearTimeout(t.current), t.current = null), s.current = requestAnimationFrame(() => {
65
+ O(!0), E(!1), t.current && (clearTimeout(t.current), t.current = null), s.current = requestAnimationFrame(() => {
65
66
  s.current = null, $(!0);
66
67
  });
67
68
  else {
68
- const i = ne();
69
- i && ((a = C.current) != null && a.contains(i)) && i.blur(), O(!0), $(!1), t.current = setTimeout(() => {
70
- t.current = null, E(!1);
69
+ const i = oe();
70
+ i && ((a = C.current) != null && a.contains(i)) && i.blur(), E(!0), $(!1), t.current = setTimeout(() => {
71
+ t.current = null, O(!1);
71
72
  }, v);
72
73
  }
73
74
  return () => {
74
75
  s.current !== null && (cancelAnimationFrame(s.current), s.current = null), t.current && (clearTimeout(t.current), t.current = null);
75
76
  };
76
- }, [c]), X ? ae(
77
+ }, [c]), Z ? le(
77
78
  // Host carries the stacking context — ShadowRootWrapper's `isolation` would otherwise
78
79
  // flatten our z-index. Not promoted to the top layer, so host dialogs can cover us.
79
80
  /* @__PURE__ */ r(
80
- le,
81
+ te,
81
82
  {
82
- hostRef: D,
83
- hostStyle: { position: "relative", zIndex: Q },
84
- hostProps: ee ? { ...F("modal"), [ue]: "" } : F("modal"),
83
+ hostRef: y,
84
+ hostStyle: { position: "relative", zIndex: ee },
85
+ hostProps: re ? { ...F("modal"), [pe]: "" } : F("modal"),
85
86
  children: /* @__PURE__ */ l(
86
87
  "div",
87
88
  {
@@ -91,36 +92,36 @@ const U = {
91
92
  "div",
92
93
  {
93
94
  "aria-hidden": "true",
94
- onClick: z ? y : void 0,
95
- className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${x ? "opacity-100" : "opacity-0"}`
95
+ onClick: z ? M : void 0,
96
+ className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${f ? "opacity-100" : "opacity-0"}`
96
97
  }
97
98
  ),
98
99
  /* @__PURE__ */ l(
99
100
  "div",
100
101
  {
101
- ref: re,
102
- role: q,
103
- "aria-hidden": Z ? "true" : void 0,
104
- "aria-modal": J ? "true" : void 0,
102
+ ref: ae,
103
+ role: H,
104
+ "aria-hidden": J ? "true" : void 0,
105
+ "aria-modal": Q ? "true" : void 0,
105
106
  "aria-describedby": [
106
107
  ...m.map((a, i) => `${S}-${i}`),
107
- K,
108
+ X,
108
109
  e != null && e.caption ? k : null
109
110
  ].filter(Boolean).join(" ") || void 0,
110
111
  "aria-busy": o || void 0,
111
112
  tabIndex: -1,
112
- "aria-label": I ? void 0 : H ?? (typeof u == "string" ? u : void 0),
113
- "aria-labelledby": I,
113
+ "aria-label": T ? void 0 : K ?? (typeof u == "string" ? u : void 0),
114
+ "aria-labelledby": T,
114
115
  className: e ? "relative flex max-h-full w-full flex-col gap-[4px] rounded-[20px] p-[4px] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-glow,var(--malachite-shadow-lg))]" : "relative flex max-h-full w-full flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-glow,var(--malachite-shadow-lg))]",
115
116
  style: {
116
- maxWidth: e ? `calc(${U[A]} + 8px)` : U[A],
117
+ maxWidth: e ? `calc(${U[_]} + 8px)` : U[_],
117
118
  ...e ? {
118
- backgroundColor: se[e.tone ?? "neutral"]
119
+ backgroundColor: ce[e.tone ?? "neutral"]
119
120
  } : {},
120
121
  // Inline: Tailwind scale/translate utilities silently break inside
121
122
  // shadow roots (see CLAUDE.md Shadow DOM caveats).
122
- transform: x ? "scale(1)" : "scale(0.96)",
123
- opacity: x ? 1 : 0,
123
+ transform: f ? "scale(1)" : "scale(0.96)",
124
+ opacity: f ? 1 : 0,
124
125
  transition: `transform ${v}ms ease-out, opacity ${v}ms ease-out`
125
126
  },
126
127
  children: [
@@ -142,7 +143,7 @@ const U = {
142
143
  p ? /* @__PURE__ */ r("span", { className: "text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]", children: p }) : null
143
144
  ] })
144
145
  ] }),
145
- N ? /* @__PURE__ */ l(P, { children: [
146
+ N ? /* @__PURE__ */ l(j, { children: [
146
147
  /* @__PURE__ */ r(
147
148
  "span",
148
149
  {
@@ -159,10 +160,10 @@ const U = {
159
160
  {
160
161
  type: "button",
161
162
  "aria-label": "Close",
162
- onClick: y,
163
+ onClick: M,
163
164
  disabled: o,
164
- className: me,
165
- children: /* @__PURE__ */ r(ie, { size: 10 })
165
+ className: ue,
166
+ children: /* @__PURE__ */ r(ne, { size: 10 })
166
167
  }
167
168
  ) : null
168
169
  ]
@@ -171,25 +172,25 @@ const U = {
171
172
  /* @__PURE__ */ l(
172
173
  "div",
173
174
  {
174
- className: `min-h-0 flex-1 overflow-y-auto ${T && m.length === 0 ? "px-[20px]" : ""}`,
175
+ className: `min-h-0 ${G === "tall" ? xe : "flex-1"} overflow-y-auto ${A && m.length === 0 ? "px-[20px]" : ""}`,
175
176
  children: [
176
177
  m.map((a, i) => /* @__PURE__ */ r(
177
- te,
178
+ ie,
178
179
  {
179
180
  id: `${S}-${i}`,
180
181
  type: a.type,
181
182
  message: a.message,
182
- renderLink: G
183
+ renderLink: q
183
184
  },
184
185
  i
185
186
  )),
186
- T ? /* @__PURE__ */ r(
187
+ A ? /* @__PURE__ */ r(
187
188
  "div",
188
189
  {
189
190
  className: m.length > 0 ? "px-[20px] pt-[18px] pb-[20px]" : `pb-[20px] ${w ? "pt-[18px]" : ""}`,
190
- children: _
191
+ children: I
191
192
  }
192
- ) : _
193
+ ) : I
193
194
  ]
194
195
  }
195
196
  ),
@@ -197,7 +198,7 @@ const U = {
197
198
  "div",
198
199
  {
199
200
  className: "flex min-h-[56px] shrink-0 items-center border-0 border-t border-solid border-[var(--malachite-card-border)] px-[12px]",
200
- style: oe,
201
+ style: se,
201
202
  children: R
202
203
  }
203
204
  ) : null
@@ -209,9 +210,9 @@ const U = {
209
210
  {
210
211
  id: k,
211
212
  className: "flex h-[48px] shrink-0 items-center justify-center px-[16px] text-[13px] tracking-[0.13px]",
212
- style: { color: ce[e.tone ?? "neutral"] },
213
+ style: { color: de[e.tone ?? "neutral"] },
213
214
  children: /* @__PURE__ */ l("span", { children: [
214
- e.caption.label ? /* @__PURE__ */ l(P, { children: [
215
+ e.caption.label ? /* @__PURE__ */ l(j, { children: [
215
216
  /* @__PURE__ */ r("span", { className: "font-medium", children: e.caption.label }),
216
217
  " "
217
218
  ] }) : null,
@@ -231,7 +232,7 @@ const U = {
231
232
  ) : null;
232
233
  };
233
234
  export {
234
- Te as Modal,
235
- Te as default
235
+ Ie as Modal,
236
+ Ie as default
236
237
  };
237
238
  //# sourceMappingURL=Modal.js.map