Skip to content

fix(visual-editor): keep dragged element at new position after rearrange (FT-1910)#28

Open
joalves wants to merge 4 commits into
mainfrom
fix/FT-1910/ve-rearrange-snap-back
Open

fix(visual-editor): keep dragged element at new position after rearrange (FT-1910)#28
joalves wants to merge 4 commits into
mainfrom
fix/FT-1910/ve-rearrange-snap-back

Conversation

@joalves
Copy link
Copy Markdown
Collaborator

@joalves joalves commented May 7, 2026

Summary

Two-part fix for the visual editor's rearrange/drag flow.

Part 1 — selector mismatch on the dragged element ("snap-back" bug)

trackMoveChange was generating both element and target selectors against the post-drop DOM, then reverting the live drop. PreviewManager runs removePreviewChanges before replaying changes in replace mode, so it queried selectors against the reverted DOM where a path like #zone > div:nth-of-type(1) resolved to a different sibling — the SDK either moved the wrong element or no element, and the dragged element appeared to snap back. Captured the destination as Element references at post-drop, revert, then generate selectors against the reverted DOM.

Part 2 — block-vs-inline-aware drop with Alt swap and Escape cancel

After Part 1 the move committed but the drop targeting was still aggressive: cursor over a card's inner <h3> nested the dragged element inside the card. New algorithm:

Element being dragged Default With Alt
Block (display: block etc.) Sibling-only — walks up to find a same-parent sibling first, falls back to any block-in-block ancestor for re-parenting Free / nested — drops directly into the cursor's element
Inline (display: inline) Free / nested Sibling-only

Alt swaps the strategy regardless of element type — one mental model.

