@stackone/malachite 2.57.0 → 2.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/COMPONENTS.md CHANGED
@@ -49,7 +49,7 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
49
49
  - **`Tooltip`** — Hover/focus tooltip; also works on disabled controls (see CLAUDE.md). It describes its trigger once shown, so `describesTrigger={false}` where the same sentence is already on screen and referenced — otherwise a screen reader reads it twice. _Key props:_ `text`, `placement`, `delay`, `maxWidth`, `shouldShow`, `triggerAs`, `describesTrigger`, `isShrinkable`, `fill`, `wrapChildren`, `suppressed` (holds the tooltip back, e.g. while the popup its trigger opens is up), `showOnFocus` (false where script can move focus onto the trigger, e.g. an option a panel focuses on open), `focusableTrigger` (makes a trigger that cannot take focus — text, a static `Tag` — a tab stop, so the tooltip is not mouse-only; not for focusable children).
50
50
  - **`TruncatedTooltip`** — Shows a tooltip only when its text is truncated.
51
51
  - **`Confetti`** — Celebratory confetti burst for success moments. _Key props:_ `pieces`.
52
- - **`ConfirmationDialog`** — Asks the customer to confirm one consequential action — a preset over `Modal`, not a second dialog implementation. `variant` picks a whole coherent set at once (badge fill, tray tint, caption colour, badge icon and confirm-button variant), so `destructive` cannot end up with a non-destructive confirm button; `destructive` also renders as `role="alertdialog"`, and `description` is wired to the dialog through `aria-describedby`, so the consequence is announced and not just the title. `confirmPhrase` gates the confirm action on typing that exact phrase, for a consequence severe enough that one click should not be able to cause it — the typed value is trimmed, since copying a name picks up a trailing space, but stays case-sensitive, and the field clears each time the dialog opens, being a per-decision gate rather than a value. Neither a destructive dialog nor one carrying a `confirmPhrase` dismisses on a scrim click, and `loading` suppresses the pointer routes — the scrim and the close button — as well as disabling the buttons. It never suppresses ESC: that is the only guaranteed keyboard exit from a focus trap, so it always reaches `onClose` and whether to abort is left to the caller. ESC reaches it whenever it is the topmost overlay, so it can be opened over a panel. `callout` renders an `Alert` in a full-width band at the top of the body — it scrolls with the body rather than being pinned under the header — and its `type` is chosen independently of `variant` — the frames pair a green badge with an amber callout. `titleAdornment` names the entity beside the title, `badgeIcon` overrides the variant’s glyph for an action-specific one, and `tip` is the `{ label?, message }` caption on the tray beneath the card, which `Modal` renders and describes. `children` is where extra body content goes. `onConfirm` does not close the dialog, so the caller can hold it open on `loading` while the request is in flight. `confirmPhraseLabel` also takes `{ prefix, suffix }`, which renders the phrase itself as a copyable token between the two — the gate is case-sensitive and space-exact, so a customer who has identified the right entity should not be locked out by a glyph they cannot tell apart. The copy control sits outside the element that names the field, so “Copy…” never lands in the field’s accessible name; `confirmPhraseCopyLabel` names it and `onPhraseCopied` reports a completed write with the phrase it copied. A rejected write says so in the field rather than failing silently, and the control is disabled where the Clipboard API is unavailable. A near miss is named rather than left to a disabled button: typing the phrase with the wrong case or the wrong spacing says which, once the whole phrase is there, and that message is the field’s `aria-describedby`. _Key props:_ `open`, `onClose`, `onConfirm`, `title`, `description`, `titleAdornment`, `badgeIcon`, `variant` (`default` | `warning` | `destructive` | `success`), `callout`, `confirmPhrase`, `confirmPhraseLabel`, `confirmPhraseCopyLabel`, `confirmPhrasePlaceholder`, `onPhraseCopied`, `confirmLabel`, `cancelLabel`, `loading`, `tip`, `size`, `aria-label`, `aria-labelledby`.
52
+ - **`ConfirmationDialog`** — Asks the customer to confirm one consequential action — a preset over `Modal`, not a second dialog implementation. `variant` picks a whole coherent set at once (badge fill, tray tint, caption colour, badge icon and confirm-button variant), so `destructive` cannot end up with a non-destructive confirm button; `destructive` also renders as `role="alertdialog"`, and `description` is wired to the dialog through `aria-describedby`, so the consequence is announced and not just the title. `confirmPhrase` gates the confirm action on typing that exact phrase, for a consequence severe enough that one click should not be able to cause it — the typed value is trimmed, since copying a name picks up a trailing space, but stays case-sensitive, and the field clears each time the dialog opens, being a per-decision gate rather than a value. Neither a destructive dialog nor one carrying a `confirmPhrase` dismisses on a scrim click, and `loading` suppresses the pointer routes — the scrim and the close button — as well as disabling the buttons. It never suppresses ESC: that is the only guaranteed keyboard exit from a focus trap, so it always reaches `onClose` and whether to abort is left to the caller. ESC reaches it whenever it is the topmost overlay, so it can be opened over a panel. `callout` renders an `Alert` in a full-width band at the top of the body — it scrolls with the body rather than being pinned under the header, and with no `description`, `children` or `confirmPhrase` there is no body, so the band sits directly on the footer — and its `type` is chosen independently of `variant` — the frames pair a green badge with an amber callout. `titleAdornment` names the entity beside the title, `badgeIcon` overrides the variant’s glyph for an action-specific one, and `tip` is the `{ label?, message }` caption on the tray beneath the card, which `Modal` renders and describes. `children` is where extra body content goes. `onConfirm` does not close the dialog, so the caller can hold it open on `loading` while the request is in flight. `confirmPhraseLabel` also takes `{ prefix, suffix }`, which renders the phrase itself as a copyable token between the two — the gate is case-sensitive and space-exact, so a customer who has identified the right entity should not be locked out by a glyph they cannot tell apart. The copy control sits outside the element that names the field, so “Copy…” never lands in the field’s accessible name; `confirmPhraseCopyLabel` names it and `onPhraseCopied` reports a completed write with the phrase it copied. A rejected write says so in the field rather than failing silently, and the control is disabled where the Clipboard API is unavailable. A near miss is named rather than left to a disabled button: typing the phrase with the wrong case or the wrong spacing says which, once the whole phrase is there, and that message is the field’s `aria-describedby`. _Key props:_ `open`, `onClose`, `onConfirm`, `title`, `description`, `titleAdornment`, `badgeIcon`, `variant` (`default` | `warning` | `destructive` | `success`), `callout`, `confirmPhrase`, `confirmPhraseLabel`, `confirmPhraseCopyLabel`, `confirmPhrasePlaceholder`, `onPhraseCopied`, `confirmLabel`, `cancelLabel`, `loading`, `tip`, `size`, `aria-label`, `aria-labelledby`.
53
53
 
54
54
  ## Lists, rows & navigation
55
55
 
@@ -1,7 +1,20 @@
1
1
  import { jsx as r } from "react/jsx-runtime";
2
- import { Alert as o } from "./Alert.js";
3
- const t = ({ type: a, message: e, renderLink: d }) => /* @__PURE__ */ r("div", { className: "border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]", children: /* @__PURE__ */ r(o, { type: a, message: e, hasMargin: !1, renderLink: d }) });
2
+ import { Alert as i } from "./Alert.js";
3
+ const p = ({
4
+ id: a,
5
+ type: e,
6
+ message: d,
7
+ renderLink: o,
8
+ divider: t = !0
9
+ }) => /* @__PURE__ */ r(
10
+ "div",
11
+ {
12
+ id: a,
13
+ className: t ? "border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]" : "p-[10px]",
14
+ children: /* @__PURE__ */ r(i, { type: e, message: d, hasMargin: !1, renderLink: o })
15
+ }
16
+ );
4
17
  export {
5
- t as default
18
+ p as default
6
19
  };
