{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "dynamic-dialog-type-to-confirm", "title": "Dynamic type to confirm Dialog", "description": "A dynamic type to confirm dialog component.", "dependencies": [ "zod", "@hookform/resolvers", "react-hook-form" ], "registryDependencies": [ "dialog", "button", "input", "form", "Quackzoer/shadcn-registry/dynamic-dialog" ], "files": [ { "path": "components/dynamic-dialog/dialogs/type-to-confirm-dialog.tsx", "content": "\"use client\"\r\n\r\nimport React, { useId } from \"react\";\r\nimport {\r\n AlertDialog,\r\n AlertDialogContent,\r\n AlertDialogDescription,\r\n AlertDialogHeader,\r\n AlertDialogTitle,\r\n} from \"@/registry/ui/alert-dialog\";\r\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/registry/ui/form\";\r\nimport { Input } from \"@/registry/ui/input\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport { Trash2 } from \"lucide-react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { z } from \"zod\";\r\nimport { dialog, type DialogComponentProps } from \"@/registry/lib/dynamic-dialog-state\";\r\nimport {\r\n type DialogActionButton,\r\n type DialogActionsContainer,\r\n renderStandardDialogActions,\r\n} from \"@/lib/dynamic-dialog-actions\";\r\n\r\nexport interface TypeToConfirmDialogProps {\r\n itemName: string;\r\n actions?: TypeToConfirmActionsConfig;\r\n}\r\n\r\ntype ResolveValue = { itemName: string };\r\ntype TCtx = { isValid: boolean };\r\n\r\n// The confirm slot's disabled state comes from form validity — passed as context.\r\n// Users who override confirmButton with a callback receive (actions, ctx) where\r\n// ctx.isValid reflects the current input state.\r\nexport interface TypeToConfirmActionsConfig {\r\n cancelButton?: DialogActionButton;\r\n confirmButton?: DialogActionButton;\r\n container?: DialogActionsContainer;\r\n}\r\n\r\nexport function TypeToConfirmDialog(\r\n props: DialogComponentProps,\r\n) {\r\n const formId = useId();\r\n const schema = z.object({ itemName: z.literal(props.itemName) });\r\n const form = useForm({ resolver: zodResolver(schema), defaultValues: { itemName: \"\" } });\r\n\r\n const handleSubmit = (data: z.infer) => {\r\n props.confirm(data);\r\n };\r\n\r\n const ctx: TCtx = { isValid: form.formState.isValid };\r\n\r\n return (\r\n \r\n \r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n Delete Confirmation\r\n \r\n \r\n This action cannot be undone\r\n \r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n
\r\n

\r\n To confirm deletion of{\" \"}\r\n \r\n {props.itemName}\r\n \r\n , please type the exact name below:\r\n

\r\n (\r\n \r\n Type to confirm\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n />\r\n {form.watch(\"itemName\") && form.watch(\"itemName\") !== props.itemName && (\r\n

\r\n Text must match exactly:{\" \"}\r\n {props.itemName}\r\n

\r\n )}\r\n
\r\n
\r\n \r\n\r\n {renderStandardDialogActions(\r\n props.actions ?? {},\r\n props,\r\n ctx,\r\n {\r\n cancel: {\r\n label: \"Cancel\",\r\n variant: \"outline\",\r\n type: \"button\",\r\n onClick: (a) => a.dismiss(\"cancel\"),\r\n },\r\n confirm: {\r\n label: \"Delete Forever\",\r\n variant: \"destructive\",\r\n type: \"submit\",\r\n form: formId,\r\n // Disabled state comes from context so users who override this slot\r\n // via the callback form also receive ctx.isValid.\r\n disabled: !ctx.isValid,\r\n },\r\n },\r\n )}\r\n
\r\n
\r\n );\r\n}\r\n\r\nexport const typeToConfirmDialog = dialog(TypeToConfirmDialog);\r\n", "type": "registry:component", "target": "@components/dynamic-dialog/dialogs/type-to-confirm-dialog.tsx" } ], "type": "registry:component" }