Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .playwright/screenshots/alignment-mixed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/display-alignment-checkbox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/display-alignment-mixed-lists.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/display-alignment-ol.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/display-alignment-ul.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-all-list-types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-checkbox-list-checked.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-checkbox-list-unchecked.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-checkbox-list-wrapped.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-images-inside-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-ordered-list-wrapped.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-ordered-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-unordered-list-wrapped.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/enriched-text-unordered-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/images-checkbox-list-placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/images-loaded-in-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/images-ol-placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/images-ul-placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .playwright/screenshots/list-keyboard-enter-bullet.png
Binary file modified .playwright/screenshots/list-keyboard-enter-checkbox.png
Binary file modified .playwright/screenshots/list-keyboard-enter-ordered.png
Binary file modified .playwright/screenshots/list-nested-html-ol-in-ul.png
Binary file modified .playwright/screenshots/list-nested-html-triple-nested-ul.png
Binary file modified .playwright/screenshots/list-nested-html-ul-in-ol.png
Binary file modified .playwright/screenshots/list-nested-html-ul-in-ul.png
Binary file modified .playwright/screenshots/paragraph-styles-visual-checkbox-list.png
Binary file modified .playwright/screenshots/paragraph-styles-visual-ordered-list.png
21 changes: 21 additions & 0 deletions .playwright/tests/enrichedTextVisual.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ test.describe('visual: complex lists and layouts', () => {
});
});

test.describe('visual: extended ordered list margin', () => {
test('ordered list adds a necessary margin to fit larger marker values', async ({
page,
}) => {
const htmlBefore = `<html><ol>${'<li>*</li>'.repeat(9)}</ol></html>`;

await gotoTestEnrichedText(page);
await setEnrichedTextValue(page, htmlBefore);
await expect(displayLocator(page)).toHaveScreenshot(
'enriched-text-ordered-list-extended-margin-before.png'
);

const htmlAfter = `<html><ol>${'<li>*</li>'.repeat(10)}</ol></html>`;

await setEnrichedTextValue(page, htmlAfter);
await expect(displayLocator(page)).toHaveScreenshot(
'enriched-text-ordered-list-extended-margin-after.png'
);
});
});

test.describe('visual: typography, blocks, and wrapping', () => {
const cases = [
{
Expand Down
20 changes: 20 additions & 0 deletions .playwright/tests/paragraphStylesVisual.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,24 @@ test.describe('paragraph styles visual', () => {
'paragraph-styles-visual-checkbox-list-wrapped.png'
);
});

test('ordered list adds a necessary margin to fit larger marker values', async ({
page,
}) => {
const htmlBefore = `<html><ol>${'<li>*</li>'.repeat(9)}</ol></html>`;
await setEditorHtml(page, htmlBefore);

const editor = editorLocator(page);

await expect(editor).toHaveScreenshot(
'paragraph-styles-visual-ordered-list-extended-margin-before.png'
);

const htmlAfter = `<html><ol>${'<li>*</li>'.repeat(10)}</ol></html>`;
await setEditorHtml(page, htmlAfter);

await expect(editor).toHaveScreenshot(
'paragraph-styles-visual-ordered-list-extended-margin-after.png'
);
});
});
36 changes: 26 additions & 10 deletions src/web/EnrichedText.css
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@
.et-view ul:not([data-type]) {
margin: 0;
list-style: none;
padding-left: calc(var(--et-ul-margin-left, 16px) + var(--et-ul-gap-width, 16px));
padding-left: calc(
var(--et-ul-margin-left, 16px) +
var(--et-ul-bullet-size, 8px) +
var(--et-ul-gap-width, 16px)
);
}

.eti-editor ul:not([data-type]) > li,
Expand All @@ -179,14 +183,20 @@
margin-right: var(--et-ul-gap-width, 16px);

position: relative;
top: -0.1em;
top: calc(var(--et-ul-bullet-size, 8px) * 0.5 - 0.35em);
}

.eti-editor ol,
.et-view ol {
margin: 0;
list-style: none;
padding-left: calc(var(--et-ol-margin-left, 16px) + var(--et-ol-gap-width, 16px));
/* marker column grows to fit the widest counter ("N."), floored at the
configured margin. */
--et-ol-marker-col: max(
var(--et-ol-margin-left, 16px),
calc((var(--et-ol-digits, 1) + 1) * 1ch)
);
padding-left: calc(var(--et-ol-marker-col) + var(--et-ol-gap-width, 16px));
counter-reset: et-ol;
}

