Repository navigation
Expand file tree
/
Copy pathDialog.tsx
More file actions
59 lines (55 loc) · 1.77 KB
/
Copy pathDialog.tsx
File metadata and controls
59 lines (55 loc) · 1.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// SPDX-FileCopyrightText: 2026 Anton Wiklund and Solid Memo contributors
//
// SPDX-License-Identifier: MIT
import type { ComponentChildren } from "preact";
import { useEffect, useId, useRef } from "preact/hooks";
import { useI18n } from "@solid-memo/ui/i18n";
/**
* A modal dialog, open while it is shown: the browser's own `<dialog>`,
* which keeps the focus in it and closes on Escape. Its heading names it.
* Its Close button closes it too, and closed (`onClose`, which stops
* showing it), the focus goes back where it was before it opened.
* Opened, the focus goes to the field marked `autoFocus` in it, if one
* is, as the browser does (and the test DOM does not). While
* it is open, the Studio's shortcuts leave its keys to it: `onKeyDown`
* has those it wants, from anywhere in it.
*/
export function Dialog({
heading,
onClose,
onKeyDown,
children,
}: {
heading: string;
/** The dialog closed: stop showing it. */
onClose: () => void;
onKeyDown?: (event: KeyboardEvent & { currentTarget: HTMLDialogElement }) => void;
children: ComponentChildren;
}) {
const { t } = useI18n();
const ref = useRef<HTMLDialogElement>(null);
const headingId = useId();
useEffect(() => {
const opener = document.activeElement as HTMLElement;
ref.current!.showModal();
ref.current!.querySelector<HTMLElement>("[autofocus]")?.focus();
return () => opener.focus();
}, []);
return (
<dialog
ref={ref}
class="studio-dialog"
aria-labelledby={headingId}
onClose={onClose}
onKeyDown={onKeyDown}
>
<header>
<h2 id={headingId}>{heading}</h2>
<button type="button" onClick={() => ref.current!.close()}>
{t("studio.shell.close")}
</button>
</header>
{children}
</dialog>
);
}