feat(editor): indentation (#2174)

* switch to default codeblock tab handling

* feat(editor): indentation
This commit is contained in:
Philip Okugbe
2026-05-08 21:40:37 +01:00
committed by GitHub
parent c66c08fa78
commit 2d8b470495
10 changed files with 328 additions and 26 deletions
@@ -34,6 +34,7 @@ import {
Mention,
Subpages,
Highlight,
Indent,
UniqueID,
Columns,
Column,
@@ -62,10 +63,11 @@ export const tiptapExtensions = [
}),
Heading,
UniqueID.configure({
types: ['heading', 'paragraph'],
types: ['heading', 'paragraph', 'transclusionSource'],
}),
Comment,
TextAlign.configure({ types: ['heading', 'paragraph'] }),
Indent,
TaskList,
TaskItem.configure({
nested: true,
@@ -0,0 +1,63 @@
import { htmlToJson, jsonToHtml } from '../../../collaboration/collaboration.util';
const findFirstChild = (
json: any,
type: string,
): any | undefined => {
if (!json || typeof json !== 'object') return undefined;
if (json.type === type) return json;
if (Array.isArray(json.content)) {
for (const child of json.content) {
const found = findFirstChild(child, type);
if (found) return found;
}
}
return undefined;
};
describe('indent attribute round-trip', () => {
it('parses data-indent on a paragraph into the indent attribute', () => {
const html = '<p data-indent="3">Hello</p>';
const json = htmlToJson(html);
const paragraph = findFirstChild(json, 'paragraph');
expect(paragraph).toBeDefined();
expect(paragraph.attrs.indent).toBe(3);
});
it('parses data-indent on a heading into the indent attribute', () => {
const html = '<h2 data-indent="2">Heading</h2>';
const json = htmlToJson(html);
const heading = findFirstChild(json, 'heading');
expect(heading).toBeDefined();
expect(heading.attrs.indent).toBe(2);
expect(heading.attrs.level).toBe(2);
});
it('clamps out-of-range data-indent values', () => {
const html = '<p data-indent="42">Too deep</p>';
const json = htmlToJson(html);
const paragraph = findFirstChild(json, 'paragraph');
expect(paragraph.attrs.indent).toBe(8);
});
it('renders nonzero indent back to data-indent on HTML serialization', () => {
const html = '<p data-indent="4">Round-trip</p>';
const json = htmlToJson(html);
const out = jsonToHtml(json);
expect(out).toContain('data-indent="4"');
});
it('omits data-indent for indent zero', () => {
const html = '<p>No indent</p>';
const json = htmlToJson(html);
const out = jsonToHtml(json);
expect(out).not.toContain('data-indent');
});
it('preserves indent through HTML → JSON → HTML', () => {
const original = '<p data-indent="5">Five deep</p>';
const json = htmlToJson(original);
const final = jsonToHtml(json);
expect(final).toContain('data-indent="5"');
});
});