@stackone/malachite 2.56.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 +5 -4
- package/dist/components/Alert.js +67 -50
- package/dist/components/Alert.js.map +1 -1
- package/dist/components/Breadcrumbs.js.map +1 -1
- package/dist/components/CalloutStrip.js +20 -0
- package/dist/components/CalloutStrip.js.map +1 -0
- package/dist/components/ConfirmationDialog.js +146 -144
- package/dist/components/ConfirmationDialog.js.map +1 -1
- package/dist/components/IconBadge.js +16 -0
- package/dist/components/IconBadge.js.map +1 -0
- package/dist/components/PageLayout/index.js.map +1 -1
- package/dist/components/PageLayout/regularLayout.js.map +1 -1
- package/dist/components/SidePanel.js +99 -82
- package/dist/components/SidePanel.js.map +1 -1
- package/dist/components/Typography/MarkdownBlock.js +89 -87
- package/dist/components/Typography/MarkdownBlock.js.map +1 -1
- package/dist/components/activeElement.js +10 -2
- package/dist/components/activeElement.js.map +1 -1
- package/dist/components/confirmationDialogVariants.js +2 -6
- package/dist/components/confirmationDialogVariants.js.map +1 -1
- package/dist/components/iconBadgeVariants.js +11 -0
- package/dist/components/iconBadgeVariants.js.map +1 -0
- package/dist/components/overlayBehaviour.js +176 -146
- package/dist/components/overlayBehaviour.js.map +1 -1
- package/dist/components/overlayLayers.js +22 -28
- package/dist/components/overlayLayers.js.map +1 -1
- package/dist/index.d.ts +31 -5
- package/dist/index.js +447 -445
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
|
@@ -1,209 +1,211 @@
|
|
|
1
|
-
import { jsxs as d, jsx as
|
|
2
|
-
import { useState as
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import { FieldMessage as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
const t = e.trim();
|
|
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
|
+
const t = typeof e == "object" && e !== null ? e : void 0;
|
|
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));
|
|
27
28
|
};
|
|
28
|
-
return { outcome: p, canCopy: m && !
|
|
29
|
-
},
|
|
29
|
+
return { outcome: p, canCopy: m && !t, copy: () => void r() };
|
|
30
|
+
}, O = ({ children: e }) => /* @__PURE__ */ i(_.Text, { size: "xsmall", color: "primary", fontWeight: "semi-bold", children: e }), xe = ({
|
|
30
31
|
phrase: e,
|
|
31
|
-
parts:
|
|
32
|
-
plainLabel:
|
|
33
|
-
placeholder:
|
|
32
|
+
parts: o,
|
|
33
|
+
plainLabel: t,
|
|
34
|
+
placeholder: c,
|
|
34
35
|
value: p,
|
|
35
36
|
onChange: m,
|
|
36
|
-
disabled:
|
|
37
|
-
copyLabel:
|
|
38
|
-
copyOutcome:
|
|
39
|
-
canCopy:
|
|
40
|
-
onCopy:
|
|
41
|
-
nearMissMessage:
|
|
37
|
+
disabled: a,
|
|
38
|
+
copyLabel: r,
|
|
39
|
+
copyOutcome: n,
|
|
40
|
+
canCopy: l,
|
|
41
|
+
onCopy: g,
|
|
42
|
+
nearMissMessage: u
|
|
42
43
|
}) => {
|
|
43
|
-
const
|
|
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;
|
|
44
45
|
return /* @__PURE__ */ d("div", { className: "flex flex-col gap-[6px]", children: [
|
|
45
|
-
|
|
46
|
-
/* @__PURE__ */ d("span", { id:
|
|
47
|
-
/* @__PURE__ */
|
|
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 }),
|
|
48
49
|
" ",
|
|
49
|
-
/* @__PURE__ */
|
|
50
|
+
/* @__PURE__ */ i(_.CodeText, { variant: "inline", size: "small", children: e })
|
|
50
51
|
] }),
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
-
|
|
52
|
+
/* @__PURE__ */ i(
|
|
53
|
+
A,
|
|
53
54
|
{
|
|
54
55
|
variant: "ghost",
|
|
55
56
|
size: "small",
|
|
56
57
|
iconOnly: !0,
|
|
57
|
-
"aria-label": `${
|
|
58
|
-
icon:
|
|
59
|
-
onClick:
|
|
60
|
-
disabled: !
|
|
58
|
+
"aria-label": `${r} ${e}`,
|
|
59
|
+
icon: n === "copied" ? /* @__PURE__ */ i(ee, { size: 13 }) : /* @__PURE__ */ i(oe, { size: 13 }),
|
|
60
|
+
onClick: g,
|
|
61
|
+
disabled: !l
|
|
61
62
|
}
|
|
62
63
|
),
|
|
63
|
-
|
|
64
|
+
o.suffix ? /* @__PURE__ */ i("span", { id: x, children: /* @__PURE__ */ i(O, { children: o.suffix }) }) : null
|
|
64
65
|
] }) : null,
|
|
65
|
-
/* @__PURE__ */
|
|
66
|
-
|
|
66
|
+
/* @__PURE__ */ i(
|
|
67
|
+
de,
|
|
67
68
|
{
|
|
68
69
|
name: "confirmation-phrase",
|
|
69
70
|
size: "large",
|
|
70
71
|
value: p,
|
|
71
72
|
onChange: m,
|
|
72
|
-
label:
|
|
73
|
-
"aria-labelledby":
|
|
74
|
-
placeholder:
|
|
73
|
+
label: o ? void 0 : t,
|
|
74
|
+
"aria-labelledby": s,
|
|
75
|
+
placeholder: c,
|
|
75
76
|
requiredIndicator: "none",
|
|
76
|
-
error: !!
|
|
77
|
-
"aria-describedby":
|
|
78
|
-
disabled:
|
|
77
|
+
error: !!u,
|
|
78
|
+
"aria-describedby": b ? C : void 0,
|
|
79
|
+
disabled: a
|
|
79
80
|
}
|
|
80
81
|
),
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
|
|
82
|
+
/* @__PURE__ */ i(re, { id: C, message: b }),
|
|
83
|
+
o ? /* @__PURE__ */ i("span", { role: "status", className: "sr-only", children: ue(n, e) }) : null
|
|
83
84
|
] });
|
|
84
|
-
},
|
|
85
|
-
default: /* @__PURE__ */
|
|
86
|
-
warning: /* @__PURE__ */
|
|
87
|
-
destructive: /* @__PURE__ */
|
|
88
|
-
success: /* @__PURE__ */
|
|
89
|
-
},
|
|
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 = ({
|
|
90
91
|
open: e,
|
|
91
|
-
onClose:
|
|
92
|
-
onConfirm:
|
|
93
|
-
title:
|
|
92
|
+
onClose: o,
|
|
93
|
+
onConfirm: t,
|
|
94
|
+
title: c,
|
|
94
95
|
titleAdornment: p,
|
|
95
96
|
badgeIcon: m,
|
|
96
|
-
description:
|
|
97
|
-
variant:
|
|
98
|
-
callout:
|
|
99
|
-
confirmPhrase:
|
|
100
|
-
confirmPhraseLabel:
|
|
101
|
-
confirmPhraseCopyLabel:
|
|
102
|
-
onPhraseCopied:
|
|
103
|
-
confirmPhrasePlaceholder:
|
|
104
|
-
confirmLabel:
|
|
105
|
-
cancelLabel:
|
|
106
|
-
loading:
|
|
107
|
-
tip:
|
|
97
|
+
description: a,
|
|
98
|
+
variant: r = "default",
|
|
99
|
+
callout: n,
|
|
100
|
+
confirmPhrase: l,
|
|
101
|
+
confirmPhraseLabel: g,
|
|
102
|
+
confirmPhraseCopyLabel: u = "Copy",
|
|
103
|
+
onPhraseCopied: y,
|
|
104
|
+
confirmPhrasePlaceholder: x,
|
|
105
|
+
confirmLabel: C = "Confirm",
|
|
106
|
+
cancelLabel: b = "Cancel",
|
|
107
|
+
loading: s = !1,
|
|
108
|
+
tip: D,
|
|
108
109
|
size: M = "medium",
|
|
109
|
-
"aria-label":
|
|
110
|
-
"aria-labelledby":
|
|
110
|
+
"aria-label": $,
|
|
111
|
+
"aria-labelledby": G,
|
|
111
112
|
children: B
|
|
112
113
|
}) => {
|
|
113
|
-
const [
|
|
114
|
-
(
|
|
115
|
-
const { parts:
|
|
116
|
-
|
|
117
|
-
|
|
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
|
+
g,
|
|
118
|
+
l
|
|
118
119
|
), {
|
|
119
|
-
outcome:
|
|
120
|
-
canCopy:
|
|
121
|
-
copy:
|
|
122
|
-
} =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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,
|
|
126
129
|
{
|
|
127
|
-
variant:
|
|
130
|
+
variant: z.confirmVariant,
|
|
128
131
|
size: "small",
|
|
129
|
-
onClick:
|
|
130
|
-
disabled:
|
|
131
|
-
loading:
|
|
132
|
-
tooltip: !
|
|
133
|
-
children:
|
|
132
|
+
onClick: t,
|
|
133
|
+
disabled: Z,
|
|
134
|
+
loading: s,
|
|
135
|
+
tooltip: !s && !S ? w : void 0,
|
|
136
|
+
children: C
|
|
134
137
|
}
|
|
135
138
|
)
|
|
136
139
|
] });
|
|
137
140
|
return /* @__PURE__ */ d(
|
|
138
|
-
|
|
141
|
+
ae,
|
|
139
142
|
{
|
|
140
143
|
open: e,
|
|
141
|
-
onClose:
|
|
142
|
-
title:
|
|
144
|
+
onClose: o,
|
|
145
|
+
title: c,
|
|
143
146
|
size: M,
|
|
144
|
-
footer:
|
|
145
|
-
busy:
|
|
146
|
-
role:
|
|
147
|
-
"aria-label":
|
|
148
|
-
"aria-labelledby":
|
|
149
|
-
"aria-describedby":
|
|
150
|
-
closeOnOverlayClick:
|
|
147
|
+
footer: Q,
|
|
148
|
+
busy: s,
|
|
149
|
+
role: r === "destructive" ? "alertdialog" : "dialog",
|
|
150
|
+
"aria-label": $,
|
|
151
|
+
"aria-labelledby": G,
|
|
152
|
+
"aria-describedby": K,
|
|
153
|
+
closeOnOverlayClick: r !== "destructive" && !l,
|
|
151
154
|
headerDivider: !0,
|
|
152
155
|
titleAdornment: p,
|
|
153
156
|
bodyPadding: !1,
|
|
154
|
-
tray: { tone:
|
|
155
|
-
icon: /* @__PURE__ */
|
|
156
|
-
|
|
157
|
+
tray: { tone: z.tray, caption: D },
|
|
158
|
+
icon: /* @__PURE__ */ i(
|
|
159
|
+
se,
|
|
157
160
|
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
style: { backgroundColor: h.badge },
|
|
161
|
-
children: m ?? de[l]
|
|
161
|
+
variant: r,
|
|
162
|
+
icon: m ?? Ce[r]
|
|
162
163
|
}
|
|
163
164
|
),
|
|
164
165
|
children: [
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
n ? /* @__PURE__ */ i(
|
|
167
|
+
X,
|
|
167
168
|
{
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
id: N,
|
|
170
|
+
type: n.type ?? z.calloutType,
|
|
171
|
+
message: n.message,
|
|
172
|
+
divider: j
|
|
171
173
|
}
|
|
172
|
-
)
|
|
173
|
-
/* @__PURE__ */ d("div", { className: "flex flex-col gap-[12px] p-[28px]", children: [
|
|
174
|
-
|
|
174
|
+
) : null,
|
|
175
|
+
j ? /* @__PURE__ */ d("div", { className: "flex flex-col gap-[12px] p-[28px]", children: [
|
|
176
|
+
a ? /* @__PURE__ */ i(
|
|
175
177
|
"div",
|
|
176
178
|
{
|
|
177
|
-
id:
|
|
179
|
+
id: F,
|
|
178
180
|
className: "text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]",
|
|
179
|
-
children:
|
|
181
|
+
children: a
|
|
180
182
|
}
|
|
181
183
|
) : null,
|
|
182
184
|
B,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
l ? /* @__PURE__ */ i(
|
|
186
|
+
xe,
|
|
185
187
|
{
|
|
186
|
-
phrase:
|
|
187
|
-
parts:
|
|
188
|
-
plainLabel:
|
|
189
|
-
placeholder:
|
|
190
|
-
value:
|
|
191
|
-
onChange:
|
|
192
|
-
disabled:
|
|
193
|
-
copyLabel:
|
|
194
|
-
copyOutcome:
|
|
195
|
-
canCopy:
|
|
196
|
-
onCopy:
|
|
197
|
-
nearMissMessage:
|
|
188
|
+
phrase: l,
|
|
189
|
+
parts: V,
|
|
190
|
+
plainLabel: w,
|
|
191
|
+
placeholder: x,
|
|
192
|
+
value: I,
|
|
193
|
+
onChange: T,
|
|
194
|
+
disabled: s,
|
|
195
|
+
copyLabel: u,
|
|
196
|
+
copyOutcome: q,
|
|
197
|
+
canCopy: W,
|
|
198
|
+
onCopy: Y,
|
|
199
|
+
nearMissMessage: H
|
|
198
200
|
}
|
|
199
201
|
) : null
|
|
200
|
-
] })
|
|
202
|
+
] }) : null
|
|
201
203
|
]
|
|
202
204
|
}
|
|
203
205
|
);
|
|
204
206
|
};
|
|
205
207
|
export {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
Oe as ConfirmationDialog,
|
|
209
|
+
Oe as default
|
|
208
210
|
};
|
|
209
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 Alert, { type AlertType } from './Alert';\nimport Button from './Button';\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 { 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 <span\n aria-hidden=\"true\"\n className=\"confirmation-badge flex size-[18px] shrink-0 items-center justify-center rounded-[7px] text-[var(--malachite-card-background)]\"\n style={{ backgroundColor: base.badge }}\n >\n {badgeIcon ?? VARIANT_ICON[variant]}\n </span>\n }\n >\n {callout ? (\n <div className=\"border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]\">\n <Alert\n type={callout.type ?? base.calloutType}\n message={callout.message}\n hasMargin={false}\n />\n </div>\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","Alert"],"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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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { ICON_BADGE_FILL as t } from "./iconBadgeVariants.js";
|
|
3
|
+
const n = "icon-badge flex size-[18px] shrink-0 items-center justify-center rounded-[7px] text-[var(--malachite-card-background)]", d = ({ icon: e, variant: r = "default", className: a }) => /* @__PURE__ */ o(
|
|
4
|
+
"span",
|
|
5
|
+
{
|
|
6
|
+
"aria-hidden": "true",
|
|
7
|
+
className: [n, a].filter(Boolean).join(" "),
|
|
8
|
+
style: { backgroundColor: t[r] },
|
|
9
|
+
children: e
|
|
10
|
+
}
|
|
11
|
+
);
|
|
12
|
+
export {
|
|
13
|
+
d as IconBadge,
|
|
14
|
+
d as default
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=IconBadge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconBadge.js","sources":["../../src/components/IconBadge.tsx"],"sourcesContent":["import type React from 'react';\nimport { ICON_BADGE_FILL, type IconBadgeVariant } from './iconBadgeVariants';\n\nexport interface IconBadgeProps {\n /** Drawn at 12px in the card background colour; an svg painting with `currentColor`. */\n icon: React.ReactNode;\n /** `accent` is the brand's interaction colour, so a rebrand repaints it. */\n variant?: IconBadgeVariant;\n className?: string;\n}\n\n/** A small filled tile carrying a glyph, for a dialog or panel header. Decorative: the title\n * beside it says what the glyph shows, so it is always hidden from assistive tech. */\n// A string literal of its own: Tailwind's scanner misses a class glued to a `${…}` interpolation.\nconst BADGE_CLASSES =\n 'icon-badge flex size-[18px] shrink-0 items-center justify-center rounded-[7px] text-[var(--malachite-card-background)]';\n\nconst IconBadge: React.FC<IconBadgeProps> = ({ icon, variant = 'default', className }) => (\n <span\n aria-hidden=\"true\"\n className={[BADGE_CLASSES, className].filter(Boolean).join(' ')}\n style={{ backgroundColor: ICON_BADGE_FILL[variant] }}\n >\n {icon}\n </span>\n);\n\nexport default IconBadge;\nexport { IconBadge };\nexport type { IconBadgeVariant };\n"],"names":["BADGE_CLASSES","IconBadge","icon","variant","className","jsx","ICON_BADGE_FILL"],"mappings":";;AAcA,MAAMA,IACF,0HAEEC,IAAsC,CAAC,EAAE,MAAAC,GAAM,SAAAC,IAAU,WAAW,WAAAC,QACtE,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,eAAY;AAAA,IACZ,WAAW,CAACL,GAAeI,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,IAC9D,OAAO,EAAE,iBAAiBE,EAAgBH,CAAO,EAAA;AAAA,IAEhD,UAAAD;AAAA,EAAA;AACL;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/components/PageLayout/index.tsx"],"sourcesContent":["import Empty from './emptyLayout';\nimport Regular from './regularLayout';\n\nexport const PageLayout = { Regular, Empty };\n\nexport default PageLayout;\nexport type { BreadcrumbLink, PageAction,
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/components/PageLayout/index.tsx"],"sourcesContent":["import Empty from './emptyLayout';\nimport Regular from './regularLayout';\n\nexport const PageLayout = { Regular, Empty };\n\nexport default PageLayout;\nexport type { BreadcrumbLink, PageAction, RenderLink } from './types';\nexport { PageActions } from './regularLayout';\nexport type { PageContentGap, RegularLayoutProps } from './regularLayout';\nexport type { EmptyLayoutProps } from './emptyLayout';\n"],"names":["PageLayout","Regular","Empty"],"mappings":";;;AAGO,MAAMA,IAAa,EAAA,SAAEC,UAASC,EAAA;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regularLayout.js","sources":["../../../src/components/PageLayout/regularLayout.tsx"],"sourcesContent":["import React from 'react';\nimport ActionMenu, { type ActionMenuItem } from '../ActionMenu';\nimport Alert, { type AlertType } from '../Alert';\nimport Breadcrumbs from '../Breadcrumbs';\nimport { hasBackButton } from '../breadcrumbsNav';\nimport Button from '../Button';\nimport OverflowRow from '../OverflowRow';\nimport Skeleton from '../Skeleton';\nimport PageTitle from '../Typography/PageTitle';\nimport Text from '../Typography/Text';\nimport { safeHref } from '../safeHref';\nimport {\n CARD_CLASSES,\n CARD_MIN_HEIGHT,\n CARD_RADIUS,\n CONTENT_INSET_VAR,\n CONTENT_MIN_HEIGHT,\n DIVIDER_CLASSES,\n HEADER_HEIGHT,\n} from './constants';\nimport type { BreadcrumbLink, PageAction, RenderBreadcrumbLink } from './types';\n\nexport type PageContentGap = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport interface RegularLayoutProps {\n breadcrumbLinks?: BreadcrumbLink[];\n breadcrumbActions?: PageAction[];\n renderLink?: RenderBreadcrumbLink;\n title?: React.ReactNode;\n titleSuffix?: React.ReactNode;\n subtitle?: string;\n description?: React.ReactNode;\n buttons?: PageAction[];\n /**\n * Hides the buttons and skeletons the title. `subtitle` and `description` are only\n * skeletoned when those props are also passed.\n */\n loading?: boolean;\n children: React.ReactNode;\n centered?: boolean;\n noPadding?: boolean;\n contentGap?: PageContentGap;\n alert?: { message: string; type?: AlertType };\n /** Demotes the default `main` landmark — pass e.g. `region` when the app owns its own. */\n role?: React.AriaRole;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst CONTENT_GAPS: Record<PageContentGap, number> = {\n small: 8,\n medium: 16,\n large: 24,\n xlarge: 40,\n};\n\nconst isDanger = (button: PageAction): boolean =>\n button.variant === 'destructive' || button.variant === 'error';\n\nconst toMenuItems = (buttons: PageAction[]): ActionMenuItem[] =>\n buttons.flatMap((button, index) => {\n const href = safeHref(button.href);\n const item: ActionMenuItem = {\n key: `${index}-${button.label}`,\n label: button.label,\n ...(href ? { href, target: button.target ?? '_blank' } : { onClick: button.onClick }),\n disabled: button.disabled,\n icon: button.icon,\n tooltip: button.tooltip,\n danger: isDanger(button),\n };\n return button.dividerBefore && index > 0\n ? [{ type: 'divider' as const, key: `divider-${index}-${button.label}` }, item]\n : [item];\n });\n\n// Not `ActionBar`: it measures by walking ancestors for `clientWidth`, and this chrome\n// mounts on every page. OverflowRow batches its measurement instead.\n// A divider must live in the same OverflowRow child as its button — a standalone child\n// would survive its hidden button and break the child-index-to-button mapping.\n/**\n * The page's action buttons, collapsing into an overflow menu as the row narrows. Exported so\n * a page that renders its own header block — e.g. one that scrolls the title away — keeps the\n * same behaviour instead of hand-rolling `buttons.map(...)` and losing the collapse, the\n * dividers and the href handling.\n */\nexport const PageActions: React.FC<{ buttons: PageAction[] }> = ({ buttons }) => {\n if (buttons.length === 0) {\n return null;\n }\n\n // min-w-0 gives OverflowRow a shrinkable container to collapse against.\n return (\n <div className=\"min-w-0\">\n <OverflowRow\n gap={8}\n justify=\"end\"\n renderOverflow={(hiddenCount) => (\n <ActionMenu\n items={toMenuItems(\n buttons.slice(Math.max(0, buttons.length - hiddenCount)),\n )}\n />\n )}\n >\n {buttons.map((button, index) => {\n const href = safeHref(button.href);\n return (\n <div key={`${index}-${button.label}`} className=\"flex items-center gap-2\">\n {button.dividerBefore && index > 0 ? (\n <span\n aria-hidden=\"true\"\n className=\"h-4 w-px bg-[var(--malachite-card-border)]\"\n />\n ) : null}\n <Button\n variant={button.variant ?? 'filled'}\n size=\"medium\"\n disabled={button.disabled}\n icon={button.icon}\n tooltip={button.tooltip}\n tooltipPlacement={button.tooltipPlacement}\n href={href}\n target={href ? (button.target ?? '_blank') : undefined}\n onClick={href ? undefined : button.onClick}\n >\n {button.label}\n </Button>\n </div>\n );\n })}\n </OverflowRow>\n </div>\n );\n};\n\nconst NO_LINKS: BreadcrumbLink[] = [];\nconst NO_BUTTONS: PageAction[] = [];\n\nconst RegularLayout: React.FC<RegularLayoutProps> = ({\n breadcrumbLinks = NO_LINKS,\n breadcrumbActions,\n renderLink,\n title,\n titleSuffix,\n subtitle,\n description,\n buttons = NO_BUTTONS,\n loading = false,\n children,\n centered = false,\n noPadding = false,\n contentGap = 'small',\n alert,\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}) => {\n const hasBack = hasBackButton(breadcrumbLinks);\n const contentPadding = noPadding ? 0 : centered ? '5vh 14vw' : '40px';\n // Published so a full-bleed child (CardStrip's bottom rule) can cancel it and re-apply\n // it as its own padding, instead of hardcoding the gutter at the call site.\n const contentInset = noPadding ? '0px' : centered ? '14vw' : '40px';\n const hasHeaderBlock = Boolean(\n loading || title || subtitle || description || buttons.length > 0,\n );\n\n const subtitleNode = subtitle ? (\n loading ? (\n <Skeleton.Input width={120} height={24} />\n ) : (\n <Text color=\"secondary\" size=\"small\">\n {subtitle}\n </Text>\n )\n ) : null;\n\n const titleNode = loading ? (\n <Skeleton.Input width={200} height={40} />\n ) : title ? (\n <div className=\"flex items-center\" style={{ gap: 12 }}>\n <PageTitle>{title}</PageTitle>\n {titleSuffix}\n </div>\n ) : null;\n\n const descriptionNode = description ? (\n loading ? (\n <Skeleton.Input width={120} height={24} />\n ) : (\n <Text color=\"secondary\" style={{ lineHeight: 1.6 }}>\n {description}\n </Text>\n )\n ) : null;\n\n return (\n <main\n className={`${CARD_CLASSES} ${className}`}\n style={{ borderRadius: CARD_RADIUS, minHeight: CARD_MIN_HEIGHT, ...style }}\n role={role}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-busy={loading || undefined}\n >\n <div\n className={`flex items-center ${DIVIDER_CLASSES}`}\n style={{\n height: HEADER_HEIGHT,\n paddingInlineStart: hasBack ? 16 : 28,\n paddingInlineEnd: 16,\n }}\n >\n <Breadcrumbs\n links={breadcrumbLinks}\n actions={breadcrumbActions}\n renderLink={renderLink}\n className=\"flex-1 min-w-0\"\n />\n </div>\n\n {alert ? (\n <div className={DIVIDER_CLASSES} style={{ padding: '10px 16px' }}>\n <Alert message={alert.message} type={alert.type} hasMargin={false} />\n </div>\n ) : null}\n\n <div\n className=\"flex flex-col\"\n style={\n {\n padding: contentPadding,\n minHeight: CONTENT_MIN_HEIGHT,\n gap: CONTENT_GAPS[contentGap],\n [CONTENT_INSET_VAR]: contentInset,\n } as React.CSSProperties\n }\n >\n {hasHeaderBlock ? (\n <div className=\"flex flex-col\" style={{ gap: 12 }}>\n {titleNode || subtitleNode || buttons.length > 0 ? (\n <div\n className=\"flex flex-wrap items-center justify-between\"\n style={{ gap: 12 }}\n >\n <div\n className=\"flex flex-col flex-auto min-w-0 overflow-hidden\"\n style={{ gap: 4 }}\n >\n {subtitleNode}\n {titleNode}\n </div>\n {loading ? null : <PageActions buttons={buttons} />}\n </div>\n ) : null}\n {descriptionNode}\n </div>\n ) : null}\n {children}\n </div>\n </main>\n );\n};\n\nexport default RegularLayout;\nexport { RegularLayout };\n"],"names":["CONTENT_GAPS","isDanger","button","toMenuItems","buttons","index","href","safeHref","item","PageActions","jsx","OverflowRow","hiddenCount","ActionMenu","jsxs","Button","NO_LINKS","NO_BUTTONS","RegularLayout","breadcrumbLinks","breadcrumbActions","renderLink","title","titleSuffix","subtitle","description","loading","children","centered","noPadding","contentGap","alert","role","ariaLabel","ariaLabelledBy","className","style","hasBack","hasBackButton","contentPadding","contentInset","hasHeaderBlock","subtitleNode","Skeleton","Text","titleNode","PageTitle","descriptionNode","CARD_CLASSES","CARD_RADIUS","CARD_MIN_HEIGHT","DIVIDER_CLASSES","HEADER_HEIGHT","Breadcrumbs","Alert","CONTENT_MIN_HEIGHT","CONTENT_INSET_VAR"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"regularLayout.js","sources":["../../../src/components/PageLayout/regularLayout.tsx"],"sourcesContent":["import React from 'react';\nimport ActionMenu, { type ActionMenuItem } from '../ActionMenu';\nimport Alert, { type AlertType } from '../Alert';\nimport Breadcrumbs from '../Breadcrumbs';\nimport { hasBackButton } from '../breadcrumbsNav';\nimport Button from '../Button';\nimport OverflowRow from '../OverflowRow';\nimport Skeleton from '../Skeleton';\nimport PageTitle from '../Typography/PageTitle';\nimport Text from '../Typography/Text';\nimport { safeHref } from '../safeHref';\nimport {\n CARD_CLASSES,\n CARD_MIN_HEIGHT,\n CARD_RADIUS,\n CONTENT_INSET_VAR,\n CONTENT_MIN_HEIGHT,\n DIVIDER_CLASSES,\n HEADER_HEIGHT,\n} from './constants';\nimport type { BreadcrumbLink, PageAction, RenderLink } from './types';\n\nexport type PageContentGap = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport interface RegularLayoutProps {\n breadcrumbLinks?: BreadcrumbLink[];\n breadcrumbActions?: PageAction[];\n renderLink?: RenderLink;\n title?: React.ReactNode;\n titleSuffix?: React.ReactNode;\n subtitle?: string;\n description?: React.ReactNode;\n buttons?: PageAction[];\n /**\n * Hides the buttons and skeletons the title. `subtitle` and `description` are only\n * skeletoned when those props are also passed.\n */\n loading?: boolean;\n children: React.ReactNode;\n centered?: boolean;\n noPadding?: boolean;\n contentGap?: PageContentGap;\n alert?: { message: string; type?: AlertType };\n /** Demotes the default `main` landmark — pass e.g. `region` when the app owns its own. */\n role?: React.AriaRole;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst CONTENT_GAPS: Record<PageContentGap, number> = {\n small: 8,\n medium: 16,\n large: 24,\n xlarge: 40,\n};\n\nconst isDanger = (button: PageAction): boolean =>\n button.variant === 'destructive' || button.variant === 'error';\n\nconst toMenuItems = (buttons: PageAction[]): ActionMenuItem[] =>\n buttons.flatMap((button, index) => {\n const href = safeHref(button.href);\n const item: ActionMenuItem = {\n key: `${index}-${button.label}`,\n label: button.label,\n ...(href ? { href, target: button.target ?? '_blank' } : { onClick: button.onClick }),\n disabled: button.disabled,\n icon: button.icon,\n tooltip: button.tooltip,\n danger: isDanger(button),\n };\n return button.dividerBefore && index > 0\n ? [{ type: 'divider' as const, key: `divider-${index}-${button.label}` }, item]\n : [item];\n });\n\n// Not `ActionBar`: it measures by walking ancestors for `clientWidth`, and this chrome\n// mounts on every page. OverflowRow batches its measurement instead.\n// A divider must live in the same OverflowRow child as its button — a standalone child\n// would survive its hidden button and break the child-index-to-button mapping.\n/**\n * The page's action buttons, collapsing into an overflow menu as the row narrows. Exported so\n * a page that renders its own header block — e.g. one that scrolls the title away — keeps the\n * same behaviour instead of hand-rolling `buttons.map(...)` and losing the collapse, the\n * dividers and the href handling.\n */\nexport const PageActions: React.FC<{ buttons: PageAction[] }> = ({ buttons }) => {\n if (buttons.length === 0) {\n return null;\n }\n\n // min-w-0 gives OverflowRow a shrinkable container to collapse against.\n return (\n <div className=\"min-w-0\">\n <OverflowRow\n gap={8}\n justify=\"end\"\n renderOverflow={(hiddenCount) => (\n <ActionMenu\n items={toMenuItems(\n buttons.slice(Math.max(0, buttons.length - hiddenCount)),\n )}\n />\n )}\n >\n {buttons.map((button, index) => {\n const href = safeHref(button.href);\n return (\n <div key={`${index}-${button.label}`} className=\"flex items-center gap-2\">\n {button.dividerBefore && index > 0 ? (\n <span\n aria-hidden=\"true\"\n className=\"h-4 w-px bg-[var(--malachite-card-border)]\"\n />\n ) : null}\n <Button\n variant={button.variant ?? 'filled'}\n size=\"medium\"\n disabled={button.disabled}\n icon={button.icon}\n tooltip={button.tooltip}\n tooltipPlacement={button.tooltipPlacement}\n href={href}\n target={href ? (button.target ?? '_blank') : undefined}\n onClick={href ? undefined : button.onClick}\n >\n {button.label}\n </Button>\n </div>\n );\n })}\n </OverflowRow>\n </div>\n );\n};\n\nconst NO_LINKS: BreadcrumbLink[] = [];\nconst NO_BUTTONS: PageAction[] = [];\n\nconst RegularLayout: React.FC<RegularLayoutProps> = ({\n breadcrumbLinks = NO_LINKS,\n breadcrumbActions,\n renderLink,\n title,\n titleSuffix,\n subtitle,\n description,\n buttons = NO_BUTTONS,\n loading = false,\n children,\n centered = false,\n noPadding = false,\n contentGap = 'small',\n alert,\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}) => {\n const hasBack = hasBackButton(breadcrumbLinks);\n const contentPadding = noPadding ? 0 : centered ? '5vh 14vw' : '40px';\n // Published so a full-bleed child (CardStrip's bottom rule) can cancel it and re-apply\n // it as its own padding, instead of hardcoding the gutter at the call site.\n const contentInset = noPadding ? '0px' : centered ? '14vw' : '40px';\n const hasHeaderBlock = Boolean(\n loading || title || subtitle || description || buttons.length > 0,\n );\n\n const subtitleNode = subtitle ? (\n loading ? (\n <Skeleton.Input width={120} height={24} />\n ) : (\n <Text color=\"secondary\" size=\"small\">\n {subtitle}\n </Text>\n )\n ) : null;\n\n const titleNode = loading ? (\n <Skeleton.Input width={200} height={40} />\n ) : title ? (\n <div className=\"flex items-center\" style={{ gap: 12 }}>\n <PageTitle>{title}</PageTitle>\n {titleSuffix}\n </div>\n ) : null;\n\n const descriptionNode = description ? (\n loading ? (\n <Skeleton.Input width={120} height={24} />\n ) : (\n <Text color=\"secondary\" style={{ lineHeight: 1.6 }}>\n {description}\n </Text>\n )\n ) : null;\n\n return (\n <main\n className={`${CARD_CLASSES} ${className}`}\n style={{ borderRadius: CARD_RADIUS, minHeight: CARD_MIN_HEIGHT, ...style }}\n role={role}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-busy={loading || undefined}\n >\n <div\n className={`flex items-center ${DIVIDER_CLASSES}`}\n style={{\n height: HEADER_HEIGHT,\n paddingInlineStart: hasBack ? 16 : 28,\n paddingInlineEnd: 16,\n }}\n >\n <Breadcrumbs\n links={breadcrumbLinks}\n actions={breadcrumbActions}\n renderLink={renderLink}\n className=\"flex-1 min-w-0\"\n />\n </div>\n\n {alert ? (\n <div className={DIVIDER_CLASSES} style={{ padding: '10px 16px' }}>\n <Alert message={alert.message} type={alert.type} hasMargin={false} />\n </div>\n ) : null}\n\n <div\n className=\"flex flex-col\"\n style={\n {\n padding: contentPadding,\n minHeight: CONTENT_MIN_HEIGHT,\n gap: CONTENT_GAPS[contentGap],\n [CONTENT_INSET_VAR]: contentInset,\n } as React.CSSProperties\n }\n >\n {hasHeaderBlock ? (\n <div className=\"flex flex-col\" style={{ gap: 12 }}>\n {titleNode || subtitleNode || buttons.length > 0 ? (\n <div\n className=\"flex flex-wrap items-center justify-between\"\n style={{ gap: 12 }}\n >\n <div\n className=\"flex flex-col flex-auto min-w-0 overflow-hidden\"\n style={{ gap: 4 }}\n >\n {subtitleNode}\n {titleNode}\n </div>\n {loading ? null : <PageActions buttons={buttons} />}\n </div>\n ) : null}\n {descriptionNode}\n </div>\n ) : null}\n {children}\n </div>\n </main>\n );\n};\n\nexport default RegularLayout;\nexport { RegularLayout };\n"],"names":["CONTENT_GAPS","isDanger","button","toMenuItems","buttons","index","href","safeHref","item","PageActions","jsx","OverflowRow","hiddenCount","ActionMenu","jsxs","Button","NO_LINKS","NO_BUTTONS","RegularLayout","breadcrumbLinks","breadcrumbActions","renderLink","title","titleSuffix","subtitle","description","loading","children","centered","noPadding","contentGap","alert","role","ariaLabel","ariaLabelledBy","className","style","hasBack","hasBackButton","contentPadding","contentInset","hasHeaderBlock","subtitleNode","Skeleton","Text","titleNode","PageTitle","descriptionNode","CARD_CLASSES","CARD_RADIUS","CARD_MIN_HEIGHT","DIVIDER_CLASSES","HEADER_HEIGHT","Breadcrumbs","Alert","CONTENT_MIN_HEIGHT","CONTENT_INSET_VAR"],"mappings":"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"}
|