(null);
+
+// Child notifies parent of dirty state
+useEffect(() => {
+ onHasChangesUpdate?.(computedHasChanges);
+}, [computedHasChanges, onHasChangesUpdate]);
+
+// Intercept navigation
+const handleSelect = (id: string) => {
+ if (editorHasChanges && currentId !== id) {
+ setPendingSwitch(id); // Show confirmation dialog
+ } else {
+ setCurrentId(id);
+ }
+};
+```
+
+**Flow**:
+1. Child computes `hasChanges` from local state vs saved data
+2. Child notifies parent via callback
+3. Parent intercepts navigation when dirty
+4. Show confirmation dialog: "Discard & Switch" or "Cancel"
+5. On confirm: reset dirty state, then switch
+
+### Pattern 3: Auto-Save with Visual Feedback
+
+**Use when**: Simple inputs that should save immediately.
+
+```typescript
+const [saved, setSaved] = useState(false);
+
+const handleBlur = async () => {
+ if (value !== savedValue) {
+ await saveToBackend(value);
+ setSaved(true);
+ setTimeout(() => setSaved(false), 2000);
+ }
+};
+
+return (
+
+
+ {saved && (
+
+ Saved
+
+ )}
+
+);
+```
+
+**When to use which**:
+| Scenario | Pattern |
+|----------|---------|
+| Complex multi-field editor | Pattern 2 (confirmation dialog) |
+| Simple single input | Pattern 3 (auto-save + feedback) |
+| List item selection | Pattern 1 (key-based remount) + Pattern 2 |
+
+---
+
## Quality Gates
### Pre-Commit Sequence