7
20
  //# sourceMappingURL=CalloutStrip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CalloutStrip.js","sources":["../../src/components/CalloutStrip.tsx"],"sourcesContent":["import type React from 'react';\nimport Alert, { type AlertType } from './Alert';\nimport type { RenderLink } from './PageLayout/types';\n\ninterface CalloutStripProps {\n type?: AlertType;\n message: string;\n renderLink?: RenderLink;\n}\n\n/** A full-bleed band holding one Alert at the top of an overlay's body. */\nconst CalloutStrip: React.FC<CalloutStripProps> = ({ type, message, renderLink }) => (\n <div className=\"border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]\">\n <Alert type={type} message={message} hasMargin={false} renderLink={renderLink} />\n </div>\n);\n\nexport default CalloutStrip;\n"],"names":["CalloutStrip","type","message","renderLink","jsx","Alert"],"mappings":";;AAWA,MAAMA,IAA4C,CAAC,EAAE,MAAAC,GAAM,SAAAC,GAAS,YAAAC,EAAA,MAChE,gBAAAC,EAAC,OAAA,EAAI,WAAU,sHACX,4BAACC,GAAA,EAAM,MAAAJ,GAAY,SAAAC,GAAkB,WAAW,IAAO,YAAAC,GAAwB,EAAA,CACnF;"}
