@shadow-garden/bapbong-layout-engine 0.1.0 → 0.2.0

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/index.cjs CHANGED
@@ -30,9 +30,21 @@ module.exports = __toCommonJS(index_exports);
30
30
 
31
31
  // packages/layout-engine/src/lib/layout-engine.ts
32
32
  var import_bapbong_model = require("@shadow-garden/bapbong-model");
33
- var DEFAULT_FONT = { family: "Arial", sizePt: 11, bold: false, italic: false };
33
+ var DEFAULT_FONT = {
34
+ family: "Arial",
35
+ sizePt: 11,
36
+ bold: false,
37
+ italic: false
38
+ };
34
39
  var PT_TO_PX = 96 / 72;
35
- var HEADING_PT = { 1: 24, 2: 18, 3: 14, 4: 12, 5: 11, 6: 11 };
40
+ var HEADING_PT = {
41
+ 1: 24,
42
+ 2: 18,
43
+ 3: 14,
44
+ 4: 12,
45
+ 5: 11,
46
+ 6: 11
47
+ };
36
48
  var LINE_HEIGHT_FACTOR = 1.2;
37
49
  var BASELINE_FACTOR = 0.8;
38
50
  var DEFAULT_TAB_WIDTH = 48;
@@ -108,11 +120,13 @@ function resolveImage(node, pos) {
108
120
  function paragraphToFlow(node, base, nodePos, allowFloats = false, marker) {
109
121
  const contentStart = nodePos + 1;
110
122
  const headingLevel = node.attrs["heading"];
111
- const runBase = headingLevel ? { ...base, sizePt: HEADING_PT[headingLevel] ?? base.sizePt, bold: true } : base;
123
+ const styleId = node.attrs["styleId"];
124
+ const runBase = headingLevel ? { ...base, sizePt: HEADING_PT[headingLevel] ?? base.sizePt, bold: true } : styleId === "Title" ? { ...base, sizePt: 28 } : styleId === "Subtitle" ? { ...base, sizePt: 14, italic: true } : base;
112
125
  const runs = [];
113
126
  const floats = [];
114
127
  node.forEach((child, offset) => {
115
- if (child.isText) runs.push(resolveRun(child, runBase, contentStart + offset));
128
+ if (child.isText)
129
+ runs.push(resolveRun(child, runBase, contentStart + offset));
116
130
  else if (child.type.name === "image") {
117
131
  const float = child.attrs["float"];
118
132
  if (float && allowFloats) {
@@ -139,7 +153,8 @@ function paragraphToFlow(node, base, nodePos, allowFloats = false, marker) {
139
153
  }
140
154
  } else if (child.type.name === "page_field")
141
155
  runs.push(resolveField(child, runBase, contentStart + offset));
142
- else if (child.type.name === "hard_break") runs.push({ break: true, pos: contentStart + offset });
156
+ else if (child.type.name === "hard_break")
157
+ runs.push({ break: true, pos: contentStart + offset });
143
158
  });
144
159
  const list = node.attrs["list"];
145
160
  const align = node.attrs["align"];
@@ -175,8 +190,15 @@ function markerFor(node, counter) {
175
190
  }
176
191
  function nodeToBlock(node, base, nodePos, allowFloats = false, counter) {
177
192
  if (node.type.name === "paragraph")
178
- return paragraphToFlow(node, base, nodePos, allowFloats, markerFor(node, counter));
179
- if (node.type.name === "table") return tableToFlow(node, base, nodePos, counter);
193
+ return paragraphToFlow(
194
+ node,
195
+ base,
196
+ nodePos,
197
+ allowFloats,
198
+ markerFor(node, counter)
199
+ );
200
+ if (node.type.name === "table")
201
+ return tableToFlow(node, base, nodePos, counter);
180
202
  return null;
181
203
  }
182
204
  function tableToFlow(node, base, nodePos, counter) {
@@ -188,7 +210,13 @@ function tableToFlow(node, base, nodePos, counter) {
188
210
  const cellPos = rowPos + 1 + cellOffset;
189
211
  const content = [];
190
212
  cellNode.forEach((child, childOffset) => {
191
- const block = nodeToBlock(child, base, cellPos + 1 + childOffset, true, counter);
213
+ const block = nodeToBlock(
214
+ child,
215
+ base,
216
+ cellPos + 1 + childOffset,
217
+ true,
218
+ counter
219
+ );
192
220
  if (block) content.push(block);
193
221
  });
194
222
  const a = cellNode.attrs;
@@ -220,7 +248,9 @@ function tableToFlow(node, base, nodePos, counter) {
220
248
  }
221
249
  function toFlowBlocks(doc, defaultFont = {}, allowFloats = true) {
222
250
  const base = { ...DEFAULT_FONT, ...defaultFont };
223
- const counter = (0, import_bapbong_model.createNumberingCounter)(doc.attrs["numbering"]);
251
+ const counter = (0, import_bapbong_model.createNumberingCounter)(
252
+ doc.attrs["numbering"]
253
+ );
224
254
  const blocks = [];
225
255
  doc.forEach((node, offset) => {
226
256
  const block = nodeToBlock(node, base, offset, allowFloats, counter);
@@ -230,7 +260,16 @@ function toFlowBlocks(doc, defaultFont = {}, allowFloats = true) {
230
260
  }
231
261
  function tokenizeInline(inline, ctx) {
232
262
  if ("break" in inline) {
233
- return [{ isBreak: true, font: ctx.base, width: 0, isSpace: false, pos: inline.pos, size: 1 }];
263
+ return [
264
+ {
265
+ isBreak: true,
266
+ font: ctx.base,
267
+ width: 0,
268
+ isSpace: false,
269
+ pos: inline.pos,
270
+ size: 1
271
+ }
272
+ ];
234
273
  }
235
274
  if ("src" in inline) {
236
275
  return [
@@ -341,7 +380,12 @@ function wrapParagraph(block, ctx, bandFn, emit) {
341
380
  return lineLeft + k * tabWidth - x;
342
381
  };
343
382
  const tabStops = block.tabs ? [...block.tabs].sort((a, b) => a.pos - b.pos) : [];
344
- const LEADER_CHARS = { dot: ".", hyphen: "-", underscore: "_", middleDot: "\xB7" };
383
+ const LEADER_CHARS = {
384
+ dot: ".",
385
+ hyphen: "-",
386
+ underscore: "_",
387
+ middleDot: "\xB7"
388
+ };
345
389
  const MIN_TAB = 2;
346
390
  const tabGroup = (ti) => {
347
391
  let width = 0;
@@ -351,7 +395,8 @@ function wrapParagraph(block, ctx, bandFn, emit) {
351
395
  if (t.isTab) break;
352
396
  if (decimalPrefix === null && t.text != null && !t.field) {
353
397
  const m = /[.,]/.exec(t.text);
354
- if (m) decimalPrefix = width + measure(t.text.slice(0, m.index), t.font);
398
+ if (m)
399
+ decimalPrefix = width + measure(t.text.slice(0, m.index), t.font);
355
400
  }
356
401
  width += t.width;
357
402
  }
@@ -474,7 +519,16 @@ function wrapParagraph(block, ctx, bandFn, emit) {
474
519
  height = target;
475
520
  }
476
521
  const painted = firstLine && marker ? [marker, ...segments] : segments;
477
- emit({ x: startX, width: lineRight - startX, height, baseline, segments: painted, images, from, to });
522
+ emit({
523
+ x: startX,
524
+ width: lineRight - startX,
525
+ height,
526
+ baseline,
527
+ segments: painted,
528
+ images,
529
+ from,
530
+ to
531
+ });
478
532
  prevTo = to;
479
533
  lineTokens = [];
480
534
  lineWidth = 0;
@@ -508,10 +562,14 @@ function wrapParagraph(block, ctx, bandFn, emit) {
508
562
  softWrapped = false;
509
563
  continue;
510
564
  }
511
- if (token.isSpace && !token.isTab && lineTokens.length === 0 && softWrapped) continue;
565
+ if (token.isSpace && !token.isTab && lineTokens.length === 0 && softWrapped)
566
+ continue;
512
567
  if (token.isTab) resolveTab(token, lineStart() + lineWidth, ti);
513
568
  if (clusterable(token) && clusterFont && sameFont(clusterFont, token.font)) {
514
- token.width = Math.max(0, measure(clusterText + token.text, token.font) - clusterWidth);
569
+ token.width = Math.max(
570
+ 0,
571
+ measure(clusterText + token.text, token.font) - clusterWidth
572
+ );
515
573
  }
516
574
  const cursor = lineStart() + lineWidth;
517
575
  if (!token.isSpace && lineTokens.length > 0 && cursor + token.width > lineRight) {
@@ -519,14 +577,21 @@ function wrapParagraph(block, ctx, bandFn, emit) {
519
577
  resetCluster();
520
578
  softWrapped = true;
521
579
  if (token.isTab) resolveTab(token, lineStart() + lineWidth, ti);
522
- else if (clusterable(token)) token.width = measure(token.text, token.font);
580
+ else if (clusterable(token))
581
+ token.width = measure(token.text, token.font);
523
582
  }
524
583
  if (clusterable(token) && lineTokens.length === 0 && token.text.length > 1 && lineStart() + token.width > lineRight) {
525
584
  const avail = lineRight - lineStart();
526
585
  let n = 1;
527
- while (n < token.text.length && measure(token.text.slice(0, n + 1), token.font) <= avail) n++;
586
+ while (n < token.text.length && measure(token.text.slice(0, n + 1), token.font) <= avail)
587
+ n++;
528
588
  const restText = token.text.slice(n);
529
- const rest = { ...token, text: restText, width: measure(restText, token.font), size: restText.length };
589
+ const rest = {
590
+ ...token,
591
+ text: restText,
592
+ width: measure(restText, token.font),
593
+ size: restText.length
594
+ };
530
595
  if (token.pos != null) rest.pos = token.pos + n;
531
596
  token.text = token.text.slice(0, n);
532
597
  token.size = n;
@@ -547,7 +612,10 @@ function wrapParagraph(block, ctx, bandFn, emit) {
547
612
  const rotH = rotatedBoxHeight(token.image);
548
613
  maxImagePx = Math.max(maxImagePx, rotH);
549
614
  maxAscent = Math.max(maxAscent, token.image.height / 2 + rotH / 2);
550
- maxDescent = Math.max(maxDescent, Math.max(0, (rotH - token.image.height) / 2));
615
+ maxDescent = Math.max(
616
+ maxDescent,
617
+ Math.max(0, (rotH - token.image.height) / 2)
618
+ );
551
619
  } else {
552
620
  maxFontPx = Math.max(maxFontPx, sizePx(token.font));
553
621
  if (metrics) {
@@ -600,7 +668,13 @@ function shiftTableX(table, dx) {
600
668
  }
601
669
  var TEXTBOX_INSET = { l: 10, t: 5, r: 10, b: 5 };
602
670
  function resolveFloat(f, x, y, ctx) {
603
- const rf = { x, y, width: f.width, height: f.height, src: f.src };
671
+ const rf = {
672
+ x,
673
+ y,
674
+ width: f.width,
675
+ height: f.height,
676
+ src: f.src
677
+ };
604
678
  if (f.pos != null) rf.pos = f.pos;
605
679
  if (f.rotation) rf.rotation = f.rotation;
606
680
  if (f.shape) rf.shape = f.shape;
@@ -646,7 +720,8 @@ function eachCell(rows, ncols, visit) {
646
720
  for (const cell of rows[r].cells) {
647
721
  while (col < ncols && spanned[col] > 0) col++;
648
722
  visit(r, cell, col);
649
- for (let k = 0; k < cell.colspan && col + k < ncols; k++) spanned[col + k] = cell.rowspan;
723
+ for (let k = 0; k < cell.colspan && col + k < ncols; k++)
724
+ spanned[col + k] = cell.rowspan;
650
725
  col += cell.colspan;
651
726
  }
652
727
  for (let i = 0; i < ncols; i++) if (spanned[i] > 0) spanned[i]--;
@@ -656,14 +731,18 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
656
731
  const avail = contentRight - contentLeft;
657
732
  const nrows = table.rows.length;
658
733
  const ncols = table.rows.reduce(
659
- (m, r) => Math.max(m, r.cells.reduce((s, c) => s + c.colspan, 0)),
734
+ (m, r) => Math.max(
735
+ m,
736
+ r.cells.reduce((s, c) => s + c.colspan, 0)
737
+ ),
660
738
  0
661
739
  );
662
740
  const colWidths = new Array(ncols).fill(0);
663
741
  eachCell(table.rows, ncols, (_r, cell, startCol) => {
664
742
  if (cell.colwidth && cell.colwidth.length === cell.colspan) {
665
743
  for (let k = 0; k < cell.colspan && startCol + k < ncols; k++) {
666
- if (colWidths[startCol + k] === 0) colWidths[startCol + k] = cell.colwidth[k];
744
+ if (colWidths[startCol + k] === 0)
745
+ colWidths[startCol + k] = cell.colwidth[k];
667
746
  }
668
747
  }
669
748
  });
@@ -671,7 +750,8 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
671
750
  const unknown = colWidths.filter((w) => w === 0).length;
672
751
  if (unknown > 0) {
673
752
  const share = Math.max(0, (avail - known) / unknown);
674
- for (let i = 0; i < ncols; i++) if (colWidths[i] === 0) colWidths[i] = share;
753
+ for (let i = 0; i < ncols; i++)
754
+ if (colWidths[i] === 0) colWidths[i] = share;
675
755
  }
676
756
  const natural = colWidths.reduce((s, w) => s + w, 0);
677
757
  if (natural > avail && natural > 0) {
@@ -691,9 +771,15 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
691
771
  const cellDrafts = [];
692
772
  eachCell(table.rows, ncols, (r, cell, col) => {
693
773
  let cellWidth = 0;
694
- for (let k = 0; k < cell.colspan && col + k < ncols; k++) cellWidth += colWidths[col + k];
774
+ for (let k = 0; k < cell.colspan && col + k < ncols; k++)
775
+ cellWidth += colWidths[col + k];
695
776
  const cellLeft = colX[col];
696
- const flow = layoutFlow(cell.content, cellLeft + pad.left, cellLeft + cellWidth - pad.right, ctx);
777
+ const flow = layoutFlow(
778
+ cell.content,
779
+ cellLeft + pad.left,
780
+ cellLeft + cellWidth - pad.right,
781
+ ctx
782
+ );
697
783
  cellDrafts.push({
698
784
  startRow: r,
699
785
  startCol: col,
@@ -713,14 +799,18 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
713
799
  const rowHeight = new Array(nrows).fill(0);
714
800
  for (const c of cellDrafts) {
715
801
  if (c.rowspan === 1) {
716
- rowHeight[c.startRow] = Math.max(rowHeight[c.startRow], c.contentHeight + pad.top + pad.bottom);
802
+ rowHeight[c.startRow] = Math.max(
803
+ rowHeight[c.startRow],
804
+ c.contentHeight + pad.top + pad.bottom
805
+ );
717
806
  }
718
807
  }
719
808
  for (const c of cellDrafts) {
720
809
  if (c.rowspan > 1) {
721
810
  const need = c.contentHeight + pad.top + pad.bottom;
722
811
  let span = 0;
723
- for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++) span += rowHeight[r];
812
+ for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++)
813
+ span += rowHeight[r];
724
814
  if (need > span) {
725
815
  const last = Math.min(c.startRow + c.rowspan - 1, nrows - 1);
726
816
  rowHeight[last] += need - span;
@@ -735,7 +825,8 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
735
825
  for (let r = 0; r < nrows; r++) rowY[r + 1] = rowY[r] + rowHeight[r];
736
826
  const cells = cellDrafts.map((c) => {
737
827
  let height = 0;
738
- for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++) height += rowHeight[r];
828
+ for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++)
829
+ height += rowHeight[r];
739
830
  const slack = Math.max(0, height - pad.top - pad.bottom - c.contentHeight);
740
831
  const vOffset = c.vAlign === "bottom" ? slack : c.vAlign === "center" ? slack / 2 : 0;
741
832
  const dy = rowY[c.startRow] + pad.top + vOffset;
@@ -753,19 +844,30 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
753
844
  if (c.background) cell.background = c.background;
754
845
  if (c.borders) cell.borders = c.borders;
755
846
  if (c.tables.length > 0) cell.tables = c.tables;
756
- if (c.floats.length > 0) cell.floats = c.floats.map((f) => ({ ...f, y: f.y + dy }));
847
+ if (c.floats.length > 0)
848
+ cell.floats = c.floats.map((f) => ({ ...f, y: f.y + dy }));
757
849
  return cell;
758
850
  });
759
- const resolved = { x: contentLeft + xShift, y: 0, width: tableWidth, height: rowY[nrows], cells };
851
+ const resolved = {
852
+ x: contentLeft + xShift,
853
+ y: 0,
854
+ width: tableWidth,
855
+ height: rowY[nrows],
856
+ cells
857
+ };
760
858
  if (table.borders) resolved.borders = table.borders;
761
859
  let headerRows = 0;
762
860
  while (headerRows < nrows && table.rows[headerRows].header) headerRows++;
763
861
  if (headerRows > 0 && headerRows < nrows) {
764
862
  const headerBottom = rowY[headerRows];
765
- const spansOut = cells.some((c) => c.y < headerBottom && c.y + c.height > headerBottom);
863
+ const spansOut = cells.some(
864
+ (c) => c.y < headerBottom && c.y + c.height > headerBottom
865
+ );
766
866
  if (!spansOut) resolved.headerBottom = headerBottom;
767
867
  }
768
- const cantSplitBands = table.rows.map((row, r) => row.cantSplit ? { top: rowY[r], bottom: rowY[r + 1] } : null).filter((b) => b !== null);
868
+ const cantSplitBands = table.rows.map(
869
+ (row, r) => row.cantSplit ? { top: rowY[r], bottom: rowY[r + 1] } : null
870
+ ).filter((b) => b !== null);
769
871
  if (cantSplitBands.length > 0) resolved.cantSplitBands = cantSplitBands;
770
872
  return resolved;
771
873
  }
@@ -798,7 +900,10 @@ function cloneTable(t) {
798
900
  return { ...t, cells: t.cells.map(cloneCell) };
799
901
  }
800
902
  function cloneCell(cell) {
801
- const copy = { ...cell, lines: cell.lines.map((l) => ({ ...l })) };
903
+ const copy = {
904
+ ...cell,
905
+ lines: cell.lines.map((l) => ({ ...l }))
906
+ };
802
907
  if (cell.tables) copy.tables = cell.tables.map(cloneTable);
803
908
  if (cell.floats) copy.floats = cell.floats.map((f) => ({ ...f }));
804
909
  return copy;
@@ -834,11 +939,19 @@ function splitTableAt(table, cut) {
834
939
  } else {
835
940
  const c = straddlers.get(cell);
836
941
  const topLines = cell.lines.filter((l) => l.y + l.height <= cut);
837
- const topTables = (cell.tables ?? []).filter((t) => t.y + t.height <= cut);
838
- const topCell = { ...cell, height: cut - cell.y, lines: topLines };
942
+ const topTables = (cell.tables ?? []).filter(
943
+ (t) => t.y + t.height <= cut
944
+ );
945
+ const topCell = {
946
+ ...cell,
947
+ height: cut - cell.y,
948
+ lines: topLines
949
+ };
839
950
  if (topTables.length > 0) topCell.tables = topTables;
840
951
  else delete topCell.tables;
841
- const topFloats = (cell.floats ?? []).filter((f) => f.y + f.height <= cut);
952
+ const topFloats = (cell.floats ?? []).filter(
953
+ (f) => f.y + f.height <= cut
954
+ );
842
955
  if (topFloats.length > 0) topCell.floats = topFloats;
843
956
  else delete topCell.floats;
844
957
  topCells.push(topCell);
@@ -861,7 +974,13 @@ function splitTableAt(table, cut) {
861
974
  restCells.push(contCell);
862
975
  }
863
976
  }
864
- const top = { x: table.x, y: 0, width: table.width, height: cut, cells: topCells };
977
+ const top = {
978
+ x: table.x,
979
+ y: 0,
980
+ width: table.width,
981
+ height: cut,
982
+ cells: topCells
983
+ };
865
984
  const rest = {
866
985
  x: table.x,
867
986
  y: 0,
@@ -883,10 +1002,14 @@ function cloneHeaderCells(table, headerBottom) {
883
1002
  tables: void 0,
884
1003
  floats: cell.floats?.map((f) => ({ ...f })),
885
1004
  lines: cell.lines.map((l) => {
886
- const line = { ...l, segments: l.segments.map((s) => ({ ...s, pos: void 0 })) };
1005
+ const line = {
1006
+ ...l,
1007
+ segments: l.segments.map((s) => ({ ...s, pos: void 0 }))
1008
+ };
887
1009
  delete line.from;
888
1010
  delete line.to;
889
- if (line.images) line.images = line.images.map((im) => ({ ...im, pos: void 0 }));
1011
+ if (line.images)
1012
+ line.images = line.images.map((im) => ({ ...im, pos: void 0 }));
890
1013
  return line;
891
1014
  })
892
1015
  }));
@@ -963,13 +1086,15 @@ function placeBlocks(items, config, ctx, band, footnotes) {
963
1086
  for (const l of ls)
964
1087
  for (const s of l.segments) {
965
1088
  const n = s.footnoteRef;
966
- if (n != null && footnotes?.has(n) && !pageFnSet.has(n) && !out.includes(n)) out.push(n);
1089
+ if (n != null && footnotes?.has(n) && !pageFnSet.has(n) && !out.includes(n))
1090
+ out.push(n);
967
1091
  }
968
1092
  };
969
1093
  for (const c of t.cells) {
970
1094
  if (c.y >= maxY) continue;
971
1095
  scan(c.lines);
972
- if (c.tables) for (const nt of c.tables) for (const nc of nt.cells) scan(nc.lines);
1096
+ if (c.tables)
1097
+ for (const nt of c.tables) for (const nc of nt.cells) scan(nc.lines);
973
1098
  }
974
1099
  return out;
975
1100
  };
@@ -998,10 +1123,16 @@ function placeBlocks(items, config, ctx, band, footnotes) {
998
1123
  return { separatorY: areaTop + FOOTNOTE_AREA_GAP / 2, lines: out };
999
1124
  };
1000
1125
  const finalizePage = () => {
1001
- const resolved = { index: pages.length, width: page.width, height: page.height, lines };
1126
+ const resolved = {
1127
+ index: pages.length,
1128
+ width: page.width,
1129
+ height: page.height,
1130
+ lines
1131
+ };
1002
1132
  if (tables.length > 0) resolved.tables = tables;
1003
1133
  if (pageFloats.length > 0) resolved.floats = pageFloats;
1004
- if (pageFnNums.length > 0) resolved.footnotes = buildFootnoteArea(pageFnNums);
1134
+ if (pageFnNums.length > 0)
1135
+ resolved.footnotes = buildFootnoteArea(pageFnNums);
1005
1136
  pages.push(resolved);
1006
1137
  lines = [];
1007
1138
  tables = [];
@@ -1091,7 +1222,9 @@ function placeBlocks(items, config, ctx, band, footnotes) {
1091
1222
  }
1092
1223
  const b = bandAt(y, estH);
1093
1224
  if (b) return b;
1094
- const blockers = exclusions.filter((ex) => ex.top < y + estH && ex.bottom > y);
1225
+ const blockers = exclusions.filter(
1226
+ (ex) => ex.top < y + estH && ex.bottom > y
1227
+ );
1095
1228
  if (blockers.length === 0) return { left: colX0(), right: colX1() };
1096
1229
  y = Math.min(...blockers.map((ex) => ex.bottom));
1097
1230
  }
@@ -1135,7 +1268,9 @@ function placeBlocks(items, config, ctx, band, footnotes) {
1135
1268
  }
1136
1269
  const drafts = item.para.drafts;
1137
1270
  const draftsHeight = drafts?.reduce((s, d) => s + d.height, 0) ?? 0;
1138
- const floatsAhead = exclusions.some((ex) => ex.bottom > y && ex.top < y + draftsHeight);
1271
+ const floatsAhead = exclusions.some(
1272
+ (ex) => ex.bottom > y && ex.top < y + draftsHeight
1273
+ );
1139
1274
  if (drafts && !floatsAhead) {
1140
1275
  for (const d of drafts) emitLine(d);
1141
1276
  } else {
@@ -1254,16 +1389,25 @@ function shiftDrafts(drafts, delta) {
1254
1389
  ...d,
1255
1390
  from: d.from != null ? d.from + delta : d.from,
1256
1391
  to: d.to != null ? d.to + delta : d.to,
1257
- segments: d.segments.map((s) => s.pos != null ? { ...s, pos: s.pos + delta } : s),
1258
- images: d.images.map((im) => im.pos != null ? { ...im, pos: im.pos + delta } : im)
1392
+ segments: d.segments.map(
1393
+ (s) => s.pos != null ? { ...s, pos: s.pos + delta } : s
1394
+ ),
1395
+ images: d.images.map(
1396
+ (im) => im.pos != null ? { ...im, pos: im.pos + delta } : im
1397
+ )
1259
1398
  }));
1260
1399
  }
1261
1400
  function cloneLineShifted(l, delta) {
1262
1401
  const out = {
1263
1402
  ...l,
1264
- segments: l.segments.map((s) => s.pos != null ? { ...s, pos: s.pos + delta } : { ...s })
1403
+ segments: l.segments.map(
1404
+ (s) => s.pos != null ? { ...s, pos: s.pos + delta } : { ...s }
1405
+ )
1265
1406
  };
1266
- if (l.images) out.images = l.images.map((im) => im.pos != null ? { ...im, pos: im.pos + delta } : { ...im });
1407
+ if (l.images)
1408
+ out.images = l.images.map(
1409
+ (im) => im.pos != null ? { ...im, pos: im.pos + delta } : { ...im }
1410
+ );
1267
1411
  if (l.from != null) out.from = l.from + delta;
1268
1412
  if (l.to != null) out.to = l.to + delta;
1269
1413
  return out;
@@ -1306,7 +1450,10 @@ function layVariants(docs, fn) {
1306
1450
  return out;
1307
1451
  }
1308
1452
  function maxBandHeight(bands) {
1309
- return Math.max(0, ...[bands.default, bands.first, bands.even].filter(Boolean).map((b) => b.height));
1453
+ return Math.max(
1454
+ 0,
1455
+ ...[bands.default, bands.first, bands.even].filter(Boolean).map((b) => b.height)
1456
+ );
1310
1457
  }
1311
1458
  function anyBandHasFields(bands) {
1312
1459
  return [bands.default, bands.first, bands.even].some(
@@ -1332,9 +1479,17 @@ function layoutChrome(doc, topY, left, right, ctx) {
1332
1479
  const lines = flow.lines.map((l) => ({ ...l, y: l.y + topY }));
1333
1480
  flow.tables.forEach((t) => offsetTable(t, topY));
1334
1481
  stripPositions(lines, flow.tables);
1335
- const band = { lines, tables: flow.tables, height: flow.height };
1482
+ const band = {
1483
+ lines,
1484
+ tables: flow.tables,
1485
+ height: flow.height
1486
+ };
1336
1487
  if (flow.floats.length > 0)
1337
- band.floats = flow.floats.map((f) => ({ ...f, y: f.y + topY, pos: void 0 }));
1488
+ band.floats = flow.floats.map((f) => ({
1489
+ ...f,
1490
+ y: f.y + topY,
1491
+ pos: void 0
1492
+ }));
1338
1493
  return band;
1339
1494
  }
1340
1495
  function layoutFooterChrome(doc, pageHeight, left, right, ctx) {
@@ -1346,12 +1501,21 @@ function layoutFooterChrome(doc, pageHeight, left, right, ctx) {
1346
1501
  height: flow.height
1347
1502
  };
1348
1503
  band.tables.forEach((t) => offsetTable(t, topY));
1349
- if (flow.floats) band.floats = flow.floats.map((f) => ({ ...f, y: f.y + topY }));
1504
+ if (flow.floats)
1505
+ band.floats = flow.floats.map((f) => ({ ...f, y: f.y + topY }));
1350
1506
  return band;
1351
1507
  }
1352
1508
  function layoutFootnoteBody(doc, left, right, ctx) {
1353
- const fnCtx = { ...ctx, base: { ...ctx.base, sizePt: ctx.base.sizePt * FOOTNOTE_FONT_SCALE } };
1354
- const flow = layoutFlow(toFlowBlocks(doc, fnCtx.base, false), left, right, fnCtx);
1509
+ const fnCtx = {
1510
+ ...ctx,
1511
+ base: { ...ctx.base, sizePt: ctx.base.sizePt * FOOTNOTE_FONT_SCALE }
1512
+ };
1513
+ const flow = layoutFlow(
1514
+ toFlowBlocks(doc, fnCtx.base, false),
1515
+ left,
1516
+ right,
1517
+ fnCtx
1518
+ );
1355
1519
  stripPositions(flow.lines, flow.tables);
1356
1520
  return { lines: flow.lines, height: flow.height };
1357
1521
  }
@@ -1360,10 +1524,24 @@ function layout(doc, config, cache, chrome, footnotes) {
1360
1524
  const { page } = config;
1361
1525
  const left = page.margin.left;
1362
1526
  const right = page.width - page.margin.right;
1363
- const headerDocs = { default: chrome?.header, first: chrome?.headerFirst, even: chrome?.headerEven };
1364
- const footerDocs = { default: chrome?.footer, first: chrome?.footerFirst, even: chrome?.footerEven };
1365
- const layHeaders = (c) => layVariants(headerDocs, (d) => layoutChrome(d, CHROME_DISTANCE, left, right, c));
1366
- const layFooters = (c) => layVariants(footerDocs, (d) => layoutFooterChrome(d, page.height, left, right, c));
1527
+ const headerDocs = {
1528
+ default: chrome?.header,
1529
+ first: chrome?.headerFirst,
1530
+ even: chrome?.headerEven
1531
+ };
1532
+ const footerDocs = {
1533
+ default: chrome?.footer,
1534
+ first: chrome?.footerFirst,
1535
+ even: chrome?.footerEven
1536
+ };
1537
+ const layHeaders = (c) => layVariants(
1538
+ headerDocs,
1539
+ (d) => layoutChrome(d, CHROME_DISTANCE, left, right, c)
1540
+ );
1541
+ const layFooters = (c) => layVariants(
1542
+ footerDocs,
1543
+ (d) => layoutFooterChrome(d, page.height, left, right, c)
1544
+ );
1367
1545
  let headers = layHeaders(ctx);
1368
1546
  let footers = layFooters(ctx);
1369
1547
  let top = page.margin.top;
@@ -1372,25 +1550,46 @@ function layout(doc, config, cache, chrome, footnotes) {
1372
1550
  top = Math.max(top, CHROME_DISTANCE + maxBandHeight(headers));
1373
1551
  }
1374
1552
  if (footers.default || footers.first || footers.even) {
1375
- bottom = Math.min(bottom, page.height - CHROME_DISTANCE - maxBandHeight(footers));
1553
+ bottom = Math.min(
1554
+ bottom,
1555
+ page.height - CHROME_DISTANCE - maxBandHeight(footers)
1556
+ );
1376
1557
  }
1377
- const counter = (0, import_bapbong_model.createNumberingCounter)(doc.attrs["numbering"]);
1558
+ const counter = (0, import_bapbong_model.createNumberingCounter)(
1559
+ doc.attrs["numbering"]
1560
+ );
1378
1561
  const sections = doc.attrs["sections"] ?? [
1379
- { blockCount: doc.childCount, columns: { count: 1, gap: 0 }, newPage: true }
1562
+ {
1563
+ blockCount: doc.childCount,
1564
+ columns: { count: 1, gap: 0 },
1565
+ newPage: true
1566
+ }
1380
1567
  ];
1381
1568
  const blockSection = [];
1382
1569
  for (const sec of sections) {
1383
1570
  for (let k = 0; k < sec.blockCount; k++) {
1384
- blockSection.push({ columns: sec.columns, start: k === 0, newPage: sec.newPage });
1571
+ blockSection.push({
1572
+ columns: sec.columns,
1573
+ start: k === 0,
1574
+ newPage: sec.newPage
1575
+ });
1385
1576
  }
1386
1577
  }
1387
1578
  const lastSec = sections[sections.length - 1];
1388
1579
  while (blockSection.length < doc.childCount) {
1389
- blockSection.push({ columns: lastSec.columns, start: false, newPage: lastSec.newPage });
1580
+ blockSection.push({
1581
+ columns: lastSec.columns,
1582
+ start: false,
1583
+ newPage: lastSec.newPage
1584
+ });
1390
1585
  }
1391
1586
  const items = [];
1392
1587
  doc.forEach((node, offset, index) => {
1393
- const bs = blockSection[index] ?? { columns: { count: 1, gap: 0 }, start: false, newPage: true };
1588
+ const bs = blockSection[index] ?? {
1589
+ columns: { count: 1, gap: 0 },
1590
+ start: false,
1591
+ newPage: true
1592
+ };
1394
1593
  const colRight = left + columnWidth(right - left, bs.columns);
1395
1594
  const tag = (item) => {
1396
1595
  if (bs.start) item.section = { ...bs.columns, newPage: bs.newPage };
@@ -1423,17 +1622,35 @@ function layout(doc, config, cache, chrome, footnotes) {
1423
1622
  }
1424
1623
  const flow = paragraphToFlow(node, ctx.base, offset, true, marker);
1425
1624
  const drafts = layoutParagraph(flow, left, colRight, ctx);
1426
- cache?.paragraphs.set(node, { left, right: colRight, basePos: contentStart, marker, drafts });
1625
+ cache?.paragraphs.set(node, {
1626
+ left,
1627
+ right: colRight,
1628
+ basePos: contentStart,
1629
+ marker,
1630
+ drafts
1631
+ });
1427
1632
  items.push(tag({ para: { ...para(drafts), getFlow: () => flow } }));
1428
1633
  } else if (node.type.name === "table") {
1429
1634
  const hit = cache?.tables.get(node);
1430
1635
  if (hit && hit.left === left && hit.right === colRight) {
1431
- items.push(tag({ table: cloneTableShifted(hit.table, offset - hit.basePos) }));
1636
+ items.push(
1637
+ tag({ table: cloneTableShifted(hit.table, offset - hit.basePos) })
1638
+ );
1432
1639
  return;
1433
1640
  }
1434
- const table = layoutTable(tableToFlow(node, ctx.base, offset, counter), left, colRight, ctx);
1641
+ const table = layoutTable(
1642
+ tableToFlow(node, ctx.base, offset, counter),
1643
+ left,
1644
+ colRight,
1645
+ ctx
1646
+ );
1435
1647
  if (cache && !tableHasList(node)) {
1436
- cache.tables.set(node, { left, right: colRight, basePos: offset, table });
1648
+ cache.tables.set(node, {
1649
+ left,
1650
+ right: colRight,
1651
+ basePos: offset,
1652
+ table
1653
+ });
1437
1654
  items.push(tag({ table: cloneTableShifted(table, 0) }));
1438
1655
  } else {
1439
1656
  items.push(tag({ table }));
@@ -1451,7 +1668,10 @@ function layout(doc, config, cache, chrome, footnotes) {
1451
1668
  assignSectionHeights(items);
1452
1669
  const resolved = placeBlocks(items, config, ctx, { top, bottom }, fnMap);
1453
1670
  if (anyBandHasFields(headers) || anyBandHasFields(footers)) {
1454
- const fieldCtx = { ...ctx, fieldPlaceholder: String(resolved.pages.length) };
1671
+ const fieldCtx = {
1672
+ ...ctx,
1673
+ fieldPlaceholder: String(resolved.pages.length)
1674
+ };
1455
1675
  headers = layHeaders(fieldCtx);
1456
1676
  footers = layFooters(fieldCtx);
1457
1677
  }
@@ -1462,7 +1682,10 @@ function layout(doc, config, cache, chrome, footnotes) {
1462
1682
  if (footers.first) resolved.pageFooterFirst = footers.first;
1463
1683
  if (footers.even) resolved.pageFooterEven = footers.even;
1464
1684
  if (chrome?.titlePg || chrome?.evenAndOdd) {
1465
- resolved.chromeSelect = { titlePg: !!chrome.titlePg, evenAndOdd: !!chrome.evenAndOdd };
1685
+ resolved.chromeSelect = {
1686
+ titlePg: !!chrome.titlePg,
1687
+ evenAndOdd: !!chrome.evenAndOdd
1688
+ };
1466
1689
  }
1467
1690
  return resolved;
1468
1691
  }