@@ -64,11 +64,12 @@ export const extractIdentifierFromConverter = (converter?: ConverterLike | null)
6464export const getHeaderFooterType = (
6565 pageNumber : number ,
6666 identifier : HeaderFooterIdentifier ,
67- options ?: { kind ?: 'header' | 'footer' } ,
67+ options ?: { kind ?: 'header' | 'footer' ; parityPageNumber ?: number } ,
6868) : HeaderFooterType | null => {
6969 if ( pageNumber <= 0 ) return null ;
7070
7171 const kind = options ?. kind ?? 'header' ;
72+ const parityPageNumber = options ?. parityPageNumber ?? pageNumber ;
7273 const ids = kind === 'header' ? identifier . headerIds : identifier . footerIds ;
7374
7475 const hasFirst = Boolean ( ids . first ) ;
@@ -83,10 +84,10 @@ export const getHeaderFooterType = (
8384 }
8485
8586 if ( identifier . alternateHeaders ) {
86- if ( pageNumber % 2 === 0 && hasEven ) {
87+ if ( parityPageNumber % 2 === 0 && hasEven ) {
8788 return 'even' ;
8889 }
89- if ( pageNumber % 2 === 1 && ( hasOdd || hasDefault ) ) {
90+ if ( parityPageNumber % 2 !== 0 && ( hasOdd || hasDefault ) ) {
9091 return hasOdd ? 'odd' : 'default' ;
9192 }
9293 return null ;
@@ -103,10 +104,12 @@ export const resolveHeaderFooterForPage = (
103104 layout : Layout ,
104105 pageIndex : number ,
105106 identifier : HeaderFooterIdentifier ,
106- options ?: { kind ?: 'header' | 'footer' } ,
107+ options ?: { kind ?: 'header' | 'footer' ; parityPageNumber ?: number } ,
107108) => {
108- const pageNumber = layout . pages [ pageIndex ] ?. number ?? pageIndex + 1 ;
109- const type = getHeaderFooterType ( pageNumber , identifier , options ) ;
109+ const layoutPage = layout . pages [ pageIndex ] ;
110+ const pageNumber = layoutPage ?. number ?? pageIndex + 1 ;
111+ const parityPageNumber = options ?. parityPageNumber ?? layoutPage ?. displayNumber ?? pageNumber ;
112+ const type = getHeaderFooterType ( pageNumber , identifier , { ...options , parityPageNumber } ) ;
110113 if ( ! type ) {
111114 return null ;
112115 }
@@ -295,7 +298,7 @@ export function buildMultiSectionIdentifier(
295298 * This function determines which header/footer variant (default, first, even, odd)
296299 * should be used for a given page number within a specific section. It respects:
297300 * - Per-section titlePg (first page of section uses 'first' variant)
298- * - Alternate headers (even/odd pages based on physical page number )
301+ * - Alternate headers (even/odd pages based on section-aware page numbering )
299302 * - Fallback to default variant
300303 *
301304 * **Important**: When `titlePg` is enabled, this function returns 'first' even if the
@@ -307,7 +310,7 @@ export function buildMultiSectionIdentifier(
307310 * @param pageNumber - Physical page number (1-indexed)
308311 * @param sectionIndex - Index of the section this page belongs to
309312 * @param identifier - Multi-section identifier with per-section mappings
310- * @param options - Optional settings (kind: 'header' | 'footer' , sectionPageNumber)
313+ * @param options - Optional settings (kind, sectionPageNumber, parityPageNumber )
311314 * @returns HeaderFooterType ('default' | 'first' | 'even' | 'odd') or null if no header/footer content exists
312315 *
313316 * @example
@@ -326,12 +329,13 @@ export function getHeaderFooterTypeForSection(
326329 pageNumber : number ,
327330 sectionIndex : number ,
328331 identifier : MultiSectionHeaderFooterIdentifier ,
329- options ?: { kind ?: 'header' | 'footer' ; sectionPageNumber ?: number } ,
332+ options ?: { kind ?: 'header' | 'footer' ; sectionPageNumber ?: number ; parityPageNumber ?: number } ,
330333) : HeaderFooterType | null {
331334 if ( pageNumber <= 0 ) return null ;
332335
333336 const kind = options ?. kind ?? 'header' ;
334337 const sectionPageNumber = options ?. sectionPageNumber ?? pageNumber ;
338+ const parityPageNumber = options ?. parityPageNumber ?? pageNumber ;
335339
336340 // Get section-specific IDs, falling back to legacy IDs for backward compatibility
337341 const sectionIds =
@@ -381,7 +385,7 @@ export function getHeaderFooterTypeForSection(
381385 // Keep parity-based variant selection even when this section doesn't
382386 // explicitly define that variant. Resolution/inheritance happens later.
383387 if ( ! hasAny ) return null ;
384- return pageNumber % 2 === 0 ? 'even' : 'odd' ;
388+ return parityPageNumber % 2 === 0 ? 'even' : 'odd' ;
385389 }
386390
387391 if ( hasDefault ) {
@@ -400,7 +404,7 @@ export function getHeaderFooterTypeForSection(
400404 *
401405 * @param page - The Page object containing sectionIndex and sectionRefs
402406 * @param identifier - Multi-section identifier (can be used for variant resolution)
403- * @param options - Optional settings (kind: 'header' | 'footer' )
407+ * @param options - Optional settings (kind, sectionPageNumber, parityPageNumber )
404408 * @returns The content ID string, or null if not available
405409 *
406410 * @example
@@ -413,16 +417,18 @@ export function getHeaderFooterTypeForSection(
413417export function getHeaderFooterIdForPage (
414418 page : Page ,
415419 identifier : MultiSectionHeaderFooterIdentifier ,
416- options ?: { kind ?: 'header' | 'footer' ; sectionPageNumber ?: number } ,
420+ options ?: { kind ?: 'header' | 'footer' ; sectionPageNumber ?: number ; parityPageNumber ?: number } ,
417421) : string | null {
418422 const kind = options ?. kind ?? 'header' ;
419423 const sectionIndex = page . sectionIndex ?? 0 ;
420424 const sectionPageNumber = options ?. sectionPageNumber ?? page . number ;
425+ const parityPageNumber = options ?. parityPageNumber ?? page . displayNumber ?? page . number ;
421426
422427 // Determine which variant type to use (default, first, even, odd)
423428 const variantType = getHeaderFooterTypeForSection ( page . number , sectionIndex , identifier , {
424429 kind,
425430 sectionPageNumber,
431+ parityPageNumber,
426432 } ) ;
427433 if ( ! variantType ) return null ;
428434
@@ -463,7 +469,7 @@ export function getHeaderFooterIdForPage(
463469 * @param layout - The complete Layout object with pages and headerFooter slots
464470 * @param pageIndex - Index of the page in layout.pages array (0-indexed)
465471 * @param identifier - Multi-section identifier with per-section mappings
466- * @param options - Optional settings (kind: 'header' | 'footer' )
472+ * @param options - Optional settings (kind, parityPageNumber )
467473 * @returns Resolution result with type, layout slot, page, and section info, or null
468474 *
469475 * @example
@@ -482,7 +488,7 @@ export function resolveHeaderFooterForPageAndSection(
482488 layout : Layout ,
483489 pageIndex : number ,
484490 identifier : MultiSectionHeaderFooterIdentifier ,
485- options ?: { kind ?: 'header' | 'footer' } ,
491+ options ?: { kind ?: 'header' | 'footer' ; parityPageNumber ?: number } ,
486492) : {
487493 type : HeaderFooterType ;
488494 layout : NonNullable < NonNullable < Layout [ 'headerFooter' ] > [ HeaderFooterType ] > ;
@@ -505,13 +511,18 @@ export function resolveHeaderFooterForPageAndSection(
505511 }
506512 const firstPageInSection = sectionFirstPageNumbers . get ( sectionIndex ) ;
507513 const sectionPageNumber = typeof firstPageInSection === 'number' ? pageNumber - firstPageInSection + 1 : pageNumber ;
514+ const parityPageNumber = options ?. parityPageNumber ?? page . displayNumber ?? pageNumber ;
508515
509516 // Determine variant type for this section
510- const type = getHeaderFooterTypeForSection ( pageNumber , sectionIndex , identifier , { kind, sectionPageNumber } ) ;
517+ const type = getHeaderFooterTypeForSection ( pageNumber , sectionIndex , identifier , {
518+ kind,
519+ sectionPageNumber,
520+ parityPageNumber,
521+ } ) ;
511522 if ( ! type ) return null ;
512523
513524 // Get content ID for this page/section
514- const contentId = getHeaderFooterIdForPage ( page , identifier , { kind, sectionPageNumber } ) ;
525+ const contentId = getHeaderFooterIdForPage ( page , identifier , { kind, sectionPageNumber, parityPageNumber } ) ;
515526
516527 // Look up the header/footer layout slot
517528 const slot = layout . headerFooter ?. [ type ] ;
0 commit comments