1
+ {"version":3,"file":"CalloutStrip.js","sources":["../../src/components/CalloutStrip.tsx"],"sourcesContent":["import type React from 'react';\nimport Alert, { type AlertType } from './Alert';\nimport type { RenderLink } from './PageLayout/types';\n\ninterface CalloutStripProps {\n id?: string;\n type?: AlertType;\n message: string;\n renderLink?: RenderLink;\n /** Off when the strip sits directly on a footer that already draws its own top rule. */\n divider?: boolean;\n}\n\n/** A full-bleed band holding one Alert at the top of an overlay's body. */\nconst CalloutStrip: React.FC<CalloutStripProps> = ({\n id,\n type,\n message,\n renderLink,\n divider = true,\n}) => (\n <div\n id={id}\n className={\n divider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]'\n : 'p-[10px]'\n }\n >\n <Alert type={type} message={message} hasMargin={false} renderLink={renderLink} />\n </div>\n);\n\nexport default CalloutStrip;\n"],"names":["CalloutStrip","id","type","message","renderLink","divider","jsx","Alert"],"mappings":";;AAcA,MAAMA,IAA4C,CAAC;AAAA,EAC/C,IAAAC;AAAA,EACA,MAAAC;AAAA,EACA,SAAAC;AAAA,EACA,YAAAC;AAAA,EACA,SAAAC,IAAU;AACd,MACI,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,IAAAL;AAAA,IACA,WACII,IACM,uHACA;AAAA,IAGV,4BAACE,GAAA,EAAM,MAAAL,GAAY,SAAAC,GAAkB,WAAW,IAAO,YAAAC,EAAA,CAAwB;AAAA,EAAA;AACnF;"}
@@ -1,201 +1,211 @@
1
- import { jsxs as d, jsx as o } from "react/jsx-runtime";
2
- import { useState as S, useId as h } from "react";
3
- import { Button as T } from "./Button.js";
4
- import H from "./CalloutStrip.js";
5
- import Z from "./CustomIcons/CheckCircleFilled.js";
6
- import J from "./CustomIcons/CheckmarkIcon.js";
7
- import K from "./CustomIcons/CopyIcon.js";
8
- import Q from "./CustomIcons/ErrorCircleFilled.js";
9
- import U from "./CustomIcons/InfoCircleFilled.js";
10
- import X from "./CustomIcons/WarningCircleFilled.js";
11
- import { FieldMessage as P } from "./FieldMessage.js";
12
- import { IconBadge as ee } from "./IconBadge.js";
13
- import { Modal as ie } from "./Modal.js";
14
- import { Typography as j } from "./Typography/index.js";
15
- import { useClipboardCopy as oe } from "./useClipboardCopy.js";
16
- import { CONFIRMATION_DIALOG_VARIANTS as te } from "./confirmationDialogVariants.js";
17
- import le from "./Input/Input.js";
18
- const C = 12, v = (e) => e.replace(/\s+/g, " "), re = (e, i) => {
1
+ import { jsxs as d, jsx as i } from "react/jsx-runtime";
2
+ import { useState as E, useId as f, Children as U } from "react";
3
+ import { Button as A } from "./Button.js";
4
+ import X from "./CalloutStrip.js";
5
+ import P from "./CustomIcons/CheckCircleFilled.js";
6
+ import ee from "./CustomIcons/CheckmarkIcon.js";
7
+ import oe from "./CustomIcons/CopyIcon.js";
8
+ import ie from "./CustomIcons/ErrorCircleFilled.js";
9
+ import te from "./CustomIcons/InfoCircleFilled.js";
10
+ import le from "./CustomIcons/WarningCircleFilled.js";
11
+ import { FieldMessage as re } from "./FieldMessage.js";
12
+ import { IconBadge as se } from "./IconBadge.js";
13
+ import { Modal as ae } from "./Modal.js";
14
+ import { Typography as _ } from "./Typography/index.js";
15
+ import { useClipboardCopy as ne } from "./useClipboardCopy.js";
16
+ import { CONFIRMATION_DIALOG_VARIANTS as ce } from "./confirmationDialogVariants.js";
17
+ import de from "./Input/Input.js";
18
+ const v = 12, h = (e) => e.replace(/\s+/g, " "), pe = (e, o) => {
19
19
  const t = e.trim();
20
- if (!(!i || t === "" || t === i) && v(t).toLowerCase() === v(i).toLowerCase())
21
- return v(t) === v(i) ? "The spacing has to match exactly." : "This is case-sensitive.";
22
- }, se = "Could not copy. Enter the phrase manually.", ae = (e, i) => {
20
+ if (!(!o || t === "" || t === o) && h(t).toLowerCase() === h(o).toLowerCase())
21
+ return h(t) === h(o) ? "The spacing has to match exactly." : "This is case-sensitive.";
22
+ }, me = "Could not copy. Enter the phrase manually.", fe = (e, o) => {
23
23
  const t = typeof e == "object" && e !== null ? e : void 0;
24
- return t ? { parts: t, text: [t.prefix, i, t.suffix].filter(Boolean).join(" ") } : { text: typeof e == "string" ? e : `Type ${i} to confirm` };
25
- }, ne = (e, i) => e === "copied" ? `${i} copied to clipboard` : "", ce = (e, i, t, a) => {
26
- const { outcome: p, canCopy: m, copy: n } = oe(`${i}|${e}`), r = async () => {
27
- e && await n(e) && queueMicrotask(() => a == null ? void 0 : a(e));
24
+ return t ? { parts: t, text: [t.prefix, o, t.suffix].filter(Boolean).join(" ") } : { text: typeof e == "string" ? e : `Type ${o} to confirm` };
25
+ }, ue = (e, o) => e === "copied" ? `${o} copied to clipboard` : "", ye = (e, o, t, c) => {
26
+ const { outcome: p, canCopy: m, copy: a } = ne(`${o}|${e}`), r = async () => {
27
+ e && await a(e) && queueMicrotask(() => c == null ? void 0 : c(e));
28
28
  };
29
29
  return { outcome: p, canCopy: m && !t, copy: () => void r() };
30
- }, k = ({ children: e }) => /* @__PURE__ */ o(j.Text, { size: "xsmall", color: "primary", fontWeight: "semi-bold", children: e }), de = ({
30
+ }, O = ({ children: e }) => /* @__PURE__ */ i(_.Text, { size: "xsmall", color: "primary", fontWeight: "semi-bold", children: e }), xe = ({
31
31
  phrase: e,
32
- parts: i,
32
+ parts: o,
33
33
  plainLabel: t,
34
- placeholder: a,
34
+ placeholder: c,
35
35
  value: p,
36
36
  onChange: m,
37
- disabled: n,
37
+ disabled: a,
38
38
  copyLabel: r,
39
- copyOutcome: c,
39
+ copyOutcome: n,
40
40
  canCopy: l,
41
41
  onCopy: g,
42
- nearMissMessage: f
42
+ nearMissMessage: u
43
43
  }) => {
44
- const u = h(), y = h(), x = h(), b = [f, c === "failed" ? se : void 0].filter(Boolean).join(" ") || void 0, s = i ? [u, i.suffix ? y : void 0].filter(Boolean).join(" ") : void 0;
44
+ const y = f(), x = f(), C = f(), b = [u, n === "failed" ? me : void 0].filter(Boolean).join(" ") || void 0, s = o ? [y, o.suffix ? x : void 0].filter(Boolean).join(" ") : void 0;
45
45
  return /* @__PURE__ */ d("div", { className: "flex flex-col gap-[6px]", children: [
46
- i ? /* @__PURE__ */ d("div", { className: "flex flex-wrap items-center gap-[6px] px-2", children: [
47
- /* @__PURE__ */ d("span", { id: u, children: [
48
- /* @__PURE__ */ o(k, { children: i.prefix }),
46
+ o ? /* @__PURE__ */ d("div", { className: "flex flex-wrap items-center gap-[6px] px-2", children: [
47
+ /* @__PURE__ */ d("span", { id: y, children: [
48
+ /* @__PURE__ */ i(O, { children: o.prefix }),
49
49
  " ",
50
- /* @__PURE__ */ o(j.CodeText, { variant: "inline", size: "small", children: e })
50
+ /* @__PURE__ */ i(_.CodeText, { variant: "inline", size: "small", children: e })
51
51
  ] }),
52
- /* @__PURE__ */ o(
53
- T,
52
+ /* @__PURE__ */ i(
53
+ A,
54
54
  {
55
55
  variant: "ghost",
56
56
  size: "small",
57
57
  iconOnly: !0,
58
58
  "aria-label": `${r} ${e}`,
59
- icon: c === "copied" ? /* @__PURE__ */ o(J, { size: 13 }) : /* @__PURE__ */ o(K, { size: 13 }),
59
+ icon: n === "copied" ? /* @__PURE__ */ i(ee, { size: 13 }) : /* @__PURE__ */ i(oe, { size: 13 }),
60
60
  onClick: g,
61
61
  disabled: !l
62
62
  }
63
63
  ),
64
- i.suffix ? /* @__PURE__ */ o("span", { id: y, children: /* @__PURE__ */ o(k, { children: i.suffix }) }) : null
64
+ o.suffix ? /* @__PURE__ */ i("span", { id: x, children: /* @__PURE__ */ i(O, { children: o.suffix }) }) : null
65
65
  ] }) : null,
66
- /* @__PURE__ */ o(
67
- le,
66
+ /* @__PURE__ */ i(
67
+ de,
68
68
  {
69
69
  name: "confirmation-phrase",
70
70
  size: "large",
71
71
  value: p,
72
72
  onChange: m,
73
- label: i ? void 0 : t,
73
+ label: o ? void 0 : t,
74
74
  "aria-labelledby": s,
75
- placeholder: a,
75
+ placeholder: c,
76
76
  requiredIndicator: "none",
77
- error: !!f,
78
- "aria-describedby": b ? x : void 0,
79
- disabled: n
77
+ error: !!u,
78
+ "aria-describedby": b ? C : void 0,
79
+ disabled: a
80
80
  }
81
81
  ),
82
- /* @__PURE__ */ o(P, { id: x, message: b }),
83
- i ? /* @__PURE__ */ o("span", { role: "status", className: "sr-only", children: ne(c, e) }) : null
82
+ /* @__PURE__ */ i(re, { id: C, message: b }),
83
+ o ? /* @__PURE__ */ i("span", { role: "status", className: "sr-only", children: ue(n, e) }) : null
84
84
  ] });
85
- }, pe = {
86
- default: /* @__PURE__ */ o(U, { size: C }),
87
- warning: /* @__PURE__ */ o(X, { size: C }),
88
- destructive: /* @__PURE__ */ o(Q, { size: C }),
89
- success: /* @__PURE__ */ o(Z, { size: C })
90
- }, we = ({
85
+ }, Ce = {
86
+ default: /* @__PURE__ */ i(te, { size: v }),
87
+ warning: /* @__PURE__ */ i(le, { size: v }),
88
+ destructive: /* @__PURE__ */ i(ie, { size: v }),
89
+ success: /* @__PURE__ */ i(P, { size: v })
90
+ }, Oe = ({
91
91
  open: e,
92
- onClose: i,
92
+ onClose: o,
93
93
  onConfirm: t,
94
- title: a,
94
+ title: c,
95
95
  titleAdornment: p,
96
96
  badgeIcon: m,
97
- description: n,
97
+ description: a,
98
98
  variant: r = "default",
99
- callout: c,
99
+ callout: n,
100
100
  confirmPhrase: l,
101
101
  confirmPhraseLabel: g,
102
- confirmPhraseCopyLabel: f = "Copy",
103
- onPhraseCopied: u,
104
- confirmPhrasePlaceholder: y,
105
- confirmLabel: x = "Confirm",
102
+ confirmPhraseCopyLabel: u = "Copy",
103
+ onPhraseCopied: y,
104
+ confirmPhrasePlaceholder: x,
105
+ confirmLabel: C = "Confirm",
106
106
  cancelLabel: b = "Cancel",
107
107
  loading: s = !1,
108
- tip: B,
109
- size: E = "medium",
110
- "aria-label": O,
111
- "aria-labelledby": _,
112
- children: D
108
+ tip: D,
109
+ size: M = "medium",
110
+ "aria-label": $,
111
+ "aria-labelledby": G,
112
+ children: B
113
113
  }) => {
114
- const [I, A] = S(""), F = h(), z = te[r], [N, M] = S({ open: e, confirmPhrase: l });
115
- (N.open !== e || N.confirmPhrase !== l) && (M({ open: e, confirmPhrase: l }), e && A(""));
116
- const { parts: $, text: L } = ae(
114
+ const [I, T] = E(""), F = f(), N = f(), z = ce[r], [L, R] = E({ open: e, confirmPhrase: l });
115
+ (L.open !== e || L.confirmPhrase !== l) && (R({ open: e, confirmPhrase: l }), e && T(""));
116
+ const { parts: V, text: w } = fe(
117
117
  g,
118
118
  l
119
119
  ), {
120
- outcome: G,
121
- canCopy: R,
122
- copy: V
123
- } = ce(l, e, s, u), w = !l || I.trim() === l, q = re(I, l), W = s || !w, Y = /* @__PURE__ */ d("div", { className: "flex w-full flex-wrap items-center justify-end gap-[8px]", children: [
124
- /* @__PURE__ */ o(T, { variant: "outline", size: "small", onClick: i, disabled: s, children: b }),
125
- /* @__PURE__ */ o(
126
- T,
120
+ outcome: q,
121
+ canCopy: W,
122
+ copy: Y
123
+ } = ye(l, e, s, y), S = !l || I.trim() === l, H = pe(I, l), Z = s || !S, J = U.toArray(B).some(
124
+ (k) => typeof k != "string" || k.trim() !== ""
125
+ ), j = !!a || J || !!l, K = [n ? N : null, a ? F : null].filter(Boolean).join(" ") || void 0, Q = /* @__PURE__ */ d("div", { className: "flex w-full flex-wrap items-center justify-end gap-[8px]", children: [
126
+ /* @__PURE__ */ i(A, { variant: "outline", size: "small", onClick: o, disabled: s, children: b }),
127
+ /* @__PURE__ */ i(
128
+ A,
127
129
  {
128
130
  variant: z.confirmVariant,
129
131
  size: "small",
130
132
  onClick: t,
131
- disabled: W,
133
+ disabled: Z,
132
134
  loading: s,
133
- tooltip: !s && !w ? L : void 0,
134
- children: x
135
+ tooltip: !s && !S ? w : void 0,
136
+ children: C
135
137
  }
136
138
  )
137
139
  ] });
138
140
  return /* @__PURE__ */ d(
139
- ie,
141
+ ae,
140
142
  {
141
143
  open: e,
142
- onClose: i,
143
- title: a,
144
- size: E,
145
- footer: Y,
144
+ onClose: o,
145
+ title: c,
146
+ size: M,
147
+ footer: Q,
146
148
  busy: s,
147
149
  role: r === "destructive" ? "alertdialog" : "dialog",
148
- "aria-label": O,
149
- "aria-labelledby": _,
150
- "aria-describedby": n ? F : void 0,
150
+ "aria-label": $,
151
+ "aria-labelledby": G,
152
+ "aria-describedby": K,
151
153
  closeOnOverlayClick: r !== "destructive" && !l,
152
154
  headerDivider: !0,
153
155
  titleAdornment: p,
154
156
  bodyPadding: !1,
155
- tray: { tone: z.tray, caption: B },
156
- icon: /* @__PURE__ */ o(
157
- ee,
157
+ tray: { tone: z.tray, caption: D },
158
+ icon: /* @__PURE__ */ i(
159
+ se,
158
160
  {
159
161
  variant: r,
160
- icon: m ?? pe[r]
162
+ icon: m ?? Ce[r]
161
163
  }
162
164
  ),
163
165
  children: [
164
- c ? /* @__PURE__ */ o(H, { type: c.type ?? z.calloutType, message: c.message }) : null,
165
- /* @__PURE__ */ d("div", { className: "flex flex-col gap-[12px] p-[28px]", children: [
166
- n ? /* @__PURE__ */ o(
166
+ n ? /* @__PURE__ */ i(
167
+ X,
168
+ {
169
+ id: N,
170
+ type: n.type ?? z.calloutType,
171
+ message: n.message,
172
+ divider: j
173
+ }
174
+ ) : null,
175
+ j ? /* @__PURE__ */ d("div", { className: "flex flex-col gap-[12px] p-[28px]", children: [
176
+ a ? /* @__PURE__ */ i(
167
177
  "div",
168
178
  {
169
179
  id: F,
170
180
  className: "text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]",
171
- children: n
181
+ children: a
172
182
  }
173
183
  ) : null,
174
- D,
175
- l ? /* @__PURE__ */ o(
176
- de,
184
+ B,
185
+ l ? /* @__PURE__ */ i(
186
+ xe,
177
187
  {
178
188
  phrase: l,
179
- parts: $,
180
- plainLabel: L,
181
- placeholder: y,
189
+ parts: V,
190
+ plainLabel: w,
191
+ placeholder: x,
182
192
  value: I,
183
- onChange: A,
193
+ onChange: T,
184
194
  disabled: s,
185
- copyLabel: f,
186
- copyOutcome: G,
187
- canCopy: R,
188
- onCopy: V,
189
- nearMissMessage: q
195
+ copyLabel: u,
196
+ copyOutcome: q,
197
+ canCopy: W,
198
+ onCopy: Y,
199
+ nearMissMessage: H
190
200
  }
191
201
  ) : null
192
- ] })
202
+ ] }) : null
193
203
  ]
194
204
  }
195
205
  );
196
206
  };
197
207
  export {
198
- we as ConfirmationDialog,
199
- we as default
208
+ Oe as ConfirmationDialog,
209
+ Oe as default
200
210
  };
201
211
  //# sourceMappingURL=ConfirmationDialog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmationDialog.js","sources":["../../src/components/ConfirmationDialog.tsx"],"sourcesContent":["import type React from 'react';\nimport { useId, useState } from 'react';\nimport type { AlertType } from './Alert';\nimport Button from './Button';\nimport CalloutStrip from './CalloutStrip';\nimport CheckCircleFilled from './CustomIcons/CheckCircleFilled';\nimport CheckmarkIcon from './CustomIcons/CheckmarkIcon';\nimport CopyIcon from './CustomIcons/CopyIcon';\nimport ErrorCircleFilled from './CustomIcons/ErrorCircleFilled';\nimport InfoCircleFilled from './CustomIcons/InfoCircleFilled';\nimport WarningCircleFilled from './CustomIcons/WarningCircleFilled';\nimport FieldMessage from './FieldMessage';\nimport IconBadge from './IconBadge';\nimport { Input } from './Input';\nimport Modal, { type ModalSize } from './Modal';\nimport Typography from './Typography';\nimport { type CopyOutcome, useClipboardCopy } from './useClipboardCopy';\nimport {\n CONFIRMATION_DIALOG_VARIANTS,\n type ConfirmationDialogVariant,\n} from './confirmationDialogVariants';\n\n/** Kept beside the component: an icon is a node, not a value the variant table can hold. */\nconst BADGE_GLYPH_SIZE = 12;\n\nconst collapseSpaces = (value: string) => value.replace(/\\s+/g, ' ');\n\nconst nearMissAgainst = (typedPhrase: string, confirmPhrase?: string): string | undefined => {\n const typed = typedPhrase.trim();\n if (!confirmPhrase || typed === '' || typed === confirmPhrase) {\n return undefined;\n }\n if (collapseSpaces(typed).toLowerCase() !== collapseSpaces(confirmPhrase).toLowerCase()) {\n return undefined;\n }\n return collapseSpaces(typed) === collapseSpaces(confirmPhrase)\n ? 'The spacing has to match exactly.'\n : 'This is case-sensitive.';\n};\n\ntype PhraseLabel = string | { prefix: string; suffix?: string };\n\nconst COPY_FAILED_MESSAGE = 'Could not copy. Enter the phrase manually.';\n\nconst resolvePhraseLabel = (\n label: PhraseLabel | undefined,\n phrase?: string,\n): { parts?: { prefix: string; suffix?: string }; text: string } => {\n const parts = typeof label === 'object' && label !== null ? label : undefined;\n if (parts) {\n return { parts, text: [parts.prefix, phrase, parts.suffix].filter(Boolean).join(' ') };\n }\n return { text: typeof label === 'string' ? label : `Type ${phrase} to confirm` };\n};\n\nconst copyStatusFor = (outcome: CopyOutcome, phrase: string): string =>\n outcome === 'copied' ? `${phrase} copied to clipboard` : '';\n\nconst usePhraseCopy = (\n phrase: string | undefined,\n open: boolean,\n disabled: boolean,\n onCopied?: (phrase: string) => void,\n): { outcome: CopyOutcome; canCopy: boolean; copy: () => void } => {\n const { outcome, canCopy, copy } = useClipboardCopy(`${open}|${phrase}`);\n\n const run = async () => {\n if (phrase && (await copy(phrase))) {\n queueMicrotask(() => onCopied?.(phrase));\n }\n };\n\n return { outcome, canCopy: canCopy && !disabled, copy: () => void run() };\n};\n\nconst LabelText: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n <Typography.Text size=\"xsmall\" color=\"primary\" fontWeight=\"semi-bold\">\n {children}\n </Typography.Text>\n);\n\ninterface PhraseFieldProps {\n phrase: string;\n parts?: { prefix: string; suffix?: string };\n plainLabel: string;\n placeholder?: string;\n value: string;\n onChange: (value: string) => void;\n disabled: boolean;\n copyLabel: string;\n copyOutcome: CopyOutcome;\n canCopy: boolean;\n onCopy: () => void;\n nearMissMessage?: string;\n}\n\nconst PhraseField: React.FC<PhraseFieldProps> = ({\n phrase,\n parts,\n plainLabel,\n placeholder,\n value,\n onChange,\n disabled,\n copyLabel,\n copyOutcome,\n canCopy,\n onCopy,\n nearMissMessage,\n}) => {\n const beforeId = useId();\n const afterId = useId();\n const messageId = useId();\n const message =\n [nearMissMessage, copyOutcome === 'failed' ? COPY_FAILED_MESSAGE : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n const labelledBy = parts\n ? [beforeId, parts.suffix ? afterId : undefined].filter(Boolean).join(' ')\n : undefined;\n\n return (\n <div className=\"flex flex-col gap-[6px]\">\n {parts ? (\n <div className=\"flex flex-wrap items-center gap-[6px] px-2\">\n <span id={beforeId}>\n <LabelText>{parts.prefix}</LabelText>{' '}\n <Typography.CodeText variant=\"inline\" size=\"small\">\n {phrase}\n </Typography.CodeText>\n </span>\n <Button\n variant=\"ghost\"\n size=\"small\"\n iconOnly\n aria-label={`${copyLabel} ${phrase}`}\n icon={\n copyOutcome === 'copied' ? (\n <CheckmarkIcon size={13} />\n ) : (\n <CopyIcon size={13} />\n )\n }\n onClick={onCopy}\n disabled={!canCopy}\n />\n {parts.suffix ? (\n <span id={afterId}>\n <LabelText>{parts.suffix}</LabelText>\n </span>\n ) : null}\n </div>\n ) : null}\n <Input\n name=\"confirmation-phrase\"\n size=\"large\"\n value={value}\n onChange={onChange}\n label={parts ? undefined : plainLabel}\n aria-labelledby={labelledBy}\n placeholder={placeholder}\n requiredIndicator=\"none\"\n error={!!nearMissMessage}\n aria-describedby={message ? messageId : undefined}\n disabled={disabled}\n />\n <FieldMessage id={messageId} message={message} />\n {parts ? (\n <span role=\"status\" className=\"sr-only\">\n {copyStatusFor(copyOutcome, phrase)}\n </span>\n ) : null}\n </div>\n );\n};\n\nconst VARIANT_ICON: Record<ConfirmationDialogVariant, React.ReactNode> = {\n default: <InfoCircleFilled size={BADGE_GLYPH_SIZE} />,\n warning: <WarningCircleFilled size={BADGE_GLYPH_SIZE} />,\n destructive: <ErrorCircleFilled size={BADGE_GLYPH_SIZE} />,\n success: <CheckCircleFilled size={BADGE_GLYPH_SIZE} />,\n};\n\nexport interface ConfirmationDialogProps {\n open: boolean;\n /** Dismiss handler — cancel, close button, ESC or scrim. `loading` suppresses every\n * route except ESC, which always reaches this so a keyboard user is never stranded. */\n onClose: () => void;\n /** Runs when the confirm action is taken. Closing is left to the consumer. */\n onConfirm: () => void;\n title: React.ReactNode;\n titleAdornment?: React.ReactNode;\n badgeIcon?: React.ReactNode;\n /** The sentence saying what is about to happen. */\n description?: React.ReactNode;\n variant?: ConfirmationDialogVariant;\n /** Coloured callout below the body. Defaults to the variant's own type. */\n callout?: { type?: AlertType; message: string };\n /**\n * Requires this exact phrase to be typed before the confirm action enables — for a\n * consequence severe enough that a single click should not be able to cause it.\n */\n confirmPhrase?: string;\n /** Label above the type-to-confirm field. `{ prefix, suffix }` makes the phrase copyable. */\n confirmPhraseLabel?: PhraseLabel;\n /** Names the copy control, e.g. `Copy profile name`. Default: `Copy`. */\n confirmPhraseCopyLabel?: string;\n /** Runs after the phrase reaches the clipboard, with what was copied. */\n onPhraseCopied?: (phrase: string) => void;\n confirmPhrasePlaceholder?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n /**\n * Disables the actions, spins the confirm button and suppresses the pointer dismissal\n * routes — but never ESC, which always reaches `onClose`.\n */\n loading?: boolean;\n tip?: { label?: string; message: string };\n size?: ModalSize;\n /** Accessible dialog name; required when `title` isn't a plain string. */\n 'aria-label'?: string;\n /** ID of a visible element naming the dialog (alternative to `aria-label`). */\n 'aria-labelledby'?: string;\n /** Extra body content between the description and the callout, e.g. an entity chip. */\n children?: React.ReactNode;\n}\n\nconst ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({\n open,\n onClose,\n onConfirm,\n title,\n titleAdornment,\n badgeIcon,\n description,\n variant = 'default',\n callout,\n confirmPhrase,\n confirmPhraseLabel,\n confirmPhraseCopyLabel = 'Copy',\n onPhraseCopied,\n confirmPhrasePlaceholder,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n loading = false,\n tip,\n size = 'medium',\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n children,\n}) => {\n const [typedPhrase, setTypedPhrase] = useState('');\n const descriptionId = useId();\n const base = CONFIRMATION_DIALOG_VARIANTS[variant];\n\n // On open, not close: the dialog outlives `open` by its exit transition, so resetting on\n // close empties the field in front of the user. Adjusted during render rather than from an\n // effect, or a reopen paints the previous answer once with confirm already enabled.\n const [answeredFor, setAnsweredFor] = useState({ open, confirmPhrase });\n if (answeredFor.open !== open || answeredFor.confirmPhrase !== confirmPhrase) {\n setAnsweredFor({ open, confirmPhrase });\n if (open) {\n setTypedPhrase('');\n }\n }\n\n const { parts: phraseParts, text: phraseLabel } = resolvePhraseLabel(\n confirmPhraseLabel,\n confirmPhrase,\n );\n const {\n outcome: copyOutcome,\n canCopy: canCopyPhrase,\n copy: handleCopyPhrase,\n } = usePhraseCopy(confirmPhrase, open, loading, onPhraseCopied);\n // Trimmed because copying an entity name commonly picks up a trailing space; the gate is\n // still exact, and deliberately case-sensitive.\n const phraseSatisfied = !confirmPhrase || typedPhrase.trim() === confirmPhrase;\n const nearMissMessage = nearMissAgainst(typedPhrase, confirmPhrase);\n const confirmDisabled = loading || !phraseSatisfied;\n\n const footer = (\n <div className=\"flex w-full flex-wrap items-center justify-end gap-[8px]\">\n <Button variant=\"outline\" size=\"small\" onClick={onClose} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button\n variant={base.confirmVariant}\n size=\"small\"\n onClick={onConfirm}\n disabled={confirmDisabled}\n loading={loading}\n // A disabled control emits no hover, so the tooltip explains the gate from the\n // wrapper Button renders for exactly this case.\n tooltip={!loading && !phraseSatisfied ? phraseLabel : undefined}\n >\n {confirmLabel}\n </Button>\n </div>\n );\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={title}\n size={size}\n footer={footer}\n busy={loading}\n // A consequential choice is an alertdialog: it asks assistive tech to announce the\n // body, which is where the consequence is written.\n role={variant === 'destructive' ? 'alertdialog' : 'dialog'}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={description ? descriptionId : undefined}\n // A choice this deliberate should not be undone by a stray click, and a scrim\n // click must not discard a phrase the customer has already typed.\n closeOnOverlayClick={variant !== 'destructive' && !confirmPhrase}\n headerDivider\n titleAdornment={titleAdornment}\n bodyPadding={false}\n tray={{ tone: base.tray, caption: tip }}\n icon={\n <IconBadge\n variant={variant}\n icon={badgeIcon ?? VARIANT_ICON[variant]}\n />\n }\n >\n {callout ? (\n <CalloutStrip type={callout.type ?? base.calloutType} message={callout.message} />\n ) : null}\n <div className=\"flex flex-col gap-[12px] p-[28px]\">\n {description ? (\n <div\n id={descriptionId}\n className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\"\n >\n {description}\n </div>\n ) : null}\n {children}\n {confirmPhrase ? (\n <PhraseField\n phrase={confirmPhrase}\n parts={phraseParts}\n plainLabel={phraseLabel}\n placeholder={confirmPhrasePlaceholder}\n value={typedPhrase}\n onChange={setTypedPhrase}\n disabled={loading}\n copyLabel={confirmPhraseCopyLabel}\n copyOutcome={copyOutcome}\n canCopy={canCopyPhrase}\n onCopy={handleCopyPhrase}\n nearMissMessage={nearMissMessage}\n />\n ) : null}\n </div>\n </Modal>\n );\n};\n\nexport default ConfirmationDialog;\nexport { ConfirmationDialog };\nexport type { ConfirmationDialogVariant };\n"],"names":["BADGE_GLYPH_SIZE","collapseSpaces","value","nearMissAgainst","typedPhrase","confirmPhrase","typed","COPY_FAILED_MESSAGE","resolvePhraseLabel","label","phrase","parts","copyStatusFor","outcome","usePhraseCopy","open","disabled","onCopied","canCopy","copy","useClipboardCopy","run","LabelText","children","jsx","Typography","PhraseField","plainLabel","placeholder","onChange","copyLabel","copyOutcome","onCopy","nearMissMessage","beforeId","useId","afterId","messageId","message","labelledBy","jsxs","Button","CheckmarkIcon","CopyIcon","Input","FieldMessage","VARIANT_ICON","InfoCircleFilled","WarningCircleFilled","ErrorCircleFilled","CheckCircleFilled","ConfirmationDialog","onClose","onConfirm","title","titleAdornment","badgeIcon","description","variant","callout","confirmPhraseLabel","confirmPhraseCopyLabel","onPhraseCopied","confirmPhrasePlaceholder","confirmLabel","cancelLabel","loading","tip","size","ariaLabel","ariaLabelledBy","setTypedPhrase","useState","descriptionId","base","CONFIRMATION_DIALOG_VARIANTS","answeredFor","setAnsweredFor","phraseParts","phraseLabel","canCopyPhrase","handleCopyPhrase","phraseSatisfied","confirmDisabled","footer","Modal","IconBadge","CalloutStrip"],"mappings":"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"}
1
+ {"version":3,"file":"ConfirmationDialog.js","sources":["../../src/components/ConfirmationDialog.tsx"],"sourcesContent":["import type React from 'react';\nimport { Children, useId, useState } from 'react';\nimport type { AlertType } from './Alert';\nimport Button from './Button';\nimport CalloutStrip from './CalloutStrip';\nimport CheckCircleFilled from './CustomIcons/CheckCircleFilled';\nimport CheckmarkIcon from './CustomIcons/CheckmarkIcon';\nimport CopyIcon from './CustomIcons/CopyIcon';\nimport ErrorCircleFilled from './CustomIcons/ErrorCircleFilled';\nimport InfoCircleFilled from './CustomIcons/InfoCircleFilled';\nimport WarningCircleFilled from './CustomIcons/WarningCircleFilled';\nimport FieldMessage from './FieldMessage';\nimport IconBadge from './IconBadge';\nimport { Input } from './Input';\nimport Modal, { type ModalSize } from './Modal';\nimport Typography from './Typography';\nimport { type CopyOutcome, useClipboardCopy } from './useClipboardCopy';\nimport {\n CONFIRMATION_DIALOG_VARIANTS,\n type ConfirmationDialogVariant,\n} from './confirmationDialogVariants';\n\n/** Kept beside the component: an icon is a node, not a value the variant table can hold. */\nconst BADGE_GLYPH_SIZE = 12;\n\nconst collapseSpaces = (value: string) => value.replace(/\\s+/g, ' ');\n\nconst nearMissAgainst = (typedPhrase: string, confirmPhrase?: string): string | undefined => {\n const typed = typedPhrase.trim();\n if (!confirmPhrase || typed === '' || typed === confirmPhrase) {\n return undefined;\n }\n if (collapseSpaces(typed).toLowerCase() !== collapseSpaces(confirmPhrase).toLowerCase()) {\n return undefined;\n }\n return collapseSpaces(typed) === collapseSpaces(confirmPhrase)\n ? 'The spacing has to match exactly.'\n : 'This is case-sensitive.';\n};\n\ntype PhraseLabel = string | { prefix: string; suffix?: string };\n\nconst COPY_FAILED_MESSAGE = 'Could not copy. Enter the phrase manually.';\n\nconst resolvePhraseLabel = (\n label: PhraseLabel | undefined,\n phrase?: string,\n): { parts?: { prefix: string; suffix?: string }; text: string } => {\n const parts = typeof label === 'object' && label !== null ? label : undefined;\n if (parts) {\n return { parts, text: [parts.prefix, phrase, parts.suffix].filter(Boolean).join(' ') };\n }\n return { text: typeof label === 'string' ? label : `Type ${phrase} to confirm` };\n};\n\nconst copyStatusFor = (outcome: CopyOutcome, phrase: string): string =>\n outcome === 'copied' ? `${phrase} copied to clipboard` : '';\n\nconst usePhraseCopy = (\n phrase: string | undefined,\n open: boolean,\n disabled: boolean,\n onCopied?: (phrase: string) => void,\n): { outcome: CopyOutcome; canCopy: boolean; copy: () => void } => {\n const { outcome, canCopy, copy } = useClipboardCopy(`${open}|${phrase}`);\n\n const run = async () => {\n if (phrase && (await copy(phrase))) {\n queueMicrotask(() => onCopied?.(phrase));\n }\n };\n\n return { outcome, canCopy: canCopy && !disabled, copy: () => void run() };\n};\n\nconst LabelText: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n <Typography.Text size=\"xsmall\" color=\"primary\" fontWeight=\"semi-bold\">\n {children}\n </Typography.Text>\n);\n\ninterface PhraseFieldProps {\n phrase: string;\n parts?: { prefix: string; suffix?: string };\n plainLabel: string;\n placeholder?: string;\n value: string;\n onChange: (value: string) => void;\n disabled: boolean;\n copyLabel: string;\n copyOutcome: CopyOutcome;\n canCopy: boolean;\n onCopy: () => void;\n nearMissMessage?: string;\n}\n\nconst PhraseField: React.FC<PhraseFieldProps> = ({\n phrase,\n parts,\n plainLabel,\n placeholder,\n value,\n onChange,\n disabled,\n copyLabel,\n copyOutcome,\n canCopy,\n onCopy,\n nearMissMessage,\n}) => {\n const beforeId = useId();\n const afterId = useId();\n const messageId = useId();\n const message =\n [nearMissMessage, copyOutcome === 'failed' ? COPY_FAILED_MESSAGE : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n const labelledBy = parts\n ? [beforeId, parts.suffix ? afterId : undefined].filter(Boolean).join(' ')\n : undefined;\n\n return (\n <div className=\"flex flex-col gap-[6px]\">\n {parts ? (\n <div className=\"flex flex-wrap items-center gap-[6px] px-2\">\n <span id={beforeId}>\n <LabelText>{parts.prefix}</LabelText>{' '}\n <Typography.CodeText variant=\"inline\" size=\"small\">\n {phrase}\n </Typography.CodeText>\n </span>\n <Button\n variant=\"ghost\"\n size=\"small\"\n iconOnly\n aria-label={`${copyLabel} ${phrase}`}\n icon={\n copyOutcome === 'copied' ? (\n <CheckmarkIcon size={13} />\n ) : (\n <CopyIcon size={13} />\n )\n }\n onClick={onCopy}\n disabled={!canCopy}\n />\n {parts.suffix ? (\n <span id={afterId}>\n <LabelText>{parts.suffix}</LabelText>\n </span>\n ) : null}\n </div>\n ) : null}\n <Input\n name=\"confirmation-phrase\"\n size=\"large\"\n value={value}\n onChange={onChange}\n label={parts ? undefined : plainLabel}\n aria-labelledby={labelledBy}\n placeholder={placeholder}\n requiredIndicator=\"none\"\n error={!!nearMissMessage}\n aria-describedby={message ? messageId : undefined}\n disabled={disabled}\n />\n <FieldMessage id={messageId} message={message} />\n {parts ? (\n <span role=\"status\" className=\"sr-only\">\n {copyStatusFor(copyOutcome, phrase)}\n </span>\n ) : null}\n </div>\n );\n};\n\nconst VARIANT_ICON: Record<ConfirmationDialogVariant, React.ReactNode> = {\n default: <InfoCircleFilled size={BADGE_GLYPH_SIZE} />,\n warning: <WarningCircleFilled size={BADGE_GLYPH_SIZE} />,\n destructive: <ErrorCircleFilled size={BADGE_GLYPH_SIZE} />,\n success: <CheckCircleFilled size={BADGE_GLYPH_SIZE} />,\n};\n\nexport interface ConfirmationDialogProps {\n open: boolean;\n /** Dismiss handler — cancel, close button, ESC or scrim. `loading` suppresses every\n * route except ESC, which always reaches this so a keyboard user is never stranded. */\n onClose: () => void;\n /** Runs when the confirm action is taken. Closing is left to the consumer. */\n onConfirm: () => void;\n title: React.ReactNode;\n titleAdornment?: React.ReactNode;\n badgeIcon?: React.ReactNode;\n /** The sentence saying what is about to happen. */\n description?: React.ReactNode;\n variant?: ConfirmationDialogVariant;\n /** Coloured callout below the body. Defaults to the variant's own type. */\n callout?: { type?: AlertType; message: string };\n /**\n * Requires this exact phrase to be typed before the confirm action enables — for a\n * consequence severe enough that a single click should not be able to cause it.\n */\n confirmPhrase?: string;\n /** Label above the type-to-confirm field. `{ prefix, suffix }` makes the phrase copyable. */\n confirmPhraseLabel?: PhraseLabel;\n /** Names the copy control, e.g. `Copy profile name`. Default: `Copy`. */\n confirmPhraseCopyLabel?: string;\n /** Runs after the phrase reaches the clipboard, with what was copied. */\n onPhraseCopied?: (phrase: string) => void;\n confirmPhrasePlaceholder?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n /**\n * Disables the actions, spins the confirm button and suppresses the pointer dismissal\n * routes — but never ESC, which always reaches `onClose`.\n */\n loading?: boolean;\n tip?: { label?: string; message: string };\n size?: ModalSize;\n /** Accessible dialog name; required when `title` isn't a plain string. */\n 'aria-label'?: string;\n /** ID of a visible element naming the dialog (alternative to `aria-label`). */\n 'aria-labelledby'?: string;\n /** Extra body content between the description and the callout, e.g. an entity chip. */\n children?: React.ReactNode;\n}\n\nconst ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({\n open,\n onClose,\n onConfirm,\n title,\n titleAdornment,\n badgeIcon,\n description,\n variant = 'default',\n callout,\n confirmPhrase,\n confirmPhraseLabel,\n confirmPhraseCopyLabel = 'Copy',\n onPhraseCopied,\n confirmPhrasePlaceholder,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n loading = false,\n tip,\n size = 'medium',\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n children,\n}) => {\n const [typedPhrase, setTypedPhrase] = useState('');\n const descriptionId = useId();\n const calloutId = useId();\n const base = CONFIRMATION_DIALOG_VARIANTS[variant];\n\n // On open, not close: the dialog outlives `open` by its exit transition, so resetting on\n // close empties the field in front of the user. Adjusted during render rather than from an\n // effect, or a reopen paints the previous answer once with confirm already enabled.\n const [answeredFor, setAnsweredFor] = useState({ open, confirmPhrase });\n if (answeredFor.open !== open || answeredFor.confirmPhrase !== confirmPhrase) {\n setAnsweredFor({ open, confirmPhrase });\n if (open) {\n setTypedPhrase('');\n }\n }\n\n const { parts: phraseParts, text: phraseLabel } = resolvePhraseLabel(\n confirmPhraseLabel,\n confirmPhrase,\n );\n const {\n outcome: copyOutcome,\n canCopy: canCopyPhrase,\n copy: handleCopyPhrase,\n } = usePhraseCopy(confirmPhrase, open, loading, onPhraseCopied);\n // Trimmed because copying an entity name commonly picks up a trailing space; the gate is\n // still exact, and deliberately case-sensitive.\n const phraseSatisfied = !confirmPhrase || typedPhrase.trim() === confirmPhrase;\n const nearMissMessage = nearMissAgainst(typedPhrase, confirmPhrase);\n const confirmDisabled = loading || !phraseSatisfied;\n const hasChildren = Children.toArray(children).some(\n (child) => typeof child !== 'string' || child.trim() !== '',\n );\n const hasBody = Boolean(description) || hasChildren || Boolean(confirmPhrase);\n // The callout is often the whole consequence, so it is announced along with the description.\n const describedBy =\n [callout ? calloutId : null, description ? descriptionId : null]\n .filter(Boolean)\n .join(' ') || undefined;\n\n const footer = (\n <div className=\"flex w-full flex-wrap items-center justify-end gap-[8px]\">\n <Button variant=\"outline\" size=\"small\" onClick={onClose} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button\n variant={base.confirmVariant}\n size=\"small\"\n onClick={onConfirm}\n disabled={confirmDisabled}\n loading={loading}\n // A disabled control emits no hover, so the tooltip explains the gate from the\n // wrapper Button renders for exactly this case.\n tooltip={!loading && !phraseSatisfied ? phraseLabel : undefined}\n >\n {confirmLabel}\n </Button>\n </div>\n );\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={title}\n size={size}\n footer={footer}\n busy={loading}\n // A consequential choice is an alertdialog: it asks assistive tech to announce the\n // body, which is where the consequence is written.\n role={variant === 'destructive' ? 'alertdialog' : 'dialog'}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={describedBy}\n // A choice this deliberate should not be undone by a stray click, and a scrim\n // click must not discard a phrase the customer has already typed.\n closeOnOverlayClick={variant !== 'destructive' && !confirmPhrase}\n headerDivider\n titleAdornment={titleAdornment}\n bodyPadding={false}\n tray={{ tone: base.tray, caption: tip }}\n icon={\n <IconBadge\n variant={variant}\n icon={badgeIcon ?? VARIANT_ICON[variant]}\n />\n }\n >\n {callout ? (\n <CalloutStrip\n id={calloutId}\n type={callout.type ?? base.calloutType}\n message={callout.message}\n divider={hasBody}\n />\n ) : null}\n {hasBody ? (\n <div className=\"flex flex-col gap-[12px] p-[28px]\">\n {description ? (\n <div\n id={descriptionId}\n className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\"\n >\n {description}\n </div>\n ) : null}\n {children}\n {confirmPhrase ? (\n <PhraseField\n phrase={confirmPhrase}\n parts={phraseParts}\n plainLabel={phraseLabel}\n placeholder={confirmPhrasePlaceholder}\n value={typedPhrase}\n onChange={setTypedPhrase}\n disabled={loading}\n copyLabel={confirmPhraseCopyLabel}\n copyOutcome={copyOutcome}\n canCopy={canCopyPhrase}\n onCopy={handleCopyPhrase}\n nearMissMessage={nearMissMessage}\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n};\n\nexport default ConfirmationDialog;\nexport { ConfirmationDialog };\nexport type { ConfirmationDialogVariant };\n"],"names":["BADGE_GLYPH_SIZE","collapseSpaces","value","nearMissAgainst","typedPhrase","confirmPhrase","typed","COPY_FAILED_MESSAGE","resolvePhraseLabel","label","phrase","parts","copyStatusFor","outcome","usePhraseCopy","open","disabled","onCopied","canCopy","copy","useClipboardCopy","run","LabelText","children","jsx","Typography","PhraseField","plainLabel","placeholder","onChange","copyLabel","copyOutcome","onCopy","nearMissMessage","beforeId","useId","afterId","messageId","message","labelledBy","jsxs","Button","CheckmarkIcon","CopyIcon","Input","FieldMessage","VARIANT_ICON","InfoCircleFilled","WarningCircleFilled","ErrorCircleFilled","CheckCircleFilled","ConfirmationDialog","onClose","onConfirm","title","titleAdornment","badgeIcon","description","variant","callout","confirmPhraseLabel","confirmPhraseCopyLabel","onPhraseCopied","confirmPhrasePlaceholder","confirmLabel","cancelLabel","loading","tip","size","ariaLabel","ariaLabelledBy","setTypedPhrase","useState","descriptionId","calloutId","base","CONFIRMATION_DIALOG_VARIANTS","answeredFor","setAnsweredFor","phraseParts","phraseLabel","canCopyPhrase","handleCopyPhrase","phraseSatisfied","confirmDisabled","hasChildren","Children","child","hasBody","describedBy","footer","Modal","IconBadge","CalloutStrip"],"mappings":"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"}
@@ -1,11 +1,19 @@
1
1
  const n = () => {
2
- var t;
2
+ var o;
3
3
  let e = document.activeElement;
4
- for (; (t = e == null ? void 0 : e.shadowRoot) != null && t.activeElement; )
4
+ for (; (o = e == null ? void 0 : e.shadowRoot) != null && o.activeElement; )
5
5
  e = e.shadowRoot.activeElement;
6
6
  return e instanceof HTMLElement ? e : null;
7
+ }, r = (e, o) => {
8
+ for (let t = o; t; ) {
9
+ if (t === e)
10
+ return !0;
11
+ t = t instanceof ShadowRoot ? t.host : t.parentNode;
12
+ }
13
+ return !1;
7
14
  };
8
15
  export {
16
+ r as containsComposed,
9
17
  n as getDeepActiveElement
10
18
  };
11
19
  //# sourceMappingURL=activeElement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"activeElement.js","sources":["../../src/components/activeElement.ts"],"sourcesContent":["/** `document.activeElement` stops at a shadow host; descend to the real focused node. */\nexport const getDeepActiveElement = (): HTMLElement | null => {\n let active: Element | null = document.activeElement;\n while (active?.shadowRoot?.activeElement) {\n active = active.shadowRoot.activeElement;\n }\n return active instanceof HTMLElement ? active : null;\n};\n"],"names":["getDeepActiveElement","_a","active"],"mappings":"AACO,MAAMA,IAAuB,MAA0B;AAAvD,MAAAC;AACH,MAAIC,IAAyB,SAAS;AACtC,UAAOD,IAAAC,KAAA,gBAAAA,EAAQ,eAAR,QAAAD,EAAoB;AACvB,IAAAC,IAASA,EAAO,WAAW;AAE/B,SAAOA,aAAkB,cAAcA,IAAS;AACpD;"}
1
+ {"version":3,"file":"activeElement.js","sources":["../../src/components/activeElement.ts"],"sourcesContent":["/** `document.activeElement` stops at a shadow host; descend to the real focused node. */\nexport const getDeepActiveElement = (): HTMLElement | null => {\n let active: Element | null = document.activeElement;\n while (active?.shadowRoot?.activeElement) {\n active = active.shadowRoot.activeElement;\n }\n return active instanceof HTMLElement ? active : null;\n};\n\n/** `Node.contains` that also follows shadow roots up to their hosts. */\nexport const containsComposed = (container: Node, node: Node | null): boolean => {\n for (let current: Node | null = node; current; ) {\n if (current === container) {\n return true;\n }\n current = current instanceof ShadowRoot ? current.host : current.parentNode;\n }\n return false;\n};\n"],"names":["getDeepActiveElement","_a","active","containsComposed","container","node","current"],"mappings":"AACO,MAAMA,IAAuB,MAA0B;AAAvD,MAAAC;AACH,MAAIC,IAAyB,SAAS;AACtC,UAAOD,IAAAC,KAAA,gBAAAA,EAAQ,eAAR,QAAAD,EAAoB;AACvB,IAAAC,IAASA,EAAO,WAAW;AAE/B,SAAOA,aAAkB,cAAcA,IAAS;AACpD,GAGaC,IAAmB,CAACC,GAAiBC,MAA+B;AAC7E,WAASC,IAAuBD,GAAMC,KAAW;AAC7C,QAAIA,MAAYF;AACZ,aAAO;AAEX,IAAAE,IAAUA,aAAmB,aAAaA,EAAQ,OAAOA,EAAQ;AAAA,EACrE;AACA,SAAO;AACX;"}