@mdbase-dev/ui 0.1.0-beta.125 → 0.1.0-beta.147

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.
Files changed (77) hide show
  1. package/README.md +159 -0
  2. package/css/brand.css +10 -10
  3. package/css/collections.css +978 -0
  4. package/css/controls.css +220 -43
  5. package/css/feedback.css +20 -20
  6. package/css/fonts.css +2 -3
  7. package/css/palette.css +10 -10
  8. package/css/screens.css +58 -16
  9. package/css/tokens.css +43 -3
  10. package/dist/AppSwitcher.js +187 -33
  11. package/dist/Checkbox.d.ts +14 -0
  12. package/dist/Checkbox.js +32 -0
  13. package/dist/CommandPalette.d.ts +4 -2
  14. package/dist/CommandPalette.js +275 -103
  15. package/dist/Dialog.js +72 -25
  16. package/dist/Feedback.js +763 -229
  17. package/dist/FeedbackMarkup.d.ts +1 -1
  18. package/dist/FeedbackMarkup.js +326 -125
  19. package/dist/FeedbackVerification.js +115 -68
  20. package/dist/SaveNotice.js +71 -28
  21. package/dist/Select.js +183 -135
  22. package/dist/SelectList.js +59 -14
  23. package/dist/ThemeSelect.js +55 -4
  24. package/dist/apps.d.ts +1 -0
  25. package/dist/apps.js +50 -29
  26. package/dist/brand.js +251 -68
  27. package/dist/codemirror.js +116 -87
  28. package/dist/collections/CollectionGate.d.ts +52 -0
  29. package/dist/collections/CollectionGate.js +456 -0
  30. package/dist/collections/CollectionSaveWarning.d.ts +10 -0
  31. package/dist/collections/CollectionSaveWarning.js +28 -0
  32. package/dist/collections/CollectionSwitcher.d.ts +26 -0
  33. package/dist/collections/CollectionSwitcher.js +579 -0
  34. package/dist/collections/SetupReview.d.ts +9 -0
  35. package/dist/collections/SetupReview.js +175 -0
  36. package/dist/collections/copy.d.ts +100 -0
  37. package/dist/collections/copy.js +937 -0
  38. package/dist/collections/dialogs.d.ts +27 -0
  39. package/dist/collections/dialogs.js +169 -0
  40. package/dist/collections/model.d.ts +146 -0
  41. package/dist/collections/model.js +337 -0
  42. package/dist/collections/mount.d.ts +18 -0
  43. package/dist/collections/mount.js +56 -0
  44. package/dist/collections/parts.d.ts +86 -0
  45. package/dist/collections/parts.js +439 -0
  46. package/dist/collections/testing.d.ts +19 -0
  47. package/dist/collections/testing.js +39 -0
  48. package/dist/collections/use-collection-ui.d.ts +140 -0
  49. package/dist/collections/use-collection-ui.js +236 -0
  50. package/dist/collections.d.ts +19 -0
  51. package/dist/collections.js +13 -0
  52. package/dist/feedback-data.d.ts +13 -12
  53. package/dist/feedback-data.js +365 -168
  54. package/dist/flock.d.ts +63 -0
  55. package/dist/flock.js +140 -0
  56. package/dist/i18n.d.ts +6 -0
  57. package/dist/i18n.js +71 -0
  58. package/dist/locales/de/messages.json +1 -0
  59. package/dist/locales/en/messages.json +1 -0
  60. package/dist/locales/es/messages.json +1 -0
  61. package/dist/locales/fr/messages.json +1 -0
  62. package/dist/locales/it/messages.json +1 -0
  63. package/dist/locales/ja/messages.json +1 -0
  64. package/dist/locales/ko/messages.json +1 -0
  65. package/dist/locales/pt/messages.json +1 -0
  66. package/dist/locales/ru/messages.json +1 -0
  67. package/dist/locales/zh/messages.json +1 -0
  68. package/dist/mark-activity.js +82 -75
  69. package/dist/permission-selection.js +27 -17
  70. package/dist/popover.js +138 -130
  71. package/dist/screens.d.ts +20 -3
  72. package/dist/screens.js +275 -6
  73. package/dist/select-model.js +34 -28
  74. package/dist/text-diff.d.ts +1 -0
  75. package/dist/text-diff.js +106 -74
  76. package/dist/theme.js +34 -40
  77. package/package.json +53 -8
