Skip to content

Fix Slides manual edit issues#2355

Open
NKoech123 wants to merge 15 commits into
mainfrom
ai_main_a4d630b36ac64b0f9252
Open

Fix Slides manual edit issues#2355
NKoech123 wants to merge 15 commits into
mainfrom
ai_main_a4d630b36ac64b0f9252

Conversation

@NKoech123

@NKoech123 NKoech123 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes bullet-list editing in the slide editor so pressing Enter at the end of a bullet correctly adds a new bullet item, and clicking a bullet list selects/edits the whole list instead of a single row.

Problem

Slide bullet lists are rendered as styled div/span rows (marker + text) rather than native <ul>/<li> markup. Because of this, contentEditable had no way to know these rows belonged together: pressing Enter inside a bullet row was trapped within that single row instead of creating a new bullet, and clicking into a bullet edited only the individual line rather than the full list, breaking highlighting, inline formatting shortcuts, and the style dock.

Solution

Added a dedicated bullet-editing module that recognizes styled bullet rows/lists by their marker glyph structure, resolves the enclosing list from a caret position or clicked element, and manually inserts a new bullet row (cloning the current row's styling) when Enter is pressed at the end of a bullet. Wired this logic into SlideEditor's smart-block detection, keydown handling, and click handling so bullet lists are treated as a single editable/selectable block.

Key Changes

  • bullet-editing.ts (new): utilities isBulletMarker, isBulletRow, bulletRowCount, isBulletList, findEnclosingList, and insertBulletAfterCaret to detect styled bullet structures and insert a new row after the caret, preserving marker glyph and font styling, with a zero-width space to keep the caret inside an empty new bullet's font context.
  • bullet-editing.test.tsx (new): unit tests covering row/list detection, resolving a bullet text span to its list, inserting a new row on Enter, splitting trailing text into the new bullet, handling bare text nodes, and tolerating a stray non-bullet child.
  • SlideEditor.tsx:
    • findSmartBlock now returns the enclosing bullet list (not just the single text leaf) so the whole list is treated as one editable block.
    • stripBuilderIds also strips stray zero-width spaces from cleaned HTML.
    • Keydown handler now ignores events originating outside the live slide content (e.g. the style dock), re-derives the enclosing list from the live caret on Enter, and calls insertBulletAfterCaret to add a new bullet instead of falling through to native Enter behavior or committing the edit.
    • Click handling now resolves the smart block for editable text (single leaf or entire bullet list) and enters inline edit / selects it for styling as one unit, instead of only handling non-text selectable elements.

Edit in Builder  Preview


To clone this PR locally use the Github CLI with command gh pr checkout 2355

You can tag me at @BuilderIO for anything you want me to fix or change

@netlify

This comment has been minimized.

@builder-io-integration builder-io-integration Bot changed the title Update from the Builder.io agent Fix Enter-to-add-bullet in styled slide bullet lists Jul 23, 2026
@NKoech123 NKoech123 changed the title Fix Enter-to-add-bullet in styled slide bullet lists Fix Slides manual edit issues Jul 23, 2026
@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

builder-io-integration[bot]

This comment was marked as outdated.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@NKoech123
NKoech123 requested a review from shomix July 23, 2026 19:12
@netlify

This comment has been minimized.

builder-io-integration[bot]

This comment was marked as outdated.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Builder reviewed your changes and found 1 potential issue 🟡

Review Details

Code Review Summary

This revision adds boundary clamping intended to protect marker glyphs when a non-collapsed selection includes a bullet. The collapsed-caret fix remains covered, and formatted-fragment handling is still present. However, the clamping introduces an unhandled same-marker selection case: moving the start after a marker and then the end before that same marker collapses the range at a row boundary, which can cause the subsequent tail extraction to include/remove the marker unexpectedly.

Key Findings

Medium severity:

  • Selecting the marker glyph itself and pressing Enter is not safely handled by the latest clamping logic. Add an explicit same-marker selection path and a regression test.

The previously reported global U+200B stripping issue remains open and was not resubmitted.

🧪 Browser testing: Attempted full verification, but browser automation tools were unavailable; all 16 planned UI cases were blocked as environment issues despite a healthy dev server.

Comment on lines +170 to +173
const startMarker = enclosingMarker(range.startContainer, list);
if (startMarker) range.setStartAfter(startMarker);
const endMarker = enclosingMarker(range.endContainer, list);
if (endMarker) range.setEndBefore(endMarker);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Handle selections wholly inside one marker explicitly

When both selection endpoints are inside the same marker, setStartAfter(startMarker) followed by setEndBefore(endMarker) collapses the range at the row boundary before the marker. The later container === row tail extraction can then treat the marker as editable content, causing the original and inserted rows to lose their bullet glyph. Detect the same-marker case before clamping and treat it like a protected marker selection; add a test that selects the marker text itself rather than only placing a collapsed caret there.

Additional Info
Confirmed by reproducing the boundary operations with a standard marker text range: after clamping, the range collapses at row offset 0, before the marker. The existing tests cover only collapsed marker carets and do not exercise this path.

Fix in Builder

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.

3 participants