rename web/ to admin/, along with the web-named build and cli identifiers
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* The destructive-action confirmation (milestone 23, ruling 5), which replaces
|
||||
* every `window.confirm` call in the app.
|
||||
*
|
||||
* `role="alertdialog"` rather than `dialog`: the message is the reason the
|
||||
* dialog exists, so it is announced with the dialog instead of after it. The
|
||||
* overlay is deliberately not dismissable — a delete needs an explicit answer,
|
||||
* and a stray outside click is not one. Escape still cancels.
|
||||
*/
|
||||
|
||||
import * as stylex from "@stylexjs/stylex";
|
||||
import { Dialog as AriaDialog, Heading, Modal, ModalOverlay } from "react-aria-components";
|
||||
import { colors } from "./tokens.stylex";
|
||||
import { styles as shared } from "./styles";
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
title: string;
|
||||
/** The full sentence the operator reads before confirming; names the entity. */
|
||||
message: string;
|
||||
confirmLabel: string;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const styles = stylex.create({
|
||||
overlay: {
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
zIndex: 50,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: "1rem",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
||||
},
|
||||
panel: {
|
||||
width: "100%",
|
||||
maxWidth: "26rem",
|
||||
borderRadius: "0.5rem",
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: colors.dangerBorder,
|
||||
backgroundColor: colors.surfaceRaised,
|
||||
color: colors.text,
|
||||
padding: "1.5rem",
|
||||
boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
||||
},
|
||||
body: {
|
||||
outlineStyle: "none",
|
||||
},
|
||||
title: {
|
||||
fontSize: "1.125rem",
|
||||
lineHeight: "1.75rem",
|
||||
fontWeight: 600,
|
||||
},
|
||||
message: {
|
||||
marginTop: "0.5rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
actions: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
gap: "0.5rem",
|
||||
marginTop: "1.5rem",
|
||||
},
|
||||
dangerButton: {
|
||||
borderRadius: "0.25rem",
|
||||
borderStyle: "none",
|
||||
backgroundColor: colors.danger,
|
||||
color: colors.primaryText,
|
||||
paddingInline: "0.75rem",
|
||||
paddingBlock: "0.375rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
fontWeight: 500,
|
||||
},
|
||||
});
|
||||
|
||||
export default function ConfirmDialog({ isOpen, title, message, confirmLabel, onConfirm, onCancel }: Props) {
|
||||
return (
|
||||
<ModalOverlay
|
||||
isOpen={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onCancel();
|
||||
}}
|
||||
className={() => stylex.props(styles.overlay).className ?? ""}
|
||||
>
|
||||
<Modal className={() => stylex.props(styles.panel).className ?? ""}>
|
||||
<AriaDialog role="alertdialog" {...stylex.props(styles.body)}>
|
||||
<Heading slot="title" level={2} {...stylex.props(styles.title)}>
|
||||
{title}
|
||||
</Heading>
|
||||
<p {...stylex.props(styles.message)}>{message}</p>
|
||||
<div {...stylex.props(styles.actions)}>
|
||||
<button type="button" onClick={onCancel} {...stylex.props(shared.button, shared.focusRing)}>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onConfirm}
|
||||
{...stylex.props(styles.dangerButton, shared.focusRing)}
|
||||
>
|
||||
{confirmLabel}
|
||||
</button>
|
||||
</div>
|
||||
</AriaDialog>
|
||||
</Modal>
|
||||
</ModalOverlay>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user