SheetForm dirty-state confirm + wire isDirty into all form consumers (R4.5)
SheetForm gains an isDirty prop. When true, any close attempt (Cancel button, header X, Radix overlay click, Escape) opens a 'Discard changes?' ConfirmDialog instead of discarding unsaved edits. Radix dismiss callbacks (onEscapeKeyDown, onPointerDownOutside) are intercepted when dirty so the guard applies uniformly. All four form consumers now compute and pass isDirty: - ServicePage: name/enabled/config differ from the persisted instance. - Settings machine editor: field-by-field draft vs editingMachine (create mode is always dirty; secret write-only fields excluded). - Message compose: subject non-empty, body differs from default, or attachments present. - WidgetConfigDialog: draft !== null (only draft mode is guarded; list mode has nothing to discard). Tests: 3 new SheetForm dirty-guard cases (prompt on cancel, abort discard, clean close when not dirty) + one focused dirty-guard test per consumer. 122 tests pass; lint/build green. Refs openspec/changes/mobile-responsive-parity/verify-report.md residual risk #1.
This commit is contained in:
@@ -315,7 +315,7 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="widget-enabled"
|
||||
className="mobile-touch-target"
|
||||
className="mobile-touch-target"
|
||||
checked={draft.enabled}
|
||||
onCheckedChange={(checked) =>
|
||||
setDraft({ ...draft, enabled: checked })
|
||||
@@ -394,8 +394,8 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</Button>
|
||||
<Switch
|
||||
className="mobile-touch-target"
|
||||
checked={instance.enabled}
|
||||
className="mobile-touch-target"
|
||||
checked={instance.enabled}
|
||||
onCheckedChange={() => toggleEnabled(instance)}
|
||||
aria-label={`Toggle ${instance.title}`}
|
||||
/>
|
||||
@@ -479,6 +479,7 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
onCancel={draft ? reset : () => handleClose(false)}
|
||||
saveLabel={draft ? "Save widget" : "Done"}
|
||||
isPending={draft ? saveWidget.isPending : false}
|
||||
isDirty={draft !== null}
|
||||
>
|
||||
<div className="flex flex-col gap-4">{draftBody}</div>
|
||||
</SheetForm>
|
||||
|
||||
Reference in New Issue
Block a user