Skip to content

Commit d944bb0

Browse files
authored
fix: include injected footnote lookup blocks in resolved layout (#2623)
1 parent 1f707df commit d944bb0

2 files changed

Lines changed: 119 additions & 8 deletions

File tree

packages/super-editor/src/editors/v1/core/presentation-editor/PresentationEditor.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4204,11 +4204,16 @@ export class PresentationEditor extends EventEmitter {
42044204
layout.pageGap = this.#getEffectivePageGap();
42054205
(layout as Layout & { layoutEpoch?: number }).layoutEpoch = layoutEpoch;
42064206

4207+
// Include footnote-injected blocks (separators, footnote paragraphs) so
4208+
// resolveLayout can find them when resolving page fragments.
4209+
const resolveBlocks = extraBlocks ? [...blocksForLayout, ...extraBlocks] : blocksForLayout;
4210+
const resolveMeasures = extraMeasures ? [...measures, ...extraMeasures] : measures;
4211+
42074212
resolvedLayout = resolveLayout({
42084213
layout,
42094214
flowMode: this.#layoutOptions.flowMode ?? 'paginated',
4210-
blocks: blocksForLayout,
4211-
measures,
4215+
blocks: resolveBlocks,
4216+
measures: resolveMeasures,
42124217
});
42134218

42144219
headerLayouts = result.headers;

packages/super-editor/src/editors/v1/core/presentation-editor/tests/PresentationEditor.footnotesPmMarkers.test.ts

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ import { PresentationEditor } from '../PresentationEditor.js';
44
let capturedLayoutOptions: any;
55
let capturedBlocksForLayout: any[] | undefined;
66

7+
const { mockIncrementalLayout, mockResolveLayout } = vi.hoisted(() => ({
8+
mockIncrementalLayout: vi.fn(async (...args: any[]) => {
9+
capturedLayoutOptions = args[3];
10+
capturedBlocksForLayout = args[2];
11+
return { layout: { pages: [] }, measures: [] };
12+
}),
13+
mockResolveLayout: vi.fn(() => ({ version: 1, flowMode: 'paginated', pageGap: 0, pages: [] })),
14+
}));
15+
716
vi.mock('../../Editor', () => ({
817
Editor: vi.fn().mockImplementation(() => ({
918
on: vi.fn(),
@@ -56,11 +65,7 @@ vi.mock('@superdoc/pm-adapter', async (importOriginal) => {
5665
});
5766

5867
vi.mock('@superdoc/layout-bridge', () => ({
59-
incrementalLayout: vi.fn(async (...args: any[]) => {
60-
capturedLayoutOptions = args[3];
61-
capturedBlocksForLayout = args[2];
62-
return { layout: { pages: [] }, measures: [] };
63-
}),
68+
incrementalLayout: mockIncrementalLayout,
6469
normalizeMargin: (value: number | undefined, fallback: number) =>
6570
Number.isFinite(value) ? (value as number) : fallback,
6671
selectionToRects: vi.fn(() => []),
@@ -105,7 +110,7 @@ vi.mock('@superdoc/painter-dom', () => ({
105110
vi.mock('@superdoc/measuring-dom', () => ({ measureBlock: vi.fn(() => ({ width: 100, height: 100 })) }));
106111

107112
vi.mock('@superdoc/layout-resolved', () => ({
108-
resolveLayout: vi.fn(() => ({ version: 1, flowMode: 'paginated', pageGap: 0, pages: [] })),
113+
resolveLayout: mockResolveLayout,
109114
}));
110115

111116
vi.mock('../../header-footer/HeaderFooterRegistry', () => ({
@@ -151,6 +156,14 @@ describe('PresentationEditor - footnote number marker PM position', () => {
151156
document.body.appendChild(container);
152157
capturedLayoutOptions = undefined;
153158
capturedBlocksForLayout = undefined;
159+
mockIncrementalLayout.mockClear();
160+
mockResolveLayout.mockClear();
161+
mockIncrementalLayout.mockImplementation(async (...args: any[]) => {
162+
capturedLayoutOptions = args[3];
163+
capturedBlocksForLayout = args[2];
164+
return { layout: { pages: [] }, measures: [] };
165+
});
166+
mockResolveLayout.mockImplementation(() => ({ version: 1, flowMode: 'paginated', pageGap: 0, pages: [] }));
154167
});
155168

156169
afterEach(() => {
@@ -210,4 +223,97 @@ describe('PresentationEditor - footnote number marker PM position', () => {
210223
expect(firstRun?.pmStart).toBeUndefined();
211224
expect(firstRun?.pmEnd).toBeUndefined();
212225
});
226+
227+
it('passes footnote-injected lookup blocks to resolveLayout', async () => {
228+
mockIncrementalLayout.mockImplementationOnce(async (...args: any[]) => {
229+
capturedLayoutOptions = args[3];
230+
capturedBlocksForLayout = args[2];
231+
return {
232+
layout: {
233+
pageSize: { w: 612, h: 792 },
234+
pages: [
235+
{
236+
number: 1,
237+
size: { w: 612, h: 792 },
238+
fragments: [
239+
{
240+
kind: 'drawing',
241+
blockId: 'footnote-separator-page-1-col-0',
242+
drawingKind: 'vectorShape',
243+
x: 0,
244+
y: 0,
245+
width: 100,
246+
height: 1,
247+
geometry: { width: 100, height: 1 },
248+
scale: 1,
249+
},
250+
{
251+
kind: 'para',
252+
blockId: 'footnote-body-1',
253+
fromLine: 0,
254+
toLine: 1,
255+
x: 0,
256+
y: 2,
257+
width: 100,
258+
},
259+
],
260+
},
261+
],
262+
},
263+
measures: [],
264+
extraBlocks: [
265+
{ kind: 'paragraph', id: 'footnote-body-1', runs: [{ kind: 'text', text: 'Body' }] },
266+
{
267+
kind: 'drawing',
268+
id: 'footnote-separator-page-1-col-0',
269+
drawingKind: 'vectorShape',
270+
geometry: { width: 100, height: 1 },
271+
shapeKind: 'rect',
272+
fillColor: '#000000',
273+
strokeColor: null,
274+
strokeWidth: 0,
275+
},
276+
],
277+
extraMeasures: [
278+
{
279+
kind: 'paragraph',
280+
lines: [
281+
{
282+
fromRun: 0,
283+
fromChar: 0,
284+
toRun: 0,
285+
toChar: 4,
286+
width: 100,
287+
ascent: 8,
288+
descent: 2,
289+
lineHeight: 10,
290+
},
291+
],
292+
totalHeight: 10,
293+
},
294+
{
295+
kind: 'drawing',
296+
drawingKind: 'vectorShape',
297+
width: 100,
298+
height: 1,
299+
scale: 1,
300+
naturalWidth: 100,
301+
naturalHeight: 1,
302+
geometry: { width: 100, height: 1 },
303+
},
304+
],
305+
};
306+
});
307+
308+
editor = new PresentationEditor({ element: container });
309+
await new Promise((r) => setTimeout(r, 100));
310+
311+
expect(mockResolveLayout).toHaveBeenCalled();
312+
const lastResolveInput = mockResolveLayout.mock.calls.at(-1)?.[0];
313+
expect(lastResolveInput).toBeTruthy();
314+
expect(lastResolveInput.blocks.map((block: { id: string }) => block.id)).toEqual(
315+
expect.arrayContaining(['footnote-body-1', 'footnote-separator-page-1-col-0']),
316+
);
317+
expect(lastResolveInput.measures).toHaveLength(lastResolveInput.blocks.length);
318+
});
213319
});

0 commit comments

Comments
 (0)