obsidian-formfire/docs/plans/2026-02-13-phase2-builder-upgrade-design.md
tolvitty b8f275e78d docs: add Phase 2 builder upgrade design document
Covers drag & drop, side-by-side preview, and snapshot-based undo/redo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:30:01 +01:00

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 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-draggingopacity: 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-layoutdisplay: grid; grid-template-columns: 1fr 1fr; gap: 24px
  • .ff-builder-previewborder-left, padding-left, sticky "Preview" header
  • .ff-builder-modalmax-width increased 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 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