Covers drag & drop, side-by-side preview, and snapshot-based undo/redo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.5 KiB
4.5 KiB
Phase 2 — Builder Upgrade Design
Status: Approved Date: 2026-02-13 Scope: Drag & drop field reordering, side-by-side live preview, snapshot-based undo/redo
Overview
Phase 2 upgrades the FormBuilderModal with three features that transform it from a basic editor into a polished builder experience. All changes are scoped to form-builder.ts and styles.css, with no new modules needed.
1. Drag & Drop Field Reordering
Implementation
Native HTML5 Drag & Drop on .ff-builder-field elements:
- Each field gets
draggable="true"and a drag handle (⠿gripper icon) in the header dragstart: Stores source index in instance variabledragSourceIndexdragover: Calculates drop position (above/below element center), shows CSS indicatordragleave: Removes drop indicatordrop: Reordersdraft.fieldsarray, callsthis.render()- Instance variable
dragSourceIndex: number | nulltracks the dragged field
Existing Up/Down buttons remain
They serve as accessibility fallback for keyboard-only users.
CSS Classes
.ff-drag-handle— Gripper icon,cursor: grab, left of field number.ff-builder-field.ff-dragging—opacity: 0.4during drag.ff-builder-field.ff-drop-above— Blue top border indicator line.ff-builder-field.ff-drop-below— Blue bottom border indicator line
2. Side-by-Side Live Preview
Layout
The render() method creates a two-column grid layout:
┌─────────────────────────────────────────────┐
│ Form Settings (h2) │
├──────────────────────┬──────────────────────┤
│ Editor (left) │ Preview (right) │
│ - General settings │ - Form title │
│ - Fields list │ - Rendered fields │
│ - Add field button │ - Submit button │
├──────────────────────┴──────────────────────┤
│ Footer: Undo/Redo | Cancel | Save │
└─────────────────────────────────────────────┘
Preview Panel
- Calls existing
renderField()fromfield-renderers.tsfor each field - Fields are fully interactive (users can test how they feel)
- Shows form title and a disabled pseudo-submit button
- Automatically updates on every
render()call (no separate mechanism) - Uses
this.appfor note-link and folder-picker autocomplete
CSS Changes
.ff-builder-layout—display: grid; grid-template-columns: 1fr 1fr; gap: 24px.ff-builder-preview—border-left,padding-left, sticky "Preview" header.ff-builder-modal—max-widthincreased from 700px to 1100px- Footer spans full width below the grid
3. Snapshot-Based Undo/Redo
State
New instance variables on FormBuilderModal:
private history: FormDefinition[] = [];
private historyIndex: number = 0;
Methods
pushSnapshot()—structuredClone(this.draft)pushed to history. Truncates forward history (everything afterhistoryIndex). Max 30 entries.undo()— DecrementshistoryIndex, restores draft from snapshot, callsrender()redo()— IncrementshistoryIndex, restores draft from snapshot, callsrender()
When snapshots are pushed
Before mutations that trigger render():
- Add field
- Delete field
- Move field (drag & drop, up/down)
- Change field type
- Change form mode (create/update)
NOT on every keystroke — only on change events (blur/enter) for text inputs.
Keyboard Shortcuts
Ctrl+Z/Cmd+Z→ undoCtrl+Shift+Z/Cmd+Shift+Z→ redo- Keydown listener on
contentEl
Visual Indicators
- Undo (
↩) and Redo (↪) buttons in footer, left-aligned (before Cancel/Save) - Buttons are disabled when at start/end of history stack
Initialization
Constructor pushes first snapshot of original form state.
Files Changed
| File | Change |
|---|---|
src/ui/form-builder.ts |
Drag & drop, preview panel, undo/redo — major rewrite |
styles.css |
DnD indicators, grid layout, preview panel, undo/redo buttons |
Out of Scope
- Undo for individual text keystrokes (browser-native handles this)
- External undo manager utility
- Drag & drop between forms
- Preview in a separate modal/window
- Collapsible preview panel