Skip to content

Commit 2bd2398

Browse files
committed
fix: fetch assets inside dynamic content (diegomura#1369, diegomura#1587, diegomura#1630, diegomura#1936, diegomura#2064)
1 parent fab09cc commit 2bd2398

4 files changed

+233
-34
lines changed

packages/layout/src/steps/resolvePagination.js

+43-27
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/* eslint-disable prefer-destructuring */
44

55
import * as P from '@react-pdf/primitives';
6-
import { isNil, omit, compose } from '@react-pdf/fns';
6+
import { isNil, omit, asyncCompose } from '@react-pdf/fns';
77

88
import isFixed from '../node/isFixed';
99
import splitText from '../text/splitText';
@@ -17,6 +17,7 @@ import resolveTextLayout from './resolveTextLayout';
1717
import resolveInheritance from './resolveInheritance';
1818
import { resolvePageDimensions } from './resolveDimensions';
1919
import { resolvePageStyles } from './resolveStyles';
20+
import resolveAssets from './resolveAssets';
2021

2122
const isText = (node) => node.type === P.Text;
2223

@@ -32,7 +33,8 @@ const allFixed = (nodes) => nodes.every(isFixed);
3233

3334
const isDynamic = (node) => !isNil(node.props?.render);
3435

35-
const relayoutPage = compose(
36+
const relayoutPage = asyncCompose(
37+
resolveAssets,
3638
resolveTextLayout,
3739
resolvePageDimensions,
3840
resolveInheritance,
@@ -175,19 +177,20 @@ const resolveDynamicNodes = (props, node) => {
175177
return Object.assign({}, node, { box, lines, children });
176178
};
177179

178-
const resolveDynamicPage = (props, page, fontStore, yoga) => {
180+
const resolveDynamicPage = async (props, page, fontStore, yoga) => {
179181
if (shouldResolveDynamicNodes(page)) {
180182
const resolvedPage = resolveDynamicNodes(props, page);
181-
return relayoutPage(resolvedPage, fontStore, yoga);
183+
const relayoutedPage = await relayoutPage(resolvedPage, fontStore, yoga);
184+
return relayoutedPage;
182185
}
183186

184187
return page;
185188
};
186189

187-
const splitPage = (page, pageNumber, fontStore, yoga) => {
190+
const splitPage = async (page, pageNumber, fontStore, yoga) => {
188191
const wrapArea = getWrapArea(page);
189192
const contentArea = getContentArea(page);
190-
const dynamicPage = resolveDynamicPage({ pageNumber }, page, fontStore, yoga);
193+
const dynamicPage = await resolveDynamicPage({ pageNumber }, page, fontStore, yoga);
191194
const height = page.style.height;
192195

193196
const [currentChilds, nextChilds] = splitNodes(
@@ -196,10 +199,10 @@ const splitPage = (page, pageNumber, fontStore, yoga) => {
196199
dynamicPage.children,
197200
);
198201

199-
const relayout = (node) => relayoutPage(node, fontStore, yoga);
202+
const relayout = async node => relayoutPage(node, fontStore, yoga);
200203

201204
const currentBox = { ...page.box, height };
202-
const currentPage = relayout(
205+
const currentPage = await relayout(
203206
Object.assign({}, page, { box: currentBox, children: currentChilds }),
204207
);
205208

@@ -209,7 +212,7 @@ const splitPage = (page, pageNumber, fontStore, yoga) => {
209212
const nextBox = omit('height', page.box);
210213
const nextProps = omit('bookmark', page.props);
211214

212-
const nextPage = relayout(
215+
const nextPage = await relayout(
213216
Object.assign({}, page, {
214217
props: nextProps,
215218
box: nextBox,
@@ -220,7 +223,7 @@ const splitPage = (page, pageNumber, fontStore, yoga) => {
220223
return [currentPage, nextPage];
221224
};
222225

223-
const resolvePageIndices = (fontStore, yoga, page, pageNumber, pages) => {
226+
const resolvePageIndices = async (fontStore, yoga, page, pageNumber, pages) => {
224227
const totalPages = pages.length;
225228

226229
const props = {
@@ -233,24 +236,25 @@ const resolvePageIndices = (fontStore, yoga, page, pageNumber, pages) => {
233236
return resolveDynamicPage(props, page, fontStore, yoga);
234237
};
235238

236-
const assocSubPageData = (subpages) => {
239+
const assocSubPageData = (subpages, pageIndex) => {
237240
return subpages.map((page, i) => ({
238241
...page,
242+
pageIndex,
239243
subPageNumber: i,
240244
subPageTotalPages: subpages.length,
241245
}));
242246
};
243247

244-
const dissocSubPageData = (page) => {
245-
return omit(['subPageNumber', 'subPageTotalPages'], page);
248+
const dissocSubPageData = page => {
249+
return omit(['pageIndex', 'subPageNumber', 'subPageTotalPages'], page);
246250
};
247251

248-
const paginate = (page, pageNumber, fontStore, yoga) => {
252+
const paginate = async (page, pageNumber, fontStore, yoga) => {
249253
if (!page) return [];
250254

251255
if (page.props?.wrap === false) return [page];
252256

253-
let splittedPage = splitPage(page, pageNumber, fontStore, yoga);
257+
let splittedPage = await splitPage(page, pageNumber, fontStore, yoga);
254258

255259
const pages = [splittedPage[0]];
256260
let nextPage = splittedPage[1];
@@ -271,28 +275,40 @@ const paginate = (page, pageNumber, fontStore, yoga) => {
271275
};
272276

273277
/**
274-
* Performs pagination. This is the step responsible of breaking the whole document
275-
* into pages following pagiation rules, such as `fixed`, `break` and dynamic nodes.
278+
* Performs pagination. This is the step responsible for breaking the whole document
279+
* into pages following pagination rules, such as `fixed`, `break` and dynamic nodes.
276280
*
277281
* @param {Object} doc node
278282
* @param {Object} fontStore font store
279283
* @returns {Object} layout node
280284
*/
281-
const resolvePagination = (doc, fontStore) => {
285+
const resolvePagination = async (doc, fontStore) => {
282286
let pages = [];
283287
let pageNumber = 1;
284288

285-
for (let i = 0; i < doc.children.length; i += 1) {
286-
const page = doc.children[i];
287-
let subpages = paginate(page, pageNumber, fontStore, doc.yoga);
289+
await Promise.all(
290+
doc.children.map(async (page, pageIndex) => {
291+
let subpages = await paginate(page, pageNumber, fontStore, doc.yoga);
288292

289-
subpages = assocSubPageData(subpages);
290-
pageNumber += subpages.length;
291-
pages = pages.concat(subpages);
292-
}
293+
subpages = assocSubPageData(subpages, pageIndex);
294+
pageNumber += subpages.length;
295+
pages.push(...subpages);
296+
}),
297+
);
298+
299+
// because the subpages are pushed into the array according to the speed they are paginated,
300+
// we sort them by their initial index, while keeping the subpages order.
301+
pages.sort((a, b) => {
302+
if (a.pageIndex !== b.pageIndex) {
303+
return a.pageIndex - b.pageIndex;
304+
}
305+
return a.subPageNumber - b.subPageNumber;
306+
});
293307

294-
pages = pages.map((...args) =>
295-
dissocSubPageData(resolvePageIndices(fontStore, doc.yoga, ...args)),
308+
pages = await Promise.all(
309+
pages.map(async (...args) =>
310+
dissocSubPageData(await resolvePageIndices(fontStore, doc.yoga, ...args)),
311+
),
296312
);
297313

298314
return assingChildren(pages, doc);

packages/layout/tests/steps/resolvePagination.test.js renamed to packages/layout/tests/steps/resolvePagination.test.jsx

+162-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { describe, expect, test } from 'vitest';
2-
3-
import { loadYoga } from '../../src/yoga';
2+
import { Text } from '@react-pdf/primitives';
43

54
import resolvePagination from '../../src/steps/resolvePagination';
65
import resolveDimensions from '../../src/steps/resolveDimensions';
6+
import { loadYoga } from '../../src/yoga';
77

88
// dimensions is required by pagination step and them are calculated here
99
const calcLayout = (node) => resolvePagination(resolveDimensions(node));
@@ -53,7 +53,7 @@ describe('pagination step', () => {
5353
],
5454
};
5555

56-
const layout = calcLayout(root);
56+
const layout = await calcLayout(root);
5757

5858
const page = layout.children[0];
5959
const view = layout.children[0].children[0];
@@ -103,7 +103,7 @@ describe('pagination step', () => {
103103
],
104104
};
105105

106-
const layout = calcLayout(root);
106+
const layout = await calcLayout(root);
107107

108108
const view1 = layout.children[0].children[0];
109109
const view2 = layout.children[1].children[0];
@@ -140,7 +140,7 @@ describe('pagination step', () => {
140140
],
141141
};
142142

143-
const layout = calcLayout(root);
143+
const layout = await calcLayout(root);
144144

145145
const view1 = layout.children[0].children[0];
146146
const view2 = layout.children[1].children[0];
@@ -151,6 +151,161 @@ describe('pagination step', () => {
151151
expect(view3.box.height).toBe(10);
152152
});
153153

154+
test.skip('should calculate height and keep the page order', async () => {
155+
const yoga = await loadYoga();
156+
157+
const root = {
158+
type: 'DOCUMENT',
159+
yoga,
160+
children: [
161+
{
162+
type: 'PAGE',
163+
box: {},
164+
style: {
165+
width: 5,
166+
height: 60,
167+
},
168+
children: [
169+
{
170+
type: 'VIEW',
171+
box: {},
172+
style: { height: 18 },
173+
props: { fixed: true },
174+
children: [],
175+
},
176+
{
177+
type: 'VIEW',
178+
box: {},
179+
style: { height: 30 },
180+
props: {},
181+
children: [],
182+
},
183+
{
184+
type: 'VIEW',
185+
box: {},
186+
style: { height: 57 },
187+
props: {},
188+
children: [],
189+
},
190+
{
191+
type: 'VIEW',
192+
box: {},
193+
style: { height: 15 },
194+
props: {},
195+
children: [],
196+
},
197+
],
198+
},
199+
{
200+
type: 'PAGE',
201+
box: {},
202+
style: {
203+
height: 50,
204+
},
205+
children: [
206+
{
207+
type: 'VIEW',
208+
box: {},
209+
style: {},
210+
props: {
211+
fixed: true,
212+
render: () => <Text style={{ height: 10 }}>rear window</Text>,
213+
},
214+
children: [],
215+
},
216+
{
217+
type: 'VIEW',
218+
box: {},
219+
style: { height: 22 },
220+
props: {},
221+
children: [],
222+
},
223+
],
224+
},
225+
{
226+
type: 'PAGE',
227+
box: {},
228+
style: {
229+
height: 40,
230+
},
231+
children: [
232+
{
233+
type: 'VIEW',
234+
box: {},
235+
style: { height: 12 },
236+
props: {},
237+
children: [],
238+
},
239+
],
240+
},
241+
{
242+
type: 'PAGE',
243+
box: {},
244+
style: {
245+
height: 30,
246+
},
247+
children: [
248+
{
249+
type: 'VIEW',
250+
box: {},
251+
style: {},
252+
props: {},
253+
children: [],
254+
},
255+
],
256+
},
257+
],
258+
};
259+
260+
const layout = await calcLayout(root);
261+
262+
const page1 = layout.children[0];
263+
const [view1, view2, view3] = page1.children;
264+
265+
const page2 = layout.children[1];
266+
const [view4, view5] = page2.children;
267+
268+
const page3 = layout.children[2];
269+
const [view6, view7, view8] = page3.children;
270+
271+
const page4 = layout.children[3];
272+
const [view9, view10] = page4.children;
273+
274+
const page5 = layout.children[4];
275+
const [view11] = page5.children;
276+
277+
const page6 = layout.children[5];
278+
279+
// page 1
280+
expect(view1.box.height).toBe(18); // fixed header
281+
expect(view2.box.height).toBe(30);
282+
expect(view3.box.height).toBe(12);
283+
expect(page1.box.height).toBe(60);
284+
285+
// page 2
286+
expect(view4.box.height).toBe(18); // fixed header
287+
expect(view5.box.height).toBe(42);
288+
expect(page2.box.height).toBe(60);
289+
290+
// page 3
291+
expect(view6.box.height).toBe(18); // fixed header
292+
expect(view7.box.height).toBe(3);
293+
expect(view8.box.height).toBe(15);
294+
expect(page3.box.height).toBe(60);
295+
296+
// page 4
297+
expect(view9.box.height).toBe(10);
298+
expect(view10.box.height).toBe(22);
299+
expect(page4.box.height).toBe(50);
300+
301+
// page 5
302+
expect(page5.box.height).toBe(40);
303+
expect(view11.box.height).toBe(12);
304+
305+
// page 6
306+
expect(page6.box.height).toBe(30);
307+
});
308+
154309
test('should not wrap page with false wrap prop', async () => {
155310
const yoga = await loadYoga();
156311

@@ -181,7 +336,7 @@ describe('pagination step', () => {
181336
],
182337
};
183338

184-
const layout = calcLayout(root);
339+
const layout = await calcLayout(root);
185340

186341
expect(layout.children.length).toBe(1);
187342
});
@@ -238,7 +393,7 @@ describe('pagination step', () => {
238393
],
239394
};
240395

241-
const layout = calcLayout(root);
396+
const layout = await calcLayout(root);
242397

243398
const page1 = layout.children[0];
244399
const page2 = layout.children[1];

0 commit comments

Comments
 (0)