@@ -1,22 +1,25 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Fragment, useEffect, useMemo, useRef, useState } from "react";
2
+ import { i18n as _i18n } from "@lingui/core";
3
+ import { useLocaleRevision } from "./i18n.js";
4
+ import { Fragment, useEffect, useId, useMemo, useRef, useState } from "react";
3
5
  export function isApplePlatform() {
4
- return typeof navigator !== "undefined" && /Mac|iPhone|iPad/u.test(navigator.platform || navigator.userAgent);
6
+ return typeof navigator !== "undefined" && /Mac|iPhone|iPad/u.test(navigator.platform || navigator.userAgent);
5
7
  }
6
8
  /** "mod+shift+f" as the platform writes it: ⌘⇧F on Apple systems, Ctrl+Shift+F elsewhere. */
7
9
  export function shortcutLabel(shortcut) {
8
- const apple = isApplePlatform();
9
- return shortcut
10
- .split("+")
11
- .map((part) => {
12
- switch (part.toLowerCase()) {
13
- case "mod": return apple ? "⌘" : "Ctrl";
14
- case "shift": return apple ? "⇧" : "Shift";
15
- case "alt": return apple ? "⌥" : "Alt";
16
- default: return part.length === 1 ? part.toUpperCase() : part;
17
- }
18
- })
19
- .join(apple ? "" : "+");
10
+ const apple = isApplePlatform();
11
+ return shortcut.split("+").map(part => {
12
+ switch (part.toLowerCase()) {
13
+ case "mod":
14
+ return apple ? "⌘" : "Ctrl";
15
+ case "shift":
16
+ return apple ? "⇧" : "Shift";
17
+ case "alt":
18
+ return apple ? "⌥" : "Alt";
19
+ default:
20
+ return part.length === 1 ? part.toUpperCase() : part;
21
+ }
22
+ }).join(apple ? "" : "+");
20
23
  }
21
24
  const browseLimit = 6;
22
25
  const searchLimit = 40;
@@ -25,106 +28,275 @@ const searchLimit = 40;
25
28
  * one, show every command matching all its terms, grouped in their original order.
26
29
  */
