@softwear/latestcollectioncore 1.0.183 → 1.0.184

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/reports.js CHANGED
@@ -61,6 +61,26 @@ function containerLoopSource(container, printBuffer) {
61
61
  return [printBuffer];
62
62
  return getProperty(container.source, printBuffer);
63
63
  }
64
+ /**
65
+ * Top-level empty-source containers (invoice “billTo” bands, wrappers) sit beside overflowing repeats.
66
+ * They are not on the nested {@link containerChain}; redraw them whenever we append a continuation page.
67
+ * Omit the overflowing root when it is chain[0] — redrawing it would recurse (e.g. wrapper around lines).
68
+ */
69
+ function redrawRootDummyBodyContainersOnNewPage(doc, layout, rootPrintBuffer, paperSize, options, context, containerChain) {
70
+ const overflowingRootContainer = containerChain.length > 0 ? containerChain[0].object : undefined;
71
+ layout.objects.forEach((object) => {
72
+ if (object.type !== 'container')
73
+ return;
74
+ if (overflowingRootContainer !== undefined && object === overflowingRootContainer)
75
+ return;
76
+ const c = object;
77
+ if (c.printOnlyAtStart === true || c.printOnlyAtEnd === true)
78
+ return;
79
+ if (!dummyLayoutSource(c.source))
80
+ return;
81
+ addObjectToPDF(0, 0, doc, object, rootPrintBuffer, paperSize, layout, options, rootPrintBuffer, [], context);
82
+ });
83
+ }
64
84
  /** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
65
85
  const FONT_STYLES = ['normal', 'bold', 'italic', 'bolditalic'];
66
86
  /** Recursively collect used custom fonts from layout objects (text/field with fontFamily) and layout default. */
@@ -399,6 +419,7 @@ function addPage(originX, originY, doc, layout, rootPrintBuffer, paperSize, opti
399
419
  }
400
420
  if (!context.measureOnly) {
401
421
  drawStaticPartOfPage(doc, layout, rootPrintBuffer, paperSize, options, context);
422
+ redrawRootDummyBodyContainersOnNewPage(doc, layout, rootPrintBuffer, paperSize, options, context, containerChain);
402
423
  }
403
424
  // Bounding box tracked for snap-to-bottom; continuation cursor is ALWAYS the passed-in coords.
404
425
  const absoluteLowerRightHandSide = { x: continuationOxTenths / 10, y: continuationOyTenths / 10 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwear/latestcollectioncore",
3
- "version": "1.0.183",
3
+ "version": "1.0.184",
4
4
  "description": "Core functions for LatestCollections applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/reports.ts CHANGED
@@ -118,6 +118,33 @@ function containerLoopSource(container: ContainerLayoutObject, printBuffer: any)
118
118
  return getProperty(container.source as string, printBuffer)
119
119
  }
120
120
 
