diff --git a/src/hooks/dialog/dialog.stories.tsx b/src/hooks/dialog/dialog.stories.tsx index 9e47938..5479f7d 100644 --- a/src/hooks/dialog/dialog.stories.tsx +++ b/src/hooks/dialog/dialog.stories.tsx @@ -98,6 +98,8 @@ export const Prompt: Story = { "Annuleren", args.onConfirm, args.onCancel, + undefined, + true, ) } > diff --git a/src/hooks/dialog/useFormDialog.tsx b/src/hooks/dialog/useFormDialog.tsx new file mode 100644 index 0000000..f59dabd --- /dev/null +++ b/src/hooks/dialog/useFormDialog.tsx @@ -0,0 +1,123 @@ +import React, { useContext, useEffect } from "react"; + +import { Form, FormProps, ModalProps, P } from "../../components"; +import { ModalServiceContext } from "../../contexts"; +import { AttributeData, FormField } from "../../lib"; +import { useDialog } from "./usedialog"; + +/** + * Returns a function which, when called: shows a form dialog with a + * confirmation callback and an optional cancellation callback. + */ +export const useFormDialog = () => { + const dialog = useDialog(); + + /** + * Shows a prompt dialog with a confirmation callback and an optional + * cancellation callback. + * @param title + * @param message + * @param fields + * @param labelConfirm + * @param labelCancel + * @param onConfirm + * @param onCancel + * @param modalProps + * @param formProps + * @param autofocus + */ + const fn = ( + title: string, + message: React.ReactNode, + fields: FormField[], + labelConfirm: string, + labelCancel: string, + onConfirm: (data: AttributeData) => void, + onCancel?: () => void, + modalProps?: Partial, + formProps?: FormProps, + autofocus?: boolean, + ) => { + dialog( + title, + <> + {typeof message === "string" ?

{message}

: message} + + , + undefined, + { allowClose: false, ...modalProps }, + ); + }; + + return fn; +}; + +const PromptForm = ({ + fields, + labelConfirm, + labelCancel, + onConfirm, + onCancel, + formProps, + autofocus = false, +}: { + message: React.ReactNode; + fields: FormField[]; + labelConfirm: string; + labelCancel: string; + onConfirm: (data: AttributeData) => void; + onCancel?: () => void; + formProps?: FormProps; + autofocus?: boolean; +}) => { + const { setModalProps } = useContext(ModalServiceContext); + + useEffect(() => { + if (!autofocus) return; + // Delay the focus slightly to ensure modal and form are fully rendered + const timer = setTimeout(() => { + // We focus a form element, and if none are found, we focus the submit button, and otherwise none + const formElement: HTMLFormElement | null = document.querySelector( + "form input , form textarea , form select , form button[type=submit]", + ); + if (formElement) { + formElement.focus(); + } + }, 100); + + return () => clearTimeout(timer); + }, []); + + return ( +
{ + setModalProps({ open: false }); + onCancel?.(); + }, + }, + ]} + validateOnChange={true} + onSubmit={(_, data) => { + setModalProps({ open: false }); + onConfirm(data); + }} + {...formProps} + /> + ); +}; diff --git a/src/hooks/dialog/useprompt.tsx b/src/hooks/dialog/useprompt.tsx index cc3e548..b6d66d9 100644 --- a/src/hooks/dialog/useprompt.tsx +++ b/src/hooks/dialog/useprompt.tsx @@ -1,16 +1,15 @@ -import React, { useContext } from "react"; +import React from "react"; -import { Form, ModalProps, P } from "../../components"; -import { ModalServiceContext } from "../../contexts"; -import { useDialog } from "./usedialog"; +import { ModalProps } from "../../components"; +import { FormField } from "../../lib"; +import { useFormDialog } from "./useFormDialog"; /** * Returns a function which, when called: shows a prompt dialog with a * confirmation callback and an optional cancellation callback. */ export const usePrompt = () => { - const dialog = useDialog(); - const { setModalProps } = useContext(ModalServiceContext); + const formDialog = useFormDialog(); /** * Shows a prompt dialog with a confirmation callback and an optional @@ -23,6 +22,7 @@ export const usePrompt = () => { * @param onConfirm * @param onCancel * @param modalProps + * @param autofocus */ const fn = ( title: string, @@ -33,34 +33,31 @@ export const usePrompt = () => { onConfirm: (message: string) => void, onCancel?: () => void, modalProps?: Partial, + autofocus?: boolean, ) => { - dialog( + const fields: FormField[] = [ + { + label, + name: "message", + required: true, + type: "text", + }, + ]; + + formDialog( title, - <> - {typeof message === "string" ?

{message}

: message} - { - setModalProps({ open: false }); - onCancel?.(); - }, - }, - ]} - validateOnChange={true} - onSubmit={(_, { message }) => { - setModalProps({ open: false }); - onConfirm(message as string); - }} - /> - , + message, + fields, + labelConfirm, + labelCancel, + (data) => { + const message = data.message as string; + onConfirm(message); + }, + onCancel, + modalProps, undefined, - { allowClose: false, ...modalProps }, + autofocus, ); };