From 91a987838d6d71ee3394c660ccf949116e50286d Mon Sep 17 00:00:00 2001 From: Gabriel Chittolina Date: Fri, 17 Apr 2026 14:39:49 -0300 Subject: [PATCH 1/6] feat: implement 2 extra types of bullet lists (square, circle) --- .../components/toolbar/BulletStyleButtons.vue | 136 ++++++++++++++++++ .../v1/components/toolbar/defaultItems.js | 25 +++- .../v1/components/toolbar/super-toolbar.js | 10 ++ .../v1/components/toolbar/toolbarIcons.js | 5 + .../editors/v1/core/commands/toggleList.js | 18 ++- .../v1/core/helpers/list-numbering-helpers.js | 14 +- .../parts/adapters/numbering-transforms.ts | 31 +++- .../v1/extensions/paragraph/paragraph.js | 12 ++ .../v1/extensions/types/paragraph-commands.ts | 3 + .../create-headless-toolbar.test.ts | 6 +- .../src/headless-toolbar/helpers/paragraph.ts | 5 + .../headless-toolbar/toolbar-registry.test.ts | 1 + .../src/headless-toolbar/toolbar-registry.ts | 2 +- shared/common/icons/list-circle-solid.svg | 1 + shared/common/icons/list-square-solid.svg | 1 + 15 files changed, 256 insertions(+), 14 deletions(-) create mode 100644 packages/super-editor/src/editors/v1/components/toolbar/BulletStyleButtons.vue create mode 100644 shared/common/icons/list-circle-solid.svg create mode 100644 shared/common/icons/list-square-solid.svg diff --git a/packages/super-editor/src/editors/v1/components/toolbar/BulletStyleButtons.vue b/packages/super-editor/src/editors/v1/components/toolbar/BulletStyleButtons.vue new file mode 100644 index 0000000000..e9dc1e5e9b --- /dev/null +++ b/packages/super-editor/src/editors/v1/components/toolbar/BulletStyleButtons.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js b/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js index a16e4b00dc..f9c6206b8a 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js @@ -4,6 +4,7 @@ import { sanitizeNumber } from './helpers'; import { useToolbarItem } from './use-toolbar-item'; import AIWriter from './AIWriter.vue'; import AlignmentButtons from './AlignmentButtons.vue'; +import BulletStyleButtons from './BulletStyleButtons.vue'; import DocumentMode from './DocumentMode.vue'; import LinkedStyle from './LinkedStyle.vue'; import LinkInput from './LinkInput.vue'; @@ -630,16 +631,34 @@ export const makeDefaultItems = ({ // bullet list const bulletedList = useToolbarItem({ - type: 'button', + type: 'dropdown', name: 'list', - command: 'toggleBulletList', + command: 'toggleBulletListStyle', icon: toolbarIcons.bulletList, - active: false, + hasCaret: true, tooltip: toolbarTexts.bulletList, restoreEditorFocus: true, + suppressActiveHighlight: true, attributes: { ariaLabel: 'Bullet list', }, + options: [ + { + type: 'render', + key: 'bullet-style-buttons', + render: () => { + const handleSelect = (style) => { + closeDropdown(bulletedList); + const item = { ...bulletedList, command: 'toggleBulletListStyle' }; + superToolbar.emitCommand({ item, argument: style }); + }; + return h(BulletStyleButtons, { + selectedStyle: bulletedList.selectedValue.value, + onSelect: handleSelect, + }); + }, + }, + ], }); // number list diff --git a/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js b/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js index c290c31ad7..9a98bd28de 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js @@ -622,6 +622,16 @@ export class SuperToolbar extends EventEmitter { if (commandState?.value != null) item.activate({ styleId: commandState.value }); else item.label.value = this.config.texts?.formatText || 'Format text'; }, + list: () => { + const markerToStyle = { '•': 'disc', '◦': 'circle', '▪': 'square' }; + if (commandState?.active) { + item.activate(); + item.selectedValue.value = markerToStyle[commandState.value] ?? null; + } else { + item.deactivate(); + item.selectedValue.value = null; + } + }, default: () => { if (commandState?.active) item.activate(); else item.deactivate(); diff --git a/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js b/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js index 70f62342f4..8b8caf0f08 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js @@ -2,6 +2,8 @@ import boldIconSvg from '@superdoc/common/icons/bold-solid.svg?raw'; import italicIconSvg from '@superdoc/common/icons/italic-solid.svg?raw'; import underlineIconSvg from '@superdoc/common/icons/underline-solid.svg?raw'; import listIconSvg from '@superdoc/common/icons/list-solid.svg?raw'; +import listCircleIconSvg from '@superdoc/common/icons/list-circle-solid.svg?raw'; +import listSquareIconSvg from '@superdoc/common/icons/list-square-solid.svg?raw'; import listOlIconSvg from '@superdoc/common/icons/list-ol-solid.svg?raw'; import imageIconSvg from '@superdoc/common/icons/image-solid.svg?raw'; import linkIconSvg from '@superdoc/common/icons/link-solid.svg?raw'; @@ -64,6 +66,9 @@ export const toolbarIcons = { alignCenter: alignCenterIconSvg, alignJustify: alignJustifyIconSvg, bulletList: listIconSvg, + bulletListDisc: listIconSvg, + bulletListCircle: listCircleIconSvg, + bulletListSquare: listSquareIconSvg, numberedList: listOlIconSvg, indentLeft: outdentIconSvg, indentRight: indentIconSvg, diff --git a/packages/super-editor/src/editors/v1/core/commands/toggleList.js b/packages/super-editor/src/editors/v1/core/commands/toggleList.js index 048bd03ec0..0c689911d9 100644 --- a/packages/super-editor/src/editors/v1/core/commands/toggleList.js +++ b/packages/super-editor/src/editors/v1/core/commands/toggleList.js @@ -26,10 +26,18 @@ function getParagraphListKind(node, editor) { return numFmtIsBullet(fmt) ? 'bullet' : 'ordered'; } -function paragraphMatchesToggleListType(node, editor, listType) { +/** @type {Record} */ +const MARKER_TEXT_TO_STYLE = { '•': 'disc', '◦': 'circle', '▪': 'square' }; + +function paragraphMatchesToggleListType(node, editor, listType, bulletStyle) { const kind = getParagraphListKind(node, editor); if (!kind) return false; - if (listType === 'bulletList') return kind === 'bullet'; + if (listType === 'bulletList') { + if (kind !== 'bullet') return false; + if (!bulletStyle) return true; + const markerText = node.attrs.listRendering?.markerText; + return MARKER_TEXT_TO_STYLE[markerText] === bulletStyle; + } if (listType === 'orderedList') return kind === 'ordered'; return false; } @@ -60,13 +68,13 @@ function getPrecedingParagraphForListReuse(doc, from, paragraphsInSelection) { } export const toggleList = - (listType) => + (listType, bulletStyle) => ({ editor, state, tr, dispatch }) => { if (listType !== 'orderedList' && listType !== 'bulletList') { return false; } - const predicate = (n) => paragraphMatchesToggleListType(n, editor, listType); + const predicate = (n) => paragraphMatchesToggleListType(n, editor, listType, bulletStyle); const { selection } = state; const { from, to } = selection; let firstListNode = null; @@ -127,7 +135,7 @@ export const toggleList = if (mode === 'create') { const numId = ListHelpers.getNewListId(editor); - ListHelpers.generateNewListDefinition({ numId: Number(numId), listType, editor }); + ListHelpers.generateNewListDefinition({ numId: Number(numId), listType, editor, bulletStyle }); sharedNumberingProperties = { numId: Number(numId), ilvl: 0, diff --git a/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js b/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js index 016e536f55..b571958183 100644 --- a/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js +++ b/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js @@ -39,10 +39,21 @@ import { mutateNumbering } from '@core/parts/adapters/numbering-mutation'; * @param {string} [param0.text] * @param {string} [param0.fmt] * @param {string} [param0.markerFontFamily] + * @param {'disc'|'circle'|'square'} [param0.bulletStyle] * @param {import('../Editor').Editor} param0.editor * @returns {Object} The new abstract and num definitions. */ -export const generateNewListDefinition = ({ numId, listType, level, start, text, fmt, editor, markerFontFamily }) => { +export const generateNewListDefinition = ({ + numId, + listType, + level, + start, + text, + fmt, + editor, + markerFontFamily, + bulletStyle, +}) => { /** @type {{ abstractDef: any, numDef: any }} */ let resultDefs; @@ -55,6 +66,7 @@ export const generateNewListDefinition = ({ numId, listType, level, start, text, text, fmt, markerFontFamily, + bulletStyle, }); resultDefs = { abstractDef: result.abstractDef, numDef: result.numDef }; }); diff --git a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts index 84d16a318f..9dfa065e42 100644 --- a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts +++ b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts @@ -30,8 +30,15 @@ interface GenerateOptions { text?: string | null; fmt?: string | null; markerFontFamily?: string | null; + bulletStyle?: 'disc' | 'circle' | 'square' | null; } +const BULLET_STYLE_CHARS: Record = { + disc: { char: '\uf0b7', font: 'Symbol' }, + circle: { char: 'o', font: 'Courier New' }, + square: { char: '\uf0a7', font: 'Wingdings' }, +}; + interface GenerateResult { numId: number; abstractId: number; @@ -72,7 +79,7 @@ function buildNumDef(numId: number, abstractId: number): any { */ export function generateNewListDefinition(numbering: NumberingModel, options: GenerateOptions): GenerateResult { let { listType } = options; - const { numId, level, start, text, fmt, markerFontFamily } = options; + const { numId, level, start, text, fmt, markerFontFamily, bulletStyle } = options; if (typeof listType !== 'string') listType = (listType as any).name; const definition = listType === 'orderedList' ? baseOrderedListDef : baseBulletList; @@ -86,6 +93,28 @@ export function generateNewListDefinition(numbering: NumberingModel, options: Ge }), ); + if (bulletStyle && listType !== 'orderedList') { + const styleChars = BULLET_STYLE_CHARS[bulletStyle]; + if (styleChars) { + const lvl0 = newAbstractDef.elements.find((el: any) => el.name === 'w:lvl' && el.attributes['w:ilvl'] === '0'); + if (lvl0) { + const lvlText = lvl0.elements.find((el: any) => el.name === 'w:lvlText'); + if (lvlText) lvlText.attributes['w:val'] = styleChars.char; + let rPr = lvl0.elements.find((el: any) => el.name === 'w:rPr'); + if (!rPr) { + rPr = { type: 'element', name: 'w:rPr', elements: [] }; + lvl0.elements.push(rPr); + } + rPr.elements = rPr.elements.filter((el: any) => el.name !== 'w:rFonts'); + rPr.elements.push({ + type: 'element', + name: 'w:rFonts', + attributes: { 'w:ascii': styleChars.font, 'w:hAnsi': styleChars.font, 'w:hint': 'default' }, + }); + } + } + } + if (level != null && start != null && text != null && fmt != null) { if (numbering.definitions[numId]) { const abstractId = numbering.definitions[numId]?.elements[0]?.attributes['w:val']; diff --git a/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js b/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js index 62525501c8..0d51b7e617 100644 --- a/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js +++ b/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js @@ -173,6 +173,7 @@ export const Paragraph = OxmlNode.create({ listRendering: { keepOnSplit: false, renderDOM: ({ listRendering }) => { + console.log('listRendering', listRendering); return { 'data-marker-type': listRendering?.markerText, 'data-list-level': listRendering?.path ? JSON.stringify(listRendering.path) : null, @@ -323,6 +324,17 @@ export const Paragraph = OxmlNode.create({ return toggleList('bulletList')(params); }, + /** + * Toggle a bullet list with a specific bullet style at the current selection + * @category Command + * @example + * editor.commands.toggleBulletListStyle('disc') + * @note Style can be 'disc' (•), 'circle' (◦), or 'square' (▪) + */ + toggleBulletListStyle: (style) => (params) => { + return toggleList('bulletList', style)(params); + }, + /** * Restart numbering for the current list * @category Command diff --git a/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts b/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts index a8f68ec827..06681a3037 100644 --- a/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts +++ b/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts @@ -15,6 +15,9 @@ export interface ParagraphCommands { /** Toggle bullet list formatting on the current selection */ toggleBulletList: () => boolean; + /** Toggle a bullet list with a specific style ('disc' | 'circle' | 'square') */ + toggleBulletListStyle: (style: 'disc' | 'circle' | 'square') => boolean; + /** Restart numbering for the current list item */ restartNumbering: () => boolean; diff --git a/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts b/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts index 53019dbe9d..41a057582c 100644 --- a/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts +++ b/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts @@ -473,10 +473,10 @@ describe('createHeadlessToolbar', () => { }); it('executes bullet-list through the registry direct command path', () => { - const toggleBulletList = vi.fn(() => true); + const toggleBulletListStyle = vi.fn(() => true); const superdoc = createActiveEditorHost({ commands: { - toggleBulletList, + toggleBulletListStyle, }, state: createSelectionState({ empty: true, @@ -495,7 +495,7 @@ describe('createHeadlessToolbar', () => { }); expect(controller.execute?.('bullet-list')).toBe(true); - expect(toggleBulletList).toHaveBeenCalledTimes(1); + expect(toggleBulletListStyle).toHaveBeenCalledTimes(1); controller.destroy(); }); diff --git a/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts b/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts index 9327cb71fd..8ff4b0598c 100644 --- a/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts +++ b/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts @@ -117,6 +117,11 @@ export const createListStateDeriver = ? activeNumberingType === 'bullet' : activeNumberingType != null && activeNumberingType !== 'bullet'; + if (numberingType === 'bullet') { + const markerText = isActive ? (paragraphNode?.attrs?.listRendering?.markerText ?? null) : null; + return { active: isActive, disabled: false, value: markerText }; + } + return { active: isActive, disabled: false, diff --git a/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts b/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts index a0a75f3510..9d705a752f 100644 --- a/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts +++ b/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts @@ -542,6 +542,7 @@ describe('createToolbarRegistry', () => { expect(state).toEqual({ active: true, disabled: false, + value: null, }); }); diff --git a/packages/super-editor/src/headless-toolbar/toolbar-registry.ts b/packages/super-editor/src/headless-toolbar/toolbar-registry.ts index a06a49ef71..a4026e9422 100644 --- a/packages/super-editor/src/headless-toolbar/toolbar-registry.ts +++ b/packages/super-editor/src/headless-toolbar/toolbar-registry.ts @@ -119,7 +119,7 @@ export const createToolbarRegistry = (): Partial diff --git a/shared/common/icons/list-square-solid.svg b/shared/common/icons/list-square-solid.svg new file mode 100644 index 0000000000..dd35473232 --- /dev/null +++ b/shared/common/icons/list-square-solid.svg @@ -0,0 +1 @@ + From 8137744afbcf0b0dec668fc7c2eadac5abbf871c Mon Sep 17 00:00:00 2001 From: Gabriel Chittolina Date: Fri, 17 Apr 2026 14:50:30 -0300 Subject: [PATCH 2/6] refactor: code reuse --- .../editors/v1/components/toolbar/super-toolbar.js | 4 ++-- .../src/editors/v1/core/commands/toggleList.js | 7 ++----- .../editors/v1/core/helpers/list-numbering-helpers.js | 11 +++++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js b/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js index 9a98bd28de..28db7b3885 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js @@ -20,6 +20,7 @@ import { useToolbarItem } from '@components/toolbar/use-toolbar-item'; import { calculateResolvedParagraphProperties } from '@extensions/paragraph/resolvedPropertiesCache.js'; import { parseSizeUnit } from '@core/utilities'; import { findElementBySelector, getParagraphFontFamilyFromProperties } from './helpers/general.js'; +import { markerTextToBulletStyle } from '@helpers/list-numbering-helpers.js'; /** * @typedef {function(CommandItem): void} CommandCallback @@ -623,10 +624,9 @@ export class SuperToolbar extends EventEmitter { else item.label.value = this.config.texts?.formatText || 'Format text'; }, list: () => { - const markerToStyle = { '•': 'disc', '◦': 'circle', '▪': 'square' }; if (commandState?.active) { item.activate(); - item.selectedValue.value = markerToStyle[commandState.value] ?? null; + item.selectedValue.value = markerTextToBulletStyle(commandState.value); } else { item.deactivate(); item.selectedValue.value = null; diff --git a/packages/super-editor/src/editors/v1/core/commands/toggleList.js b/packages/super-editor/src/editors/v1/core/commands/toggleList.js index 0c689911d9..7aebd43a76 100644 --- a/packages/super-editor/src/editors/v1/core/commands/toggleList.js +++ b/packages/super-editor/src/editors/v1/core/commands/toggleList.js @@ -1,6 +1,6 @@ // @ts-check import { updateNumberingProperties } from './changeListLevel.js'; -import { ListHelpers } from '@helpers/list-numbering-helpers.js'; +import { ListHelpers, markerTextToBulletStyle } from '@helpers/list-numbering-helpers.js'; import { getResolvedParagraphProperties } from '@extensions/paragraph/resolvedPropertiesCache.js'; import { isVisuallyEmptyParagraph } from './removeNumberingProperties.js'; import { Selection, TextSelection } from 'prosemirror-state'; @@ -26,9 +26,6 @@ function getParagraphListKind(node, editor) { return numFmtIsBullet(fmt) ? 'bullet' : 'ordered'; } -/** @type {Record} */ -const MARKER_TEXT_TO_STYLE = { '•': 'disc', '◦': 'circle', '▪': 'square' }; - function paragraphMatchesToggleListType(node, editor, listType, bulletStyle) { const kind = getParagraphListKind(node, editor); if (!kind) return false; @@ -36,7 +33,7 @@ function paragraphMatchesToggleListType(node, editor, listType, bulletStyle) { if (kind !== 'bullet') return false; if (!bulletStyle) return true; const markerText = node.attrs.listRendering?.markerText; - return MARKER_TEXT_TO_STYLE[markerText] === bulletStyle; + return markerTextToBulletStyle(markerText) === bulletStyle; } if (listType === 'orderedList') return kind === 'ordered'; return false; diff --git a/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js b/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js index b571958183..3c584f2b70 100644 --- a/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js +++ b/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js @@ -29,6 +29,17 @@ import { mutateNumbering } from '@core/parts/adapters/numbering-mutation'; // Shims will be removed as callers migrate in Phases 1b–1d. // --------------------------------------------------------------------------- +/** + * Maps a bullet marker character (from `listRendering.markerText`) to its named bullet style. + * Returns null for unrecognized markers. + * @param {string|null|undefined} markerText + * @returns {'disc'|'circle'|'square'|null} + */ +export function markerTextToBulletStyle(markerText) { + const map = { '•': 'disc', '◦': 'circle', '▪': 'square' }; + return map[markerText] ?? null; +} + /** * Generate a new list definition for the given list type. * @param {Object} param0 From 778c18e51af1ee3cf382473bcd062273bfd7be86 Mon Sep 17 00:00:00 2001 From: Gabriel Chittolina Date: Fri, 17 Apr 2026 15:14:03 -0300 Subject: [PATCH 3/6] refactor: simplified code removing font override --- .../parts/adapters/numbering-transforms.ts | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts index 9dfa065e42..2d5280df17 100644 --- a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts +++ b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts @@ -33,10 +33,10 @@ interface GenerateOptions { bulletStyle?: 'disc' | 'circle' | 'square' | null; } -const BULLET_STYLE_CHARS: Record = { - disc: { char: '\uf0b7', font: 'Symbol' }, - circle: { char: 'o', font: 'Courier New' }, - square: { char: '\uf0a7', font: 'Wingdings' }, +const BULLET_STYLE_CHARS: Record = { + disc: '•', + circle: '◦', + square: '▪', }; interface GenerateResult { @@ -93,24 +93,19 @@ export function generateNewListDefinition(numbering: NumberingModel, options: Ge }), ); - if (bulletStyle && listType !== 'orderedList') { - const styleChars = BULLET_STYLE_CHARS[bulletStyle]; - if (styleChars) { + // Override the bullet style for the new list if a bullet style is provided + const shouldOverrideBulletStyle = bulletStyle && listType !== 'orderedList'; + if (shouldOverrideBulletStyle) { + const char = BULLET_STYLE_CHARS[bulletStyle]; + if (char) { const lvl0 = newAbstractDef.elements.find((el: any) => el.name === 'w:lvl' && el.attributes['w:ilvl'] === '0'); if (lvl0) { const lvlText = lvl0.elements.find((el: any) => el.name === 'w:lvlText'); - if (lvlText) lvlText.attributes['w:val'] = styleChars.char; - let rPr = lvl0.elements.find((el: any) => el.name === 'w:rPr'); - if (!rPr) { - rPr = { type: 'element', name: 'w:rPr', elements: [] }; - lvl0.elements.push(rPr); - } - rPr.elements = rPr.elements.filter((el: any) => el.name !== 'w:rFonts'); - rPr.elements.push({ - type: 'element', - name: 'w:rFonts', - attributes: { 'w:ascii': styleChars.font, 'w:hAnsi': styleChars.font, 'w:hint': 'default' }, - }); + if (lvlText) lvlText.attributes['w:val'] = char; + + // Remove any inherited font so the Unicode char renders in the document's default font + const rPr = lvl0.elements.find((el: any) => el.name === 'w:rPr'); + if (rPr) rPr.elements = rPr.elements.filter((el: any) => el.name !== 'w:rFonts'); } } } From ce505e4c06582fb38bf7171a16048b4b5be26d01 Mon Sep 17 00:00:00 2001 From: Gabriel Chittolina Date: Fri, 17 Apr 2026 15:17:56 -0300 Subject: [PATCH 4/6] chore: small code tweaks --- .../src/editors/v1/core/parts/adapters/numbering-transforms.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts index 2d5280df17..487a80a99e 100644 --- a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts +++ b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts @@ -97,8 +97,10 @@ export function generateNewListDefinition(numbering: NumberingModel, options: Ge const shouldOverrideBulletStyle = bulletStyle && listType !== 'orderedList'; if (shouldOverrideBulletStyle) { const char = BULLET_STYLE_CHARS[bulletStyle]; + if (char) { const lvl0 = newAbstractDef.elements.find((el: any) => el.name === 'w:lvl' && el.attributes['w:ilvl'] === '0'); + if (lvl0) { const lvlText = lvl0.elements.find((el: any) => el.name === 'w:lvlText'); if (lvlText) lvlText.attributes['w:val'] = char; From a1e646077727d26f3b704f7cdef0051f119bf42c Mon Sep 17 00:00:00 2001 From: Gabriel Chittolina Date: Mon, 20 Apr 2026 15:46:35 -0300 Subject: [PATCH 5/6] feat: extra ordered list types --- .../toolbar/NumberedStyleButtons.vue | 140 ++++++++++++++++++ .../v1/components/toolbar/defaultItems.js | 25 +++- .../v1/components/toolbar/super-toolbar.js | 9 ++ .../v1/components/toolbar/toolbarIcons.js | 14 ++ .../editors/v1/core/commands/toggleList.js | 29 +++- .../v1/core/helpers/list-numbering-helpers.js | 24 ++- .../parts/adapters/numbering-transforms.ts | 32 +++- .../v1/extensions/paragraph/paragraph.js | 9 ++ .../v1/extensions/types/paragraph-commands.ts | 12 ++ .../create-headless-toolbar.test.ts | 6 +- .../src/headless-toolbar/helpers/paragraph.ts | 12 +- .../headless-toolbar/toolbar-registry.test.ts | 2 + .../src/headless-toolbar/toolbar-registry.ts | 2 +- .../common/icons/list-decimal-paren-solid.svg | 13 ++ shared/common/icons/list-decimal-solid.svg | 13 ++ .../icons/list-lower-alpha-paren-solid.svg | 6 + .../common/icons/list-lower-alpha-solid.svg | 6 + .../common/icons/list-lower-roman-solid.svg | 6 + .../common/icons/list-upper-alpha-solid.svg | 6 + .../common/icons/list-upper-roman-solid.svg | 6 + 20 files changed, 353 insertions(+), 19 deletions(-) create mode 100644 packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue create mode 100644 shared/common/icons/list-decimal-paren-solid.svg create mode 100644 shared/common/icons/list-decimal-solid.svg create mode 100644 shared/common/icons/list-lower-alpha-paren-solid.svg create mode 100644 shared/common/icons/list-lower-alpha-solid.svg create mode 100644 shared/common/icons/list-lower-roman-solid.svg create mode 100644 shared/common/icons/list-upper-alpha-solid.svg create mode 100644 shared/common/icons/list-upper-roman-solid.svg diff --git a/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue b/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue new file mode 100644 index 0000000000..1226159611 --- /dev/null +++ b/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js b/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js index f9c6206b8a..5ae142f028 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/defaultItems.js @@ -5,6 +5,7 @@ import { useToolbarItem } from './use-toolbar-item'; import AIWriter from './AIWriter.vue'; import AlignmentButtons from './AlignmentButtons.vue'; import BulletStyleButtons from './BulletStyleButtons.vue'; +import NumberedStyleButtons from './NumberedStyleButtons.vue'; import DocumentMode from './DocumentMode.vue'; import LinkedStyle from './LinkedStyle.vue'; import LinkInput from './LinkInput.vue'; @@ -663,16 +664,34 @@ export const makeDefaultItems = ({ // number list const numberedList = useToolbarItem({ - type: 'button', + type: 'dropdown', name: 'numberedlist', - command: 'toggleOrderedList', + command: 'toggleOrderedListStyle', icon: toolbarIcons.numberedList, - active: false, + hasCaret: true, tooltip: toolbarTexts.numberedList, restoreEditorFocus: true, + suppressActiveHighlight: true, attributes: { ariaLabel: 'Numbered list', }, + options: [ + { + type: 'render', + key: 'numbered-style-buttons', + render: () => { + const handleSelect = (style) => { + closeDropdown(numberedList); + const item = { ...numberedList, command: 'toggleOrderedListStyle' }; + superToolbar.emitCommand({ item, argument: style }); + }; + return h(NumberedStyleButtons, { + selectedStyle: numberedList.selectedValue.value, + onSelect: handleSelect, + }); + }, + }, + ], }); // indent left diff --git a/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js b/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js index 28db7b3885..11ff4ab090 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/super-toolbar.js @@ -632,6 +632,15 @@ export class SuperToolbar extends EventEmitter { item.selectedValue.value = null; } }, + numberedlist: () => { + if (commandState?.active) { + item.activate(); + item.selectedValue.value = commandState.value; + } else { + item.deactivate(); + item.selectedValue.value = null; + } + }, default: () => { if (commandState?.active) item.activate(); else item.deactivate(); diff --git a/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js b/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js index 8b8caf0f08..275a39e5e8 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js +++ b/packages/super-editor/src/editors/v1/components/toolbar/toolbarIcons.js @@ -5,6 +5,13 @@ import listIconSvg from '@superdoc/common/icons/list-solid.svg?raw'; import listCircleIconSvg from '@superdoc/common/icons/list-circle-solid.svg?raw'; import listSquareIconSvg from '@superdoc/common/icons/list-square-solid.svg?raw'; import listOlIconSvg from '@superdoc/common/icons/list-ol-solid.svg?raw'; +import listDecimalIconSvg from '@superdoc/common/icons/list-decimal-solid.svg?raw'; +import listDecimalParenIconSvg from '@superdoc/common/icons/list-decimal-paren-solid.svg?raw'; +import listUpperRomanIconSvg from '@superdoc/common/icons/list-upper-roman-solid.svg?raw'; +import listLowerRomanIconSvg from '@superdoc/common/icons/list-lower-roman-solid.svg?raw'; +import listUpperAlphaIconSvg from '@superdoc/common/icons/list-upper-alpha-solid.svg?raw'; +import listLowerAlphaIconSvg from '@superdoc/common/icons/list-lower-alpha-solid.svg?raw'; +import listLowerAlphaParenIconSvg from '@superdoc/common/icons/list-lower-alpha-paren-solid.svg?raw'; import imageIconSvg from '@superdoc/common/icons/image-solid.svg?raw'; import linkIconSvg from '@superdoc/common/icons/link-solid.svg?raw'; import alignLeftIconSvg from '@superdoc/common/icons/align-left-solid.svg?raw'; @@ -70,6 +77,13 @@ export const toolbarIcons = { bulletListCircle: listCircleIconSvg, bulletListSquare: listSquareIconSvg, numberedList: listOlIconSvg, + numberedListDecimal: listDecimalIconSvg, + numberedListDecimalParen: listDecimalParenIconSvg, + numberedListUpperRoman: listUpperRomanIconSvg, + numberedListLowerRoman: listLowerRomanIconSvg, + numberedListUpperAlpha: listUpperAlphaIconSvg, + numberedListLowerAlpha: listLowerAlphaIconSvg, + numberedListLowerAlphaParen: listLowerAlphaParenIconSvg, indentLeft: outdentIconSvg, indentRight: indentIconSvg, pageBreak: fileHalfDashedIconSvg, diff --git a/packages/super-editor/src/editors/v1/core/commands/toggleList.js b/packages/super-editor/src/editors/v1/core/commands/toggleList.js index 7aebd43a76..4eeccdbb9f 100644 --- a/packages/super-editor/src/editors/v1/core/commands/toggleList.js +++ b/packages/super-editor/src/editors/v1/core/commands/toggleList.js @@ -1,6 +1,6 @@ // @ts-check import { updateNumberingProperties } from './changeListLevel.js'; -import { ListHelpers, markerTextToBulletStyle } from '@helpers/list-numbering-helpers.js'; +import { ListHelpers, markerTextToBulletStyle, numberingInfoToOrderedStyle } from '@helpers/list-numbering-helpers.js'; import { getResolvedParagraphProperties } from '@extensions/paragraph/resolvedPropertiesCache.js'; import { isVisuallyEmptyParagraph } from './removeNumberingProperties.js'; import { Selection, TextSelection } from 'prosemirror-state'; @@ -26,7 +26,14 @@ function getParagraphListKind(node, editor) { return numFmtIsBullet(fmt) ? 'bullet' : 'ordered'; } -function paragraphMatchesToggleListType(node, editor, listType, bulletStyle) { +/** + * @param {any} node + * @param {any} editor + * @param {string} listType + * @param {'disc'|'circle'|'square'|null} [bulletStyle] + * @param {import('../../extensions/types/paragraph-commands.js').OrderedListStyle|null} [orderedStyle] + */ +function paragraphMatchesToggleListType(node, editor, listType, bulletStyle, orderedStyle) { const kind = getParagraphListKind(node, editor); if (!kind) return false; if (listType === 'bulletList') { @@ -35,7 +42,12 @@ function paragraphMatchesToggleListType(node, editor, listType, bulletStyle) { const markerText = node.attrs.listRendering?.markerText; return markerTextToBulletStyle(markerText) === bulletStyle; } - if (listType === 'orderedList') return kind === 'ordered'; + if (listType === 'orderedList') { + if (kind !== 'ordered') return false; + if (!orderedStyle) return true; + const { numberingType, markerText } = node.attrs.listRendering ?? {}; + return numberingInfoToOrderedStyle(numberingType, markerText) === orderedStyle; + } return false; } @@ -64,14 +76,19 @@ function getPrecedingParagraphForListReuse(doc, from, paragraphsInSelection) { return nb?.type?.name === 'paragraph' ? nb : null; } +/** + * @param {string} listType + * @param {'disc'|'circle'|'square'|null} [bulletStyle] + * @param {import('../../extensions/types/paragraph-commands.js').OrderedListStyle|null} [orderedStyle] + */ export const toggleList = - (listType, bulletStyle) => + (listType, bulletStyle, orderedStyle) => ({ editor, state, tr, dispatch }) => { if (listType !== 'orderedList' && listType !== 'bulletList') { return false; } - const predicate = (n) => paragraphMatchesToggleListType(n, editor, listType, bulletStyle); + const predicate = (n) => paragraphMatchesToggleListType(n, editor, listType, bulletStyle, orderedStyle); const { selection } = state; const { from, to } = selection; let firstListNode = null; @@ -132,7 +149,7 @@ export const toggleList = if (mode === 'create') { const numId = ListHelpers.getNewListId(editor); - ListHelpers.generateNewListDefinition({ numId: Number(numId), listType, editor, bulletStyle }); + ListHelpers.generateNewListDefinition({ numId: Number(numId), listType, editor, bulletStyle, orderedStyle }); sharedNumberingProperties = { numId: Number(numId), ilvl: 0, diff --git a/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js b/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js index 3c584f2b70..84cddff10a 100644 --- a/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js +++ b/packages/super-editor/src/editors/v1/core/helpers/list-numbering-helpers.js @@ -5,7 +5,6 @@ import { translator as wNumTranslator } from '@core/super-converter/v3/handlers/ import { baseBulletList, baseOrderedListDef } from './baseListDefinitions'; import { updateNumberingProperties } from '@core/commands/changeListLevel'; import { findParentNode } from './findParentNode.js'; - import { generateNewListDefinition as pureGenerateNewListDefinition, changeNumIdSameAbstract as pureChangeNumIdSameAbstract, @@ -40,6 +39,26 @@ export function markerTextToBulletStyle(markerText) { return map[markerText] ?? null; } +/** + * Maps `listRendering.numberingType` + last char of `listRendering.markerText` to a named ordered style. + * Returns null for unrecognized combinations. + * @param {import('../../extensions/types/paragraph-commands.js').OrderedListStyle|null|undefined} numberingType + * @param {string|null|undefined} markerText + * @returns {import('../../extensions/types/paragraph-commands.js').OrderedListStyle|null} + */ +export function numberingInfoToOrderedStyle(numberingType, markerText) { + const suffix = markerText?.slice(-1); + /** @type {Record>} */ + const map = { + decimal: { '.': 'decimal', ')': 'decimal-paren' }, + upperRoman: { '.': 'upper-roman' }, + lowerRoman: { '.': 'lower-roman' }, + upperLetter: { '.': 'upper-alpha' }, + lowerLetter: { '.': 'lower-alpha', ')': 'lower-alpha-paren' }, + }; + return map[numberingType]?.[suffix] ?? null; +} + /** * Generate a new list definition for the given list type. * @param {Object} param0 @@ -51,6 +70,7 @@ export function markerTextToBulletStyle(markerText) { * @param {string} [param0.fmt] * @param {string} [param0.markerFontFamily] * @param {'disc'|'circle'|'square'} [param0.bulletStyle] + * @param {import('../../extensions/types/paragraph-commands.js').OrderedListStyle} [param0.orderedStyle] * @param {import('../Editor').Editor} param0.editor * @returns {Object} The new abstract and num definitions. */ @@ -64,6 +84,7 @@ export const generateNewListDefinition = ({ editor, markerFontFamily, bulletStyle, + orderedStyle, }) => { /** @type {{ abstractDef: any, numDef: any }} */ let resultDefs; @@ -78,6 +99,7 @@ export const generateNewListDefinition = ({ fmt, markerFontFamily, bulletStyle, + orderedStyle, }); resultDefs = { abstractDef: result.abstractDef, numDef: result.numDef }; }); diff --git a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts index 487a80a99e..929a138b94 100644 --- a/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts +++ b/packages/super-editor/src/editors/v1/core/parts/adapters/numbering-transforms.ts @@ -12,6 +12,7 @@ */ import { baseBulletList, baseOrderedListDef } from '../../helpers/baseListDefinitions.js'; +import type { OrderedListStyle } from '../../../extensions/types/paragraph-commands.js'; // --------------------------------------------------------------------------- // Types @@ -31,6 +32,7 @@ interface GenerateOptions { fmt?: string | null; markerFontFamily?: string | null; bulletStyle?: 'disc' | 'circle' | 'square' | null; + orderedStyle?: OrderedListStyle | null; } const BULLET_STYLE_CHARS: Record = { @@ -39,6 +41,16 @@ const BULLET_STYLE_CHARS: Record = { square: '▪', }; +const ORDERED_LIST_STYLES: Record = { + decimal: { fmt: 'decimal', text: '%1.' }, + 'decimal-paren': { fmt: 'decimal', text: '%1)' }, + 'upper-roman': { fmt: 'upperRoman', text: '%1.' }, + 'lower-roman': { fmt: 'lowerRoman', text: '%1.' }, + 'upper-alpha': { fmt: 'upperLetter', text: '%1.' }, + 'lower-alpha': { fmt: 'lowerLetter', text: '%1.' }, + 'lower-alpha-paren': { fmt: 'lowerLetter', text: '%1)' }, +}; + interface GenerateResult { numId: number; abstractId: number; @@ -79,7 +91,7 @@ function buildNumDef(numId: number, abstractId: number): any { */ export function generateNewListDefinition(numbering: NumberingModel, options: GenerateOptions): GenerateResult { let { listType } = options; - const { numId, level, start, text, fmt, markerFontFamily, bulletStyle } = options; + const { numId, level, start, text, fmt, markerFontFamily, bulletStyle, orderedStyle } = options; if (typeof listType !== 'string') listType = (listType as any).name; const definition = listType === 'orderedList' ? baseOrderedListDef : baseBulletList; @@ -112,6 +124,24 @@ export function generateNewListDefinition(numbering: NumberingModel, options: Ge } } + // Override the ordered list style for the new list if an ordered style is provided + const shouldOverrideOrderedStyle = orderedStyle && listType === 'orderedList'; + if (shouldOverrideOrderedStyle) { + const styleConfig = ORDERED_LIST_STYLES[orderedStyle]; + + if (styleConfig) { + const lvl0 = newAbstractDef.elements.find((el: any) => el.name === 'w:lvl' && el.attributes['w:ilvl'] === '0'); + + if (lvl0) { + const numFmt = lvl0.elements.find((el: any) => el.name === 'w:numFmt'); + if (numFmt) numFmt.attributes['w:val'] = styleConfig.fmt; + + const lvlText = lvl0.elements.find((el: any) => el.name === 'w:lvlText'); + if (lvlText) lvlText.attributes['w:val'] = styleConfig.text; + } + } + } + if (level != null && start != null && text != null && fmt != null) { if (numbering.definitions[numId]) { const abstractId = numbering.definitions[numId]?.elements[0]?.attributes['w:val']; diff --git a/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js b/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js index 0d51b7e617..f8e8de976a 100644 --- a/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js +++ b/packages/super-editor/src/editors/v1/extensions/paragraph/paragraph.js @@ -334,6 +334,15 @@ export const Paragraph = OxmlNode.create({ toggleBulletListStyle: (style) => (params) => { return toggleList('bulletList', style)(params); }, + /** + * Toggle an ordered list with a specific numbering style at the current selection + * @category Command + * @example + * editor.commands.toggleOrderedListStyle('upper-roman') + */ + toggleOrderedListStyle: (style) => (params) => { + return toggleList('orderedList', null, style)(params); + }, /** * Restart numbering for the current list diff --git a/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts b/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts index 06681a3037..c06b7fcc65 100644 --- a/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts +++ b/packages/super-editor/src/editors/v1/extensions/types/paragraph-commands.ts @@ -4,6 +4,15 @@ * @module ParagraphCommands */ +export type OrderedListStyle = + | 'decimal' + | 'decimal-paren' + | 'upper-roman' + | 'lower-roman' + | 'upper-alpha' + | 'lower-alpha' + | 'lower-alpha-paren'; + export interface ParagraphCommands { // ============================================ // LIST COMMANDS @@ -18,6 +27,9 @@ export interface ParagraphCommands { /** Toggle a bullet list with a specific style ('disc' | 'circle' | 'square') */ toggleBulletListStyle: (style: 'disc' | 'circle' | 'square') => boolean; + /** Toggle an ordered list with a specific numbering style */ + toggleOrderedListStyle: (style: OrderedListStyle) => boolean; + /** Restart numbering for the current list item */ restartNumbering: () => boolean; diff --git a/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts b/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts index 41a057582c..f035397218 100644 --- a/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts +++ b/packages/super-editor/src/headless-toolbar/create-headless-toolbar.test.ts @@ -501,10 +501,10 @@ describe('createHeadlessToolbar', () => { }); it('executes numbered-list through the registry direct command path', () => { - const toggleOrderedList = vi.fn(() => true); + const toggleOrderedListStyle = vi.fn(() => true); const superdoc = createActiveEditorHost({ commands: { - toggleOrderedList, + toggleOrderedListStyle, }, state: createSelectionState({ empty: true, @@ -523,7 +523,7 @@ describe('createHeadlessToolbar', () => { }); expect(controller.execute?.('numbered-list')).toBe(true); - expect(toggleOrderedList).toHaveBeenCalledTimes(1); + expect(toggleOrderedListStyle).toHaveBeenCalledTimes(1); controller.destroy(); }); diff --git a/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts b/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts index 8ff4b0598c..785a7d1433 100644 --- a/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts +++ b/packages/super-editor/src/headless-toolbar/helpers/paragraph.ts @@ -1,4 +1,6 @@ import { isList } from '../../editors/v1/core/commands/list-helpers/is-list.js'; +import { numberingInfoToOrderedStyle } from '../../editors/v1/core/helpers/list-numbering-helpers.js'; +import type { OrderedListStyle } from '../../editors/v1/extensions/types/paragraph-commands.js'; import { twipsToLines } from '../../editors/v1/core/super-converter/helpers.js'; import { getQuickFormatList } from '../../editors/v1/extensions/linked-styles/index.js'; import { getCurrentParagraphParent, getCurrentResolvedParagraphProperties, resolveStateEditor } from './context.js'; @@ -122,10 +124,12 @@ export const createListStateDeriver = return { active: isActive, disabled: false, value: markerText }; } - return { - active: isActive, - disabled: false, - }; + const activeNumberingFmt = isActive ? (paragraphNode?.attrs?.listRendering?.numberingType ?? null) : null; + const activeMarkerText = isActive ? (paragraphNode?.attrs?.listRendering?.markerText ?? null) : null; + const orderedStyleValue = ( + activeNumberingFmt && activeMarkerText ? numberingInfoToOrderedStyle(activeNumberingFmt, activeMarkerText) : null + ) as OrderedListStyle | null; + return { active: isActive, disabled: false, value: orderedStyleValue }; }; export const createIndentIncreaseExecute = diff --git a/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts b/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts index 9d705a752f..391142e6a5 100644 --- a/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts +++ b/packages/super-editor/src/headless-toolbar/toolbar-registry.test.ts @@ -566,6 +566,7 @@ describe('createToolbarRegistry', () => { attrs: { listRendering: { numberingType: 'decimal', + markerText: '1.', }, paragraphProperties: { numberingProperties: { @@ -589,6 +590,7 @@ describe('createToolbarRegistry', () => { expect(state).toEqual({ active: true, disabled: false, + value: 'decimal', }); }); diff --git a/packages/super-editor/src/headless-toolbar/toolbar-registry.ts b/packages/super-editor/src/headless-toolbar/toolbar-registry.ts index a4026e9422..a6c7943eac 100644 --- a/packages/super-editor/src/headless-toolbar/toolbar-registry.ts +++ b/packages/super-editor/src/headless-toolbar/toolbar-registry.ts @@ -124,7 +124,7 @@ export const createToolbarRegistry = (): Partial + + + + + + + + + + + + diff --git a/shared/common/icons/list-decimal-solid.svg b/shared/common/icons/list-decimal-solid.svg new file mode 100644 index 0000000000..3fd9c615c1 --- /dev/null +++ b/shared/common/icons/list-decimal-solid.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/shared/common/icons/list-lower-alpha-paren-solid.svg b/shared/common/icons/list-lower-alpha-paren-solid.svg new file mode 100644 index 0000000000..cb808f946f --- /dev/null +++ b/shared/common/icons/list-lower-alpha-paren-solid.svg @@ -0,0 +1,6 @@ + + + a) + b) + c) + diff --git a/shared/common/icons/list-lower-alpha-solid.svg b/shared/common/icons/list-lower-alpha-solid.svg new file mode 100644 index 0000000000..a68f8f6037 --- /dev/null +++ b/shared/common/icons/list-lower-alpha-solid.svg @@ -0,0 +1,6 @@ + + + a. + b. + c. + diff --git a/shared/common/icons/list-lower-roman-solid.svg b/shared/common/icons/list-lower-roman-solid.svg new file mode 100644 index 0000000000..8043cb4059 --- /dev/null +++ b/shared/common/icons/list-lower-roman-solid.svg @@ -0,0 +1,6 @@ + + + i. + ii. + iii. + diff --git a/shared/common/icons/list-upper-alpha-solid.svg b/shared/common/icons/list-upper-alpha-solid.svg new file mode 100644 index 0000000000..08ddfeeba1 --- /dev/null +++ b/shared/common/icons/list-upper-alpha-solid.svg @@ -0,0 +1,6 @@ + + + A. + B. + C. + diff --git a/shared/common/icons/list-upper-roman-solid.svg b/shared/common/icons/list-upper-roman-solid.svg new file mode 100644 index 0000000000..e74d50cc38 --- /dev/null +++ b/shared/common/icons/list-upper-roman-solid.svg @@ -0,0 +1,6 @@ + + + I. + II. + III. + From 69b0ccbdd39b9219bc273feeb8db77a5da0805ef Mon Sep 17 00:00:00 2001 From: Gabriel Chittolina Date: Mon, 20 Apr 2026 15:53:39 -0300 Subject: [PATCH 6/6] chore: small UI tweaks --- .../editors/v1/components/toolbar/NumberedStyleButtons.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue b/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue index 1226159611..2281d02914 100644 --- a/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue +++ b/packages/super-editor/src/editors/v1/components/toolbar/NumberedStyleButtons.vue @@ -101,8 +101,8 @@ onMounted(() => { padding: 5px; font-size: var(--sd-ui-font-size-600, 16px); color: var(--sd-ui-dropdown-text, #47484a); - width: 40px; - height: 40px; + width: 30px; + height: 30px; border-radius: var(--sd-ui-dropdown-option-radius, 3px); display: flex; justify-content: center;