121
+ /**
122
+ * Top-level empty-source containers (invoice “billTo” bands, wrappers) sit beside overflowing repeats.
123
+ * They are not on the nested {@link containerChain}; redraw them whenever we append a continuation page.
124
+ * Omit the overflowing root when it is chain[0] — redrawing it would recurse (e.g. wrapper around lines).
125
+ */
126
+ function redrawRootDummyBodyContainersOnNewPage(
127
+ doc: jsPDF,
128
+ layout: Layout,
129
+ rootPrintBuffer: any,
130
+ paperSize: PaperSize,
131
+ options: GenPdfOptions,
132
+ context: RenderContext,
133
+ containerChain: { object: ContainerLayoutObject; printBuffer: any }[]
134
+ ): void {
135
+ const overflowingRootContainer =
136
+ containerChain.length > 0 ? (containerChain[0].object as ContainerLayoutObject) : undefined
137
+
138
+ layout.objects.forEach((object) => {
139
+ if (object.type !== 'container') return
140
+ if (overflowingRootContainer !== undefined && object === overflowingRootContainer) return
141
+ const c = object as ContainerLayoutObject
142
+ if (c.printOnlyAtStart === true || c.printOnlyAtEnd === true) return
143
+ if (!dummyLayoutSource(c.source)) return
144
+ addObjectToPDF(0, 0, doc, object, rootPrintBuffer, paperSize, layout, options, rootPrintBuffer, [], context)
145
+ })
146
+ }
147
+
121
148
  /** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
122
149
  const FONT_STYLES = ['normal', 'bold', 'italic', 'bolditalic'] as const
123
150
 
@@ -472,6 +499,7 @@ function addPage(
472
499
  }
473
500
  if (!context.measureOnly) {
474
501
  drawStaticPartOfPage(doc, layout, rootPrintBuffer, paperSize, options, context)
502
+ redrawRootDummyBodyContainersOnNewPage(doc, layout, rootPrintBuffer, paperSize, options, context, containerChain)
475
503
  }
476
504
  // Bounding box tracked for snap-to-bottom; continuation cursor is ALWAYS the passed-in coords.
477
505
  const absoluteLowerRightHandSide = { x: continuationOxTenths / 10, y: continuationOyTenths / 10 }
@@ -263,4 +263,72 @@ describe('genPDF', () => {
263
263
  expect(pdfText).toContain('ROW_0_MARK')
264
264
  expect(pdfText).toContain('ROW_35_MARK')
265
265
  })
266
+
267
+ it('redraws top-level empty-source body containers on every continuation page beside an overflowing sibling', async () => {
268
+ const chromeText = {
269
+ type: 'text' as const,
270
+ name: 'chrome-label',
271
+ x: 0,
272
+ y: 0,
273
+ width: 300,
274
+ height: 48,
275
+ active: true,
276
+ text: 'CHROME_EACH_PAGE',
277
+ textAlign: 1 as const,
278
+ fontFamily: 'Helvetica',
279
+ fontSize: 28,
280
+ fontStyle: 0,
281
+ }
282
+ const lineField = {
283
+ type: 'field' as const,
284
+ name: 'ln',
285
+ x: 0,
286
+ y: 0,
287
+ width: 800,
288
+ height: 96,
289
+ active: true,
290
+ source: 'line',
291
+ textAlign: 1 as const,
292
+ fontFamily: 'Helvetica',
293
+ fontSize: 36,
294
+ fontStyle: 0,
295
+ }
296
+ const ITEMS = Array.from({ length: 48 }, (_, i) => ({ line: `SKU_${i}` }))
297
+ const layout: Layout = {
298
+ name: 'sibling-chrome',
299
+ paperSize: { width: 210, height: 297, footerHeight: 20 },
300
+ objects: [
301
+ {
302
+ type: 'container',
303
+ name: 'addressBand',
304
+ x: 60,
305
+ y: 440,
306
+ width: 400,
307
+ height: 280,
308
+ active: true,
309
+ source: '',
310
+ children: [chromeText],
311
+ },
312
+ {
313
+ type: 'container',
314
+ name: 'lines',
315
+ x: 500,
316
+ y: 440,
317
+ width: 1500,
318
+ height: 200,
319
+ active: true,
320
+ source: 'ITEMS',
321
+ repeatContainer: 'vertical' as const,
322
+ children: [lineField],
323
+ },
324
+ ],
325
+ }
326
+
327
+ const doc = await genPDF(layout, { ITEMS })
328
+ expect(doc.getNumberOfPages()).toBeGreaterThanOrEqual(2)
329
+ const pdfText = Buffer.from(doc.output('arraybuffer')).toString('latin1')
330
+ const chromeMatches = pdfText.match(/\(CHROME_EACH_PAGE\)/g)
331
+ expect(chromeMatches?.length ?? 0).toBeGreaterThanOrEqual(doc.getNumberOfPages())
332
+ expect(pdfText).toContain('SKU_20')
333
+ })
266
334
  })