Other behaviour changes:

  • Escape cancels an in-progress drag without recording a move (capture-phase keydown so it always reaches us).
  • 10s auto-exit setTimeout removed — it was kicking users out mid-decision, and native dragend cleanup makes it redundant.
  • getSmartDraggableElement now returns named inline elements (a / button / span) directly instead of walking past them to a block ancestor — span-with-text drags drag the span, not the containing card.
  • trackMoveChange only-child position picker now prefers "lastChild" over "firstChild" so the SDK reproduces what appendChild did instead of dropping the element before any text content.
  • Drop visualization: sibling-mode = thin coloured line on the top or bottom edge of the candidate (clear insertion point); free/nested = dashed outline + light fill in a different colour, so you can tell which strategy is active.
  • JSON-button tooltip discoverability: Button.tsx no longer suppresses pointer events when disabled, so the existing "Cannot edit JSON while Visual Editor is active" tooltip fires on hover.
  • .gitignore: !tests/e2e/** so new e2e files don't need git add -f; .claude/worktrees/ so per-feature worktree dirs don't show as untracked on main.

Deferred to a follow-up

  • Live reposition preview (dragged element rearranges in real time as the cursor moves) — fundamentally different drag loop, deserves its own PR.
  • testBlockAltDropNests e2e coverage — the function is implemented and exported, but pulling it into testRearrangeAllScenarios exposes a marker-cleanup quirk where nesting a block into another card's <p> leaves a production-experiment-named [data-absmartly-experiment] attribute that VE.stop's removePreviewChanges("__visual_editor__") doesn't sweep. The drop logic itself works (manual smoke-testing confirms Alt-on-block correctly nests); the marker-cleanup path is a separate fix.

Test plan

  • npm run build:dev
  • npx playwright test tests/e2e/visual-editor-complete.spec.ts — passes locally in ~12s
  • bun run typecheck
  • e2e covers: snap-back regression, block-snaps-to-sibling on inner-child cursor, inline-default-nests, inline+Alt-sibling, Escape-cancels
  • CI green
  • Manual: block + Alt nest into target's <p> (deferred from e2e per note above)
  • Manual: launch VE on real page, drag with cursor over various inner children, confirm sibling snapping
  • Manual: confirm Alt visibly switches the indicator between line-on-edge and full-outline modes
  • Manual: confirm Escape during drag leaves no change recorded
  • Manual: confirm JSON-button tooltip "Cannot edit JSON while Visual Editor is active" appears on hover when VE is open

JIRA: FT-1910

Summary by CodeRabbit

  • New Features

    • Visual drop indicators for sibling/nested placements in the editor
    • Better inline-element drag handling for interactive inline targets
  • Bug Fixes

    • Disabled button now shows a not-allowed cursor while keeping opacity cues
  • Tests

    • Added E2E coverage for visual-editor rearrange drag-and-drop and integrated it into the full workflow
    • Improved CodeMirror content verification in tests
    • Added test fixtures for rearrange scenarios
  • Chores

    • Updated ignore rules to track e2e test sources and bumped version 1.5.1 → 1.5.2

joalves added 2 commits May 7, 2026 20:22
…nge (FT-1910)

trackMoveChange generated both element and target selectors against the
post-drop DOM and only then reverted the live drop. PreviewManager runs
removePreviewChanges before replaying changes in replace mode, so it
queried selectors against the reverted DOM where a path like
`#zone > div:nth-of-type(1)` resolved to a different sibling — the SDK
either moved the wrong element or no element, and the user-visible
symptom was the dragged element snapping back to its original position.

Capture the destination as Element references (anchor + position
semantic) at post-drop, revert, then generate both elementSelector and
targetSelector against the reverted DOM. The Element refs stay valid
across the move; the selectors now resolve to the same nodes the SDK
sees on replay. The vestigial originalTargetSelector / originalPosition
locals were never written into the change object and have been dropped.

Other changes:
* Button.tsx: drop disabled:pointer-events-none in favor of
  disabled:cursor-not-allowed so existing title tooltips on disabled
  buttons fire on hover. The HTML disabled attribute already blocks
  clicks, making pointer-events-none belt-and-suspenders that broke
  tooltip discoverability — most visibly on the JSON-editor button when
  the Visual Editor is active.
* tests/e2e/helpers/ve-rearrange.ts: new helper that drives a real
  HTML5 drag/drop on class-less siblings under #rearrange-zone via
  page.evaluate. Playwright's mouse-based dragTo doesn't reliably
  trigger HTML5 drag events in headless Chromium, so the events are
  dispatched directly. Polls for the expected order after the SDK
  postMessage round-trip.
* visual-editor-complete.spec.ts: wires the rearrange step in after
  testAllVisualEditorActions.
* tests/test-pages/visual-editor-test.html: adds #rearrange-zone with
  three id-less, class-less divs. id-less is required because the
  selector generator returns the id directly when present, bypassing
  the parent-context path that surfaces the bug.
* tests/e2e/helpers/ve-url-filter.ts: read the JSON editor's full doc
  by scrolling cm-scroller and accumulating cm-line text. CodeMirror v6
  only renders visible lines, so reading cm-content.textContent missed
  urlFilter once the saved variant config grew past the viewport — the
  rearrange change pushed it over.
* tests/e2e/visual-editor-context-menu.spec.ts: deleted. Zero expect()
  calls, posted a window message the codebase never handled, every
  step gated behind `if (await contextMenu.isVisible())`. The same
  context-menu actions are covered with real assertions in
  visual-editor-complete.spec.ts via testAllVisualEditorActions.

Verification: 5 sequential passes of `npx playwright test
tests/e2e/visual-editor-complete.spec.ts` (~12s each).
…-1910)

`tests/` was ignoring the whole tree, which forced every new file under
tests/e2e/ to be added with `git add -f`. Add `!tests/e2e/**` so the
e2e helpers, specs, and fixtures are tracked without that workaround.
Subsequent rules (`*.png` etc.) keep test-run artifacts out.

Also add `.claude/worktrees/` so the per-feature worktree directory
this repo uses doesn't show up as untracked in `git status` on main.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

Walkthrough

This pull request refactors the visual-editor rearrange flow to compute a drop anchor (nested vs sibling before/after), updates dragover/drop handlers to insert according to that anchor, reverts the DOM before generating selectors in trackMoveChange, and ensures Escape cancels rearrange via a capture keydown. It adds injected CSS for drop indicators, tweaks Button disabled cursor, adds Playwright rearrange helpers and tests (with CodeMirror v6 reading fix), introduces rearrange fixtures in the test page, updates the Visual Editor complete test to run the scenarios, adjusts .gitignore to track tests/e2e/**, and bumps version to 1.5.2.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • absmartly/browser-extension#24: Modifies the same trackMoveChange logic in src/visual-editor/core/edit-modes.ts, indicating related or dependent rearrange functionality work.

Poem

🐰 I hopped through DOM and shadow light,

anchors set by cursor's sight,
Spans and cards I coax to dance,
Tests ensure each careful chance,
A little rabbit cheers: rearrange! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary bug fix (dragged element snapping back after rearrange) and references the ticket, accurately summarizing the main changeset.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/FT-1910/ve-rearrange-snap-back

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
tests/e2e/helpers/ve-rearrange.ts (1)

40-41: ⚡ Quick win

Avoid the text-coupled locator for the dragged card.

This helper is validating sibling order, not fixture copy, so hasText: "Gamma" makes it fail on harmless label edits. Prefer a structural locator anchored under #rearrange-zone, for example zone.locator(":scope > div").nth(2). Playwright scopes nested locators to the outer locator, and its CSS examples use full relative selectors rather than a bare leading combinator. (playwright.dev)

♻️ Suggested change
-  const gamma = zone.locator("> div", { hasText: "Gamma" })
+  const gamma = zone.locator(":scope > div").nth(2)

As per coding guidelines "Always add id attributes to elements and use ID selectors (e.g., #id) in tests, never use text-based selectors like getByText() or has-text()".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/helpers/ve-rearrange.ts` around lines 40 - 41, Replace the
text-coupled locator used to find the "Gamma" card (the `gamma` variable created
from `zone.locator(...)`) with a structural, index-based locator anchored to the
`zone` root; e.g., use a scoped child selector like `:scope > div` with
`.nth(2)` on the same `zone.locator` call so the test targets the third sibling
structurally instead of matching by text, complying with the ID/text-less
selector guideline in ve-rearrange helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitignore:
- Around line 62-65: The negation pattern is ineffective because the file
currently ignores the directory with "tests/" which prevents Git from descending
into subdirs and honoring "!tests/e2e/**"; update the .gitignore by replacing
the "tests/" ignore entry and the "!tests/e2e/**" negation with the recommended
pair: use "tests/*" to ignore direct children of tests and add "!tests/e2e/" to
re-include the e2e directory (so files under tests/e2e/ are tracked); locate the
existing "tests/" and "!tests/e2e/**" lines and make this replacement.

In `@src/visual-editor/core/edit-modes.ts`:
- Around line 563-576: The rollback catch block around
originalParent.insertBefore/appendChild can fail and, if it does, the function
continues and emits selectors from the post-drop DOM; update the catch in the
block that uses originalParent, originalNextSibling and element (the try that
calls insertBefore/appendChild and logs via debugWarn) to return immediately
after logging (or otherwise abort tracking/throw) so we do not persist a
corrupted move change or emit selectors from the wrong tree.

In `@tests/e2e/helpers/ve-url-filter.ts`:
- Around line 96-103: The helper currently queries CodeMirror by brittle class
selectors (scroller and content) — update the queries to use stable ID
selectors: change the document.querySelector(".cm-scroller") and
document.querySelector(".cm-content") calls in this helper (references:
scroller, content, collect, seen) to use document.getElementById or
document.querySelector("#your-id") and ensure the corresponding DOM where
CodeMirror is instantiated has id attributes (e.g., id="editor-scroller",
id="editor-content"); keep the null-check and early return logic the same and
only replace the selector strings so collect() still iterates
content.querySelectorAll(".cm-line") unchanged.

In `@tests/e2e/visual-editor-complete.spec.ts`:
- Around line 97-100: The testRearrangeDragDrop(testPage) step adds a new "move"
change, so the later assertion still using verifySidebarHasChanges(sidebar, 4)
is stale; update the spec to reflect the extra saved change by either having
testRearrangeDragDrop undo its change or increment the expected count in the
later verifySidebarHasChanges call (e.g., change the expected value from 4 to 5)
so the sidebar change count matches the new move entry.

---

Nitpick comments:
In `@tests/e2e/helpers/ve-rearrange.ts`:
- Around line 40-41: Replace the text-coupled locator used to find the "Gamma"
card (the `gamma` variable created from `zone.locator(...)`) with a structural,
index-based locator anchored to the `zone` root; e.g., use a scoped child
selector like `:scope > div` with `.nth(2)` on the same `zone.locator` call so
the test targets the third sibling structurally instead of matching by text,
complying with the ID/text-less selector guideline in ve-rearrange helpers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aeae7006-5646-48dc-9157-6f8a0edc5bc2

📥 Commits

Reviewing files that changed from the base of the PR and between ad20d26 and 62e876e.

📒 Files selected for processing (8)
  • .gitignore
  • src/components/ui/Button.tsx
  • src/visual-editor/core/edit-modes.ts
  • tests/e2e/helpers/ve-rearrange.ts
  • tests/e2e/helpers/ve-url-filter.ts
  • tests/e2e/visual-editor-complete.spec.ts
  • tests/e2e/visual-editor-context-menu.spec.ts
  • tests/test-pages/visual-editor-test.html
💤 Files with no reviewable changes (1)
  • tests/e2e/visual-editor-context-menu.spec.ts

Comment thread .gitignore
Comment on lines 62 to +65
tests/
# …but track the e2e test sources / helpers / fixtures. Without this exception
# every new file under tests/e2e/ has to be added with `git add -f`.
!tests/e2e/**
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Test whether the gitignore pattern correctly allows tests/e2e/** files

# Create a temporary test file under tests/e2e/
TEST_FILE="tests/e2e/gitignore-pattern-test-temp.txt"
mkdir -p tests/e2e
echo "test" > "$TEST_FILE"

# Check if Git considers this file for tracking (should show as untracked, not ignored)
if git check-ignore -v "$TEST_FILE" > /dev/null 2>&1; then
  echo "❌ FAIL: $TEST_FILE is ignored by .gitignore (pattern may not work correctly)"
  git check-ignore -v "$TEST_FILE"
  RESULT=1
else
  echo "✅ PASS: $TEST_FILE is not ignored and can be tracked"
  RESULT=0
fi

# Clean up
rm -f "$TEST_FILE"

exit $RESULT

Repository: absmartly/browser-extension

Length of output: 242


Fix the gitignore negation pattern for tests/e2e/ directory.

The current pattern tests/ on line 62 followed by !tests/e2e/** on line 65 does not work as intended. When a directory is ignored with a trailing slash, Git does not descend into it to evaluate negation patterns for subdirectories. A test confirms that new files under tests/e2e/ are currently being ignored.

To fix this, change the pattern to:

Recommended pattern
tests/*
!tests/e2e/

This ignores all direct children of tests/ but re-includes the tests/e2e/ directory (and implicitly all files beneath it).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.gitignore around lines 62 - 65, The negation pattern is ineffective because
the file currently ignores the directory with "tests/" which prevents Git from
descending into subdirs and honoring "!tests/e2e/**"; update the .gitignore by
replacing the "tests/" ignore entry and the "!tests/e2e/**" negation with the
recommended pair: use "tests/*" to ignore direct children of tests and add
"!tests/e2e/" to re-include the e2e directory (so files under tests/e2e/ are
tracked); locate the existing "tests/" and "!tests/e2e/**" lines and make this
replacement.

Comment thread src/visual-editor/core/edit-modes.ts
Comment on lines +96 to +103
const scroller = document.querySelector(".cm-scroller") as HTMLElement | null
const content = document.querySelector(".cm-content")
if (!scroller || !content) return ""

const seen = new Set<string>()
const collect = () => {
content.querySelectorAll(".cm-line").forEach((line) => {
seen.add(line.textContent ?? "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use stable ID selectors for the CodeMirror query path.

Line 96 and Line 97 currently rely on library class selectors (.cm-scroller, .cm-content), which makes this helper brittle and breaks the test selector rule.

Suggested update in this helper
-    const scroller = document.querySelector(".cm-scroller") as HTMLElement | null
-    const content = document.querySelector(".cm-content")
+    const scroller = document.querySelector("#json-editor-scroller") as HTMLElement | null
+    const content = document.querySelector("#json-editor-content") as HTMLElement | null
     if (!scroller || !content) return ""

     const seen = new Set<string>()
     const collect = () => {
-      content.querySelectorAll(".cm-line").forEach((line) => {
-        seen.add(line.textContent ?? "")
-      })
+      seen.add(content.textContent ?? "")
     }

As per coding guidelines, Always add id attributes to elements and use ID selectors (e.g., #id) in tests, never use text-based selectors like getByText() or has-text().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/helpers/ve-url-filter.ts` around lines 96 - 103, The helper
currently queries CodeMirror by brittle class selectors (scroller and content) —
update the queries to use stable ID selectors: change the
document.querySelector(".cm-scroller") and document.querySelector(".cm-content")
calls in this helper (references: scroller, content, collect, seen) to use
document.getElementById or document.querySelector("#your-id") and ensure the
corresponding DOM where CodeMirror is instantiated has id attributes (e.g.,
id="editor-scroller", id="editor-content"); keep the null-check and early return
logic the same and only replace the selector strings so collect() still iterates
content.querySelectorAll(".cm-line") unchanged.

Comment thread tests/e2e/visual-editor-complete.spec.ts
joalves added 2 commits May 8, 2026 09:17
…e cancel (FT-1910)

Iterates on the snap-back fix to make rearrange usable on real pages.

Behaviour:
* Block elements default to *sibling-only* placement. Walking up from
  the cursor's e.target, the algorithm prefers an ancestor whose parent
  IS the dragged element's parent (true sibling), and falls back to the
  innermost block-in-block ancestor (re-parent to a new container at
  the right hierarchy level). Without this, dropping the cursor over a
  card's <h3> nested the dragged element inside the card — exactly the
  precision problem the user hit on the launchpad grid.
* Inline elements (computed display === "inline") default to *free /
  nested* placement: the dragged element nests directly into the
  cursor's element. That's the natural "drop a span into a paragraph"
  outcome.
* Alt SWAPS the strategy — block + Alt → free, inline + Alt → sibling.
  No new key per element type; one mental model.
* Escape cancels an in-progress drag without recording a move. Capture-
  phase keydown listener so it always reaches us before any page-level
  handler. Cleans up listeners and class state via the same handleDragEnd
  path the native dragend uses.
* The 10s auto-exit setTimeout is gone. It was kicking the user out of
  rearrange mode mid-decision and the native dragend cleanup makes it
  redundant for the orphan-listener case it was guarding.

getSmartDraggableElement now returns named inline elements (a / button
/ span) directly instead of walking past them to a block ancestor — a
span-with-text drag should drag the span, not its containing card.

trackMoveChange's only-element-child position picker now prefers
"lastChild" over "firstChild". The drop runs appendChild, so the SDK
needs to reproduce that on replay; "firstChild" would call
insertBefore(target.firstChild) and land the element BEFORE any text
content of the container, which doesn't match what the user just saw.

Drop visualization (styles.ts):
* Sibling-mode candidate now shows a 3px coloured line on its top or
  bottom edge instead of a fill highlight, so the insertion point is
  unambiguous between cards.
* Free / nested mode shows a dashed outline + light fill on the
  container the dragged element will nest into, plus a different colour
  from sibling mode so the user can see at a glance which strategy is
  active.

Tests:
* tests/test-pages/visual-editor-test.html: #rearrange-zone-deep block
  with id-less, class-less divs each containing inner h3 + p. id-less
  is required because the selector generator returns the id directly
  when present, bypassing the parent-context path. The inner content
  is required because the precision case is "cursor over inner child".
  Plus a #rearrange-inline <p> with three <span> children for the
  inline-default and inline+Alt scenarios.
* tests/e2e/helpers/ve-rearrange.ts: split into scenario functions
  driven by a dispatchDrag helper that emits a full HTML5 drag-event
  sequence with a configurable altKey. testRearrangeAllScenarios runs
  the snap-back regression, block-snaps-to-sibling, inline-default-
  nests, inline-Alt-sibling, and Escape-cancels in sequence.
* testBlockAltDropNests is exported but NOT wired into the runner: it
  exposes a marker-cleanup edge case where nesting a block into another
  card's <p> leaves a production-experiment-named [data-absmartly-
  experiment] attribute that VE.stop's removePreviewChanges("__visual_
  editor__") doesn't sweep. The drop logic itself works (manual smoke-
  testing confirms Alt-on-block correctly nests); the marker-cleanup
  path is a separate fix outside this PR.

Live reposition preview (the dragged element rearranging in real time
as the cursor moves) is deferred to a follow-up ticket — that's a
fundamentally different drag loop and deserves its own PR.

Verification: npx playwright test tests/e2e/visual-editor-complete.spec.ts
passes locally in ~12s. typecheck clean.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/visual-editor/core/edit-modes.ts (1)

725-738: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Abort tracking if the rollback fails.

The catch block logs the error but does not return early. If insertBefore/appendChild throws, the method continues and emits selectors from the post-drop tree, which recreates the same mismatch this fix is trying to remove.

🛡️ Suggested fix
       } catch (err) {
         debugWarn("[ABSmartly] Failed to revert drop pre-replay:", err)
+        return
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/visual-editor/core/edit-modes.ts` around lines 725 - 738, The catch block
around DOM reattachment (where originalParent.insertBefore/appendChild is called
for element with originalNextSibling) currently only logs via debugWarn and
allows execution to continue; change it to abort further tracking by returning
early (or otherwise stopping the function) when the reattachment fails so the
function does not proceed to emit selectors from the post-drop tree. Locate the
try/catch that references originalParent, originalNextSibling, element,
insertBefore and appendChild and update the catch to return (or throw) after
calling debugWarn to prevent subsequent selector emission.
🧹 Nitpick comments (2)
tests/e2e/helpers/ve-rearrange.ts (1)

358-373: ⚡ Quick win

Remove duplicate JSDoc comment block.

The JSDoc comment explaining why testBlockAltDropNests is excluded appears twice (lines 358-365 and 362-373). Remove the first occurrence.

🧹 Suggested fix
-/**
- * Run every rearrange scenario in sequence. Order matters — each scenario
- * leaves the DOM in a known state that the next one builds on.
- */
 /**
  * Run every rearrange scenario in sequence. Order matters — each scenario
  * leaves the DOM in a known state that the next one builds on.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/helpers/ve-rearrange.ts` around lines 358 - 373, Delete the
duplicated JSDoc block that explains why testBlockAltDropNests is excluded; keep
a single copy of the explanatory comment and remove the first occurrence so only
one JSDoc describing testBlockAltDropNests remains adjacent to the exported
function name testBlockAltDropNests (ensure surrounding blank lines remain
consistent after removal).
src/visual-editor/core/edit-modes.ts (1)

84-99: 💤 Low value

Remove the unused nearestBlockAncestor function.

The function defined at line 84 is not called anywhere in the codebase and should be deleted to eliminate dead code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/visual-editor/core/edit-modes.ts` around lines 84 - 99, Delete the unused
helper function declaration named nearestBlockAncestor from
src/visual-editor/core/edit-modes.ts by removing the entire const
nearestBlockAncestor = (el: Element): Element | null => { ... } block; ensure
you only remove that function and its inner logic (do not alter smartElement or
isBlockLevel usages elsewhere), and run a quick project-wide search to confirm
there are no remaining references to nearestBlockAncestor so the codebase
remains clean.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/visual-editor/core/edit-modes.ts`:
- Around line 725-738: The catch block around DOM reattachment (where
originalParent.insertBefore/appendChild is called for element with
originalNextSibling) currently only logs via debugWarn and allows execution to
continue; change it to abort further tracking by returning early (or otherwise
stopping the function) when the reattachment fails so the function does not
proceed to emit selectors from the post-drop tree. Locate the try/catch that
references originalParent, originalNextSibling, element, insertBefore and
appendChild and update the catch to return (or throw) after calling debugWarn to
prevent subsequent selector emission.

---

Nitpick comments:
In `@src/visual-editor/core/edit-modes.ts`:
- Around line 84-99: Delete the unused helper function declaration named
nearestBlockAncestor from src/visual-editor/core/edit-modes.ts by removing the
entire const nearestBlockAncestor = (el: Element): Element | null => { ... }
block; ensure you only remove that function and its inner logic (do not alter
smartElement or isBlockLevel usages elsewhere), and run a quick project-wide
search to confirm there are no remaining references to nearestBlockAncestor so
the codebase remains clean.

In `@tests/e2e/helpers/ve-rearrange.ts`:
- Around line 358-373: Delete the duplicated JSDoc block that explains why
testBlockAltDropNests is excluded; keep a single copy of the explanatory comment
and remove the first occurrence so only one JSDoc describing
testBlockAltDropNests remains adjacent to the exported function name
testBlockAltDropNests (ensure surrounding blank lines remain consistent after
removal).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca3f3e43-d240-42cd-b273-4aaf6bf238b0

📥 Commits

Reviewing files that changed from the base of the PR and between ead169b and e6d30ce.

📒 Files selected for processing (5)
  • src/visual-editor/core/edit-modes.ts
  • src/visual-editor/ui/styles.ts
  • tests/e2e/helpers/ve-rearrange.ts
  • tests/e2e/visual-editor-complete.spec.ts
  • tests/test-pages/visual-editor-test.html
✅ Files skipped from review due to trivial changes (1)
  • tests/e2e/visual-editor-complete.spec.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant