Feature/ordered list and indent buttons#503
Conversation
…buttons Adds editor.toggleOrderedList, editor.indentListItem, editor.outdentListItem and editor.createOrderedList to all 13 translation files.
Adds three buttons after the existing bulletList button: - orderedList (LeftToRightListNumberIcon, Ctrl+Shift+7, dual-mode aware) - indent/sinkListItem (TextIndentMoreIcon, disabled when not in a list) - outdent/liftListItem (TextIndentLessIcon, disabled when not in a list)
Inserts an orderedList item directly after bulletList in the slash command list, using LeftToRightListNumberIcon and the existing toggleOrderedList command.
- Indent: was disabled for first list item (can().sinkListItem returns false
without a previous sibling). Changed to isActive('listItem') so the button
stays visible; clicking on an unsinkable item is a no-op but less confusing
than a grayed-out button.
- Outdent: was enabled on top-level list items, causing liftListItem to remove
the list entirely on click. Added a ProseMirror depth check so outdent is
only enabled when the item is nested (grandgrandparent node is a listItem).
- Ordered list button: bypass handleButtonClick wrapper for rich-text mode.
The wrapper saved/restored cursor positions (from/to) around the command,
but toggleOrderedList changes document structure so the saved positions
become stale, causing the next click to land outside the list and create
a new one instead of toggling. Now calls chain().focus() directly.
- Indent disabled: changed from isActive('listItem') (checks current block
type = paragraph, always false) to isActive('bulletList')||isActive('orderedList').
- Outdent disabled: same reliable list-active check, depth condition unchanged.
TipTap's built-in ListItem Tab handler wasn't reliably firing after the custom extension returned false. Now explicitly: - Tab in ordered/bullet list: sinkListItem (indent), event always consumed to prevent browser focus-jump even if the item has no previous sibling. - Shift-Tab in list: liftListItem only when nested (depth check); at level 1 the event is consumed but the list is preserved.
- Import useEditorState (TipTap v3) to subscribe to selection changes; the toolbar now re-renders when the cursor moves in/out of a list, fixing the stale disabled state on mouse-click and arrow-key navigation. - Selector computes isInList, isNested (ancestor traversal, no fixed depth offset), isInOrderedList, and currentItemIsEmpty — all driven by the live editor state. - Ordered list toggle: when already in an ordered list with an empty item, use liftListItem instead of toggleOrderedList, which avoids the "cursor jumps / extra 1. inserted" bug that occurs on empty paragraphs. - Outdent disabled: replaced editor.state.selection.$anchor.node(depth-3) fixed-offset heuristic with a proper ancestor walk through listItem nodes, which works correctly regardless of document nesting depth.
Same root cause as the ordered list fix: toggleBulletList on an empty list item caused cursor jumps or extra bullet symbols. Now uses liftListItem when the current item is empty, consistent with the ordered list behaviour. Also adds isInBulletList to the useEditorState selector so the button's active variant is driven by reactive state rather than a stale isActive call.
|
Hey @reniko This works mostly perfectly, however when you are in markdown mode the whole thing is very finnicky, you may want to double check the functionality there, especially the indent one is doing nothing (the numbered list works fine, but it's not smart enough to understand a list already has a number (e.g. if i click it whilst selecting I also wonder if we should have bullet point menus being a dropdown instead (bit like the code block one) as otherwise half of the toolbar now is bullet point buttons :) |
Turndown serialises bullet items as '- ' (dash + 3 spaces) and ordered items as 'N. ' (number + dot + 2 spaces), placing text at column 4. The insertBulletList and insertOrderedList helpers used single-space variants, causing visual inconsistency after a RT→MD roundtrip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pressing Enter on a numbered list line ('1. text') now inserts a new
line with the incremented number and same spacing ('2. '). Pressing
Enter on an empty numbered item ('1. ') removes the marker, consistent
with bullet list behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds two text-based helpers in markdown-editor-utils that operate on all selected lines (or the cursor line when nothing is selected). indentLines prepends 4 spaces; outdentLines removes the first 4 spaces if present, otherwise leaves the line unchanged — consistent with the library's Shift+Tab outdent behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Indent and outdent buttons now route to the text-based indentLines/ outdentLines helpers in MD mode instead of calling TipTap commands that have no effect there. The disabled condition is also corrected: buttons are always enabled in MD mode (outdent on a line with <4 spaces is a no-op, consistent with Shift+Tab). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New key for the list menu dropdown trigger button label, added to en, de, es, fr, it, ko, nl, pl, ru, tr, zh, klingon, and pirate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bullet list, ordered list, indent and outdent are now grouped under a single dropdown in the toolbar, following the same pattern as CodeBlocksDropdown. The dropdown handles both rich-text (TipTap commands) and MD mode (text-based helpers), and shows an active state when the cursor is inside a list in rich-text mode. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
handleBulletListEnter and handleOrderedListEnter matched only at the line start, so pressing Enter on a nested/indented item (e.g. ' - sub') inserted a plain newline instead of continuing the list. Regex now captures leading whitespace and includes it in the new line prefix so all indent levels work correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… mode Replaced isInList/isNested with reactive editor.can().sinkListItem() and editor.can().liftListItem() calls so the dropdown items are disabled precisely when TipTap cannot execute the command — e.g. indent is now correctly disabled on the first item of a list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
remark does not reliably parse nested ordered lists starting at numbers other than 1 (a CommonMark edge case where the 'cannot interrupt paragraph' rule is over-applied). To ensure the MD→RT roundtrip is always correct, indentLines now renumbers ordered list items in the selection starting from 1 when they are indented. Each contiguous group of ordered items gets its own counter that resets at blank lines and non-ordered lines. Also fixes the RT indent disabled state: uses editor.can().sinkListItem and editor.can().liftListItem so the dropdown items reflect the exact command availability, e.g. indent is disabled on the first item of a list level. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r after indent Two fixes in markdown-editor-utils: 1. insertBulletList / insertOrderedList now add list markers to empty lines when toggling on, so clicking the list button on a blank line produces a list item. When toggling off (allMatch), empty lines are left unchanged as before. 2. indentLines / outdentLines collapse the selection to a cursor after the operation. processLineSelection selected the full modified block which caused the next keystroke to delete all indented content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
processLineSelection treated empty lines as 'matching' the pattern so an all-empty selection produced allMatch=true, sending the callback into toggle-off mode instead of toggle-on. Added a hasNonEmpty guard so allMatch is only true when at least one non-empty line actually matches. Result: clicking the ordered list button (or bullet list) on a blank line now inserts a list marker, consistent with non-empty lines. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add liftOutOfList() loop in ListMenuDropdown that repeatedly calls liftListItem until the cursor is no longer inside any list, instead of lifting only one level. Also enables cross-type switching (bullet ↔ ordered) without first exiting the list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e switching Rewrite insertBulletList and insertOrderedList to use /^\s*-\s/ and /^\s*\d+\.\s/ patterns so indented list items are recognized. When all selected lines are already a list of the other type, convert markers instead of stacking a new marker on top. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The paragraphInLi Turndown rule only stripped paragraph block-wrapping when P was the sole child of LI. Lifting that restriction ensures P elements inside LI are inlined even when a nested list is a sibling, preventing a blank line from appearing before the nested list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add getListDepth() to count listItem ancestors and switchListType() that lifts the item all the way out, toggles to the new list type, then sinks back to the original depth. This fixes the bug where switching bullet↔ ordered on a nested item always moved it to level 1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…in RT mode" This reverts commit 20a5bd2.
Detect the innermost list type with a ProseMirror ancestor walk instead of listState flags, which are both true for nested lists. When the clicked type differs from the innermost list, call toggleBulletList/ toggleOrderedList directly — their internal toggleList implementation runs setNodeMarkup on the immediate parent list and preserves nesting depth. Same-type clicks still call liftOutOfList for a full exit. This restores the ability to switch a level-2 bullet to a level-2 ordered list (and vice versa) without flattening to level 1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Ok, second try finished. I tried my best with Claude but changes started getting a little complex. Could you please check? New FeaturesOrdered list support (initial)
Toolbar UX improvement
i18nAdded translation keys editor.listOptions, editor.toggleOrderedList, editor.indentListItem, editor.outdentListItem to all 13 locale files Bug Fixes (post-review)Markdown mode
Rich Text mode
Rich Text → Markdown conversion
|
|
Good job to you and the robots, it's clean and works well, merged! |
Summary
Executed tests
🤖 Generated with Claude Code.
Manual review and tests done. But as generated in assistance with claude code and with limited understanding of the complete architecture maybe please be careful ;-)