Expand All @@ -202,10 +212,10 @@
.et-view ol > li::before {
content: counter(et-ol) '.';
flex-shrink: 0;
width: var(--et-ol-margin-left, 16px);
width: var(--et-ol-marker-col, var(--et-ol-margin-left, 16px));
text-align: right;
margin-right: calc(var(--et-ol-gap-width, 16px) / 2);
margin-left: calc(-1 * (var(--et-ol-margin-left, 16px) + (var(--et-ol-gap-width, 16px) / 2)));
margin-right: calc(var(--et-ol-gap-width, 16px));
margin-left: calc(-1 * (var(--et-ol-marker-col, var(--et-ol-margin-left, 16px)) + var(--et-ol-gap-width, 16px)));

color: var(--et-ol-marker-color, currentColor);
font-weight: var(--et-ol-marker-font-weight, inherit);
Expand Down Expand Up @@ -258,7 +268,11 @@
.eti-editor ul[data-type='checkboxList'] {
margin: 0;
list-style: none;
padding-left: calc(var(--et-checkbox-margin-left, 16px) + var(--et-checkbox-gap-width, 16px));
padding-left: calc(
var(--et-checkbox-margin-left, 16px) +
var(--et-checkbox-box-size, 24px) +
var(--et-checkbox-gap-width, 16px)
);
}

.eti-editor ul[data-type='checkboxList'] > li {
Expand All @@ -279,7 +293,7 @@

margin-top: 0;
position: relative;
top: 0.15em;
top: calc(var(--et-checkbox-box-size, 24px) * 0.5 - 0.35em);
}

.eti-editor ul[data-type='checkboxList'] > li > label input[type='checkbox'] {
Expand All @@ -301,7 +315,9 @@
margin: 0;
list-style: none;
padding-left: calc(
var(--et-checkbox-margin-left, 16px) + var(--et-checkbox-gap-width, 16px)
var(--et-checkbox-margin-left, 16px) +
var(--et-checkbox-box-size, 24px) +
var(--et-checkbox-gap-width, 16px)
);
}

Expand All @@ -328,7 +344,7 @@

margin-top: 0;
position: relative;
top: 0.15em;
top: calc(var(--et-checkbox-box-size, 24px) * 0.5 - 0.35em);
}

.et-view ul[data-type="checkbox"] > li > label {
Expand Down
3 changes: 3 additions & 0 deletions src/web/EnrichedText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { usePressInteractions } from './usePressInteractions';
import { adaptWebToNativeEvent } from './adaptWebToNativeEvent';
import { useStableRef } from './useStableRef';
import { assertBrowserEnvironment } from './assertBrowserEnvironment';
import { useOrderedListMarkerWidth } from './useOrderedListMarkerWidth';

export const EnrichedText = memo(
({
Expand Down Expand Up @@ -105,6 +106,8 @@ export const EnrichedText = memo(
const onLinkPressRef = useStableRef(onLinkPress);
const onMentionPressRef = useStableRef(onMentionPress);

useOrderedListMarkerWidth(containerRef, finalHtml);

useImageErrorFallback(containerRef);
usePressInteractions(containerRef, onLinkPressRef, onMentionPressRef);

Expand Down
2 changes: 2 additions & 0 deletions src/web/EnrichedTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import { EnrichedTextAlign } from './formats/EnrichedTextAlign';
import { StripBoldInStyledHeadingsPlugin } from './pmPlugins/StripBoldInStyledHeadingsPlugin';
import { StrictMarksPlugin } from './pmPlugins/StrictMarksPlugin';
import { MergeAdjacentSameKindBlocksPlugin } from './pmPlugins/MergeAdjacentSameKindBlocksPlugin';
import { OrderedListMarkerWidthPlugin } from './pmPlugins/OrderedListMarkerWidthPlugin';
import { StripMarksInCodeBlockPlugin } from './pmPlugins/StripMarksInCodeBlockPlugin';
import { handleClipboardPasteImages } from './pasteImages';
import {
Expand Down Expand Up @@ -228,6 +229,7 @@ export const EnrichedTextInput = ({
getHtmlStyle: () => htmlStyleRef.current,
}),
MergeAdjacentSameKindBlocksPlugin,
OrderedListMarkerWidthPlugin,
StrictMarksPlugin,
MentionPlugin.configure({
getIndicators: () => mentionIndicatorsRef.current,
Expand Down
43 changes: 43 additions & 0 deletions src/web/pmPlugins/OrderedListMarkerWidthPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Extension } from '@tiptap/core';
import { Plugin, PluginKey } from '@tiptap/pm/state';
import { Decoration, DecorationSet } from '@tiptap/pm/view';

// Finds the ordered list markers with the largest values,
// exposing the digit count as --et-ol-digits per <ol>.
export const OrderedListMarkerWidthPlugin = Extension.create({
name: 'orderedListMarkerWidth',

addProseMirrorPlugins() {
return [
new Plugin({
key: new PluginKey('orderedListMarkerWidth'),
props: {
decorations: (state) => {
const decorations: Decoration[] = [];

state.doc.descendants((node, pos) => {
if (node.type.name !== 'orderedList') {
return true;
}

const start =
typeof node.attrs.start === 'number' ? node.attrs.start : 1;
const maxNumber = start + Math.max(0, node.childCount - 1);
const digits = String(maxNumber).length;

decorations.push(
Decoration.node(pos, pos + node.nodeSize, {
style: `--et-ol-digits:${digits}`,
})
);

return false;
});

return DecorationSet.create(state.doc, decorations);
},
},
}),
];
},
});
20 changes: 20 additions & 0 deletions src/web/useOrderedListMarkerWidth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useLayoutEffect, type RefObject } from 'react';

// Finds the ordered list markers with the largest values,
// exposing the digit count as --et-ol-digits per <ol>.
export function useOrderedListMarkerWidth(
containerRef: RefObject<HTMLElement | null>,
finalHtml: string
) {
useLayoutEffect(() => {
const root = containerRef.current;
if (!root) return;

root.querySelectorAll('ol').forEach((ol) => {
const startAttr = Number(ol.getAttribute('start'));
const start = Number.isFinite(startAttr) && startAttr > 0 ? startAttr : 1;
const maxNumber = start + Math.max(0, ol.children.length - 1);
ol.style.setProperty('--et-ol-digits', String(String(maxNumber).length));
});
}, [containerRef, finalHtml]);
}
Loading