Skip to content

feat: dnd-kit + Tiptap spike harness (#268) - #282

Merged
ViewFromTheBox merged 2 commits into
add/phase-onefrom
feature/268-dnd-kit-spike-harness
Apr 13, 2026
Merged

ViewFromTheBox merged 2 commits into
add/phase-onefrom
feature/268-dnd-kit-spike-harness

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented Apr 13, 2026 •

Copy link
Copy Markdown
Member

Description

Phase 1.6 de-risking spike for #237. Validates that @dnd-kit/core +
@dnd-kit/sortable coexist cleanly with @tiptap/react before #271
integrates dnd-kit into the production BlockList. The harness lives
under resources/js/visual-editor/editor/__dnd-kit-spike__/, reuses the
same useTiptap hook production blocks use, and is excluded from the
editor bundle (dist/editor/main.js stays 1.20 kB).

Closes: #268

Type of Change

  • New feature (adds new functionality)

Related Issue

Issue: #268

Motivation and Context

PHASE-0-FINDINGS.md finding #3 flagged that the Phase 0 spike never
integrated dnd-kit, so we had no empirical signal on Tiptap + dnd-kit
interactions (sensor conflicts, DOM ownership, drag handles inside
contenteditable regions). #268 is the throwaway harness that answers
those questions before #271 commits production code to a specific
dnd-kit integration shape.

Changes Made

  • Add @dnd-kit/core and @dnd-kit/sortable as deps
  • New DndKitSpike harness with 4 sortable blocks, each backed by
    useTiptap — separate handle DOM, PointerSensor with 8px distance
    threshold, KeyboardSensor with sortableKeyboardCoordinates
  • Dev-only mount at /__dnd-kit-spike__/ under npm run dev:editor;
    excluded from build:editor via rollupOptions.input
  • Add @spike alias in vite.editor.config.ts to reuse the Phase 0
    useTiptap hook
  • Vitest coverage for the four interaction checks
  • docs/phase-1-dnd-kit-findings.md with decision, constraints for
    Phase 1.9: dnd-kit integration in production BlockList (top-level) #271, and known gaps (nested sortables, drop indicators, a11y
    announcements)

How Has This Been Tested?

Testing Environment:

  • Operating System: macOS (Darwin 25.3.0)
  • Browser: Chrome/Safari via npm run dev:editor
  • PHP Version: n/a (frontend-only change)
  • Project Version: 1.0.0-spike

Tests Performed:

  1. npm test — 113 tests across 12 files, all green (4 new tests for
    the spike harness)
  2. npm run build:editor — verified dist/editor/main.js stays 1.20 kB,
    confirming the spike is excluded from the editor bundle
  3. Manual browser test at /__dnd-kit-spike__/:
    • Text selection inside a block does not trigger drag
    • Clicking the handle without moving does not start a drag (8px
      activation threshold works)
    • Reordering a block after editing its content preserves the edits
      in the dragged block and leaves other blocks' Tiptap state
      untouched
    • Keyboard drag via Tab → Space → Arrow keys → Space works; typing
      inside Tiptap does not trigger the keyboard sensor

Accessibility Tests Run

  • Keyboard navigation tested
  • Screen reader tested
  • Color contrast verified
  • ARIA labels checked

Details: Keyboard drag through KeyboardSensor was exercised
manually. Accessibility announcements (DragOverlay + announcements
prop) are out of scope for this spike and explicitly flagged in the
findings doc as a must-land-with-#271 item. The harness is throwaway
dev-only code.

Tests Added

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests passing

Test details: DndKitSpike.test.tsx covers: (1) Tiptap editor
mounts inside every sortable block, (2) drag handle and Tiptap DOM are
siblings rather than ancestors, (3) editor state stays independent per
block through edits, (4) pointer + keyboard sensors register without
throwing. Full suite: 113 passing.

Documentation

  • Inline code documentation added
  • README updated
  • Wiki updated
  • API documentation updated

