diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/Basic.tsx index cbd78fc..513eede 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/Basic.tsx @@ -7,39 +7,21 @@ export const DeleteModalBasic: React.FunctionComponent = () => { const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false); const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false); - const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false); - - const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false); - const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false); - - const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => { + const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { setIsModalRecoverableOpen(!isModalRecoverableOpen); }; - const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { setIsModalDestructiveOpen(!isModalDestructiveOpen); }; - const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen); }; - const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen); - }; - - const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalModelRegistryOpen(!isModalModelRegistryOpen); - }; - - const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalPipelineServerOpen(!isModalPipelineServerOpen); - }; - return ( <> -
Modals with one item to delete
- -
- - -
Modals with custom delete messages
- - - - - - -
- handleModalRecoverableToggle(undefined)} deleteVariant="easily-recoverable" - item="user group" - itemName="my-team-abc" isOpen={isModalRecoverableOpen} onClose={handleModalRecoverableToggle} - /> + > + User group 123 will be deleted. + handleModalDestructiveToggle(undefined)} deleteVariant="destructive" - item="pipeline" - itemName="pipeline_456" isOpen={isModalDestructiveOpen} onClose={handleModalDestructiveToggle} - /> + > + Experiment cool-exp will be deleted. + handleModalExtraDestructiveToggle(undefined)} deleteVariant="extra-destructive" - item="project" - itemName="super-123-project" isOpen={isModalExtraDestructiveOpen} onClose={handleModalExtraDestructiveToggle} - /> - - {/* Modals with multiple items to delete */} - - - {/* Modals with custom delete messages */} - - + > + Project RedHatAwesome will be deleted. + ); }; diff --git a/packages/module/patternfly-docs/content/examples/basic.md b/packages/module/patternfly-docs/content/examples/basic.md index 31e66de..db04270 100644 --- a/packages/module/patternfly-docs/content/examples/basic.md +++ b/packages/module/patternfly-docs/content/examples/basic.md @@ -28,3 +28,143 @@ import { DeleteModal } from "@patternfly/ai-infra-ui-components"; ```js file="./Basic.tsx" isFullscreen ``` + +### DeleteModal implementation + +```ts +import React from 'react'; +import { + Alert, + AlertProps, + Button, + Flex, + FlexItem, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ModalProps, + Stack, + StackItem, + TextInput, + TextInputProps +} from '@patternfly/react-core'; + +export type DeleteModalProps = ModalProps & { + /** Content rendered inside the modal header title. */ + title: React.ReactNode; + /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ + deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; + /** Text which the user should type in to confirm deletion (only for extra-destructive delete variant) */ + deleteName: string; + /** Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant) */ + confirmationMessage?: (deleteName: string) => React.ReactNode; + /** Text of the delete button */ + deleteButtonText?: string; + /** Text of the cancel button */ + cancelButtonText?: string; + /** Callback on clicking the delete button */ + onDelete: () => void; + /** Flag indicating that deletion is currently in progress */ + isDeleting?: boolean; + /** Error indicating deletion has failed */ + error?: Error; + /** Id of the modal for testing purposes (defaults to "delete-modal") */ + testId?: string; + /** Additional props for confirmation text input (only for extra-destructive delete variant) */ + textInputProps?: TextInputProps; + /** Additional props for error alert */ + errorAlertProps?: AlertProps; + /** Modal ref */ + ref?: React.RefObject; +}; + +export const DeleteModal: React.FunctionComponent = ({ + children, + title, + deleteVariant = 'extra-destructive', + deleteName, + confirmationMessage = (deleteName) => ( + <> + Type {deleteName} to confirm deletion: + + ), + deleteButtonText = 'Delete', + cancelButtonText = 'Cancel', + onDelete, + isDeleting, + error, + testId, + textInputProps, + errorAlertProps, + onClose, + isOpen, + ...props +}: DeleteModalProps) => { + const [confirmationText, setConfirmationText] = React.useState(''); + const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true; + + React.useEffect(() => { + if (!isOpen) { + setConfirmationText(''); + } + }, [isOpen]); + + return ( + + + + + {children} + {deleteVariant === 'extra-destructive' && ( + + + {confirmationMessage(deleteName)} + setConfirmationText(value)} + onKeyDown={(event) => { + if (event.key === 'Enter' && confirmed && !isDeleting) { + event.preventDefault(); + onDelete(); + } + }} + /> + + + )} + {error && ( + + + {error.message} + + + )} + + + + + + + + ); +}; + +``` diff --git a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js index 2f20f82..d06d9a3 100644 --- a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js +++ b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js @@ -32,11 +32,35 @@ const pageData = { "name": "DeleteModal", "description": "", "props": [ + { + "name": "cancelButtonText", + "type": "string", + "description": "Text of the cancel button", + "defaultValue": "'Cancel'" + }, + { + "name": "confirmationMessage", + "type": "(deleteName: string) => React.ReactNode", + "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", + "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" + }, + { + "name": "deleteButtonText", + "type": "string", + "description": "Text of the delete button", + "defaultValue": "'Delete'" + }, + { + "name": "deleteName", + "type": "string", + "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", + "required": true + }, { "name": "deleteVariant", "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", - "defaultValue": "'destructive'" + "defaultValue": "'extra-destructive'" }, { "name": "error", @@ -44,26 +68,48 @@ const pageData = { "description": "Error indicating deletion has failed" }, { - "name": "message", - "type": "{\n toDelete?: string;\n resourcesToDelete?: string;\n endNote?: string;\n}", - "description": "Message describing what will deleted", - "defaultValue": "{\n resourcesToDelete: '',\n endNote: ''\n}" + "name": "errorAlertProps", + "type": "AlertProps", + "description": "Additional props for error alert" }, { - "name": "onCancel", - "type": "() => void", - "description": "Callback on clicking the cancel button" + "name": "isDeleting", + "type": "boolean", + "description": "Flag indicating that deletion is currently in progress" }, { "name": "onDelete", "type": "() => void", - "description": "Callback on clicking the delete button" + "description": "Callback on clicking the delete button", + "required": true + }, + { + "name": "ref", + "type": "React.RefObject", + "description": "Modal ref" + }, + { + "name": "testId", + "type": "string", + "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" + }, + { + "name": "textInputProps", + "type": "TextInputProps", + "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" + }, + { + "name": "title", + "type": "React.ReactNode", + "description": "Content rendered inside the modal header title.", + "required": true } ] } ], "examples": [ - "Example" + "Example", + "DeleteModal implementation" ], "fullscreenExamples": [ "Fullscreen example" @@ -75,11 +121,15 @@ pageData.liveContext = { }; pageData.examples = { 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false);\n\n const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false);\n const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen);\n };\n\n const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalModelRegistryOpen(!isModalModelRegistryOpen);\n };\n\n const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalPipelineServerOpen(!isModalPipelineServerOpen);\n };\n\n return (\n <>\n \n
Modals with one item to delete
\n \n \n \n \n \n \n \n \n \n
\n\n \n
Modals with multiple items to delete
\n \n \n \n
\n\n \n
Modals with custom delete messages
\n \n \n \n \n \n \n
\n\n \n \n \n\n {/* Modals with multiple items to delete */}\n \n\n {/* Modals with custom delete messages */}\n \n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n User group 123 will be deleted.\n
\n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n Experiment cool-exp will be deleted.\n
\n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n Project RedHatAwesome will be deleted.\n
\n \n );\n};\n","title":"Example","lang":"js","className":""}}> , 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false);\n\n const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false);\n const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen);\n };\n\n const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalModelRegistryOpen(!isModalModelRegistryOpen);\n };\n\n const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalPipelineServerOpen(!isModalPipelineServerOpen);\n };\n\n return (\n <>\n \n
Modals with one item to delete
\n \n \n \n \n \n \n \n \n \n
\n\n \n
Modals with multiple items to delete
\n \n \n \n
\n\n \n
Modals with custom delete messages
\n \n \n \n \n \n \n
\n\n \n \n \n\n {/* Modals with multiple items to delete */}\n \n\n {/* Modals with custom delete messages */}\n \n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n User group 123 will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n Experiment cool-exp will be deleted.\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n Project RedHatAwesome will be deleted.\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + + , + 'DeleteModal implementation': props => + React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> }; @@ -91,6 +141,7 @@ const Component = () => ( {React.createElement(pageData.examples["Example"])} {React.createElement(pageData.examples["Fullscreen example"])} + {React.createElement(pageData.examples["DeleteModal implementation"])} ); Component.displayName = 'ExtensionsAiInfraUiComponentsReactDocs'; diff --git a/packages/module/patternfly-docs/generated/index.js b/packages/module/patternfly-docs/generated/index.js index 61e8536..db67d53 100644 --- a/packages/module/patternfly-docs/generated/index.js +++ b/packages/module/patternfly-docs/generated/index.js @@ -2,8 +2,8 @@ module.exports = { '/extensions/ai-infra-ui-components/react': { id: "AI-infra-ui-components", title: "AI-infra-ui-components", - toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"}]], - examples: ["Example"], + toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"},{"text":"DeleteModal implementation"}]], + examples: ["Example","DeleteModal implementation"], fullscreenExamples: ["Fullscreen example"], section: "extensions", subsection: "", diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx index 17acee1..1099ff0 100644 --- a/packages/module/src/DeleteModal/DeleteModal.tsx +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { Alert, + AlertProps, Button, - FormGroup, - List, - ListItem, + Flex, + FlexItem, Modal, ModalBody, ModalFooter, @@ -12,144 +12,122 @@ import { ModalProps, Stack, StackItem, - TextInput + TextInput, + TextInputProps } from '@patternfly/react-core'; -/** Props specifying either one item or a list of items to delete */ -type ItemProps = - | { - /** Type of item to delete (e.g. project, pipeline server, model registry) */ - item: string; - /** Name of the item to delete */ - itemName: string; - items?: never; - itemNames?: never; - } - | { - /** Type of items to delete in plural (e.g. projects, pipeline servers, model registries) */ - items: string; - /** List of names of the items to delete */ - itemNames: string[]; - item?: never; - itemName?: never; - }; - -export type DeleteModalProps = Omit & - ItemProps & { - /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ - deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; - /** Message describing what will deleted */ - message?: { - toDelete?: string; - resourcesToDelete?: string; - endNote?: string; - }; - /** Callback on clicking the delete button */ - onDelete?: () => void; - /** Callback on clicking the cancel button */ - onCancel?: () => void; - /** Error indicating deletion has failed */ - error?: Error; - /** Modal ref */ - ref: React.RefObject; - }; +export type DeleteModalProps = ModalProps & { + /** Content rendered inside the modal header title. */ + title: React.ReactNode; + /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ + deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; + /** Text which the user should type in to confirm deletion (only for extra-destructive delete variant) */ + deleteName: string; + /** Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant) */ + confirmationMessage?: (deleteName: string) => React.ReactNode; + /** Text of the delete button */ + deleteButtonText?: string; + /** Text of the cancel button */ + cancelButtonText?: string; + /** Callback on clicking the delete button */ + onDelete: () => void; + /** Flag indicating that deletion is currently in progress */ + isDeleting?: boolean; + /** Error indicating deletion has failed */ + error?: Error; + /** Id of the modal for testing purposes (defaults to "delete-modal") */ + testId?: string; + /** Additional props for confirmation text input (only for extra-destructive delete variant) */ + textInputProps?: TextInputProps; + /** Additional props for error alert */ + errorAlertProps?: AlertProps; + /** Modal ref */ + ref?: React.RefObject; +}; export const DeleteModal: React.FunctionComponent = ({ - item, - items, - itemName, - itemNames, - deleteVariant = 'destructive', + children, + title, + deleteVariant = 'extra-destructive', + deleteName, + confirmationMessage = (deleteName) => ( + <> + Type {deleteName} to confirm deletion: + + ), + deleteButtonText = 'Delete', + cancelButtonText = 'Cancel', onDelete, - onCancel, - message = { - resourcesToDelete: '', - endNote: '' - }, + isDeleting, error, + testId, + textInputProps, + errorAlertProps, + onClose, + isOpen, ...props }: DeleteModalProps) => { - const isPlural = item === undefined; - const [confirmationText, setConfirmationText] = React.useState(''); - const expectedConfirmationText = isPlural ? `delete ${itemNames.length} ${items}` : itemName; - - const confirmed = deleteVariant === 'extra-destructive' ? confirmationText === expectedConfirmationText : true; - - const toDeleteMessage = message.toDelete ?? ` and all of ${isPlural ? 'their' : 'its'} resources`; + const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true; - const itemToDelete = `${itemNames ? `${itemNames.length} ` : ''}${item ?? items}`; - const modalHeaderTitle = `Delete ${itemToDelete}?`; + React.useEffect(() => { + if (!isOpen) { + setConfirmationText(''); + } + }, [isOpen]); return ( - - + + - - The{' '} - {isPlural ? ( - `following ${items}` - ) : ( - <> - {itemName} {item} - - )} - {toDeleteMessage} - {message.resourcesToDelete} will be deleted{isPlural && !message.endNote ? ':' : '.'} {message.endNote} - {isPlural && ( - - {itemNames.map((name) => ( - - {name} - - ))} - - )} - + {children} {deleteVariant === 'extra-destructive' && ( - - Type {expectedConfirmationText} to confirm deletion: - - } - > + + {confirmationMessage(deleteName)} setConfirmationText(value)} - // validated={confirmed ? 'success' : 'default'} + onKeyDown={(event) => { + if (event.key === 'Enter' && confirmed && !isDeleting) { + event.preventDefault(); + onDelete(); + } + }} /> - + + + )} + {error && ( + + + {error.message} + )} - - {error && ( - - {error.message} - - )} );