Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,26 @@ const encode = (params) => {
const { nodes = [], nodeListHandler } = params || {};
const node = nodes[0];

const processedContent = nodeListHandler.handler({
let processedContent = nodeListHandler.handler({
...params,
nodes: node.elements || [],
});
const hasParagraphBlocks = (processedContent || []).some((child) => child?.type === 'paragraph');
if (!hasParagraphBlocks) {
processedContent = [
{
type: 'paragraph',
content: processedContent.filter((child) => Boolean(child && child.type)),
},
];
}
const attrs = {
instruction: node.attributes?.instruction || '',
};
attrs.rightAlignPageNumbers = deriveRightAlignPageNumbers(processedContent);
const processedNode = {
type: 'tableOfContents',
attrs: {
instruction: node.attributes?.instruction || '',
rightAlignPageNumbers: deriveRightAlignPageNumbers(processedContent),
},
attrs,
content: processedContent,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,73 @@ describe('sd:tableOfContents translator', () => {
const result = config.encode(params);
expect(result.attrs.rightAlignPageNumbers).toBe(false);
});

it('wraps inline children into a paragraph when parent accepts blocks', () => {
const mockNodeListHandler = {
handler: vi.fn(() => [{ type: 'text', text: 'Inline content' }]),
};
const params = {
nodes: [
{
name: 'sd:tableOfContents',
attributes: { instruction: 'TOC \\h' },
elements: [{ name: 'w:r', elements: [] }],
},
],
nodeListHandler: mockNodeListHandler,
};

const result = config.encode(params);
expect(result).toEqual({
type: 'tableOfContents',
attrs: { instruction: 'TOC \\h', rightAlignPageNumbers: true },
content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Inline content' }] }],
});
});

it('does not wrap when content already contains paragraph blocks', () => {
const mockNodeListHandler = {
handler: vi.fn(() => [
{ type: 'paragraph', content: [{ type: 'text', text: 'Para' }] },
{ type: 'text', text: 'trailing inline' },
]),
};
const params = {
nodes: [
{
name: 'sd:tableOfContents',
attributes: { instruction: 'TOC \\o "1-3"' },
elements: [{ name: 'w:p', elements: [] }],
},
],
nodeListHandler: mockNodeListHandler,
};

const result = config.encode(params);
expect(result.content).toEqual([
{ type: 'paragraph', content: [{ type: 'text', text: 'Para' }] },
{ type: 'text', text: 'trailing inline' },
]);
});

it('filters out null and typeless children when wrapping', () => {
const mockNodeListHandler = {
handler: vi.fn(() => [null, { type: 'text', text: 'valid' }, undefined, {}]),
};
const params = {
nodes: [
{
name: 'sd:tableOfContents',
attributes: { instruction: 'TOC \\h' },
elements: [{ name: 'w:r', elements: [] }],
},
],
nodeListHandler: mockNodeListHandler,
};

const result = config.encode(params);
expect(result.content).toEqual([{ type: 'paragraph', content: [{ type: 'text', text: 'valid' }] }]);
});
});

describe('decode', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/super-editor/src/editors/v1/extensions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ export {
TableCell,
TableHeader,
DocumentIndex,
TableOfContents,
IndexEntry,
TableOfContentsEntry,
TocPageNumber,
Expand Down
29 changes: 29 additions & 0 deletions tests/behavior/tests/importing/sd-2440-field-based-toc.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { test, expect } from '../../fixtures/superdoc.js';
import { assertDocumentApiReady, getDocumentText } from '../../helpers/document-api.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DOC_PATH = path.resolve(
__dirname,
'../../test-data/rendering/sd-2440-field-based-toc-list-of-tables-figures.docx',
);

test.skip(!fs.existsSync(DOC_PATH), 'Test document not available — run pnpm corpus:pull');

test.use({ config: { toolbar: 'full', comments: 'off' } });

test('loads document with field-based TOC list of tables/figures without schema errors (SD-2440)', async ({
superdoc,
}) => {
await superdoc.loadDocument(DOC_PATH);
await superdoc.waitForStable();
await assertDocumentApiReady(superdoc.page);

const text = await getDocumentText(superdoc.page);
expect(text.length).toBeGreaterThan(0);

await expect(superdoc.page.locator('.superdoc-page').first()).toBeVisible();
await expect(superdoc.page.locator('.superdoc-line').first()).toBeVisible();
});
Loading