1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

frontend: upgrade compound & simplify the confirmation modal implementation

This commit is contained in:
Quentin Gliech
2023-09-18 11:08:57 +02:00
parent 4d123b75af
commit ae484604f8
4 changed files with 52 additions and 58 deletions

View File

@@ -18,7 +18,7 @@
"@urql/exchange-refocus": "^1.0.2", "@urql/exchange-refocus": "^1.0.2",
"@urql/exchange-request-policy": "^1.0.2", "@urql/exchange-request-policy": "^1.0.2",
"@vector-im/compound-design-tokens": "^0.0.5", "@vector-im/compound-design-tokens": "^0.0.5",
"@vector-im/compound-web": "^0.4.0", "@vector-im/compound-web": "^0.4.1",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
"graphql": "^16.8.0", "graphql": "^16.8.0",
@@ -9321,9 +9321,9 @@
} }
}, },
"node_modules/@vector-im/compound-web": { "node_modules/@vector-im/compound-web": {
"version": "0.4.0", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@vector-im/compound-web/-/compound-web-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@vector-im/compound-web/-/compound-web-0.4.1.tgz",
"integrity": "sha512-45pshpwpVBwOwIevKZrnWX718Z+qPvxnrSUv3KY4x4ej+PDMt8Qorxv1n98bB7fgF7vwBHK5PQdjq2kTFit+wQ==", "integrity": "sha512-F1KshkUANrapjSzgzmAnHEnNGnyo22ZVHeg0Kjt15Q6I8TuMlnFJ41F0R6GEVOOnsRFi/8DApnh1pB70BJ7OgA==",
"dependencies": { "dependencies": {
"@radix-ui/react-form": "^0.0.3", "@radix-ui/react-form": "^0.0.3",
"@radix-ui/react-tooltip": "^1.0.6", "@radix-ui/react-tooltip": "^1.0.6",

View File

@@ -25,7 +25,7 @@
"@urql/exchange-refocus": "^1.0.2", "@urql/exchange-refocus": "^1.0.2",
"@urql/exchange-request-policy": "^1.0.2", "@urql/exchange-request-policy": "^1.0.2",
"@vector-im/compound-design-tokens": "^0.0.5", "@vector-im/compound-design-tokens": "^0.0.5",
"@vector-im/compound-web": "^0.4.0", "@vector-im/compound-web": "^0.4.1",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
"graphql": "^16.8.0", "graphql": "^16.8.0",

View File

@@ -84,6 +84,16 @@ describe("<ConfirmationModal />", () => {
// no cancel button without onDeny // no cancel button without onDeny
expect(screen.queryByText("Cancel")).toBeFalsy(); expect(screen.queryByText("Cancel")).toBeFalsy();
// The dialog does not close on escape
fireEvent.keyDown(screen.getByRole("alertdialog"), {
key: "Escape",
code: "Escape",
keyCode: 27,
});
// dialog still open
expect(screen.queryByRole("alertdialog")).toBeTruthy();
}); });
it("calls onConfirm on confirmation", () => { it("calls onConfirm on confirmation", () => {

View File

@@ -25,7 +25,7 @@ import {
} from "@radix-ui/react-alert-dialog"; } from "@radix-ui/react-alert-dialog";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import classNames from "classnames"; import classNames from "classnames";
import { ReactNode, useState } from "react"; import { ReactNode } from "react";
import styles from "./ConfirmationModal.module.css"; import styles from "./ConfirmationModal.module.css";
@@ -40,7 +40,7 @@ type Props = {
/** /**
* Generic confirmation modal * Generic confirmation modal
* controls its own open state * controls its own open state
* calls onDeny on cancel, esc, or overlay click * calls onDeny on cancel or esc
* calls onConfirm on confirm click * calls onConfirm on confirm click
*/ */
const ConfirmationModal: React.FC<React.PropsWithChildren<Props>> = ({ const ConfirmationModal: React.FC<React.PropsWithChildren<Props>> = ({
@@ -50,49 +50,34 @@ const ConfirmationModal: React.FC<React.PropsWithChildren<Props>> = ({
children, children,
trigger, trigger,
title, title,
}) => { }) => (
const [isOpen, setIsOpen] = useState(false); <Root>
const onClose = (callback?: () => void) => (): void => {
setIsOpen(false);
callback?.();
};
// radix's autofocus doesn't work for some reason
// maybe https://www.radix-ui.com/primitives/docs/guides/composition#your-component-must-forward-ref
// when this is replaced with compound's own/wrapped dialog this should be fixed
// until then, focus the cancel button for a deniable modal
// and continue button otherwise
const onOpenAutoFocus = (e: Event): void => {
const focusButtonKind = onDeny ? "tertiary" : "destructive";
(e.target as Element)
?.querySelector<HTMLButtonElement>(
`button[data-kind="${focusButtonKind}"]`,
)
?.focus();
};
return (
<Root open={isOpen} onOpenChange={setIsOpen}>
<Trigger asChild>{trigger}</Trigger> <Trigger asChild>{trigger}</Trigger>
<Portal> <Portal>
<Overlay className={styles.overlay} onClick={onClose(onDeny)} /> <Overlay className={styles.overlay} />
<Content <Content
className={classNames(styles.content, className)} className={classNames(styles.content, className)}
onEscapeKeyDown={onClose(onDeny)} onEscapeKeyDown={(event): void => {
onOpenAutoFocus={onOpenAutoFocus} if (onDeny) {
onDeny();
} else {
// if there is no deny callback, we should prevent the escape key from closing the modal
event.preventDefault();
}
}}
> >
<Title>{title}</Title> <Title>{title}</Title>
<Description>{children}</Description> <Description>{children}</Description>
<div className={styles.buttons}> <div className={styles.buttons}>
{onDeny && ( {onDeny && (
<Cancel asChild> <Cancel asChild>
<Button kind="tertiary" size="sm" onClick={onClose(onDeny)}> <Button kind="tertiary" size="sm" onClick={onDeny}>
Cancel Cancel
</Button> </Button>
</Cancel> </Cancel>
)} )}
<Action asChild> <Action asChild>
<Button kind="destructive" size="sm" onClick={onClose(onConfirm)}> <Button kind="destructive" size="sm" onClick={onConfirm}>
Continue Continue
</Button> </Button>
</Action> </Action>
@@ -101,6 +86,5 @@ const ConfirmationModal: React.FC<React.PropsWithChildren<Props>> = ({
</Portal> </Portal>
</Root> </Root>
); );
};
export default ConfirmationModal; export default ConfirmationModal;