Covers drag & drop, side-by-side preview, and snapshot-based undo/redo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
135 lines
4.5 KiB
Markdown
135 lines
4.5 KiB
Markdown
# 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 variable `dragSourceIndex`
|
|
- `dragover`: Calculates drop position (above/below element center), shows CSS indicator
|
|
- `dragleave`: Removes drop indicator
|
|
- `drop`: Reorders `draft.fields` array, calls `this.render()`
|
|
- Instance variable `dragSourceIndex: number | null` tracks 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.4` during 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()` from `field-renderers.ts` for 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.app` for 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-width` increased from 700px to 1100px
|
|
- Footer spans full width below the grid
|
|
|
|
---
|
|
|
|
## 3. Snapshot-Based Undo/Redo
|
|
|
|
### State
|
|
|
|
New instance variables on `FormBuilderModal`:
|
|
|
|
```typescript
|
|
private history: FormDefinition[] = [];
|
|
private historyIndex: number = 0;
|
|
```
|
|
|
|
### Methods
|
|
|
|
- `pushSnapshot()` — `structuredClone(this.draft)` pushed to history. Truncates forward history (everything after `historyIndex`). Max 30 entries.
|
|
- `undo()` — Decrements `historyIndex`, restores draft from snapshot, calls `render()`
|
|
- `redo()` — Increments `historyIndex`, restores draft from snapshot, calls `render()`
|
|
|
|
### 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` → undo
|
|
- `Ctrl+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
|