Accepted
Admin destructive actions used the browser's confirm(). Two problems:
- Bug. On
/admin/categories, Cancel still deleted. A synchronousconfirm()insideonsubmitcould not reliably suppress thefetchalready queued byuse:enhance. Categories cascade-delete items, so the blast radius was large. - UX. Native dialog was unthemed and ambiguous about which button is destructive. Some actions (deleting a whole category) warrant more friction than a single OK.
Wrapping the public Dialog.svelte was rejected: its hardcoded content-sized chrome doesn't fit an admin confirm, and wrapping would couple admin/public sizing.
- Built
src/lib/components/admin/ConfirmDialog.sveltedirectly on<dialog>. Cancel autofocused so accidental Enter never deletes. - Destructive actions drive imperatively from
onconfirm(fetch('?/...', …)thengoto/invalidateAll). Droppeduse:enhance+onsubmit={confirm(...)}for those forms — the race is impossible by construction. - Generic typed-confirmation mode via
requireTypedConfirmation/typedConfirmationLabel/typedConfirmationHintprops (slug-agnostic). Applied to category deletes (list + detail) where the cascade hits items. Single-item deletes, CMS reset, sort-by-score, and discard-unsaved kept as simple confirms. - Migrated every admin
confirm()call site (categories list, category detail, category create, items list, item form, CMS general).Button.sveltegotdisabled:styling so the typed-confirmation gate is visibly inactive. - E2E regressions:
admin-categories.e2e.tsexercises cancel-doesn't-delete, then drives the typed-confirmation gate (disabled by default, disabled on wrong text, enabled on correct slug).admin-items.e2e.tsadds a cancel-doesn't-delete check on the items list.
- Bug fixed by construction — no form submission is tied to the destructive click.
- Small
<dialog>open/close logic duplicated with publicDialog.svelteuntil a third caller justifies extracting a shareduseDialogaction — rule of three. Button.sveltenow disables visually via Tailwinddisabled:utilities; existingdisabledconsumers (CMS Save when over byte limit) get the styling for free.
Future typed-confirmation candidates (out of scope here): bulk operations, account deletion, destructive imports.