27
30
  export function matchingCommands(commands, query, showAll = []) {
28
- const terms = query.trim().toLocaleLowerCase().split(/\s+/u).filter(Boolean);
29
- if (terms.length === 0) {
30
- const counts = new Map();
31
- return commands.filter((command) => {
32
- const count = counts.get(command.group) ?? 0;
33
- counts.set(command.group, count + 1);
34
- return showAll.includes(command.group) || count < browseLimit;
35
- });
36
- }
37
- const matches = commands.filter((command) => {
38
- const content = `${command.label} ${command.detail ?? ""} ${command.group} ${command.keywords ?? ""}`.toLocaleLowerCase();
39
- return terms.every((term) => content.includes(term));
31
+ const terms = query.trim().toLocaleLowerCase().split(/\s+/u).filter(Boolean);
32
+ if (terms.length === 0) {
33
+ const counts = new Map();
34
+ return commands.filter(command => {
35
+ const count = counts.get(command.group) ?? 0;
36
+ counts.set(command.group, count + 1);
37
+ return showAll.includes(command.group) || count < browseLimit;
40
38
  });
41
- const groups = [...new Set(matches.map(({ group }) => group))];
42
- return groups.flatMap((group) => matches.filter((command) => command.group === group)).slice(0, searchLimit);
39
+ }
40
+ const matches = commands.filter(command => {
41
+ const content = `${command.label} ${command.detail ?? ""} ${command.group} ${command.keywords ?? ""}`.toLocaleLowerCase();
42
+ return terms.every(term => content.includes(term));
43
+ });
44
+ const groups = [...new Set(matches.map(({
45
+ group
46
+ }) => group))];
47
+ return groups.flatMap(group => matches.filter(command => command.group === group)).slice(0, searchLimit);
43
48
  }
44
49
  /**
45
50
  * Find or run anything: every mdbase app opens it with Mod+K. Typing filters commands; the
46
51
  * arrows move, Enter runs, Shift+Enter runs a command's alternate, Escape closes.
47
52
  */
48
- export function CommandPalette({ open, commands, onClose, label = "Commands", placeholder = "Search commands", showAll }) {
49
- return open ? _jsx(OpenCommandPalette, { commands: commands, onClose: onClose, label: label, placeholder: placeholder, showAll: showAll }) : null;
53
+ export function CommandPalette({
54
+ open,
55
+ commands,
56
+ onClose,
57
+ label = _i18n._(
58
+ /** i18n */
59
+ {
60
+ id: "45MZFs",
61
+ message: "Commands"
62
+ }),
63
+ placeholder = _i18n._(
64
+ /** i18n */
65
+ {
66
+ id: "AbNeva",
67
+ message: "Search commands"
68
+ }),
69
+ showAll,
70
+ groupLabel
71
+ }) {
72
+ useLocaleRevision();
73
+ return open ? _jsx(OpenCommandPalette, {
74
+ commands: commands,
75
+ onClose: onClose,
76
+ label: label,
77
+ placeholder: placeholder,
78
+ showAll: showAll,
79
+ groupLabel: groupLabel
80
+ }) : null;
50
81
  }
51
- function OpenCommandPalette({ commands, onClose, label, placeholder, showAll }) {
52
- const [query, setQuery] = useState("");
53
- const [active, setActive] = useState(0);
54
- const inputRef = useRef(null);
55
- const paletteRef = useRef(null);
56
- const matches = useMemo(() => matchingCommands(commands, query, showAll), [commands, query, showAll]);
57
- useEffect(() => {
58
- const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
59
- globalThis.setTimeout(() => inputRef.current?.focus(), 0);
60
- return () => previous?.focus();
61
- }, []);
62
- const run = (command, alternate = false) => {
63
- onClose();
64
- (alternate && command.alternate ? command.alternate.run : command.run)();
65
- };
66
- const hintId = `${label.replace(/\W+/gu, "-").toLowerCase()}-hint`;
67
- return _jsxs("dialog", { className: "mdbase-command-backdrop", open: true, children: [_jsx("button", { className: "mdbase-command-dismiss", type: "button", "aria-label": `Close ${label.toLowerCase()}`, onClick: onClose }), _jsxs("section", { ref: paletteRef, className: "mdbase-command-palette", role: "dialog", "aria-modal": "true", "aria-label": label, onKeyDown: (event) => {
68
- if (event.key === "Escape") {
69
- event.preventDefault();
70
- onClose();
71
- }
72
- else if (event.key === "Tab") {
73
- trapFocus(event, paletteRef.current);
74
- }
75
- }, children: [_jsxs("label", { className: "mdbase-command-search", children: [_jsxs("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", fill: "none", stroke: "currentColor", strokeWidth: "1.6", children: [_jsx("circle", { cx: "11", cy: "11", r: "6.5" }), _jsx("path", { d: "m16 16 4 4" })] }), _jsx("span", { className: "mdbase-visually-hidden", children: placeholder }), _jsx("input", { ref: inputRef, value: query, placeholder: placeholder, onChange: (event) => {
76
- setQuery(event.target.value);
77
- setActive(0);
78
- }, onKeyDown: (event) => handleKeys(event, matches, active, setActive, run, onClose) })] }), _jsx("div", { className: "mdbase-command-results", role: "listbox", "aria-label": "Results", "aria-describedby": hintId, children: matches.length > 0
79
- ? matches.map((command, index) => _jsxs(Fragment, { children: [command.group !== matches[index - 1]?.group
80
- ? _jsx("div", { className: "mdbase-command-group", role: "presentation", children: command.group })
81
- : null, _jsx(CommandRow, { command: command, active: index === active, onRun: run })] }, command.id))
82
- : _jsx("div", { className: "mdbase-command-empty", children: "Nothing matches" }) }), _jsxs("footer", { className: "mdbase-command-footer", id: hintId, children: [_jsxs("span", { children: [_jsx("kbd", { children: "\u2191" }), _jsx("kbd", { children: "\u2193" }), " to move"] }), _jsxs("span", { children: [_jsx("kbd", { children: "\u21B5" }), " to open"] }), matches[active]?.alternate
83
- ? _jsxs("span", { children: [_jsx("kbd", { children: shortcutLabel("shift") }), _jsx("kbd", { children: "\u21B5" }), " ", matches[active].alternate.label.toLocaleLowerCase()] })
84
- : null, _jsxs("span", { children: [_jsx("kbd", { children: "Esc" }), " to close"] })] })] })] });
82
+ function OpenCommandPalette({
83
+ commands,
84
+ onClose,
85
+ label,
86
+ placeholder,
87
+ showAll,
88
+ groupLabel
89
+ }) {
90
+ useLocaleRevision();
91
+ const [query, setQuery] = useState("");
92
+ const [active, setActive] = useState(0);
93
+ const inputRef = useRef(null);
94
+ const paletteRef = useRef(null);
95
+ const matches = useMemo(() => matchingCommands(commands, query, showAll), [commands, query, showAll]);
96
+ useEffect(() => {
97
+ const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
98
+ globalThis.setTimeout(() => inputRef.current?.focus(), 0);
99
+ return () => previous?.focus();
100
+ }, []);
101
+ const run = (command, alternate = false) => {
102
+ onClose();
103
+ (alternate && command.alternate ? command.alternate.run : command.run)();
104
+ };
105
+ const hintId = useId();
106
+ return _jsxs("dialog", {
107
+ className: "mdbase-command-backdrop",
108
+ open: true,
109
+ children: [_jsx("button", {
110
+ className: "mdbase-command-dismiss",
111
+ type: "button",
112
+ "aria-label": _i18n._(
113
+ /** i18n */
114
+ {
115
+ id: "WbUtOC",
116
+ message: "Close {label}",
117
+ values: {
118
+ label: label
119
+ }
120
+ }),
121
+ onClick: onClose
122
+ }), _jsxs("section", {
123
+ ref: paletteRef,
124
+ className: "mdbase-command-palette",
125
+ role: "dialog",
126
+ "aria-modal": "true",
127
+ "aria-label": label,
128
+ onKeyDown: event => {
129
+ if (event.key === "Escape") {
130
+ event.preventDefault();
131
+ onClose();
132
+ } else if (event.key === "Tab") {
133
+ trapFocus(event, paletteRef.current);
134
+ }
135
+ },
136
+ children: [_jsxs("label", {
137
+ className: "mdbase-command-search",
138
+ children: [_jsxs("svg", {
139
+ viewBox: "0 0 24 24",
140
+ "aria-hidden": "true",
141
+ fill: "none",
142
+ stroke: "currentColor",
143
+ strokeWidth: "1.6",
144
+ children: [_jsx("circle", {
145
+ cx: "11",
146
+ cy: "11",
147
+ r: "6.5"
148
+ }), _jsx("path", {
149
+ d: "m16 16 4 4"
150
+ })]
151
+ }), _jsx("span", {
152
+ className: "mdbase-visually-hidden",
153
+ children: placeholder
154
+ }), _jsx("input", {
155
+ ref: inputRef,
156
+ value: query,
157
+ placeholder: placeholder,
158
+ onChange: event => {
159
+ setQuery(event.target.value);
160
+ setActive(0);
161
+ },
162
+ onKeyDown: event => handleKeys(event, matches, active, setActive, run, onClose)
163
+ })]
164
+ }), _jsx("div", {
165
+ className: "mdbase-command-results",
166
+ role: "listbox",
167
+ "aria-label": _i18n._(
168
+ /** i18n */
169
+ {
170
+ id: "kx0s-n",
171
+ message: "Results"
172
+ }),
173
+ "aria-describedby": hintId,
174
+ children: matches.length > 0 ? matches.map((command, index) => _jsxs(Fragment, {
175
+ children: [command.group !== matches[index - 1]?.group ? _jsx("div", {
176
+ className: "mdbase-command-group",
177
+ role: "presentation",
178
+ children: groupLabel ? groupLabel(command.group) : command.group
179
+ }) : null, _jsx(CommandRow, {
180
+ command: command,
181
+ active: index === active,
182
+ onRun: run
183
+ })]
184
+ }, command.id)) : _jsx("div", {
185
+ className: "mdbase-command-empty",
186
+ children: _i18n._(
187
+ /** i18n */
188
+ {
189
+ id: "DViXWV",
190
+ message: "Nothing matches"
191
+ })
192
+ })
193
+ }), _jsxs("footer", {
194
+ className: "mdbase-command-footer",
195
+ id: hintId,
196
+ children: [_jsxs("span", {
197
+ children: [_jsx("kbd", {
198
+ children: "\u2191"
199
+ }), _jsx("kbd", {
200
+ children: "\u2193"
201
+ }), " ", _i18n._(
202
+ /** i18n */
203
+ {
204
+ id: "2UA-qq",
205
+ message: "to move"
206
+ })]
207
+ }), _jsxs("span", {
208
+ children: [_jsx("kbd", {
209
+ children: "\u21B5"
210
+ }), " ", _i18n._(
211
+ /** i18n */
212
+ {
213
+ id: "2cqK5k",
214
+ message: "to open"
215
+ })]
216
+ }), matches[active]?.alternate ? _jsxs("span", {
217
+ children: [_jsx("kbd", {
218
+ children: shortcutLabel("shift")
219
+ }), _jsx("kbd", {
220
+ children: "\u21B5"
221
+ }), " ", matches[active].alternate.label.toLocaleLowerCase()]
222
+ }) : null, _jsxs("span", {
223
+ children: [_jsx("kbd", {
224
+ children: _i18n._(
225
+ /** i18n */
226
+ {
227
+ id: "zO1gmR",
228
+ message: "Esc"
229
+ })
230
+ }), " ", _i18n._(
231
+ /** i18n */
232
+ {
233
+ id: "UbVgIu",
234
+ message: "to close"
235
+ })]
236
+ })]
237
+ })]
238
+ })]
239
+ });
85
240
  }
86
241
  function trapFocus(event, container) {
87
- if (!container)
88
- return;
89
- const items = [...container.querySelectorAll("input, button, [tabindex]:not([tabindex='-1'])")];
90
- const first = items[0];
91
- const last = items.at(-1);
92
- if (!first || !last)
93
- return;
94
- if (event.shiftKey && document.activeElement === first) {
95
- event.preventDefault();
96
- last.focus();
97
- }
98
- else if (!event.shiftKey && document.activeElement === last) {
99
- event.preventDefault();
100
- first.focus();
101
- }
242
+ if (!container) return;
243
+ const items = [...container.querySelectorAll("input, button, [tabindex]:not([tabindex='-1'])")];
244
+ const first = items[0];
245
+ const last = items.at(-1);
246
+ if (!first || !last) return;
247
+ if (event.shiftKey && document.activeElement === first) {
248
+ event.preventDefault();
249
+ last.focus();
250
+ } else if (!event.shiftKey && document.activeElement === last) {
251
+ event.preventDefault();
252
+ first.focus();
253
+ }
102
254
  }
103
- function CommandRow({ command, active, onRun }) {
104
- const ref = useRef(null);
105
- useEffect(() => {
106
- if (active)
107
- ref.current?.scrollIntoView({ block: "nearest" });
108
- }, [active]);
109
- return _jsxs("button", { ref: ref, type: "button", role: "option", "aria-selected": active, onMouseDown: (event) => onRun(command, event.shiftKey), children: [_jsxs("span", { children: [_jsx("strong", { children: command.label }), command.detail ? _jsx("small", { children: command.detail }) : null] }), command.alternate && active
110
- ? _jsxs("span", { className: "mdbase-command-alternate", children: [shortcutLabel("shift"), "\u21B5 ", command.alternate.label] })
111
- : null, command.shortcut ? _jsx("kbd", { children: shortcutLabel(command.shortcut) }) : null] });
255
+ function CommandRow({
256
+ command,
257
+ active,
258
+ onRun
259
+ }) {
260
+ useLocaleRevision();
261
+ const ref = useRef(null);
262
+ useEffect(() => {
263
+ if (active) ref.current?.scrollIntoView({
264
+ block: "nearest"
265
+ });
266
+ }, [active]);
267
+ return _jsxs("button", {
268
+ ref: ref,
269
+ type: "button",
270
+ role: "option",
271
+ "aria-selected": active,
272
+ onMouseDown: event => onRun(command, event.shiftKey),
273
+ children: [_jsxs("span", {
274
+ children: [_jsx("strong", {
275
+ children: command.label
276
+ }), command.detail ? _jsx("small", {
277
+ children: command.detail
278
+ }) : null]
279
+ }), command.alternate && active ? _jsxs("span", {
280
+ className: "mdbase-command-alternate",
281
+ children: [shortcutLabel("shift"), "\u21B5 ", command.alternate.label]
282
+ }) : null, command.shortcut ? _jsx("kbd", {
283
+ children: shortcutLabel(command.shortcut)
284
+ }) : null]
285
+ });
112
286
  }
113
287
  function handleKeys(event, matches, active, setActive, run, close) {
114
- if (event.key === "Escape") {
115
- event.preventDefault();
116
- close();
117
- }
118
- else if (event.key === "ArrowDown" || event.key === "ArrowUp") {
119
- event.preventDefault();
120
- const direction = event.key === "ArrowDown" ? 1 : -1;
121
- setActive((active + direction + matches.length) % Math.max(1, matches.length));
122
- }
123
- else if (event.key === "Enter") {
124
- const command = matches[active];
125
- if (command) {
126
- event.preventDefault();
127
- run(command, event.shiftKey);
128
- }
288
+ if (event.key === "Escape") {
289
+ event.preventDefault();
290
+ close();
291
+ } else if (event.key === "ArrowDown" || event.key === "ArrowUp") {
292
+ event.preventDefault();
293
+ const direction = event.key === "ArrowDown" ? 1 : -1;
294
+ setActive((active + direction + matches.length) % Math.max(1, matches.length));
295
+ } else if (event.key === "Enter") {
296
+ const command = matches[active];
297
+ if (command) {
298
+ event.preventDefault();
299
+ run(command, event.shiftKey);
129
300
  }
301
+ }
130
302
  }
package/dist/Dialog.js CHANGED
@@ -1,32 +1,79 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { i18n as _i18n } from "@lingui/core";
3
+ import { useLocaleRevision } from "./i18n.js";
2
4
  import { useLayoutEffect, useRef } from "react";
3
5
  /**
4
6
  * A modal dialog on the native <dialog>: the browser keeps focus inside it and the page
5
7
  * behind it inert. Escape, the close button or a press on the backdrop closes it.
6
8
  */
7
- export function Dialog({ open, onClose, title, className, closeDisabled = false, children }) {
8
- const ref = useRef(null);
9
- useLayoutEffect(() => {
10
- const previous = document.activeElement instanceof HTMLElement ? document.activeElement : undefined;
11
- return () => { ref.current?.close(); previous?.focus(); };
12
- }, []);
13
- // A layout effect, so the dialog is open before fields inside it ask to be focused.
14
- useLayoutEffect(() => {
15
- const dialog = ref.current;
16
- if (!dialog)
17
- return;
18
- if (open && !dialog.open)
19
- dialog.showModal();
20
- else if (!open && dialog.open)
21
- dialog.close();
22
- }, [open]);
23
- return _jsx("dialog", { ref: ref, className: ["mdbase-dialog", className].filter(Boolean).join(" "), "aria-label": title, onKeyDown: (event) => event.stopPropagation(), onCancel: (event) => {
24
- event.preventDefault();
25
- if (!closeDisabled)
26
- onClose();
27
- }, onClose: () => { if (!closeDisabled)
28
- onClose(); }, onMouseDown: (event) => {
29
- if (!closeDisabled && event.target === event.currentTarget)
30
- onClose();
31
- }, children: open && _jsxs("div", { className: "mdbase-dialog-body", children: [_jsxs("header", { className: "mdbase-dialog-header", children: [_jsx("h2", { children: title }), _jsx("button", { type: "button", className: "mdbase-icon-button", disabled: closeDisabled, onClick: onClose, "aria-label": "Close", children: _jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", children: _jsx("path", { d: "m6 6 12 12M18 6 6 18" }) }) })] }), children] }) });
9
+ export function Dialog({
10
+ open,
11
+ onClose,
12
+ title,
13
+ className,
14
+ closeDisabled = false,
15
+ children
16
+ }) {
17
+ useLocaleRevision();
18
+ const ref = useRef(null);
19
+ useLayoutEffect(() => {
20
+ const previous = document.activeElement instanceof HTMLElement ? document.activeElement : undefined;
21
+ return () => {
22
+ ref.current?.close();
23
+ previous?.focus();
24
+ };
25
+ }, []);
26
+ // A layout effect, so the dialog is open before fields inside it ask to be focused.
27
+ useLayoutEffect(() => {
28
+ const dialog = ref.current;
29
+ if (!dialog) return;
30
+ if (open && !dialog.open) dialog.showModal();else if (!open && dialog.open) dialog.close();
31
+ }, [open]);
32
+ return _jsx("dialog", {
33
+ ref: ref,
34
+ className: ["mdbase-dialog", className].filter(Boolean).join(" "),
35
+ "aria-label": title,
36
+ onKeyDown: event => event.stopPropagation(),
37
+ onCancel: event => {
38
+ event.preventDefault();
39
+ if (!closeDisabled) onClose();
40
+ },
41
+ onClose: () => {
42
+ if (!closeDisabled) onClose();
43
+ },
44
+ onMouseDown: event => {
45
+ if (!closeDisabled && event.target === event.currentTarget) onClose();
46
+ },
47
+ children: open && _jsxs("div", {
48
+ className: "mdbase-dialog-body",
49
+ children: [_jsxs("header", {
50
+ className: "mdbase-dialog-header",
51
+ children: [_jsx("h2", {
52
+ children: title
53
+ }), _jsx("button", {
54
+ type: "button",
55
+ className: "mdbase-icon-button",
56
+ disabled: closeDisabled,
57
+ onClick: onClose,
58
+ "aria-label": _i18n._(
59
+ /** i18n */
60
+ {
61
+ id: "yz7wBu",
62
+ message: "Close"
63
+ }),
64
+ children: _jsx("svg", {
65
+ viewBox: "0 0 24 24",
66
+ "aria-hidden": "true",
67
+ fill: "none",
68
+ stroke: "currentColor",
69
+ strokeWidth: "1.6",
70
+ strokeLinecap: "round",
71
+ children: _jsx("path", {
72
+ d: "m6 6 12 12M18 6 6 18"
73
+ })
74
+ })
75
+ })]
76
+ }), children]
77
+ })
78
+ });
32
79
  }