Skip to content
Draft
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
42 changes: 35 additions & 7 deletions packages/layout/src/steps/resolvePagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,40 @@ const resolvePageIndices = (fontStore, yoga, page, pageNumber, pages) => {
return resolveDynamicPage(props, page, fontStore, yoga);
};

const assocSubPageData = (subpages) => {
return subpages.map((page, i) => ({
...page,
subPageNumber: i,
subPageTotalPages: subpages.length,
}));
const assocSubPageData = (
subpages: SafePageNode[],
originalPage?: SafePageNode,
startPageNumber?: number,
) => {
return subpages.map((page, i) => {
const basePage = {
...page,
subPageNumber: i,
subPageTotalPages: subpages.length,
};

// Apply wrapStyles if provided
// Always apply wrapStyles (even for single pages) to ensure correct styling
// based on absolute page number in the document
if (originalPage?.props?.wrapStyles) {
// Calculate absolute page number for this subpage
const absolutePageNumber =
startPageNumber !== undefined ? startPageNumber + i : i + 1;
const wrapStyles = originalPage.props.wrapStyles(
i,
subpages.length,
absolutePageNumber,
);
if (wrapStyles) {
// Merge wrapStyles with existing style
basePage.style = Array.isArray(basePage.style)
? ([...basePage.style, wrapStyles] as any)
: ([basePage.style || {}, wrapStyles] as any);
}
}

return basePage;
});
};

const dissocSubPageData = (page) => {
Expand Down Expand Up @@ -332,7 +360,7 @@ const resolvePagination = (
const page = root.children[i];
let subpages = paginate(page, pageNumber, fontStore, root.yoga);

subpages = assocSubPageData(subpages);
subpages = assocSubPageData(subpages, page, pageNumber);
pageNumber += subpages.length;
pages = pages.concat(subpages);
}
Expand Down
9 changes: 9 additions & 0 deletions packages/layout/src/types/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ interface PageProps extends NodeProps {
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
/**
* Styles to apply to each page when wrapping occurs.
* Function receives page index (0-based), total pages count, and absolute page number.
*/
wrapStyles?: (
pageIndex: number,
totalPages: number,
absolutePageNumber: number,
) => Style | Style[];
size?: PageSize;
orientation?: Orientation;
dpi?: number;
Expand Down
134 changes: 134 additions & 0 deletions packages/layout/tests/steps/resolvePagination.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,4 +339,138 @@ describe('pagination step', () => {
// If calcLayout returns then we did not hit an infinite loop
expect(true).toBe(true);
});

test('should apply wrapStyles to each wrapped page', async () => {
const yoga = await loadYoga();

const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
style: {},
children: [
{
type: 'PAGE',
style: {
width: 5,
height: 60,
},
props: {
wrap: true,
wrapStyles: (pageIndex: number) => ({
backgroundColor: pageIndex === 0 ? 'red' : 'blue',
padding: pageIndex * 10,
}),
},
children: [
{
type: 'VIEW',
style: { height: 130 },
props: {},
children: [],
},
],
},
],
});

expect(layout.children.length).toBe(3);

// First page should have red background and no padding
const page1 = layout.children[0];
expect(page1.style).toEqual([
{ width: 5, height: 60 },
{ backgroundColor: 'red', padding: 0 },
]);

// Second page should have blue background and padding of 10
const page2 = layout.children[1];
expect(page2.style).toEqual([
{ width: 5, height: 60 },
{ backgroundColor: 'blue', padding: 10 },
]);

// Third page should have blue background and padding of 20
const page3 = layout.children[2];
expect(page3.style).toEqual([
{ width: 5, height: 60 },
{ backgroundColor: 'blue', padding: 20 },
]);
});

test('should not apply wrapStyles when wrap is false', async () => {
const yoga = await loadYoga();

const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
style: {},
children: [
{
type: 'PAGE',
style: {
width: 5,
height: 60,
},
props: {
wrap: false,
wrapStyles: () => ({
backgroundColor: 'red',
}),
},
children: [
{
type: 'VIEW',
style: { height: 130 },
props: {},
children: [],
},
],
},
],
});

expect(layout.children.length).toBe(1);
const page = layout.children[0];
expect(page.style).toEqual({ width: 5, height: 60 });
});

test('should not apply wrapStyles when only one page is generated', async () => {
const yoga = await loadYoga();

const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
style: {},
children: [
{
type: 'PAGE',
style: {
width: 5,
height: 60,
},
props: {
wrap: true,
wrapStyles: () => ({
backgroundColor: 'red',
}),
},
children: [
{
type: 'VIEW',
style: { height: 30 },
props: {},
children: [],
},
],
},
],
});

expect(layout.children.length).toBe(1);
const page = layout.children[0];
expect(page.style).toEqual({ width: 5, height: 60 });
});
});
9 changes: 9 additions & 0 deletions packages/renderer/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ declare namespace ReactPDF {
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
/**
* Styles to apply to each page when wrapping occurs.
* Function receives page index (0-based), total pages count, and absolute page number.
*/
wrapStyles?: (
pageIndex: number,
totalPages: number,
absolutePageNumber: number,
) => Style | Style[];
size?: PageSize;
orientation?: Orientation;
dpi?: number;
Expand Down
9 changes: 9 additions & 0 deletions packages/types/node.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ interface ViewProps extends BaseProps {

interface PageProps extends BaseProps {
wrap?: boolean;
/**
* Styles to apply to each page when wrapping occurs.
* Function receives page index (0-based), total pages count, and absolute page number.
*/
wrapStyles?: (
pageIndex: number,
totalPages: number,
absolutePageNumber: number,
) => Style | Style[];
size?: PageSize;
orientation?: Orientation;
dpi?: number;
Expand Down