Documentation details: docs/phase-1-dnd-kit-findings.md documents
the decision (🟢 green light for #271), per-check results, constraints
#271 must carry forward, and known gaps. The harness folder is named
__dnd-kit-spike__ to signal throwaway status.

Screenshots

n/a — dev-only harness.

Pre-Submission Checklist

  • Followed contributing guidelines
  • Checked for other open PRs for same update
  • Code passes all tests
  • Code has been linted
  • Accessibility tests completed (keyboard only; see note above)
  • Code follows project style guide
  • Self-review completed
  • Comments added for complex code
  • No new warnings generated

Summary by CodeRabbit

  • Documentation

    • Added findings and a “GREEN LIGHT” decision for integrating drag‑and‑drop with rich‑text editing, plus known gaps and a carry‑forward checklist.
  • New Features

    • Introduced a dev‑only interactive spike for drag‑and‑drop reordering with editable rich‑text blocks (handle-based activation, keyboard/pointer sensors).
  • Chores

    • Added dnd‑kit dependencies, a dev entrypoint and styles, new module alias, and test coverage for the spike harness; harness excluded from production build.

Validate that @dnd-kit/core + @dnd-kit/sortable coexist with @tiptap/react
before #271 integrates dnd-kit into production BlockList. The harness lives
under resources/js/visual-editor/editor/__dnd-kit-spike__/, reuses the same
useTiptap hook production blocks use, and is excluded from the editor
bundle via rollupOptions.input (dist/editor/main.js stays 1.20 kB).

All four interaction checks from PHASE-0-FINDINGS.md finding #3 pass:
drag handles do not interfere with Tiptap text selection, pointer sensor
uses an 8px distance threshold to avoid contenteditable conflicts, stable
id-keyed reorders preserve Tiptap state in remaining blocks, and the
keyboard sensor is scoped to the handle so Tiptap keyboard handling is
never hijacked. Findings and carry-forward constraints for #271 are
documented in docs/phase-1-dnd-kit-findings.md.

Closes #268
@coderabbitai

coderabbitai Bot commented Apr 13, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 15a98b35-ece5-4e81-b984-2be37dc69f21

📥 Commits

Reviewing files that changed from the base of the PR and between d418aad and cf3c167.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
📒 Files selected for processing (1)
  • package.json
✅ Files skipped from review due to trivial changes (1)
  • package.json

📝 Walkthrough

Walkthrough

Adds a dev-only drag-and-drop spike harness integrating @dnd-kit and @tiptap/react to validate sensor coexistence, DOM interaction, and state preservation. Includes components, tests, docs, CSS, a dev entrypoint, and a Vite alias; the harness is excluded from the production editor bundle.

Changes

Cohort / File(s) Summary
Documentation
docs/phase-1-dnd-kit-findings.md
Documents a "GREEN LIGHT" for @dnd-kit + Tiptap in the BlockList with a structural invariant (handle activator and Tiptap contenteditable in separate DOM subtrees), records sensor constraints (8px pointer activation, touch-action: none on handle), test results, known gaps, and carry-forward checklist.
Dependencies
package.json
Added runtime deps: @dnd-kit/core, @dnd-kit/sortable, and @dnd-kit/utilities.
Spike Components
resources/js/visual-editor/editor/__dnd-kit-spike__/DndKitSpike.tsx, resources/js/visual-editor/editor/__dnd-kit-spike__/SpikeBlock.tsx
New spike harness and block components using DndContext, pointer (8px activation) and keyboard sensors, useSortable for handles, Tiptap editors per block, and reorder logic via arrayMove; handle is a separate DOM subtree from the editor.
Spike Tests
resources/js/visual-editor/editor/__dnd-kit-spike__/__tests__/DndKitSpike.test.tsx
Adds Vitest/JSDOM tests verifying editors mount per block, handle-vs-editor DOM separation, per-block Tiptap state isolation across edits/reorders, and successful sensor registration.
Spike Entrypoint & Assets
resources/js/visual-editor/editor/__dnd-kit-spike__/main.tsx, resources/js/visual-editor/editor/__dnd-kit-spike__/index.html, resources/js/visual-editor/editor/__dnd-kit-spike__/spike.css
Dev-only HTML mount, React entrypoint mounting DndKitSpike, and CSS for layout, handle styling (touch-action: none, grab cursor), and rich-text presentation.
Build Configuration
vite.editor.config.ts
Added @spike path alias resolving to resources/js/editor-spike for dev build/module resolution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #277: Modifies the visual-editor Vite configuration and dev entrypoints — related change to editor build/aliasing and dev scaffolding.

Poem

🐰
I hopped in with keyboard, handle, and cheer,
Tiptap and dnd-kit dance, no fear.
Handles apart, editors stay true—
Reordered, saved, the state grew.
Spike says yes, green light anew!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a dnd-kit + Tiptap spike harness for validation before production integration.
Linked Issues check ✅ Passed The PR fully addresses all coding objectives from #268: harness setup complete with DndKitSpike/SpikeBlock components, dev-only mounting and build exclusion configured, all four interaction checks implemented and tested, and findings documentation provided.
Out of Scope Changes check ✅ Passed All changes are directly aligned with #268 spike objectives; no unrelated modifications to production code or unscoped feature work detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/268-dnd-kit-spike-harness

Comment @coderabbitai help to get the list of available commands and usage tips.

@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review April 13, 2026 22:28
@ViewFromTheBox ViewFromTheBox linked an issue Apr 13, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
package.json (1)

27-34: ⚠️ Potential issue | 🟠 Major

Add explicit @dnd-kit/utilities dependency

SpikeBlock.tsx directly imports @dnd-kit/utilities, but it is not declared in dependencies. Relying on transitive installs is brittle and can break with strict package manager layouts.

🔧 Proposed fix
     "dependencies": {
         "@dnd-kit/core": "^6.3.1",
         "@dnd-kit/sortable": "^10.0.0",
+        "@dnd-kit/utilities": "^3.2.2",
         "@tiptap/extension-link": "^3.22.3",
         "@tiptap/react": "^3.22.3",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 27 - 34, SpikeBlock.tsx imports symbols from
`@dnd-kit/utilities` but package.json lacks that dependency; add an explicit
dependency entry for "@dnd-kit/utilities" to package.json (use a version aligned
with `@dnd-kit/core`, e.g. "^6.3.1") so the import in SpikeBlock.tsx resolves
reliably without relying on transitive installs.
🧹 Nitpick comments (1)
docs/phase-1-dnd-kit-findings.md (1)

29-30: Avoid hard-coded bundle size in findings text

The explicit 1.20 kB value will age quickly and can become misleading. Consider wording this as “no spike entry is included in build:editor output” or timestamping the measurement.

Also applies to: 120-121

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/phase-1-dnd-kit-findings.md` around lines 29 - 30, Replace the
hard-coded "1.20 kB" bundle-size callout in the findings text (the string "1.20
kB" referencing dist/editor/main.js and the build:editor output) with a
non-aging statement such as "no spike entry is included in build:editor output"
or include a measurement plus timestamp; update the same wording wherever the
size is repeated (also mentioned for lines 120-121) so the doc no longer
contains a fixed byte value that will become stale.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@package.json`:
- Around line 27-34: SpikeBlock.tsx imports symbols from `@dnd-kit/utilities` but
package.json lacks that dependency; add an explicit dependency entry for
"@dnd-kit/utilities" to package.json (use a version aligned with `@dnd-kit/core`,
e.g. "^6.3.1") so the import in SpikeBlock.tsx resolves reliably without relying
on transitive installs.

---

Nitpick comments:
In `@docs/phase-1-dnd-kit-findings.md`:
- Around line 29-30: Replace the hard-coded "1.20 kB" bundle-size callout in the
findings text (the string "1.20 kB" referencing dist/editor/main.js and the
build:editor output) with a non-aging statement such as "no spike entry is
included in build:editor output" or include a measurement plus timestamp; update
the same wording wherever the size is repeated (also mentioned for lines
120-121) so the doc no longer contains a fixed byte value that will become
stale.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 618fd494-cee6-4b2f-915c-679c987c7d55

📥 Commits

Reviewing files that changed from the base of the PR and between 96d1100 and d418aad.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
📒 Files selected for processing (9)
  • docs/phase-1-dnd-kit-findings.md
  • package.json
  • resources/js/visual-editor/editor/__dnd-kit-spike__/DndKitSpike.tsx
  • resources/js/visual-editor/editor/__dnd-kit-spike__/SpikeBlock.tsx
  • resources/js/visual-editor/editor/__dnd-kit-spike__/__tests__/DndKitSpike.test.tsx
  • resources/js/visual-editor/editor/__dnd-kit-spike__/index.html
  • resources/js/visual-editor/editor/__dnd-kit-spike__/main.tsx
  • resources/js/visual-editor/editor/__dnd-kit-spike__/spike.css
  • vite.editor.config.ts

SpikeBlock.tsx imports CSS from @dnd-kit/utilities, which was previously
only available transitively through @dnd-kit/sortable. Pin it explicitly
so the import resolves independently of sortable's install tree.
@ViewFromTheBox
ViewFromTheBox merged commit f9c970b into add/phase-one Apr 13, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in ArtisanPack UI Overview Apr 13, 2026
@ViewFromTheBox
ViewFromTheBox deleted the feature/268-dnd-kit-spike-harness branch April 13, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Phase 1.6: dnd-kit spike harness — validate Tiptap interaction

1 participant