ooxml-core 1.8.4 → 1.10.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.
Files changed (347) hide show
  1. package/dist/PptxHandler-5UURGJEV.mjs +2 -0
  2. package/dist/{PptxHandler-BL4B7CZO.mjs → PptxHandler-ADEFY476.mjs} +2 -2
  3. package/dist/PptxHandler-U5XB2HUE.cjs +11 -0
  4. package/dist/automation/index.cjs +7239 -4037
  5. package/dist/automation/index.mjs +7239 -4037
  6. package/dist/chunk-3N6XMMTT.cjs +87913 -0
  7. package/dist/{chunk-TTPZITQN.mjs → chunk-5NVJN4E6.mjs} +30 -2
  8. package/dist/{chunk-ZAP5WLEN.mjs → chunk-A6P7G3UK.mjs} +1 -1
  9. package/dist/{chunk-CPKNMQLX.cjs → chunk-AWIDASUW.cjs} +25 -2
  10. package/dist/{chunk-SVQZXP3F.mjs → chunk-CBNKBVX5.mjs} +25 -2
  11. package/dist/{chunk-GAGSCAR3.mjs → chunk-CCHYFCPD.mjs} +1199 -348
  12. package/dist/chunk-R6KSBNKX.mjs +44133 -0
  13. package/dist/chunk-S6DOCMQC.cjs +44451 -0
  14. package/dist/{chunk-Z7IQR4S4.mjs → chunk-WUE5ZHU3.mjs} +269 -21
  15. package/dist/chunk-ZE53K7DH.mjs +87907 -0
  16. package/dist/{chunk-NIHPA63A.mjs → chunk-ZOUGMAZG.mjs} +54 -37
  17. package/dist/docx/block-parser.d.ts.map +1 -1
  18. package/dist/docx/cell-blocks.d.ts +4 -0
  19. package/dist/docx/cell-blocks.d.ts.map +1 -0
  20. package/dist/docx/document-paragraphs.d.ts.map +1 -1
  21. package/dist/docx/document-parts.d.ts +2 -0
  22. package/dist/docx/document-parts.d.ts.map +1 -1
  23. package/dist/docx/embedded.cjs +189 -20
  24. package/dist/docx/embedded.mjs +189 -20
  25. package/dist/docx/index.cjs +219 -24
  26. package/dist/docx/index.mjs +219 -24
  27. package/dist/docx/layout/adapt-table.d.ts +2 -2
  28. package/dist/docx/layout/adapt-table.d.ts.map +1 -1
  29. package/dist/docx/layout/adapter.d.ts.map +1 -1
  30. package/dist/docx/layout/flow-paragraph.d.ts +5 -0
  31. package/dist/docx/layout/flow-paragraph.d.ts.map +1 -1
  32. package/dist/docx/layout/flow-table.d.ts +2 -1
  33. package/dist/docx/layout/flow-table.d.ts.map +1 -1
  34. package/dist/docx/layout/footnote-columns.d.ts +22 -0
  35. package/dist/docx/layout/footnote-columns.d.ts.map +1 -0
  36. package/dist/docx/layout/footnote-flow.d.ts +27 -0
  37. package/dist/docx/layout/footnote-flow.d.ts.map +1 -0
  38. package/dist/docx/layout/footnote-split.d.ts +7 -0
  39. package/dist/docx/layout/footnote-split.d.ts.map +1 -0
  40. package/dist/docx/layout/index.cjs +1528 -119
  41. package/dist/docx/layout/index.mjs +1528 -120
  42. package/dist/docx/layout/input.d.ts +17 -1
  43. package/dist/docx/layout/input.d.ts.map +1 -1
  44. package/dist/docx/layout/legacy-footnote-flow.d.ts +18 -0
  45. package/dist/docx/layout/legacy-footnote-flow.d.ts.map +1 -0
  46. package/dist/docx/layout/line-metrics.d.ts.map +1 -1
  47. package/dist/docx/layout/nested-frame-profile.d.ts +9 -0
  48. package/dist/docx/layout/nested-frame-profile.d.ts.map +1 -0
  49. package/dist/docx/layout/page-cursor.d.ts +15 -8
  50. package/dist/docx/layout/page-cursor.d.ts.map +1 -1
  51. package/dist/docx/layout/page-flow.d.ts.map +1 -1
  52. package/dist/docx/layout/paragraph-layout.d.ts.map +1 -1
  53. package/dist/docx/layout/paragraph-tokens.d.ts +2 -0
  54. package/dist/docx/layout/paragraph-tokens.d.ts.map +1 -1
  55. package/dist/docx/layout/reference-footnotes.d.ts +7 -0
  56. package/dist/docx/layout/reference-footnotes.d.ts.map +1 -0
  57. package/dist/docx/layout/result.d.ts +44 -0
  58. package/dist/docx/layout/result.d.ts.map +1 -1
  59. package/dist/docx/layout/section-flow.d.ts +2 -0
  60. package/dist/docx/layout/section-flow.d.ts.map +1 -1
  61. package/dist/docx/layout/table-border-layout.d.ts +16 -0
  62. package/dist/docx/layout/table-border-layout.d.ts.map +1 -0
  63. package/dist/docx/layout/table-cell-layout.d.ts +12 -0
  64. package/dist/docx/layout/table-cell-layout.d.ts.map +1 -0
  65. package/dist/docx/layout/table-content.d.ts +4 -0
  66. package/dist/docx/layout/table-content.d.ts.map +1 -0
  67. package/dist/docx/layout/table-footnotes.d.ts +32 -0
  68. package/dist/docx/layout/table-footnotes.d.ts.map +1 -0
  69. package/dist/docx/layout/table-frames.d.ts +4 -0
  70. package/dist/docx/layout/table-frames.d.ts.map +1 -0
  71. package/dist/docx/layout/table-layout.d.ts +16 -5
  72. package/dist/docx/layout/table-layout.d.ts.map +1 -1
  73. package/dist/docx/layout/table-note-completion.d.ts +5 -0
  74. package/dist/docx/layout/table-note-completion.d.ts.map +1 -0
  75. package/dist/docx/layout/table-note-stories.d.ts +6 -0
  76. package/dist/docx/layout/table-note-stories.d.ts.map +1 -0
  77. package/dist/docx/load/index.cjs +194 -25
  78. package/dist/docx/load/index.mjs +194 -25
  79. package/dist/docx/model-run.d.ts +2 -0
  80. package/dist/docx/model-run.d.ts.map +1 -1
  81. package/dist/docx/model.d.ts +7 -0
  82. package/dist/docx/model.d.ts.map +1 -1
  83. package/dist/docx/notes.d.ts +5 -0
  84. package/dist/docx/notes.d.ts.map +1 -1
  85. package/dist/docx/parse-table.d.ts.map +1 -1
  86. package/dist/docx/parse.d.ts.map +1 -1
  87. package/dist/docx/save.d.ts.map +1 -1
  88. package/dist/docx/section-model.d.ts +2 -0
  89. package/dist/docx/section-model.d.ts.map +1 -1
  90. package/dist/docx/sections.d.ts.map +1 -1
  91. package/dist/docx/settings.d.ts +2 -0
  92. package/dist/docx/settings.d.ts.map +1 -1
  93. package/dist/docx/table-model.d.ts +3 -1
  94. package/dist/docx/table-model.d.ts.map +1 -1
  95. package/dist/docx/ui/index.cjs +55 -0
  96. package/dist/docx/ui/index.d.ts +1 -0
  97. package/dist/docx/ui/index.d.ts.map +1 -1
  98. package/dist/docx/ui/index.mjs +55 -1
  99. package/dist/docx/ui/table-structure-guard.d.ts +4 -0
  100. package/dist/docx/ui/table-structure-guard.d.ts.map +1 -0
  101. package/dist/docx/write-footnote-columns.d.ts +3 -0
  102. package/dist/docx/write-footnote-columns.d.ts.map +1 -0
  103. package/dist/docx/write-notes.d.ts.map +1 -1
  104. package/dist/docx/write-run.d.ts.map +1 -1
  105. package/dist/docx/write-sections.d.ts.map +1 -1
  106. package/dist/index.cjs +8 -5
  107. package/dist/index.mjs +8 -5
  108. package/dist/opc/clone-part-graph.d.ts +4 -0
  109. package/dist/opc/clone-part-graph.d.ts.map +1 -1
  110. package/dist/opc/index.cjs +8 -5
  111. package/dist/opc/index.mjs +8 -5
  112. package/dist/pptx/automation/index.cjs +1156 -389
  113. package/dist/pptx/automation/index.d.ts +4 -4
  114. package/dist/pptx/automation/index.mjs +5 -5
  115. package/dist/pptx/chunks/{index-CKIUurnd.d.ts → index-Cuxtr76Y.d.ts} +29 -10
  116. package/dist/pptx/chunks/index-Cuxtr76Y.d.ts.map +1 -0
  117. package/dist/pptx/chunks/{index-Cn-GzYGp.d.ts → index-DUCGeZh7.d.ts} +94 -5
  118. package/dist/pptx/chunks/index-DUCGeZh7.d.ts.map +1 -0
  119. package/dist/pptx/chunks/{smart-art-Q2kZQtHh.d.ts → smart-art-D-sXa_Nb.d.ts} +11 -1
  120. package/dist/pptx/chunks/smart-art-D-sXa_Nb.d.ts.map +1 -0
  121. package/dist/pptx/chunks/{text-operations-BHfAm5K9.d.ts → text-operations-BqHmLaLA.d.ts} +54 -13
  122. package/dist/pptx/chunks/text-operations-BqHmLaLA.d.ts.map +1 -0
  123. package/dist/pptx/cli/index.cjs +1157 -395
  124. package/dist/pptx/cli/index.d.ts +1 -1
  125. package/dist/pptx/cli/index.mjs +4 -4
  126. package/dist/pptx/converter/index.cjs +54 -36
  127. package/dist/pptx/converter/index.d.ts +1 -1
  128. package/dist/pptx/converter/index.mjs +2 -2
  129. package/dist/pptx/editor/render/collaboration-live-patch-target.cjs +2 -2
  130. package/dist/pptx/editor/render/collaboration-live-patch-target.mjs +1 -1
  131. package/dist/pptx/editor/render/find-replace.cjs +416 -45
  132. package/dist/pptx/editor/render/find-replace.d.ts +35 -4
  133. package/dist/pptx/editor/render/find-replace.d.ts.map +1 -1
  134. package/dist/pptx/editor/render/find-replace.mjs +416 -46
  135. package/dist/pptx/editor/render/remap-text.cjs +2 -2
  136. package/dist/pptx/editor/render/remap-text.d.ts.map +1 -1
  137. package/dist/pptx/editor/render/remap-text.mjs +1 -1
  138. package/dist/pptx/editor/render/slide-operations.cjs +87 -0
  139. package/dist/pptx/editor/render/slide-operations.d.ts +17 -1
  140. package/dist/pptx/editor/render/slide-operations.d.ts.map +1 -1
  141. package/dist/pptx/editor/render/slide-operations.mjs +83 -1
  142. package/dist/pptx/editor/render/slide-search.cjs +6 -10
  143. package/dist/pptx/editor/render/slide-search.d.ts +1 -1
  144. package/dist/pptx/editor/render/slide-search.mjs +6 -10
  145. package/dist/pptx/editor/render/template-editing.d.ts +1 -1
  146. package/dist/pptx/editor/render/template-editing.d.ts.map +1 -1
  147. package/dist/pptx/index.cjs +1651 -419
  148. package/dist/pptx/index.d.ts +5 -5
  149. package/dist/pptx/index.mjs +5 -5
  150. package/dist/pptx/smartart-layouts/index.d.ts +1 -1
  151. package/dist/teams/index.cjs +965 -34
  152. package/dist/teams/index.mjs +965 -34
  153. package/dist/visio/accessibility.d.ts +10 -0
  154. package/dist/visio/accessibility.d.ts.map +1 -0
  155. package/dist/visio/cell-formula.d.ts +2 -0
  156. package/dist/visio/cell-formula.d.ts.map +1 -1
  157. package/dist/visio/connector-curve-aligned.d.ts +5 -0
  158. package/dist/visio/connector-curve-aligned.d.ts.map +1 -0
  159. package/dist/visio/connector-curve-spans.d.ts +14 -0
  160. package/dist/visio/connector-curve-spans.d.ts.map +1 -0
  161. package/dist/visio/connector-jumps.d.ts +5 -0
  162. package/dist/visio/connector-jumps.d.ts.map +1 -0
  163. package/dist/visio/connector-route-walk.d.ts +2 -1
  164. package/dist/visio/connector-route-walk.d.ts.map +1 -1
  165. package/dist/visio/date-cache.d.ts +3 -0
  166. package/dist/visio/date-cache.d.ts.map +1 -0
  167. package/dist/visio/edit-alt-text-scope.d.ts +5 -0
  168. package/dist/visio/edit-alt-text-scope.d.ts.map +1 -0
  169. package/dist/visio/edit-alt-text.d.ts +3 -0
  170. package/dist/visio/edit-alt-text.d.ts.map +1 -0
  171. package/dist/visio/edit-commands.d.ts +7 -2
  172. package/dist/visio/edit-commands.d.ts.map +1 -1
  173. package/dist/visio/edit-formatting-commands.d.ts +5 -0
  174. package/dist/visio/edit-formatting-commands.d.ts.map +1 -1
  175. package/dist/visio/edit-formatting-paint.d.ts.map +1 -1
  176. package/dist/visio/edit-formatting-scope.d.ts.map +1 -1
  177. package/dist/visio/edit-line-jump-cache.d.ts +4 -0
  178. package/dist/visio/edit-line-jump-cache.d.ts.map +1 -0
  179. package/dist/visio/edit-master-index.d.ts.map +1 -1
  180. package/dist/visio/edit-metadata-commands.d.ts +10 -2
  181. package/dist/visio/edit-metadata-commands.d.ts.map +1 -1
  182. package/dist/visio/edit-metadata.d.ts +3 -1
  183. package/dist/visio/edit-metadata.d.ts.map +1 -1
  184. package/dist/visio/edit-page-alt-text.d.ts +4 -0
  185. package/dist/visio/edit-page-alt-text.d.ts.map +1 -0
  186. package/dist/visio/edit-page-layout.d.ts.map +1 -1
  187. package/dist/visio/edit-page-rename.d.ts.map +1 -1
  188. package/dist/visio/edit-page-setup-commands.d.ts +7 -1
  189. package/dist/visio/edit-page-setup-commands.d.ts.map +1 -1
  190. package/dist/visio/edit-page-size.d.ts.map +1 -1
  191. package/dist/visio/edit-pages.d.ts.map +1 -1
  192. package/dist/visio/edit-recalculate-index.d.ts.map +1 -1
  193. package/dist/visio/edit-scope.d.ts.map +1 -1
  194. package/dist/visio/edit-shape-create.d.ts.map +1 -1
  195. package/dist/visio/edit-stencil-connector-write.d.ts.map +1 -1
  196. package/dist/visio/edit-style-admission.d.ts.map +1 -1
  197. package/dist/visio/edit-text-field.d.ts.map +1 -1
  198. package/dist/visio/edit-text.d.ts.map +1 -1
  199. package/dist/visio/edit.d.ts +1 -1
  200. package/dist/visio/edit.d.ts.map +1 -1
  201. package/dist/visio/index.cjs +1215 -248
  202. package/dist/visio/index.d.ts +2 -1
  203. package/dist/visio/index.d.ts.map +1 -1
  204. package/dist/visio/index.mjs +1215 -249
  205. package/dist/visio/line-jumps.d.ts +1 -5
  206. package/dist/visio/line-jumps.d.ts.map +1 -1
  207. package/dist/visio/model.d.ts +13 -0
  208. package/dist/visio/model.d.ts.map +1 -1
  209. package/dist/visio/page-layout.d.ts +11 -2
  210. package/dist/visio/page-layout.d.ts.map +1 -1
  211. package/dist/visio/parser.d.ts.map +1 -1
  212. package/dist/visio/shape-metadata.d.ts +6 -0
  213. package/dist/visio/shape-metadata.d.ts.map +1 -1
  214. package/dist/visio/shapes.d.ts.map +1 -1
  215. package/dist/visio/text-field-case.d.ts +2 -0
  216. package/dist/visio/text-field-case.d.ts.map +1 -0
  217. package/dist/visio/text-field-display.d.ts.map +1 -1
  218. package/dist/visio/text-field-fraction.d.ts +3 -0
  219. package/dist/visio/text-field-fraction.d.ts.map +1 -0
  220. package/dist/visio/text-field-numeric.d.ts +4 -0
  221. package/dist/visio/text-field-numeric.d.ts.map +1 -0
  222. package/dist/visio/text-field-system-date.d.ts +4 -0
  223. package/dist/visio/text-field-system-date.d.ts.map +1 -0
  224. package/dist/visio/text-fields.d.ts +1 -0
  225. package/dist/visio/text-fields.d.ts.map +1 -1
  226. package/dist/visio/ui/connector-preview.d.ts +1 -1
  227. package/dist/visio/ui/connector-preview.d.ts.map +1 -1
  228. package/dist/visio/ui/data-graphic-rules.d.ts +2 -0
  229. package/dist/visio/ui/data-graphic-rules.d.ts.map +1 -1
  230. package/dist/visio/ui/data-graphics.d.ts +3 -2
  231. package/dist/visio/ui/data-graphics.d.ts.map +1 -1
  232. package/dist/visio/ui/edit-commands.d.ts.map +1 -1
  233. package/dist/visio/ui/index.cjs +19310 -18157
  234. package/dist/visio/ui/index.mjs +19310 -18158
  235. package/dist/visio/ui/scene-details.d.ts.map +1 -1
  236. package/dist/visio/ui/scene-validation.d.ts.map +1 -1
  237. package/dist/visio/ui/snapshot-scene.d.ts +2 -1
  238. package/dist/visio/ui/snapshot-scene.d.ts.map +1 -1
  239. package/dist/visio/ui/text-field-catalog.d.ts.map +1 -1
  240. package/dist/visio/xml-attribute-whitespace.d.ts +5 -0
  241. package/dist/visio/xml-attribute-whitespace.d.ts.map +1 -0
  242. package/dist/xlsx/edit/index.d.ts +1 -0
  243. package/dist/xlsx/edit/index.d.ts.map +1 -1
  244. package/dist/xlsx/edit/insert-guard.d.ts.map +1 -1
  245. package/dist/xlsx/edit/merge.d.ts.map +1 -1
  246. package/dist/xlsx/edit/page-breaks.d.ts +5 -0
  247. package/dist/xlsx/edit/page-breaks.d.ts.map +1 -0
  248. package/dist/xlsx/edit/pivots.d.ts +8 -0
  249. package/dist/xlsx/edit/pivots.d.ts.map +1 -0
  250. package/dist/xlsx/edit/print-titles.d.ts +7 -0
  251. package/dist/xlsx/edit/print-titles.d.ts.map +1 -0
  252. package/dist/xlsx/edit/session.d.ts.map +1 -1
  253. package/dist/xlsx/edit/sheets.d.ts.map +1 -1
  254. package/dist/xlsx/edit/shift-formulas.d.ts.map +1 -1
  255. package/dist/xlsx/edit/shift-sheet.d.ts.map +1 -1
  256. package/dist/xlsx/edit/sparkline-ranges.d.ts +11 -0
  257. package/dist/xlsx/edit/sparkline-ranges.d.ts.map +1 -0
  258. package/dist/xlsx/edit/sparkline-xml.d.ts +13 -0
  259. package/dist/xlsx/edit/sparkline-xml.d.ts.map +1 -0
  260. package/dist/xlsx/edit/sparklines.d.ts +16 -0
  261. package/dist/xlsx/edit/sparklines.d.ts.map +1 -0
  262. package/dist/xlsx/edit/table-edits.d.ts.map +1 -1
  263. package/dist/xlsx/edit/tables.d.ts.map +1 -1
  264. package/dist/xlsx/edit/types.d.ts +22 -1
  265. package/dist/xlsx/edit/types.d.ts.map +1 -1
  266. package/dist/xlsx/formula/functions/text-regex.d.ts.map +1 -1
  267. package/dist/xlsx/index.cjs +3638 -1199
  268. package/dist/xlsx/index.d.ts +1 -0
  269. package/dist/xlsx/index.d.ts.map +1 -1
  270. package/dist/xlsx/index.mjs +3619 -1200
  271. package/dist/xlsx/layout/cell-view.d.ts +2 -0
  272. package/dist/xlsx/layout/cell-view.d.ts.map +1 -1
  273. package/dist/xlsx/layout/header-footer.d.ts +58 -0
  274. package/dist/xlsx/layout/header-footer.d.ts.map +1 -0
  275. package/dist/xlsx/layout/index.d.ts +5 -0
  276. package/dist/xlsx/layout/index.d.ts.map +1 -1
  277. package/dist/xlsx/layout/print-breaks.d.ts +11 -0
  278. package/dist/xlsx/layout/print-breaks.d.ts.map +1 -0
  279. package/dist/xlsx/layout/print-layout.d.ts +34 -0
  280. package/dist/xlsx/layout/print-layout.d.ts.map +1 -0
  281. package/dist/xlsx/layout/print-merges.d.ts +18 -0
  282. package/dist/xlsx/layout/print-merges.d.ts.map +1 -0
  283. package/dist/xlsx/layout/print-repeat.d.ts +12 -0
  284. package/dist/xlsx/layout/print-repeat.d.ts.map +1 -0
  285. package/dist/xlsx/layout/print-titles.d.ts +20 -0
  286. package/dist/xlsx/layout/print-titles.d.ts.map +1 -0
  287. package/dist/xlsx/layout/sparkline-data.d.ts.map +1 -1
  288. package/dist/xlsx/layout/sparkline-view.d.ts.map +1 -1
  289. package/dist/xlsx/load/index.cjs +8165 -6945
  290. package/dist/xlsx/load/index.mjs +8165 -6945
  291. package/dist/xlsx/model-pivots.d.ts +67 -0
  292. package/dist/xlsx/model-pivots.d.ts.map +1 -0
  293. package/dist/xlsx/model.d.ts +5 -0
  294. package/dist/xlsx/model.d.ts.map +1 -1
  295. package/dist/xlsx/pivot/admission.d.ts +5 -0
  296. package/dist/xlsx/pivot/admission.d.ts.map +1 -0
  297. package/dist/xlsx/pivot/aggregate.d.ts +21 -0
  298. package/dist/xlsx/pivot/aggregate.d.ts.map +1 -0
  299. package/dist/xlsx/pivot/cache-xml.d.ts +9 -0
  300. package/dist/xlsx/pivot/cache-xml.d.ts.map +1 -0
  301. package/dist/xlsx/pivot/data.d.ts +12 -0
  302. package/dist/xlsx/pivot/data.d.ts.map +1 -0
  303. package/dist/xlsx/pivot/hierarchy-first.d.ts +21 -0
  304. package/dist/xlsx/pivot/hierarchy-first.d.ts.map +1 -0
  305. package/dist/xlsx/pivot/hierarchy.d.ts +5 -0
  306. package/dist/xlsx/pivot/hierarchy.d.ts.map +1 -0
  307. package/dist/xlsx/pivot/index.d.ts +3 -0
  308. package/dist/xlsx/pivot/index.d.ts.map +1 -0
  309. package/dist/xlsx/pivot/measures.d.ts +13 -0
  310. package/dist/xlsx/pivot/measures.d.ts.map +1 -0
  311. package/dist/xlsx/pivot/read.d.ts +5 -0
  312. package/dist/xlsx/pivot/read.d.ts.map +1 -0
  313. package/dist/xlsx/pivot/table-xml.d.ts +5 -0
  314. package/dist/xlsx/pivot/table-xml.d.ts.map +1 -0
  315. package/dist/xlsx/pivot/values-axis.d.ts +9 -0
  316. package/dist/xlsx/pivot/values-axis.d.ts.map +1 -0
  317. package/dist/xlsx/pivot/write.d.ts +11 -0
  318. package/dist/xlsx/pivot/write.d.ts.map +1 -0
  319. package/dist/xlsx/read/load.d.ts.map +1 -1
  320. package/dist/xlsx/read/sheet-props.d.ts.map +1 -1
  321. package/dist/xlsx/ui/commands/i18n/index.d.ts.map +1 -1
  322. package/dist/xlsx/ui/commands/i18n/navigation.d.ts.map +1 -1
  323. package/dist/xlsx/ui/commands/i18n/pivots.d.ts +3 -0
  324. package/dist/xlsx/ui/commands/i18n/pivots.d.ts.map +1 -0
  325. package/dist/xlsx/ui/commands/i18n/print-layout.d.ts +3 -0
  326. package/dist/xlsx/ui/commands/i18n/print-layout.d.ts.map +1 -0
  327. package/dist/xlsx/ui/commands/i18n/sparklines.d.ts +3 -0
  328. package/dist/xlsx/ui/commands/i18n/sparklines.d.ts.map +1 -0
  329. package/dist/xlsx/ui/commands/i18n/tools.d.ts.map +1 -1
  330. package/dist/xlsx/ui/commands/page-breaks.d.ts +3 -0
  331. package/dist/xlsx/ui/commands/page-breaks.d.ts.map +1 -0
  332. package/dist/xlsx/ui/index.cjs +2421 -288
  333. package/dist/xlsx/ui/index.d.ts +1 -0
  334. package/dist/xlsx/ui/index.d.ts.map +1 -1
  335. package/dist/xlsx/ui/index.mjs +2421 -289
  336. package/dist/xlsx/write/page-setup.d.ts.map +1 -1
  337. package/dist/xlsx/write/save.d.ts.map +1 -1
  338. package/dist/xlsx/write/sheet-parts.d.ts +1 -0
  339. package/dist/xlsx/write/sheet-parts.d.ts.map +1 -1
  340. package/dist/xlsx/write/workbook-part.d.ts +1 -1
  341. package/dist/xlsx/write/workbook-part.d.ts.map +1 -1
  342. package/dist/xlsx/write/worksheet.d.ts.map +1 -1
  343. package/package.json +1 -1
  344. package/dist/pptx/chunks/index-CKIUurnd.d.ts.map +0 -1
  345. package/dist/pptx/chunks/index-Cn-GzYGp.d.ts.map +0 -1
  346. package/dist/pptx/chunks/smart-art-Q2kZQtHh.d.ts.map +0 -1
  347. package/dist/pptx/chunks/text-operations-BHfAm5K9.d.ts.map +0 -1
@@ -37,8 +37,8 @@ function named(element, local, ns, lenient = true) {
37
37
  }
38
38
  var children = (parent, local, ns, lenient = true) => elements(parent).filter((element) => named(element, local, ns, lenient));
39
39
  var first = (parent, local, ns, lenient = true) => parent ? children(parent, local, ns, lenient)[0] : void 0;
40
- function attr(element, local, ns, prefix) {
41
- return element?.getAttributeNS(ns, local) ?? element?.getAttribute(`${prefix}:${local}`) ?? void 0;
40
+ function attr(element, local, ns, prefix2) {
41
+ return element?.getAttributeNS(ns, local) ?? element?.getAttribute(`${prefix2}:${local}`) ?? void 0;
42
42
  }
43
43
 
44
44
  // docx/xml.ts
@@ -2649,11 +2649,11 @@ function cssFontFamily(name) {
2649
2649
  // chart/render/chart-svg-appearance.ts
2650
2650
  var nextPaintId = 0;
2651
2651
  function chartGradientPaint(model, width = 1024, height = 768) {
2652
- const prefix = `xlsx-chart-${++nextPaintId}`;
2652
+ const prefix2 = `xlsx-chart-${++nextPaintId}`;
2653
2653
  const appearance = { ...model.appearance };
2654
2654
  const defs = [];
2655
2655
  const shadowPaint = (shadow, suffix) => {
2656
- const id = `${prefix}-${suffix}`;
2656
+ const id = `${prefix2}-${suffix}`;
2657
2657
  const pad = Math.max(4, shadow.blur * 3 + Math.abs(shadow.dx) + Math.abs(shadow.dy));
2658
2658
  defs.push(
2659
2659
  `<filter id="${id}" filterUnits="userSpaceOnUse" x="${n(-pad)}" y="${n(-pad)}" width="${n(width + pad * 2)}" height="${n(height + pad * 2)}" color-interpolation-filters="sRGB">${svgDropShadowElement(shadow, { number: n, color: (value) => esc(value) })}</filter>`
@@ -2668,7 +2668,7 @@ function chartGradientPaint(model, width = 1024, height = 768) {
2668
2668
  };
2669
2669
  }
2670
2670
  const paint = (gradient, suffix, bounds) => {
2671
- const def = buildChartGradientDef(`${prefix}-${suffix}`, gradient, bounds);
2671
+ const def = buildChartGradientDef(`${prefix2}-${suffix}`, gradient, bounds);
2672
2672
  defs.push(chartGradientMarkup(def));
2673
2673
  return `url(#${def.id})`;
2674
2674
  };
@@ -3708,6 +3708,14 @@ function mapDocumentParagraphs(model, map) {
3708
3708
  ...section.footers ? { footers: slots(section.footers) } : {}
3709
3709
  }))
3710
3710
  } : {},
3711
+ ...model.footnoteSeparators ? {
3712
+ footnoteSeparators: Object.fromEntries(
3713
+ Object.entries(model.footnoteSeparators).map(([kind, note]) => [
3714
+ kind,
3715
+ { ...note, blocks: mapBlockParagraphs(note.blocks, map) }
3716
+ ])
3717
+ )
3718
+ } : {},
3711
3719
  ...model.footnotes ? {
3712
3720
  footnotes: model.footnotes.map((note) => ({
3713
3721
  ...note,
@@ -3728,6 +3736,32 @@ function fieldName(instr) {
3728
3736
  return instr.trim().split(/\s+/)[0]?.toUpperCase() ?? "";
3729
3737
  }
3730
3738
 
3739
+ // docx/cell-blocks.ts
3740
+ function cellSourceBlocks(cell) {
3741
+ if (!cell.sourceBlocks) return cell.paragraphs;
3742
+ const originalIds = new Set(
3743
+ cell.sourceBlocks.filter((block) => block.type === "paragraph").map((block) => block.id)
3744
+ );
3745
+ const positions = new Map(cell.paragraphs.map((paragraph, index) => [paragraph.id, index]));
3746
+ const blocks = [];
3747
+ let cursor = 0;
3748
+ for (const source of cell.sourceBlocks) {
3749
+ if (source.type === "table") {
3750
+ blocks.push(source);
3751
+ continue;
3752
+ }
3753
+ const position = positions.get(source.id);
3754
+ if (position !== void 0 && position >= cursor) {
3755
+ blocks.push(...cell.paragraphs.slice(cursor, position + 1));
3756
+ cursor = position + 1;
3757
+ }
3758
+ while (cursor < cell.paragraphs.length && !originalIds.has(cell.paragraphs[cursor].id))
3759
+ blocks.push(cell.paragraphs[cursor++]);
3760
+ }
3761
+ blocks.push(...cell.paragraphs.slice(cursor));
3762
+ return blocks;
3763
+ }
3764
+
3731
3765
  // docx/notes.ts
3732
3766
  var romanNumerals = [
3733
3767
  [1e3, "M"],
@@ -3792,7 +3826,7 @@ function walkBlocks(blocks, kind, order) {
3792
3826
  if (block.type === "paragraph") walkParagraph(block, kind, order);
3793
3827
  else
3794
3828
  for (const row of block.rows)
3795
- for (const cell of row) walkBlocks(cell.paragraphs, kind, order);
3829
+ for (const cell of row) walkBlocks(cellSourceBlocks(cell), kind, order);
3796
3830
  }
3797
3831
  }
3798
3832
  function numberNotesInOrder(blocks, kind) {
@@ -4391,6 +4425,12 @@ function appendBreakMarker(tokens, runIndex, sourceStart, kind) {
4391
4425
  tokens.push({ kind: kind === "page" ? "pageBreak" : "columnBreak", runIndex, sourceStart });
4392
4426
  }
4393
4427
 
4428
+ // docx/layout/result.ts
4429
+ function cellVerticalOffset(geometry, rowHeightPx) {
4430
+ const free = Math.max(0, (geometry.alignmentHeightPx ?? rowHeightPx) - geometry.contentHeightPx);
4431
+ return geometry.verticalAlign === "center" ? free / 2 : geometry.verticalAlign === "bottom" ? free : 0;
4432
+ }
4433
+
4394
4434
  // docx/layout/page-fields.ts
4395
4435
  function fieldDisplayText(run, values) {
4396
4436
  if (!run.field || isFieldLocked(run)) return run.text;
@@ -4503,6 +4543,9 @@ function resolveIndents(paragraph) {
4503
4543
  firstLineExtraPx
4504
4544
  };
4505
4545
  }
4546
+ function sourceLengthOf(run) {
4547
+ return run.sourceLength ?? (run.object ? 1 : run.text.length || (run.breakAfter ? 1 : 0));
4548
+ }
4506
4549
  function tokenizeParagraph(paragraph) {
4507
4550
  const tokens = [];
4508
4551
  const runOffsets = [];
@@ -4510,7 +4553,7 @@ function tokenizeParagraph(paragraph) {
4510
4553
  paragraph.runs.forEach((run, runIndex) => {
4511
4554
  runOffsets.push(cursor);
4512
4555
  if (run.hidden) {
4513
- if (!run.synthetic) cursor += run.sourceLength ?? run.text.length;
4556
+ if (!run.synthetic) cursor += sourceLengthOf(run);
4514
4557
  return;
4515
4558
  }
4516
4559
  if (run.object) tokens.push({ kind: "object", runIndex, sourceStart: 0 });
@@ -4526,7 +4569,7 @@ function tokenizeParagraph(paragraph) {
4526
4569
  if (run.breakAfter) appendBreakMarker(tokens, runIndex, run.text.length, run.breakAfter);
4527
4570
  if (run.synthetic) {
4528
4571
  for (const token of tokens) if (token.runIndex === runIndex) token.sourceStart = 0;
4529
- } else cursor += run.sourceLength ?? run.text.length;
4572
+ } else cursor += sourceLengthOf(run);
4530
4573
  });
4531
4574
  return { tokens, runOffsets };
4532
4575
  }
@@ -4548,7 +4591,9 @@ function lineMetrics(placed, fonts, paragraph, measurer) {
4548
4591
  let above = 0;
4549
4592
  let below = 0;
4550
4593
  for (const token of tokens) {
4551
- const extent = tokenExtent(token, paragraph, fonts, measurer);
4594
+ const run = paragraph.runs[token.runIndex];
4595
+ const metrics = run?.object?.noteSeparator ? fontMetrics(measurer, fonts[token.runIndex] ?? fontOf(run)) : void 0;
4596
+ const extent = metrics ? { above: metrics.ascent, below: metrics.descent } : tokenExtent(token, paragraph, fonts, measurer);
4552
4597
  above = Math.max(above, extent.above);
4553
4598
  below = Math.max(below, extent.below);
4554
4599
  }
@@ -4623,7 +4668,18 @@ function layoutParagraph(paragraph, contentWidthPx, measurer, note, lineBox, sta
4623
4668
  const bodyWidth = Math.max(1, contentWidthPx - leftPx - rightPx);
4624
4669
  const fonts = paragraph.runs.map(fontOf);
4625
4670
  const { tokens, runOffsets } = tokenizeParagraph(paragraph);
4626
- const globalOffset = (token) => expectDefined(runOffsets[token.runIndex], "run offset index") + token.sourceStart;
4671
+ const globalOffset = (token, advance = 0) => {
4672
+ const run = expectDefined(paragraph.runs[token.runIndex], "source run");
4673
+ const length = sourceLengthOf(run);
4674
+ const offset = run.synthetic ? 0 : Math.max(
4675
+ 0,
4676
+ Math.min(
4677
+ length,
4678
+ Math.round((token.sourceStart + advance) * length / Math.max(1, run.text.length))
4679
+ )
4680
+ );
4681
+ return expectDefined(runOffsets[token.runIndex], "run offset index") + offset;
4682
+ };
4627
4683
  const effectiveAlign = paragraph.align ?? (paragraph.direction === "rtl" ? "right" : "left");
4628
4684
  const lines = [];
4629
4685
  const pageBreakAfterLine = /* @__PURE__ */ new Set();
@@ -4674,9 +4730,9 @@ function layoutParagraph(paragraph, contentWidthPx, measurer, note, lineBox, sta
4674
4730
  const token = expectDefined(tokens[next], "token index");
4675
4731
  if (ends.has(token.kind)) break;
4676
4732
  if (beforeDecimalPx === void 0 && token.kind === "word" && /[.,]/.test(token.text)) {
4677
- const prefix = token.text.slice(0, token.text.search(/[.,]/));
4733
+ const prefix2 = token.text.slice(0, token.text.search(/[.,]/));
4678
4734
  beforeDecimalPx = followingPx + runTextWidth(
4679
- prefix,
4735
+ prefix2,
4680
4736
  expectDefined(paragraph.runs[token.runIndex], "decimal run"),
4681
4737
  measurer
4682
4738
  );
@@ -4695,14 +4751,17 @@ function layoutParagraph(paragraph, contentWidthPx, measurer, note, lineBox, sta
4695
4751
  const [firstPlaced] = placed;
4696
4752
  const start = firstPlaced ? globalOffset(firstPlaced.token) : 0;
4697
4753
  const last = placed.at(-1)?.token;
4698
- const end = last ? globalOffset(last) + (last.kind === "word" || last.kind === "space" ? last.text.length : 1) : start;
4754
+ const end = last ? globalOffset(last, last.kind === "word" || last.kind === "space" ? last.text.length : 1) : start;
4699
4755
  const gapBeforePx = boxFor(lineIndex).gapBeforePx;
4700
4756
  const { heightPx, baselinePx } = lineMetrics(placed, fonts, paragraph, measurer);
4701
4757
  rendered.forEach(({ token }, index) => {
4702
4758
  const extent2 = tokenExtent(token, paragraph, fonts, measurer);
4703
4759
  const fragment = expectDefined(fragments[index], "fragment for rendered token");
4704
4760
  fragment.sourceStart = globalOffset(token);
4705
- fragment.sourceEnd = fragment.sourceStart + (paragraph.runs[token.runIndex]?.synthetic ? 0 : token.kind === "word" || token.kind === "space" ? token.text.length : 1);
4761
+ fragment.sourceEnd = globalOffset(
4762
+ token,
4763
+ token.kind === "word" || token.kind === "space" ? token.text.length : 1
4764
+ );
4706
4765
  fragment.topPx = baselinePx - extent2.above;
4707
4766
  if (token.kind !== "object") fragment.boxHeightPx = extent2.ascent + extent2.descent;
4708
4767
  });
@@ -4836,6 +4895,176 @@ function widowControlEnabled(value) {
4836
4895
  return value !== false;
4837
4896
  }
4838
4897
 
4898
+ // docx/layout/table-content.ts
4899
+ function cellContentBottom(boxes, paddingBottom = 0) {
4900
+ return Math.max(
4901
+ 0,
4902
+ ...boxes.map(
4903
+ (box) => box.yPx + box.heightPx + (box.tableFrameInsets?.bottom ?? 0) + paddingBottom
4904
+ )
4905
+ );
4906
+ }
4907
+
4908
+ // docx/layout/table-frames.ts
4909
+ function clipTableFrames(tables, start, end, inset = 0) {
4910
+ return tables.flatMap((table) => {
4911
+ const top = Math.max(start, table.yPx);
4912
+ const bottom = Math.min(end, table.yPx + table.heightPx);
4913
+ if (bottom <= top) return [];
4914
+ const rows = table.rows.flatMap((row) => {
4915
+ const rowTop = table.yPx + row.yPx;
4916
+ const a = Math.max(top, rowTop), b = Math.min(bottom, rowTop + row.heightPx);
4917
+ if (b <= a) return [];
4918
+ return [
4919
+ {
4920
+ ...row,
4921
+ yPx: a - top,
4922
+ heightPx: b - a,
4923
+ ...row.cellTables ? {
4924
+ cellTables: row.cellTables.map(
4925
+ (nested) => clipTableFrames(nested, a - rowTop, b - rowTop)
4926
+ )
4927
+ } : {}
4928
+ }
4929
+ ];
4930
+ });
4931
+ return [{ ...table, yPx: top - start + inset, heightPx: bottom - top, rows }];
4932
+ });
4933
+ }
4934
+
4935
+ // docx/layout/nested-frame-profile.ts
4936
+ var equal = (a, b) => a !== void 0 && b !== void 0 && a.style === b.style && a.color === b.color && Math.abs(a.widthPx - b.widthPx) < 1e-6;
4937
+ function nestedFrameProfile(table, tableWidthPx = table.widthPx) {
4938
+ const sides = table.rows.flatMap(
4939
+ (row) => row.cells.flatMap(
4940
+ (cell) => ["top", "right", "bottom", "left"].map((side) => cell.borders?.[side])
4941
+ )
4942
+ );
4943
+ if (sides.every((side) => !side)) return { leftPx: 0, rightPx: 0, bottomPx: 0 };
4944
+ if (!sides.every((side) => side?.style === "solid" && side.widthPx > 0)) return void 0;
4945
+ const first3 = table.rows[0], left = first3.cells[0].borders.left, right = first3.cells.at(-1).borders.right;
4946
+ for (const [index, row] of table.rows.entries()) {
4947
+ if (row.cells.length !== first3.cells.length || !equal(row.cells[0]?.borders?.left, left) || !equal(row.cells.at(-1)?.borders?.right, right))
4948
+ return void 0;
4949
+ for (const [column, cell] of row.cells.entries()) {
4950
+ const sourceWidth = cell.widthPx ?? (tableWidthPx === void 0 ? void 0 : tableWidthPx / row.cells.length);
4951
+ const paintWidth = sourceWidth === void 0 ? void 0 : sourceWidth + (cell.borders.left.widthPx - cell.borders.right.widthPx) / 2 + (column === row.cells.length - 1 ? cell.borders.right.widthPx : 0);
4952
+ if (paintWidth !== void 0 && paintWidth <= 0) return void 0;
4953
+ if (!equal(cell.borders?.top, row.cells[0]?.borders?.top) || !equal(cell.borders?.bottom, row.cells[0]?.borders?.bottom))
4954
+ return void 0;
4955
+ if (column && !equal(row.cells[column - 1]?.borders?.right, cell.borders?.left))
4956
+ return void 0;
4957
+ if (index) {
4958
+ const previous = table.rows[index - 1].cells[column];
4959
+ if (previous.xPx !== cell.xPx || previous.widthPx !== cell.widthPx || !equal(previous.borders?.bottom, cell.borders?.top))
4960
+ return void 0;
4961
+ }
4962
+ }
4963
+ }
4964
+ return {
4965
+ leftPx: left.widthPx,
4966
+ rightPx: right.widthPx,
4967
+ bottomPx: table.rows.at(-1).cells[0].borders.bottom.widthPx
4968
+ };
4969
+ }
4970
+
4971
+ // docx/layout/table-cell-layout.ts
4972
+ function cellParagraphs(cell) {
4973
+ const walk = (blocks) => blocks.flatMap(
4974
+ (block) => block.kind === "paragraph" ? [block] : block.rows.flatMap((row) => row.cells.flatMap(cellParagraphs))
4975
+ );
4976
+ return cell.blocks ? walk(cell.blocks) : cell.paragraphs;
4977
+ }
4978
+ function stackCellBlocks(cell, width, measurer, note, top, starts) {
4979
+ if (!cell.blocks)
4980
+ return stackParagraphs(
4981
+ starts ? cell.paragraphs.filter((p) => starts.has(p.id)) : cell.paragraphs,
4982
+ width,
4983
+ measurer,
4984
+ note,
4985
+ top,
4986
+ starts
4987
+ );
4988
+ let y = top;
4989
+ const boxes = [];
4990
+ const tables = [];
4991
+ for (const block of cell.blocks) {
4992
+ if (block.kind === "paragraph") {
4993
+ if (starts && !starts.has(block.id)) continue;
4994
+ const result = stackParagraphs([block], width, measurer, note, y, starts);
4995
+ boxes.push(...result.boxes);
4996
+ y = result.heightPx;
4997
+ continue;
4998
+ }
4999
+ const tableWidth = block.widthPx ?? width;
5000
+ const profile = nestedFrameProfile(block, tableWidth);
5001
+ const reserveBorders = profile !== void 0;
5002
+ if (!reserveBorders)
5003
+ note(
5004
+ "Nested table border occupancy is approximate for missing edges, non-solid or conflicting shared borders and changing row grids."
5005
+ );
5006
+ const externalRight = profile ? (profile.leftPx + profile.rightPx) / 2 : 0;
5007
+ const paintedWidth = tableWidth + externalRight;
5008
+ const x = block.alignment === "center" ? Math.max(0, (width - paintedWidth) / 2) : block.alignment === "right" ? Math.max(0, width - paintedWidth) : block.indentPx ?? 0;
5009
+ const frame = {
5010
+ kind: "table",
5011
+ blockId: block.id,
5012
+ xPx: x,
5013
+ widthPx: paintedWidth,
5014
+ yPx: y,
5015
+ heightPx: 0,
5016
+ rows: []
5017
+ };
5018
+ for (const row of block.rows) {
5019
+ if (starts && !row.cells.some((nested) => cellParagraphs(nested).some((p) => starts.has(p.id))))
5020
+ continue;
5021
+ const layout = layoutRow(
5022
+ row,
5023
+ tableWidth,
5024
+ measurer,
5025
+ note,
5026
+ void 0,
5027
+ starts,
5028
+ reserveBorders,
5029
+ profile?.leftPx
5030
+ );
5031
+ frame.rows.push({
5032
+ yPx: y - frame.yPx,
5033
+ heightPx: layout.heightPx,
5034
+ repeated: false,
5035
+ cells: layout.cells,
5036
+ geometry: layout.geometry,
5037
+ ...layout.cellTables ? { cellTables: layout.cellTables } : {}
5038
+ });
5039
+ layout.cells.forEach((paragraphs, index) => {
5040
+ const geometry = layout.geometry[index];
5041
+ for (const paragraph of paragraphs)
5042
+ boxes.push({
5043
+ ...paragraph,
5044
+ yPx: y + paragraph.yPx + cellVerticalOffset(geometry, layout.heightPx),
5045
+ xPx: x + geometry.xPx + geometry.paddingLeftPx + (paragraph.xPx ?? 0),
5046
+ widthPx: paragraph.widthPx ?? Math.max(1, geometry.widthPx - geometry.paddingLeftPx - geometry.paddingRightPx),
5047
+ readOnly: true,
5048
+ tableFrameInsets: {
5049
+ top: (paragraph.tableFrameInsets?.top ?? 0) + (reserveBorders ? geometry.borders?.top?.widthPx ?? 0 : 0),
5050
+ bottom: (paragraph.tableFrameInsets?.bottom ?? 0) + (reserveBorders ? geometry.borders?.bottom?.widthPx ?? 0 : 0)
5051
+ }
5052
+ });
5053
+ });
5054
+ y += layout.heightPx;
5055
+ }
5056
+ const bottomBorder = profile?.bottomPx ?? 0;
5057
+ if (frame.rows.length) {
5058
+ frame.rows.at(-1).heightPx += bottomBorder;
5059
+ y += bottomBorder;
5060
+ frame.heightPx = y - frame.yPx;
5061
+ tables.push(frame);
5062
+ }
5063
+ }
5064
+ boxes.sort((a, b) => a.yPx - b.yPx);
5065
+ return { heightPx: y, boxes, tables };
5066
+ }
5067
+
4839
5068
  // docx/layout/table-layout.ts
4840
5069
  function stackParagraphs(paragraphs, widthPx, measurer, note, topPx = 0, startTokens) {
4841
5070
  let y = topPx;
@@ -4851,30 +5080,42 @@ function stackParagraphs(paragraphs, widthPx, measurer, note, topPx = 0, startTo
4851
5080
  );
4852
5081
  y += layout.spacingBeforePx;
4853
5082
  const top = y;
4854
- const lines = layout.lines.map((line2) => ({ ...line2, yPx: line2.yPx + top }));
5083
+ const lines = layout.lines.map((line2) => ({ ...line2 }));
4855
5084
  boxes.push({
4856
5085
  kind: "paragraph",
4857
5086
  blockId: paragraph.id,
4858
5087
  yPx: top,
4859
5088
  heightPx: layout.contentHeightPx,
4860
- lines
5089
+ lines,
5090
+ ...layout.frame ? { frame: layout.frame } : {}
4861
5091
  });
4862
5092
  y += layout.contentHeightPx + layout.spacingAfterPx;
4863
5093
  }
4864
5094
  return { heightPx: y, boxes };
4865
5095
  }
4866
- function layoutRow(row, tableWidthPx, measurer, note, remaining) {
5096
+ function layoutRow(row, tableWidthPx, measurer, note, remaining, startTokens, frameBorders = false, frameLeftBorderPx) {
4867
5097
  const count = row.cells.length || 1;
4868
5098
  let x = 0;
4869
5099
  const geometry = [];
4870
5100
  const laidOut = row.cells.map((cell) => {
4871
5101
  const continuation = remaining?.[geometry.length];
4872
- const starts = continuation ? new Map(continuation.map((box) => [box.blockId, box.lines[0]?.firstToken ?? 0])) : void 0;
5102
+ const starts = continuation ? new Map(continuation.map((box) => [box.blockId, box.lines[0]?.firstToken ?? 0])) : startTokens;
4873
5103
  const widthPx = cell.widthPx ?? tableWidthPx / count;
4874
- const padding = cell.padding ?? { top: 0, right: 0, bottom: 0, left: 0 };
4875
- const content2 = stackParagraphs(
4876
- starts ? cell.paragraphs.filter((paragraph) => starts.has(paragraph.id)) : cell.paragraphs,
4877
- Math.max(1, widthPx - padding.left - padding.right),
5104
+ const margins = cell.padding ?? { top: 0, right: 0, bottom: 0, left: 0 };
5105
+ const leftBorder = frameBorders ? cell.borders?.left?.widthPx ?? 0 : 0;
5106
+ const rightBorder = frameBorders ? cell.borders?.right?.widthPx ?? 0 : 0;
5107
+ const padding = frameBorders ? {
5108
+ top: margins.top + (cell.borders?.top?.widthPx ?? 0),
5109
+ bottom: margins.bottom,
5110
+ left: leftBorder / 2 + Math.max(margins.left, leftBorder / 2),
5111
+ right: Math.max(margins.right, rightBorder / 2) - rightBorder / 2
5112
+ } : margins;
5113
+ const externalRight = frameBorders && geometry.length === row.cells.length - 1 ? rightBorder : 0;
5114
+ const paintWidth = widthPx + (frameBorders ? (leftBorder - rightBorder) / 2 + externalRight : 0);
5115
+ const frameX = frameBorders ? ((frameLeftBorderPx ?? leftBorder) - leftBorder) / 2 : 0;
5116
+ const content2 = stackCellBlocks(
5117
+ cell,
5118
+ Math.max(1, paintWidth - padding.left - padding.right - externalRight),
4878
5119
  measurer,
4879
5120
  note,
4880
5121
  padding.top,
@@ -4882,93 +5123,496 @@ function layoutRow(row, tableWidthPx, measurer, note, remaining) {
4882
5123
  );
4883
5124
  const heightPx2 = content2.heightPx + padding.bottom;
4884
5125
  geometry.push({
4885
- xPx: cell.xPx ?? x,
4886
- widthPx,
5126
+ xPx: (cell.xPx ?? x) + frameX,
5127
+ widthPx: paintWidth,
5128
+ ...frameBorders ? { borderInsetsReserved: true } : {},
4887
5129
  paddingLeftPx: padding.left,
4888
- paddingRightPx: padding.right,
5130
+ paddingRightPx: padding.right + externalRight,
4889
5131
  contentHeightPx: heightPx2,
4890
5132
  ...cell.borders ? { borders: cell.borders } : {},
4891
5133
  ...cell.shading ? { shading: cell.shading } : {},
4892
5134
  ...cell.verticalAlign ? { verticalAlign: cell.verticalAlign } : {}
4893
5135
  });
4894
5136
  x = (cell.xPx ?? x) + widthPx;
4895
- return { heightPx: heightPx2, boxes: content2.boxes };
5137
+ return { heightPx: heightPx2, boxes: content2.boxes, tables: content2.tables ?? [] };
4896
5138
  });
4897
5139
  const content = Math.max(0, ...laidOut.map((cell) => cell.heightPx));
4898
5140
  const heightPx = row.heightPx === void 0 ? content : row.heightRule === "exact" ? row.heightPx : Math.max(content, row.heightPx);
4899
- return { heightPx, cells: laidOut.map((cell) => cell.boxes), geometry };
5141
+ if (frameBorders) for (const cell of geometry) cell.alignmentHeightPx = heightPx;
5142
+ return {
5143
+ heightPx,
5144
+ cells: laidOut.map((cell) => cell.boxes),
5145
+ geometry,
5146
+ ...laidOut.some((cell) => cell.tables.length) ? { cellTables: laidOut.map((cell) => cell.tables) } : {},
5147
+ cellPadding: row.cells.map((cell) => ({
5148
+ top: cell.padding?.top ?? 0,
5149
+ bottom: cell.padding?.bottom ?? 0
5150
+ }))
5151
+ };
4900
5152
  }
4901
- function splitCellAtHeight(boxes, cutHeightPx) {
5153
+ function splitCellAtHeight(boxes, cutHeightPx, paragraphCuts) {
4902
5154
  const before = [];
4903
5155
  const after = [];
4904
- let afterOrigin = null;
4905
5156
  let beforeHeightPx = 0;
4906
5157
  for (const box of boxes) {
4907
- if (afterOrigin !== null) {
4908
- after.push({ ...box, yPx: box.yPx - afterOrigin });
4909
- continue;
4910
- }
4911
- if (box.yPx + box.heightPx <= cutHeightPx) {
5158
+ const cut = paragraphCuts?.get(box.blockId) ?? cutHeightPx;
5159
+ if (box.yPx + box.heightPx + (box.tableFrameInsets?.bottom ?? 0) <= cut) {
4912
5160
  before.push(box);
4913
- beforeHeightPx = box.yPx + box.heightPx;
4914
- continue;
4915
- }
4916
- if (box.yPx >= cutHeightPx) {
4917
- afterOrigin = box.yPx;
4918
- after.push({ ...box, yPx: 0 });
5161
+ beforeHeightPx = Math.max(
5162
+ beforeHeightPx,
5163
+ box.yPx + box.heightPx + (box.tableFrameInsets?.bottom ?? 0)
5164
+ );
4919
5165
  continue;
4920
5166
  }
4921
5167
  const beforeLines = box.lines.filter(
4922
- (line2) => box.yPx + line2.yPx + line2.heightPx <= cutHeightPx
5168
+ (line2) => box.yPx + line2.yPx + line2.heightPx + (box.tableFrameInsets?.bottom ?? 0) <= cut
4923
5169
  );
4924
5170
  const afterLines = box.lines.slice(beforeLines.length);
4925
5171
  if (beforeLines.length) {
4926
5172
  const bottom = beforeLines.at(-1).yPx + beforeLines.at(-1).heightPx;
4927
5173
  before.push({ ...box, heightPx: bottom, lines: beforeLines });
4928
- beforeHeightPx = box.yPx + bottom;
5174
+ beforeHeightPx = Math.max(
5175
+ beforeHeightPx,
5176
+ box.yPx + bottom + (box.tableFrameInsets?.bottom ?? 0)
5177
+ );
4929
5178
  }
4930
5179
  if (afterLines.length) {
4931
5180
  const shift = expectDefined(afterLines[0], "first line after split").yPx;
4932
- afterOrigin = box.yPx + shift;
4933
5181
  after.push({
4934
5182
  ...box,
4935
- yPx: 0,
5183
+ yPx: box.yPx + shift,
4936
5184
  heightPx: afterLines.at(-1).yPx + afterLines.at(-1).heightPx - shift,
4937
5185
  lines: afterLines.map((line2) => ({ ...line2, yPx: line2.yPx - shift }))
4938
5186
  });
4939
- } else {
4940
- afterOrigin = box.yPx + box.heightPx;
4941
5187
  }
4942
5188
  }
4943
- return { before, after, beforeHeightPx };
4944
- }
4945
- function splitRowAtHeight(row, cutHeightPx) {
4946
- const splits = row.cells.map((cell) => splitCellAtHeight(cell, cutHeightPx));
5189
+ const afterOrigin = Math.min(...after.map((box) => box.yPx - (box.tableFrameInsets?.top ?? 0)));
5190
+ for (const box of after) box.yPx -= afterOrigin;
5191
+ return { before, after, beforeHeightPx, ...after.length ? { afterOrigin } : {} };
5192
+ }
5193
+ function splitRowAtHeight(row, cutHeightPx, cellCuts, paragraphCuts) {
5194
+ const splits = row.cells.map((cell, index) => {
5195
+ const padding = row.cellPadding?.[index] ?? { top: 0, bottom: 0 };
5196
+ const cuts = paragraphCuts ? new Map(
5197
+ cell.flatMap((box) => {
5198
+ const cut = paragraphCuts.get(box.blockId);
5199
+ return cut === void 0 ? [] : [[box.blockId, cut - padding.bottom]];
5200
+ })
5201
+ ) : void 0;
5202
+ const split = splitCellAtHeight(
5203
+ cell,
5204
+ (cellCuts?.[index] ?? cutHeightPx) - padding.bottom,
5205
+ cuts
5206
+ );
5207
+ if (split.before.length) split.beforeHeightPx += padding.bottom;
5208
+ if (split.after.length)
5209
+ split.after = split.after.map((box) => ({ ...box, yPx: box.yPx + padding.top }));
5210
+ return split;
5211
+ });
4947
5212
  const anyAfter = splits.some((split) => split.after.length > 0);
5213
+ const beforeHeightPx = Math.max(0, ...splits.map((split) => split.beforeHeightPx));
4948
5214
  const before = {
4949
- heightPx: Math.max(0, ...splits.map((split) => split.beforeHeightPx)),
5215
+ heightPx: beforeHeightPx,
4950
5216
  cells: splits.map((split) => split.before),
4951
- geometry: row.geometry
5217
+ ...row.cellTables ? {
5218
+ cellTables: row.cellTables.map(
5219
+ (tables, index) => clipTableFrames(
5220
+ tables,
5221
+ 0,
5222
+ splits[index].beforeHeightPx - (row.cellPadding?.[index]?.bottom ?? 0)
5223
+ )
5224
+ )
5225
+ } : {},
5226
+ geometry: row.geometry.map((geometry, index) => ({
5227
+ ...geometry,
5228
+ contentHeightPx: splits[index].beforeHeightPx,
5229
+ ...row.borderBottomPx !== void 0 ? { alignmentHeightPx: beforeHeightPx } : {}
5230
+ })),
5231
+ ...row.cellPadding ? { cellPadding: row.cellPadding } : {},
5232
+ ...row.borderBottomPx !== void 0 ? { borderBottomPx: row.borderBottomPx } : {}
4952
5233
  };
4953
5234
  if (!anyAfter) return { before, after: null };
5235
+ const afterHeightPx = Math.max(
5236
+ 0,
5237
+ ...splits.map(
5238
+ (split, index) => cellContentBottom(split.after, row.cellPadding?.[index]?.bottom ?? 0)
5239
+ )
5240
+ );
4954
5241
  const after = {
4955
- heightPx: Math.max(
4956
- 0,
4957
- ...splits.map(
4958
- (split) => split.after.reduce((max, box) => Math.max(max, box.yPx + box.heightPx), 0)
4959
- )
4960
- ),
5242
+ heightPx: afterHeightPx,
4961
5243
  cells: splits.map((split) => split.after),
4962
- geometry: row.geometry
5244
+ ...row.cellTables ? {
5245
+ cellTables: row.cellTables.map(
5246
+ (tables, index) => splits[index].after.length ? clipTableFrames(
5247
+ tables,
5248
+ splits[index].afterOrigin ?? 0,
5249
+ row.heightPx,
5250
+ row.cellPadding?.[index]?.top ?? 0
5251
+ ) : []
5252
+ )
5253
+ } : {},
5254
+ geometry: row.geometry.map((geometry, index) => ({
5255
+ ...geometry,
5256
+ contentHeightPx: cellContentBottom(
5257
+ splits[index].after,
5258
+ row.cellPadding?.[index]?.bottom ?? 0
5259
+ ),
5260
+ ...row.borderBottomPx !== void 0 ? { alignmentHeightPx: afterHeightPx } : {}
5261
+ })),
5262
+ ...row.cellPadding ? { cellPadding: row.cellPadding } : {},
5263
+ ...row.borderBottomPx !== void 0 ? { borderBottomPx: row.borderBottomPx } : {}
4963
5264
  };
4964
5265
  return { before, after };
4965
5266
  }
4966
5267
 
4967
- // docx/layout/page-cursor.ts
5268
+ // docx/layout/footnote-split.ts
5269
+ function splitNote(note, budget) {
5270
+ if (note.heightPx <= budget + 1e-6) return { before: note };
5271
+ const before = [];
5272
+ const after = [];
5273
+ let origin;
5274
+ const sourceTokenStarts = { ...note.sourceTokenStarts };
5275
+ for (const paragraph of note.paragraphs) {
5276
+ if (origin !== void 0) {
5277
+ after.push({ ...paragraph, yPx: paragraph.yPx - origin });
5278
+ continue;
5279
+ }
5280
+ if (paragraph.yPx + paragraph.heightPx <= budget + 1e-6) {
5281
+ before.push(paragraph);
5282
+ continue;
5283
+ }
5284
+ const count = paragraph.lines.filter(
5285
+ (line2) => paragraph.yPx + line2.yPx + line2.heightPx <= budget + 1e-6
5286
+ ).length;
5287
+ const head = paragraph.lines.slice(0, count);
5288
+ const tail = paragraph.lines.slice(count);
5289
+ if (head.length) {
5290
+ const bottom = head.at(-1).yPx + head.at(-1).heightPx;
5291
+ before.push({ ...paragraph, heightPx: bottom, lines: head });
5292
+ }
5293
+ const first3 = tail[0];
5294
+ if (head.length)
5295
+ sourceTokenStarts[paragraph.blockId] = head.at(-1).nextToken ?? sourceTokenStarts[paragraph.blockId] ?? 0;
5296
+ origin = paragraph.yPx + (first3?.yPx ?? 0);
5297
+ after.push({
5298
+ ...paragraph,
5299
+ yPx: 0,
5300
+ heightPx: Math.max(0, paragraph.heightPx - (first3?.yPx ?? 0)),
5301
+ lines: tail.map((line2) => ({ ...line2, yPx: line2.yPx - (first3?.yPx ?? 0) }))
5302
+ });
5303
+ }
5304
+ if (!before.length) return { after: note };
5305
+ const last = before.at(-1);
5306
+ return {
5307
+ before: { ...note, heightPx: last.yPx + last.heightPx, paragraphs: before },
5308
+ ...after.length ? {
5309
+ after: {
5310
+ ...note,
5311
+ yPx: 0,
5312
+ heightPx: Math.max(0, note.heightPx - (origin ?? 0)),
5313
+ paragraphs: after,
5314
+ continued: true,
5315
+ sourceTokenStarts
5316
+ }
5317
+ } : {}
5318
+ };
5319
+ }
5320
+
5321
+ // docx/layout/footnote-columns.ts
5322
+ function footnoteColumns(page, columns) {
5323
+ const width = page.widthPx - page.marginLeftPx - page.marginRightPx;
5324
+ const equal2 = (width - columns.gapPx * (columns.count - 1)) / columns.count;
5325
+ let x = 0;
5326
+ return Array.from({ length: columns.count }, (_, index) => {
5327
+ const own = columns.widths?.[index];
5328
+ const column = { xPx: x, widthPx: Math.max(1, own?.widthPx ?? equal2) };
5329
+ x += column.widthPx + (own?.gapPx ?? columns.gapPx);
5330
+ return column;
5331
+ });
5332
+ }
5333
+ function packFootnotes(notes, columns, height, reflow) {
5334
+ const remaining = [...notes], placed = [];
5335
+ let used = 0;
5336
+ for (const [columnIndex, column] of columns.entries()) {
5337
+ let y = 0;
5338
+ while (remaining.length) {
5339
+ const current = reflow(remaining[0], column.widthPx);
5340
+ const split = splitNote(current, Math.max(0, height - y));
5341
+ if (!split.before) break;
5342
+ placed.push({
5343
+ ...split.before,
5344
+ yPx: y,
5345
+ xPx: column.xPx,
5346
+ widthPx: column.widthPx,
5347
+ columnIndex
5348
+ });
5349
+ y += split.before.heightPx;
5350
+ used = Math.max(used, y);
5351
+ if (split.after) {
5352
+ remaining[0] = { ...split.after, continued: !!current.continued };
5353
+ break;
5354
+ }
5355
+ remaining.shift();
5356
+ }
5357
+ }
5358
+ return { placed, remaining, heightPx: used };
5359
+ }
5360
+ function balancedFootnotes(notes, columns, limit, reflow) {
5361
+ if (!notes.length) return { placed: [], remaining: [], heightPx: 0 };
5362
+ const full = packFootnotes(notes, columns, limit, reflow);
5363
+ if (full.remaining.length) return full;
5364
+ let lower = 0, upper = limit;
5365
+ for (let step = 0; step < 24 && upper - lower > 5e-3; step++) {
5366
+ const middle = (lower + upper) / 2;
5367
+ if (packFootnotes(notes, columns, middle, reflow).remaining.length) lower = middle;
5368
+ else upper = middle;
5369
+ }
5370
+ return packFootnotes(notes, columns, Math.ceil(upper * 100) / 100, reflow);
5371
+ }
5372
+ function minimumFootnoteHeight(notes, columns, reflow) {
5373
+ const width = columns[0].widthPx;
5374
+ const maximum = notes.reduce((sum, note) => sum + reflow(note, width).heightPx, 0);
5375
+ return balancedFootnotes(notes, columns, maximum, reflow).heightPx;
5376
+ }
5377
+
5378
+ // docx/layout/footnote-flow.ts
5379
+ function firstLineBottom(note) {
5380
+ const first3 = note?.paragraphs[0];
5381
+ return first3 ? first3.yPx + (first3.lines[0]?.yPx ?? 0) + (first3.lines[0]?.heightPx ?? first3.heightPx) : note?.heightPx ?? 0;
5382
+ }
4968
5383
  var FOOTNOTE_SEPARATOR_PX = 12;
5384
+ var FootnoteFlow = class {
5385
+ constructor(report, separator, columns, reflow = (note) => note) {
5386
+ this.report = report;
5387
+ this.separator = separator;
5388
+ this.columns = columns;
5389
+ this.reflow = reflow;
5390
+ }
5391
+ report;
5392
+ separator;
5393
+ columns;
5394
+ reflow;
5395
+ pending;
5396
+ remaining = [];
5397
+ sources = /* @__PURE__ */ new WeakMap();
5398
+ separatorHeight(page, notes = this.pending?.notes ?? []) {
5399
+ return (page.footnoteSeparator ?? this.separator?.(page, !!notes[0]?.continued))?.heightPx ?? FOOTNOTE_SEPARATOR_PX;
5400
+ }
5401
+ get hasContinuation() {
5402
+ return this.remaining.length > 0;
5403
+ }
5404
+ hold(blockId, notes, bodyMinimum, freshBodyMinimum = bodyMinimum) {
5405
+ this.pending = notes.length ? { blockId, notes, bodyMinimum, freshBodyMinimum } : void 0;
5406
+ }
5407
+ reserved(page, _columnIndex = 0) {
5408
+ return page.footnotes?.length ? this.separatorHeight(page) + (page.footnoteHeightPx ?? page.footnotes.reduce((sum, note) => sum + note.heightPx, 0)) : 0;
5409
+ }
5410
+ pendingHeight(page, capacity, bodyUsed, _columnIndex = 0) {
5411
+ if (!this.pending) return 0;
5412
+ if (this.columns) {
5413
+ const existing = this.sources.get(page) ?? [];
5414
+ const height = minimumFootnoteHeight(
5415
+ [...existing, ...this.pending.notes],
5416
+ footnoteColumns(page, this.columns),
5417
+ this.reflow
5418
+ ) + this.separatorHeight(page);
5419
+ if (height + this.pending.freshBodyMinimum <= capacity)
5420
+ return Math.max(0, height - this.reserved(page));
5421
+ return Math.max(
5422
+ firstLineBottom(this.pending.notes[0]) + (page.footnotes?.length ? 0 : this.separatorHeight(page)),
5423
+ capacity - bodyUsed - this.reserved(page) - this.pending.bodyMinimum
5424
+ );
5425
+ }
5426
+ const total = this.pending.notes.reduce((sum, note) => sum + note.heightPx, 0);
5427
+ const separator = page.footnotes?.length ? 0 : this.separatorHeight(page);
5428
+ if (total + this.separatorHeight(page) + this.pending.freshBodyMinimum <= capacity)
5429
+ return total + separator;
5430
+ return Math.max(
5431
+ firstLineBottom(this.pending.notes[0]) + separator,
5432
+ capacity - bodyUsed - this.reserved(page) - this.pending.bodyMinimum
5433
+ );
5434
+ }
5435
+ /** A later column cannot grow the page-wide note area into body content already placed. */
5436
+ blockedByEarlierColumn(page, capacity, bodyBottom) {
5437
+ if (!this.pending) return false;
5438
+ if (this.columns)
5439
+ return bodyBottom + this.reserved(page) + this.pendingHeight(page, capacity, bodyBottom) > capacity;
5440
+ const total = this.pending.notes.reduce((sum, note) => sum + note.heightPx, 0);
5441
+ const minimum = firstLineBottom(this.pending.notes[0]);
5442
+ const needed = total + this.separatorHeight(page) + this.pending.freshBodyMinimum <= capacity ? total : minimum;
5443
+ return bodyBottom + this.reserved(page) + needed + (page.footnotes?.length ? 0 : this.separatorHeight(page)) > capacity;
5444
+ }
5445
+ commit(blockId, page, available, _columnIndex = 0) {
5446
+ if (this.pending?.blockId !== blockId) return false;
5447
+ const notes = this.pending.notes;
5448
+ this.pending = void 0;
5449
+ this.append(page, notes, available);
5450
+ return true;
5451
+ }
5452
+ resume(page, capacity, _columnIndex, width) {
5453
+ const notes = width === void 0 ? this.remaining : this.remaining.map((note) => this.reflow(note, width));
5454
+ this.remaining = [];
5455
+ this.append(page, notes, capacity);
5456
+ }
5457
+ append(page, notes, available) {
5458
+ if (!page.footnotes?.length && notes.length) {
5459
+ const separator = this.separator?.(page, !!notes[0]?.continued);
5460
+ if (separator) page.footnoteSeparator = separator;
5461
+ }
5462
+ if (this.columns) {
5463
+ const sources = [...this.sources.get(page) ?? [], ...notes];
5464
+ this.sources.set(page, sources);
5465
+ const geometry = footnoteColumns(page, this.columns);
5466
+ const previousHeight = page.footnoteHeightPx ?? 0;
5467
+ const capacity = Math.max(
5468
+ 0,
5469
+ available + previousHeight - (page.footnotes?.length ? 0 : this.separatorHeight(page))
5470
+ );
5471
+ let packed = balancedFootnotes(sources, geometry, capacity, this.reflow);
5472
+ if (!packed.placed.length && sources.length) {
5473
+ this.report(
5474
+ "A footnote line was taller than its available page area and was placed without splitting."
5475
+ );
5476
+ packed = balancedFootnotes(
5477
+ sources,
5478
+ geometry,
5479
+ firstLineBottom(this.reflow(sources[0], geometry[0].widthPx)),
5480
+ this.reflow
5481
+ );
5482
+ }
5483
+ page.footnotes = packed.placed;
5484
+ page.footnoteHeightPx = packed.heightPx;
5485
+ this.remaining = packed.remaining.map((note) => ({
5486
+ ...note,
5487
+ continued: !!note.continued || packed.placed.some((fragment) => fragment.id === note.id)
5488
+ }));
5489
+ return;
5490
+ }
5491
+ let top = page.footnotes?.reduce((sum, note) => sum + note.heightPx, 0) ?? 0;
5492
+ let budget = Math.max(0, available - (page.footnotes?.length ? 0 : this.separatorHeight(page)));
5493
+ for (let index = 0; index < notes.length; index++) {
5494
+ const note = notes[index];
5495
+ let split = splitNote(note, budget);
5496
+ if (!split.before && !page.footnotes?.length) {
5497
+ split = splitNote(note, firstLineBottom(note));
5498
+ this.report(
5499
+ "A footnote line was taller than its available page area and was placed without splitting."
5500
+ );
5501
+ }
5502
+ if (split.before) {
5503
+ (page.footnotes ??= []).push({ ...split.before, yPx: top });
5504
+ top += split.before.heightPx;
5505
+ budget -= split.before.heightPx;
5506
+ }
5507
+ if (split.after) {
5508
+ this.remaining.push(split.after, ...notes.slice(index + 1));
5509
+ break;
5510
+ }
5511
+ }
5512
+ }
5513
+ };
5514
+
5515
+ // docx/layout/legacy-footnote-flow.ts
5516
+ var LegacyFootnoteFlow = class {
5517
+ flow;
5518
+ views = /* @__PURE__ */ new WeakMap();
5519
+ constructor(report, separator, reflow = (note) => note) {
5520
+ this.flow = new FootnoteFlow(report, separator, void 0, reflow);
5521
+ }
5522
+ view(page, index) {
5523
+ let views = this.views.get(page);
5524
+ if (!views) {
5525
+ views = /* @__PURE__ */ new Map();
5526
+ this.views.set(page, views);
5527
+ }
5528
+ let view = views.get(index);
5529
+ if (!view) {
5530
+ const {
5531
+ footnotes: _notes,
5532
+ footnoteSeparator: _separator,
5533
+ footnoteHeightPx: _height,
5534
+ footnoteColumnAreas: _areas,
5535
+ ...geometry
5536
+ } = page;
5537
+ view = {
5538
+ ...geometry,
5539
+ widthPx: page.columns[index].widthPx,
5540
+ marginLeftPx: 0,
5541
+ marginRightPx: 0,
5542
+ columns: []
5543
+ };
5544
+ views.set(index, view);
5545
+ }
5546
+ return view;
5547
+ }
5548
+ sync(page) {
5549
+ const views = this.views.get(page);
5550
+ if (!views) return;
5551
+ const areas = [...views].filter(([, view]) => view.footnotes?.length).map(([columnIndex, view]) => {
5552
+ const column = page.columns[columnIndex];
5553
+ return {
5554
+ columnIndex,
5555
+ xPx: column.xPx,
5556
+ widthPx: column.widthPx,
5557
+ heightPx: view.footnotes.reduce((sum, note) => sum + note.heightPx, 0),
5558
+ continued: !!view.footnotes[0]?.continued,
5559
+ ...view.footnoteSeparator ? { separator: view.footnoteSeparator } : {},
5560
+ yPx: 0
5561
+ };
5562
+ });
5563
+ const height = Math.max(0, ...areas.map((area) => area.heightPx));
5564
+ for (const area of areas) area.yPx = height - area.heightPx;
5565
+ page.footnoteColumnAreas = areas;
5566
+ page.footnoteHeightPx = height;
5567
+ page.footnotes = areas.flatMap(
5568
+ (area) => this.view(page, area.columnIndex).footnotes.map((note) => ({
5569
+ ...note,
5570
+ xPx: area.xPx,
5571
+ widthPx: area.widthPx,
5572
+ columnIndex: area.columnIndex,
5573
+ yPx: area.yPx + note.yPx
5574
+ }))
5575
+ );
5576
+ }
5577
+ get hasContinuation() {
5578
+ return this.flow.hasContinuation;
5579
+ }
5580
+ hold(blockId, notes, bodyMinimum, freshBodyMinimum = bodyMinimum) {
5581
+ this.flow.hold(blockId, notes, bodyMinimum, freshBodyMinimum);
5582
+ }
5583
+ reserved(page, columnIndex = 0) {
5584
+ return this.flow.reserved(this.view(page, columnIndex));
5585
+ }
5586
+ pendingHeight(page, capacity, bodyUsed, columnIndex = 0) {
5587
+ return this.flow.pendingHeight(this.view(page, columnIndex), capacity, bodyUsed);
5588
+ }
5589
+ blockedByEarlierColumn(_page, _capacity, _bodyBottom) {
5590
+ return false;
5591
+ }
5592
+ commit(blockId, page, available, columnIndex = 0) {
5593
+ if (this.flow.commit(blockId, this.view(page, columnIndex), available)) this.sync(page);
5594
+ }
5595
+ resume(page, capacity, columnIndex) {
5596
+ if (!this.flow.hasContinuation) return;
5597
+ const indexes = columnIndex === void 0 ? page.columns.map((_, index) => index) : [columnIndex];
5598
+ for (const index of indexes) {
5599
+ if (!this.flow.hasContinuation) break;
5600
+ const view = this.view(page, index);
5601
+ if (view.footnotes?.length) continue;
5602
+ this.flow.resume(view, capacity, void 0, view.widthPx);
5603
+ }
5604
+ this.sync(page);
5605
+ }
5606
+ };
5607
+
5608
+ // docx/layout/page-cursor.ts
4969
5609
  var PageCursor = class {
4970
- constructor(pages, geometry, columns, sectionIndex = 0, continueAt, balance) {
5610
+ constructor(pages, geometry, columns, sectionIndex = 0, continueAt, balance, report = () => {
5611
+ }, separator, noteColumns, reflow, legacyFootnoteColumns = false) {
4971
5612
  this.balance = balance;
5613
+ this.noteColumns = noteColumns;
5614
+ this.legacyFootnoteColumns = legacyFootnoteColumns;
5615
+ this.footnotes = legacyFootnoteColumns ? new LegacyFootnoteFlow(report, separator, reflow) : new FootnoteFlow(report, separator, noteColumns, reflow);
4972
5616
  this.sectionIndex = sectionIndex;
4973
5617
  this.pages = pages;
4974
5618
  this.geometry = geometry;
@@ -4992,6 +5636,8 @@ var PageCursor = class {
4992
5636
  }
4993
5637
  }
4994
5638
  balance;
5639
+ noteColumns;
5640
+ legacyFootnoteColumns;
4995
5641
  pages;
4996
5642
  equalColumnWidthPx;
4997
5643
  activeColumns = [];
@@ -5002,10 +5648,7 @@ var PageCursor = class {
5002
5648
  yPx = 0;
5003
5649
  sectionIndex;
5004
5650
  pageInSection = 0;
5005
- /** Height taken by footnotes (and their separator) at the bottom of the current page. */
5006
- reservedPx = 0;
5007
- /** Footnotes of the paragraph about to be placed; they join the page its first box lands on. */
5008
- pending;
5651
+ footnotes;
5009
5652
  columnBoxes(offsetPx = 0) {
5010
5653
  const columnBoxes = [];
5011
5654
  let xPx = offsetPx;
@@ -5040,7 +5683,7 @@ var PageCursor = class {
5040
5683
  this.columnIndex = 0;
5041
5684
  this.columnTopPx = 0;
5042
5685
  this.yPx = 0;
5043
- this.reservedPx = 0;
5686
+ this.footnotes.resume(this.page, this.physicalColumnHeightPx);
5044
5687
  }
5045
5688
  get page() {
5046
5689
  return this.pages.at(-1);
@@ -5048,6 +5691,9 @@ var PageCursor = class {
5048
5691
  get column() {
5049
5692
  return expectDefined(this.activeColumns[this.columnIndex], "current page column");
5050
5693
  }
5694
+ get noteColumnIndex() {
5695
+ return this.legacyFootnoteColumns ? this.page.columns.indexOf(this.column) : this.columnIndex;
5696
+ }
5051
5697
  get columnWidthPx() {
5052
5698
  return this.column.widthPx;
5053
5699
  }
@@ -5062,6 +5708,9 @@ var PageCursor = class {
5062
5708
  endBalance() {
5063
5709
  this.balance = void 0;
5064
5710
  }
5711
+ get footnoteWidthPx() {
5712
+ return this.noteColumns ? footnoteColumns(this.page, this.noteColumns)[0].widthPx : this.columnWidthPx;
5713
+ }
5065
5714
  get y() {
5066
5715
  return this.yPx;
5067
5716
  }
@@ -5084,8 +5733,12 @@ var PageCursor = class {
5084
5733
  this.page.heightPx - this.page.marginTopPx - this.geometry.marginBottomPx - this.columnTopPx
5085
5734
  );
5086
5735
  }
5736
+ /** Number of independently balanced note columns, distinct from legacy body-column notes. */
5737
+ get footnoteColumnCount() {
5738
+ return this.legacyFootnoteColumns ? 1 : this.noteColumns?.count ?? 1;
5739
+ }
5087
5740
  remainingHeightPx() {
5088
- return this.columnHeightPx - (this.yPx - this.columnTopPx) - this.reservedPx - this.pendingHeightPx();
5741
+ return this.columnHeightPx - (this.yPx - this.columnTopPx) - this.footnotes.reserved(this.page, this.noteColumnIndex) - this.pendingHeightPx();
5089
5742
  }
5090
5743
  /** Close this section's column band before another section shares its page. */
5091
5744
  finishBand() {
@@ -5104,16 +5757,41 @@ var PageCursor = class {
5104
5757
  return bottom;
5105
5758
  }
5106
5759
  pendingHeightPx() {
5107
- if (!this.pending) return 0;
5108
- return this.pending.heightPx + (this.page.footnotes?.length ? 0 : FOOTNOTE_SEPARATOR_PX);
5760
+ return this.footnotes.pendingHeight(
5761
+ this.page,
5762
+ this.columnHeightPx,
5763
+ this.usedColumnHeightPx,
5764
+ this.noteColumnIndex
5765
+ );
5109
5766
  }
5110
5767
  /**
5111
5768
  * Reserves room for a paragraph's footnotes on whichever page its first box is placed, so the
5112
5769
  * notes print on the same page as their reference, as Word does.
5113
5770
  */
5114
- holdFootnotes(blockId, notes) {
5115
- const heightPx = notes.reduce((sum, note) => sum + note.heightPx, 0);
5116
- this.pending = notes.length ? { blockId, notes, heightPx } : void 0;
5771
+ holdFootnotes(blockId, notes, bodyMinimum = 0, freshBodyMinimum = bodyMinimum) {
5772
+ this.footnotes.hold(blockId, notes, bodyMinimum, freshBodyMinimum);
5773
+ }
5774
+ /** Finish long notes even when the section has no more body paragraphs. */
5775
+ finishFootnotes() {
5776
+ while (this.footnotes.hasContinuation) {
5777
+ if (this.legacyFootnoteColumns) this.newColumn();
5778
+ else this.newPage();
5779
+ }
5780
+ }
5781
+ /** Continued notes can occupy an otherwise empty page, before body/table content starts. */
5782
+ advancePastFootnotes(minimumBodyHeight) {
5783
+ while (this.page.footnotes?.length && this.atColumnTop && this.remainingHeightPx() < minimumBodyHeight - 1e-6 || this.columnIndex > 0 && this.footnotes.blockedByEarlierColumn(
5784
+ this.page,
5785
+ this.columnHeightPx,
5786
+ Math.max(
5787
+ 0,
5788
+ ...this.activeColumns.slice(0, this.columnIndex).flatMap(
5789
+ (column) => column.blocks.map((block) => block.yPx + block.heightPx - this.columnTopPx)
5790
+ )
5791
+ )
5792
+ ))
5793
+ if (this.legacyFootnoteColumns) this.newColumn();
5794
+ else this.newPage();
5117
5795
  }
5118
5796
  newPage() {
5119
5797
  this.pushPage();
@@ -5123,6 +5801,8 @@ var PageCursor = class {
5123
5801
  if (this.columnIndex + 1 < this.columns.count) {
5124
5802
  this.columnIndex++;
5125
5803
  this.yPx = this.columnTopPx;
5804
+ if (this.legacyFootnoteColumns)
5805
+ this.footnotes.resume(this.page, this.physicalColumnHeightPx, this.noteColumnIndex);
5126
5806
  } else {
5127
5807
  this.pushPage();
5128
5808
  }
@@ -5136,25 +5816,54 @@ var PageCursor = class {
5136
5816
  box.yPx = this.yPx;
5137
5817
  this.column.blocks.push(box);
5138
5818
  this.yPx += advancePx;
5139
- if (this.pending && this.pending.blockId === box.blockId) {
5140
- this.reservedPx += this.pendingHeightPx();
5141
- const page = this.page;
5142
- let top = page.footnotes?.reduce((sum, note) => sum + note.heightPx, 0) ?? 0;
5143
- for (const note of this.pending.notes) {
5144
- (page.footnotes ??= []).push({ ...note, yPx: top });
5145
- top += note.heightPx;
5146
- }
5147
- this.pending = void 0;
5148
- }
5819
+ const bodyBottom = this.legacyFootnoteColumns ? this.yPx : Math.max(
5820
+ this.yPx,
5821
+ ...this.activeColumns.flatMap(
5822
+ (column) => column.blocks.map((block) => block.yPx + block.heightPx)
5823
+ )
5824
+ );
5825
+ this.footnotes.commit(
5826
+ box.blockId,
5827
+ this.page,
5828
+ this.columnHeightPx - (bodyBottom - this.columnTopPx) - this.footnotes.reserved(this.page, this.noteColumnIndex),
5829
+ this.noteColumnIndex
5830
+ );
5149
5831
  }
5150
5832
  };
5151
5833
 
5152
5834
  // docx/layout/flow-paragraph.ts
5153
5835
  function placeParagraph(cursor, placement, note) {
5154
5836
  const { paragraph, spacingBeforePx, requiredTogetherPx, reflow } = placement;
5155
- let layout = placement.layout;
5837
+ const trailingBreakLine = (result) => {
5838
+ const last = result.lines.at(-1);
5839
+ if (!placement.trimLeadingColumnBreak || !last || !result.columnBreakAfterLine.has(result.lines.length - 1))
5840
+ return result;
5841
+ return {
5842
+ ...result,
5843
+ contentHeightPx: result.contentHeightPx + last.heightPx,
5844
+ lines: [
5845
+ ...result.lines,
5846
+ {
5847
+ ...last,
5848
+ yPx: last.yPx + last.heightPx,
5849
+ fragments: [],
5850
+ sourceStart: last.sourceEnd,
5851
+ sourceEnd: last.sourceEnd
5852
+ }
5853
+ ]
5854
+ };
5855
+ };
5856
+ let layout = trailingBreakLine(placement.layout);
5156
5857
  let width = cursor.columnWidthPx;
5157
5858
  if (paragraph.pageBreakBefore && cursor.hasPageContent) cursor.newPage();
5859
+ if (requiredTogetherPx > 0 && placement.footnotes) {
5860
+ cursor.holdFootnotes(
5861
+ paragraph.id,
5862
+ placement.footnotes(layout.lines, true),
5863
+ requiredTogetherPx,
5864
+ layout.lines[0]?.heightPx ?? 0
5865
+ );
5866
+ }
5158
5867
  if (requiredTogetherPx > 0 && requiredTogetherPx <= cursor.columnHeightPx && requiredTogetherPx > cursor.remainingHeightPx() && !cursor.atColumnTop) {
5159
5868
  cursor.newColumn();
5160
5869
  }
@@ -5162,9 +5871,23 @@ function placeParagraph(cursor, placement, note) {
5162
5871
  let lineCursor = 0;
5163
5872
  let nextToken = 0;
5164
5873
  let firstSegment = true;
5874
+ const lineHeight = (line2, index) => placement.trimLeadingColumnBreak && layout.columnBreakAfterLine.has(index) && line2.fragments.every((fragment) => !fragment.text && !fragment.object) ? 0 : line2.heightPx;
5875
+ const placedNotes = /* @__PURE__ */ new Set();
5876
+ const notesFor = (lines) => (placement.footnotes?.(lines, firstSegment) ?? []).filter((item) => !placedNotes.has(item.id));
5877
+ const hold = (lines, bodyMinimum) => {
5878
+ const notes = notesFor(lines);
5879
+ if (placement.footnotes)
5880
+ cursor.holdFootnotes(
5881
+ paragraph.id,
5882
+ notes,
5883
+ bodyMinimum,
5884
+ Math.max(0, ...lines.map((line2) => line2.heightPx))
5885
+ );
5886
+ return notes;
5887
+ };
5165
5888
  const reflowIfNeeded = () => {
5166
5889
  if (!reflow || cursor.columnWidthPx === width) return;
5167
- layout = reflow(nextToken);
5890
+ layout = trailingBreakLine(reflow(nextToken));
5168
5891
  lineCursor = 0;
5169
5892
  width = cursor.columnWidthPx;
5170
5893
  };
@@ -5178,15 +5901,27 @@ function placeParagraph(cursor, placement, note) {
5178
5901
  }
5179
5902
  while (lineCursor < layout.lines.length) {
5180
5903
  reflowIfNeeded();
5181
- const budget = cursor.remainingHeightPx() - (firstSegment ? spacingBeforePx : 0);
5904
+ hold(
5905
+ layout.lines.slice(lineCursor, lineCursor + 1),
5906
+ layout.lines[lineCursor] ? lineHeight(layout.lines[lineCursor], lineCursor) : 0
5907
+ );
5908
+ cursor.advancePastFootnotes(
5909
+ layout.lines[lineCursor] ? lineHeight(layout.lines[lineCursor], lineCursor) : 0
5910
+ );
5911
+ reflowIfNeeded();
5182
5912
  let cumulative = 0;
5183
5913
  let end = lineCursor;
5184
5914
  let forced;
5185
5915
  for (let i = lineCursor; i < layout.lines.length; i++) {
5186
5916
  const line2 = expectDefined(layout.lines[i], "paragraph line index");
5187
5917
  const gap = i === lineCursor && !firstSegment ? 0 : line2.gapBeforePx ?? 0;
5188
- const height = line2.heightPx + gap;
5189
- if (cumulative + height > budget && (end > lineCursor || !cursor.atColumnTop)) break;
5918
+ const height = lineHeight(line2, i) + gap;
5919
+ hold(
5920
+ layout.lines.slice(lineCursor, i + 1),
5921
+ cumulative + height + (firstSegment ? spacingBeforePx : 0)
5922
+ );
5923
+ const budget = cursor.remainingHeightPx() - (firstSegment ? spacingBeforePx : 0);
5924
+ if (cumulative + height > budget + 1e-6 && (end > lineCursor || !cursor.atColumnTop)) break;
5190
5925
  cumulative += height;
5191
5926
  end = i + 1;
5192
5927
  if (layout.pageBreakAfterLine.has(i)) {
@@ -5211,9 +5946,17 @@ function placeParagraph(cursor, placement, note) {
5211
5946
  );
5212
5947
  placedCount = Math.max(1, end - lineCursor);
5213
5948
  }
5949
+ const committedNotes = hold(
5950
+ layout.lines.slice(lineCursor, lineCursor + placedCount),
5951
+ cumulative + (firstSegment ? spacingBeforePx : 0)
5952
+ );
5214
5953
  const first3 = expectDefined(layout.lines[lineCursor], "first line of paragraph segment");
5215
5954
  const origin = first3.yPx - (firstSegment ? (first3.gapBeforePx ?? 0) + layout.insetTopPx : 0);
5216
- const segmentLines = layout.lines.slice(lineCursor, lineCursor + placedCount).map((line2) => ({ ...line2, yPx: line2.yPx - origin }));
5955
+ const segmentLines = layout.lines.slice(lineCursor, lineCursor + placedCount).map((line2, index) => ({
5956
+ ...line2,
5957
+ yPx: line2.yPx - origin,
5958
+ heightPx: lineHeight(line2, lineCursor + index)
5959
+ }));
5217
5960
  const isFinal = lineCursor + placedCount >= layout.lines.length;
5218
5961
  const lastLine = segmentLines.at(-1);
5219
5962
  const isLastSegment = lineCursor + placedCount >= layout.lines.length;
@@ -5228,6 +5971,7 @@ function placeParagraph(cursor, placement, note) {
5228
5971
  };
5229
5972
  const advance = (firstSegment ? spacingBeforePx : 0) + segmentHeight + (isFinal ? layout.spacingAfterPx : 0);
5230
5973
  cursor.place(box, advance);
5974
+ for (const item of committedNotes) placedNotes.add(item.id);
5231
5975
  nextToken = layout.lines[lineCursor + placedCount - 1]?.nextToken ?? nextToken;
5232
5976
  lineCursor += placedCount;
5233
5977
  firstSegment = false;
@@ -5237,50 +5981,494 @@ function placeParagraph(cursor, placement, note) {
5237
5981
  }
5238
5982
  }
5239
5983
 
5984
+ // docx/layout/table-note-stories.ts
5985
+ function independentNoteStories(cell) {
5986
+ const first3 = cell.blocks?.[0];
5987
+ if (first3?.kind !== "table" || first3.rows.length !== 1 || cell.verticalAlign && cell.verticalAlign !== "top")
5988
+ return void 0;
5989
+ if (cell.blocks.slice(1).some((block) => block.kind !== "paragraph" || block.footnotes?.length))
5990
+ return void 0;
5991
+ const row = first3.rows[0];
5992
+ if (row.heightPx !== void 0 || row.cantSplit || row.isHeader || !nestedFrameProfile(first3, first3.widthPx))
5993
+ return void 0;
5994
+ if (row.cells.some(
5995
+ (inner) => inner.blocks?.some((block) => block.kind === "table") || cellParagraphs(inner).some(
5996
+ (paragraph) => paragraph.keepLines || paragraph.keepNext || paragraph.pageBreakBefore
5997
+ ) || inner.verticalAlign && inner.verticalAlign !== "top"
5998
+ ))
5999
+ return void 0;
6000
+ if (!measuredNoteReferences(row.cells.flatMap(cellParagraphs))) return void 0;
6001
+ const groups = /* @__PURE__ */ new Map();
6002
+ row.cells.forEach((inner, index) => {
6003
+ for (const paragraph of cellParagraphs(inner)) groups.set(paragraph.id, first3.id + ":" + index);
6004
+ });
6005
+ return groups.size ? groups : void 0;
6006
+ }
6007
+ function measuredNoteReferences(paragraphs) {
6008
+ const markers = paragraphs.flatMap(
6009
+ (paragraph) => paragraph.runs.flatMap(
6010
+ (run) => run.footnoteReferenceId === void 0 ? [] : [run.footnoteReferenceId]
6011
+ )
6012
+ );
6013
+ const ids = new Set(markers);
6014
+ const unanchored = paragraphs.flatMap(
6015
+ (paragraph) => (paragraph.footnotes ?? []).filter(
6016
+ (note) => !paragraph.runs.some((run) => run.footnoteReferenceId === note.id)
6017
+ )
6018
+ ).length;
6019
+ return markers.length + unanchored <= 3 && ids.size === markers.length && !(markers.length + unanchored > 1 && unanchored);
6020
+ }
6021
+
6022
+ // docx/layout/table-border-layout.ts
6023
+ function layoutBorderedRow(row, width, measurer, note, profile, remaining) {
6024
+ const reserved = profile !== void 0 && (profile.leftPx > 0 || profile.rightPx > 0 || profile.bottomPx > 0);
6025
+ const layout = layoutRow(
6026
+ row,
6027
+ width,
6028
+ measurer,
6029
+ note,
6030
+ remaining,
6031
+ void 0,
6032
+ reserved,
6033
+ profile?.leftPx
6034
+ );
6035
+ if (!reserved) return layout;
6036
+ const bottom = Math.max(0, ...layout.geometry.map((cell) => cell.borders?.bottom?.widthPx ?? 0));
6037
+ return {
6038
+ ...layout,
6039
+ heightPx: layout.heightPx + bottom,
6040
+ borderBottomPx: bottom,
6041
+ cellPadding: row.cells.map((cell) => ({
6042
+ top: (cell.padding?.top ?? 0) + (cell.borders?.top?.widthPx ?? 0),
6043
+ bottom: (cell.padding?.bottom ?? 0) + (cell.borders?.bottom?.widthPx ?? 0)
6044
+ }))
6045
+ };
6046
+ }
6047
+ var TableFragmentBorders = class {
6048
+ bottom = 0;
6049
+ included = true;
6050
+ record(bottom) {
6051
+ this.bottom = bottom ?? 0;
6052
+ this.included = true;
6053
+ }
6054
+ remove(row) {
6055
+ if (!row || !this.included) return 0;
6056
+ row.heightPx -= this.bottom;
6057
+ this.included = false;
6058
+ return -this.bottom;
6059
+ }
6060
+ restore(row) {
6061
+ if (!row || this.included) return 0;
6062
+ row.heightPx += this.bottom;
6063
+ this.included = true;
6064
+ return this.bottom;
6065
+ }
6066
+ };
6067
+
6068
+ // docx/layout/table-note-completion.ts
6069
+ function completedNoteStoryMinimum(row, stories, pendingBlocks, available) {
6070
+ let minimum = 0;
6071
+ for (const [index, cell] of row.cells.entries()) {
6072
+ const groups = /* @__PURE__ */ new Map();
6073
+ for (const box of cell) {
6074
+ const group = stories.get(box.blockId);
6075
+ if (group !== void 0) {
6076
+ const boxes = groups.get(group) ?? [];
6077
+ boxes.push(box);
6078
+ groups.set(group, boxes);
6079
+ }
6080
+ }
6081
+ for (const boxes of groups.values()) {
6082
+ if (boxes.reduce((count, box) => count + box.lines.length, 0) !== 1 || boxes.some((box) => pendingBlocks.has(box.blockId)))
6083
+ continue;
6084
+ const bottom = cellContentBottom(boxes, row.cellPadding?.[index]?.bottom ?? 0);
6085
+ if (bottom <= available + 1e-6) minimum = Math.max(minimum, bottom);
6086
+ }
6087
+ }
6088
+ return minimum;
6089
+ }
6090
+
6091
+ // docx/layout/table-footnotes.ts
6092
+ function prefix(row, cut, cellCuts, paragraphCuts) {
6093
+ const cells = row.cells.map((cell, index) => {
6094
+ const padding = row.cellPadding?.[index]?.bottom ?? 0;
6095
+ const boxes = [];
6096
+ for (const box of cell) {
6097
+ const contentCut = (paragraphCuts?.get(box.blockId) ?? cellCuts?.[index] ?? cut) - padding;
6098
+ if (box.yPx >= contentCut + 1e-6) {
6099
+ if (!paragraphCuts?.size) break;
6100
+ continue;
6101
+ }
6102
+ if (box.yPx + box.heightPx + (box.tableFrameInsets?.bottom ?? 0) <= contentCut + 1e-6) {
6103
+ boxes.push(box);
6104
+ continue;
6105
+ }
6106
+ const lines = [];
6107
+ for (const line2 of box.lines) {
6108
+ if (box.yPx + line2.yPx + line2.heightPx + (box.tableFrameInsets?.bottom ?? 0) > contentCut + 1e-6)
6109
+ break;
6110
+ lines.push(line2);
6111
+ }
6112
+ if (lines.length)
6113
+ boxes.push({ ...box, lines, heightPx: lines.at(-1).yPx + lines.at(-1).heightPx });
6114
+ continue;
6115
+ }
6116
+ return boxes;
6117
+ });
6118
+ if (cells.every(
6119
+ (cell, index) => cell.length === row.cells[index].length && cell.every(
6120
+ (box, boxIndex) => box.lines.length === row.cells[index][boxIndex].lines.length
6121
+ )
6122
+ ))
6123
+ return row;
6124
+ return {
6125
+ ...row,
6126
+ cells,
6127
+ heightPx: Math.max(
6128
+ 0,
6129
+ ...cells.map((cell, index) => cellContentBottom(cell, row.cellPadding?.[index]?.bottom ?? 0))
6130
+ )
6131
+ };
6132
+ }
6133
+ var TableFootnotes = class {
6134
+ constructor(cursor, table, height, resolve) {
6135
+ this.cursor = cursor;
6136
+ this.table = table;
6137
+ this.height = height;
6138
+ this.resolve = resolve;
6139
+ for (const row of table.rows) {
6140
+ const measured = measuredNoteReferences(row.cells.flatMap(cellParagraphs));
6141
+ for (const cell of row.cells) {
6142
+ for (const paragraph of cellParagraphs(cell))
6143
+ if (paragraph.footnotes?.length) this.paragraphs.set(paragraph.id, paragraph);
6144
+ for (const [id, group] of (measured ? independentNoteStories(cell) : void 0) ?? []) {
6145
+ this.stories.set(id, group);
6146
+ }
6147
+ }
6148
+ }
6149
+ }
6150
+ cursor;
6151
+ table;
6152
+ height;
6153
+ resolve;
6154
+ paragraphs = /* @__PURE__ */ new Map();
6155
+ stories = /* @__PURE__ */ new Map();
6156
+ placed = /* @__PURE__ */ new Set();
6157
+ fragment = /* @__PURE__ */ new Map();
6158
+ references(row) {
6159
+ const refs = /* @__PURE__ */ new Map();
6160
+ for (const cell of row.cells)
6161
+ for (const box of cell) {
6162
+ const source = this.paragraphs.get(box.blockId);
6163
+ if (!source) continue;
6164
+ for (const note of this.resolve(
6165
+ source,
6166
+ box.lines,
6167
+ (box.lines[0]?.sourceStart ?? 0) === 0
6168
+ )) {
6169
+ if (this.placed.has(note.id)) continue;
6170
+ const line2 = box.lines.find(
6171
+ (line3) => line3.fragments.some(
6172
+ (fragment) => source.runs[fragment.runIndex]?.footnoteReferenceId === note.id
6173
+ )
6174
+ ) ?? box.lines[0];
6175
+ const bottom = Math.min(
6176
+ row.heightPx,
6177
+ box.yPx + (line2?.yPx ?? 0) + (line2?.heightPx ?? box.heightPx) + (box.tableFrameInsets?.bottom ?? 0)
6178
+ );
6179
+ const prior = refs.get(note.id);
6180
+ if (!prior || bottom < prior.bottom)
6181
+ refs.set(note.id, {
6182
+ note,
6183
+ bottom,
6184
+ blockId: box.blockId,
6185
+ before: box.yPx + (line2?.yPx ?? 0) + (box.tableFrameInsets?.bottom ?? 0)
6186
+ });
6187
+ }
6188
+ }
6189
+ return [...refs.values()];
6190
+ }
6191
+ /** A consumed marker no longer constrains its story. Deferred markers stop just before
6192
+ * their own line, allowing another pending story to use a different complete prefix. */
6193
+ storyCut(pending, boxes, padding, cut, space, included) {
6194
+ const ids = new Set(boxes.map((box) => box.blockId));
6195
+ const refs = pending.filter((ref) => ids.has(ref.blockId));
6196
+ let limit = refs.some((ref) => included.has(ref.note.id)) ? Math.min(cut, space) : space;
6197
+ for (const ref of refs)
6198
+ if (!included.has(ref.note.id)) limit = Math.min(limit, ref.before + padding);
6199
+ return limit;
6200
+ }
6201
+ hold(refs, minimumBody = 0) {
6202
+ const referenceBottom = Math.max(0, ...[...refs.values()].map((ref) => ref.bottom));
6203
+ const bodyHeight = Math.max(referenceBottom, minimumBody);
6204
+ this.cursor.holdFootnotes(
6205
+ this.table.id,
6206
+ [...refs.values()].map((ref) => ref.note),
6207
+ bodyHeight,
6208
+ this.cursor.usedColumnHeightPx + referenceBottom
6209
+ );
6210
+ }
6211
+ holdCandidate(row, completionMinimum = 0) {
6212
+ const refs = new Map(this.fragment);
6213
+ for (const ref of this.references(row))
6214
+ if (!refs.has(ref.note.id))
6215
+ refs.set(ref.note.id, { ...ref, bottom: this.height() + ref.bottom });
6216
+ const referenceBottom = Math.max(0, ...[...refs.values()].map((ref) => ref.bottom));
6217
+ const contentBottom = this.height() + Math.max(0, ...row.cells.map((cell) => cellContentBottom(cell)));
6218
+ const paddingBottom = Math.max(0, ...(row.cellPadding ?? []).map((padding) => padding.bottom));
6219
+ this.hold(
6220
+ refs,
6221
+ Math.max(
6222
+ completionMinimum,
6223
+ contentBottom <= referenceBottom + 1e-6 ? this.height() + row.heightPx : referenceBottom + paddingBottom
6224
+ )
6225
+ );
6226
+ }
6227
+ /** Largest complete prefix that keeps each new marker with available note content. */
6228
+ choose(row, atomic) {
6229
+ this.cursor.holdFootnotes(this.table.id, [], 0);
6230
+ const available = this.cursor.remainingHeightPx() - this.height();
6231
+ if (row.heightPx <= available + 1e-6) {
6232
+ this.holdCandidate(row);
6233
+ if (row.heightPx <= this.cursor.remainingHeightPx() - this.height() + 1e-6)
6234
+ return { layout: row, cut: row.heightPx };
6235
+ }
6236
+ if (!atomic) {
6237
+ const independent = row.cells.some(
6238
+ (cell) => cell.some((box) => this.stories.has(box.blockId))
6239
+ );
6240
+ const pending = independent ? this.references(row) : [];
6241
+ const completing = (this.cursor.footnoteColumnCount === 2 || this.cursor.footnoteColumnCount === 3) && pending.length === 1 && !this.stories.has(pending[0].blockId) ? completedNoteStoryMinimum(
6242
+ row,
6243
+ this.stories,
6244
+ new Set(pending.map((ref) => ref.blockId)),
6245
+ available
6246
+ ) : 0;
6247
+ const cuts = /* @__PURE__ */ new Set();
6248
+ for (const [index, cell] of row.cells.entries())
6249
+ for (const box of cell) {
6250
+ if (box.yPx > available + 1e-6) break;
6251
+ for (const line2 of box.lines) {
6252
+ const bottom = box.yPx + line2.yPx + line2.heightPx + (box.tableFrameInsets?.bottom ?? 0) + (row.cellPadding?.[index]?.bottom ?? 0);
6253
+ if (bottom > available + 1e-6) break;
6254
+ if (bottom > 0) cuts.add(bottom);
6255
+ }
6256
+ }
6257
+ for (const cut of [...cuts].sort((a, b) => b - a)) {
6258
+ const candidate = prefix(row, cut);
6259
+ const included = new Set(this.references(candidate).map((ref) => ref.note.id));
6260
+ const completion = completing > 0 && included.has(pending[0]?.note.id ?? "") ? this.height() + completing : 0;
6261
+ this.holdCandidate(candidate, completion);
6262
+ if (candidate.heightPx <= this.cursor.remainingHeightPx() - this.height() + 1e-6) {
6263
+ const space = this.cursor.remainingHeightPx() - this.height();
6264
+ const cellCuts = row.cells.map(
6265
+ (cell, index) => independent ? this.storyCut(
6266
+ pending,
6267
+ cell,
6268
+ row.cellPadding?.[index]?.bottom ?? 0,
6269
+ cut,
6270
+ space,
6271
+ included
6272
+ ) : cell.some((box) => this.paragraphs.has(box.blockId)) ? cut : space
6273
+ );
6274
+ const paragraphCuts = /* @__PURE__ */ new Map();
6275
+ for (const [index, cell] of row.cells.entries()) {
6276
+ const groups = /* @__PURE__ */ new Map();
6277
+ for (const box of cell) {
6278
+ const group = this.stories.get(box.blockId);
6279
+ if (group !== void 0) {
6280
+ const boxes = groups.get(group) ?? [];
6281
+ boxes.push(box);
6282
+ groups.set(group, boxes);
6283
+ }
6284
+ }
6285
+ for (const boxes of groups.values()) {
6286
+ const limit = this.storyCut(
6287
+ pending,
6288
+ boxes,
6289
+ row.cellPadding?.[index]?.bottom ?? 0,
6290
+ cut,
6291
+ space,
6292
+ included
6293
+ );
6294
+ for (const box of boxes) paragraphCuts.set(box.blockId, limit);
6295
+ }
6296
+ }
6297
+ const expanded = prefix(row, cut, cellCuts, paragraphCuts);
6298
+ this.holdCandidate(expanded, completion);
6299
+ if (expanded.heightPx <= this.cursor.remainingHeightPx() - this.height() + 1e-6)
6300
+ return {
6301
+ layout: expanded,
6302
+ cut,
6303
+ cellCuts,
6304
+ ...paragraphCuts.size ? { paragraphCuts } : {}
6305
+ };
6306
+ this.holdCandidate(candidate, completion);
6307
+ return { layout: candidate, cut };
6308
+ }
6309
+ }
6310
+ }
6311
+ this.holdFragment();
6312
+ return void 0;
6313
+ }
6314
+ add(row, repeated) {
6315
+ if (repeated) return;
6316
+ for (const ref of this.references(row))
6317
+ if (!this.fragment.has(ref.note.id))
6318
+ this.fragment.set(ref.note.id, { ...ref, bottom: this.height() + ref.bottom });
6319
+ }
6320
+ holdFragment() {
6321
+ this.hold(this.fragment);
6322
+ }
6323
+ flushed() {
6324
+ for (const id of this.fragment.keys()) this.placed.add(id);
6325
+ this.fragment.clear();
6326
+ }
6327
+ };
6328
+
5240
6329
  // docx/layout/flow-table.ts
5241
- function placeTable(cursor, table, measurer, note) {
6330
+ function placeTable(cursor, table, measurer, note, resolveFootnotes) {
5242
6331
  const firstBodyRow = table.rows.findIndex((row) => !row.isHeader);
5243
6332
  const headerRows = table.rows.slice(0, firstBodyRow < 0 ? table.rows.length : firstBodyRow);
5244
6333
  const xPosition = () => {
5245
- const width = table.widthPx ?? cursor.columnWidthPx;
6334
+ const width = (table.widthPx ?? cursor.columnWidthPx) + (activeBorders ? (profile.leftPx + profile.rightPx) / 2 : 0);
5246
6335
  return table.alignment === "center" ? Math.max(0, (cursor.columnWidthPx - width) / 2) : table.alignment === "right" ? Math.max(0, cursor.columnWidthPx - width) : table.indentPx ?? 0;
5247
6336
  };
6337
+ const profile = nestedFrameProfile(table, table.widthPx ?? cursor.columnWidthPx);
6338
+ const activeBorders = profile !== void 0 && (profile.leftPx > 0 || profile.rightPx > 0 || profile.bottomPx > 0);
6339
+ if (!profile && table.rows.some((row) => row.cells.some((cell) => cell.borders)))
6340
+ note(
6341
+ "Ordinary table border occupancy remains approximate for missing edges, non-solid or conflicting shared borders and changing row grids."
6342
+ );
6343
+ const layoutRow2 = (row, width, m, n2, remaining) => layoutBorderedRow(
6344
+ row,
6345
+ activeBorders ? table.widthPx ?? width : width,
6346
+ m,
6347
+ n2,
6348
+ profile,
6349
+ remaining
6350
+ );
6351
+ const fragmentBorders = new TableFragmentBorders();
5248
6352
  let fragmentRows = [];
5249
6353
  let fragmentHeight = 0;
6354
+ const footnotes = resolveFootnotes ? new TableFootnotes(cursor, table, () => fragmentHeight, resolveFootnotes) : void 0;
5250
6355
  const toRowBox = (layout, repeated) => {
6356
+ fragmentHeight += fragmentBorders.remove(fragmentRows.at(-1));
6357
+ footnotes?.add(layout, repeated);
5251
6358
  const box = {
5252
6359
  yPx: fragmentHeight,
5253
6360
  heightPx: layout.heightPx,
5254
6361
  repeated,
5255
6362
  cells: layout.cells,
5256
- geometry: layout.geometry
6363
+ geometry: layout.geometry,
6364
+ ...layout.cellTables ? { cellTables: layout.cellTables } : {}
5257
6365
  };
5258
6366
  fragmentHeight += layout.heightPx;
6367
+ fragmentBorders.record(layout.borderBottomPx);
5259
6368
  return box;
5260
6369
  };
5261
6370
  function flushFragment() {
5262
- if (!fragmentRows.length) return;
6371
+ fragmentHeight += fragmentBorders.restore(fragmentRows.at(-1));
6372
+ if (!fragmentRows.length) {
6373
+ footnotes?.holdFragment();
6374
+ return;
6375
+ }
5263
6376
  const box = {
5264
6377
  kind: "table",
5265
6378
  blockId: table.id,
6379
+ ...activeBorders ? {
6380
+ widthPx: (table.widthPx ?? cursor.columnWidthPx) + (profile.leftPx + profile.rightPx) / 2
6381
+ } : {},
5266
6382
  ...xPosition() ? { xPx: xPosition() } : {},
5267
6383
  yPx: 0,
5268
6384
  heightPx: fragmentHeight,
5269
6385
  rows: fragmentRows
5270
6386
  };
6387
+ footnotes?.holdFragment();
5271
6388
  cursor.place(box, fragmentHeight);
6389
+ footnotes?.flushed();
5272
6390
  fragmentRows = [];
5273
6391
  fragmentHeight = 0;
5274
6392
  }
5275
6393
  function startNewFragment() {
5276
6394
  flushFragment();
5277
6395
  cursor.newColumn();
6396
+ addHeaders();
6397
+ }
6398
+ function addHeaders() {
5278
6399
  for (const header of headerRows)
5279
- fragmentRows.push(toRowBox(layoutRow(header, cursor.columnWidthPx, measurer, note), true));
6400
+ fragmentRows.push(toRowBox(layoutRow2(header, cursor.columnWidthPx, measurer, note), true));
5280
6401
  }
5281
6402
  function placeRow(row, initial, cantSplit) {
5282
6403
  let remainingRow = initial;
5283
6404
  while (remainingRow) {
6405
+ fragmentHeight += fragmentBorders.remove(fragmentRows.at(-1));
6406
+ const minimum = cantSplit ? Math.min(remainingRow.heightPx, cursor.columnHeightPx) : Math.min(
6407
+ ...remainingRow.cells.flatMap(
6408
+ (cell, index) => cell.map(
6409
+ (paragraph) => paragraph.yPx + (paragraph.lines[0]?.yPx ?? 0) + (paragraph.lines[0]?.heightPx ?? 0) + (remainingRow.borderBottomPx !== void 0 ? (remainingRow.cellPadding?.[index]?.bottom ?? 0) + (paragraph.tableFrameInsets?.bottom ?? 0) : 0)
6410
+ )
6411
+ )
6412
+ );
6413
+ if (fragmentRows.every((item) => item.repeated)) {
6414
+ const width = cursor.columnWidthPx;
6415
+ cursor.advancePastFootnotes(fragmentHeight + (Number.isFinite(minimum) ? minimum : 0));
6416
+ if (width !== cursor.columnWidthPx) {
6417
+ remainingRow = layoutRow2(
6418
+ remainingRow === initial ? row : { ...row, heightPx: 0, heightRule: "atLeast" },
6419
+ cursor.columnWidthPx,
6420
+ measurer,
6421
+ note,
6422
+ remainingRow.cells
6423
+ );
6424
+ if (fragmentRows.length) {
6425
+ fragmentRows = [];
6426
+ fragmentHeight = 0;
6427
+ addHeaders();
6428
+ }
6429
+ continue;
6430
+ }
6431
+ }
6432
+ if (footnotes) {
6433
+ const selected = footnotes.choose(remainingRow, cantSplit);
6434
+ if (selected) {
6435
+ if (selected.layout === remainingRow) {
6436
+ fragmentRows.push(toRowBox(remainingRow, false));
6437
+ remainingRow = null;
6438
+ continue;
6439
+ }
6440
+ const { before: before2, after: after2 } = splitRowAtHeight(
6441
+ remainingRow,
6442
+ selected.cut + 1e-6,
6443
+ selected.cellCuts?.map((cut) => cut + 1e-6),
6444
+ selected.paragraphCuts ? new Map([...selected.paragraphCuts].map(([id, cut]) => [id, cut + 1e-6])) : void 0
6445
+ );
6446
+ fragmentRows.push(toRowBox(before2, false));
6447
+ const previousWidth2 = cursor.columnWidthPx;
6448
+ startNewFragment();
6449
+ remainingRow = after2 && (selected.paragraphCuts || previousWidth2 !== cursor.columnWidthPx) ? layoutRow2(
6450
+ { ...row, heightPx: 0, heightRule: "atLeast" },
6451
+ cursor.columnWidthPx,
6452
+ measurer,
6453
+ note,
6454
+ after2.cells
6455
+ ) : after2;
6456
+ continue;
6457
+ }
6458
+ if (fragmentRows.length || !cursor.atColumnTop) {
6459
+ const previousWidth2 = cursor.columnWidthPx;
6460
+ startNewFragment();
6461
+ if (previousWidth2 !== cursor.columnWidthPx)
6462
+ remainingRow = layoutRow2(
6463
+ remainingRow === initial ? row : { ...row, heightPx: 0, heightRule: "atLeast" },
6464
+ cursor.columnWidthPx,
6465
+ measurer,
6466
+ note,
6467
+ remainingRow === initial ? void 0 : remainingRow.cells
6468
+ );
6469
+ continue;
6470
+ }
6471
+ }
5284
6472
  const remaining = cursor.remainingHeightPx() - fragmentHeight;
5285
6473
  if (remainingRow.heightPx <= remaining) {
5286
6474
  fragmentRows.push(toRowBox(remainingRow, false));
@@ -5290,7 +6478,19 @@ function placeTable(cursor, table, measurer, note) {
5290
6478
  if (cantSplit) {
5291
6479
  if (fragmentRows.length || !cursor.atColumnTop) {
5292
6480
  startNewFragment();
5293
- remainingRow = layoutRow(row, cursor.columnWidthPx, measurer, note);
6481
+ remainingRow = layoutRow2(row, cursor.columnWidthPx, measurer, note);
6482
+ }
6483
+ const noteWidth = cursor.columnWidthPx;
6484
+ cursor.advancePastFootnotes(
6485
+ fragmentHeight + Math.min(remainingRow.heightPx, cursor.columnHeightPx)
6486
+ );
6487
+ if (noteWidth !== cursor.columnWidthPx) {
6488
+ remainingRow = layoutRow2(row, cursor.columnWidthPx, measurer, note);
6489
+ if (fragmentRows.length) {
6490
+ fragmentRows = [];
6491
+ fragmentHeight = 0;
6492
+ addHeaders();
6493
+ }
5294
6494
  }
5295
6495
  const freshRemaining = cursor.remainingHeightPx() - fragmentHeight;
5296
6496
  if (remainingRow.heightPx > freshRemaining)
@@ -5311,7 +6511,7 @@ function placeTable(cursor, table, measurer, note) {
5311
6511
  const previousWidth = cursor.columnWidthPx;
5312
6512
  if (before.cells.some((cell) => cell.length)) fragmentRows.push(toRowBox(before, false));
5313
6513
  startNewFragment();
5314
- remainingRow = after && previousWidth !== cursor.columnWidthPx ? layoutRow(
6514
+ remainingRow = after && previousWidth !== cursor.columnWidthPx ? layoutRow2(
5315
6515
  { ...row, heightPx: 0, heightRule: "atLeast" },
5316
6516
  cursor.columnWidthPx,
5317
6517
  measurer,
@@ -5321,12 +6521,44 @@ function placeTable(cursor, table, measurer, note) {
5321
6521
  }
5322
6522
  }
5323
6523
  for (const row of table.rows) {
5324
- const layout = layoutRow(row, cursor.columnWidthPx, measurer, note);
5325
- placeRow(row, layout, Boolean(row.cantSplit) || headerRows.includes(row));
6524
+ const layout = layoutRow2(row, cursor.columnWidthPx, measurer, note);
6525
+ if (activeBorders && layout.heightPx > cursor.remainingHeightPx() && row.cells.some(
6526
+ (cell) => (!measuredNoteReferences(row.cells.flatMap(cellParagraphs)) || !independentNoteStories(cell)) && cell.blocks?.some((block) => block.kind === "table") && cellParagraphs(cell).some((p) => p.footnotes?.length)
6527
+ ))
6528
+ note(
6529
+ "Independent inner-cell continuation around nested note references remains approximate when an enclosing bordered row splits."
6530
+ );
6531
+ placeRow(
6532
+ row,
6533
+ layout,
6534
+ Boolean(row.cantSplit) || headerRows.includes(row) || !!footnotes && row.heightRule === "exact"
6535
+ );
5326
6536
  }
5327
6537
  flushFragment();
5328
6538
  }
5329
6539
 
6540
+ // docx/layout/reference-footnotes.ts
6541
+ function createReferenceFootnotes(width, measurer, report) {
6542
+ const cache = /* @__PURE__ */ new Map();
6543
+ return (paragraph, lines, includeUnanchored) => {
6544
+ const selected = new Set(
6545
+ lines.flatMap(
6546
+ (line2) => line2.fragments.map((fragment) => paragraph.runs[fragment.runIndex]?.footnoteReferenceId)
6547
+ )
6548
+ );
6549
+ const anchored = new Set(paragraph.runs.map((run) => run.footnoteReferenceId));
6550
+ return (paragraph.footnotes ?? []).filter((note) => selected.has(note.id) || includeUnanchored && !anchored.has(note.id)).map((note) => {
6551
+ const key = `${note.id}:${width()}`;
6552
+ const prior = cache.get(key);
6553
+ if (prior) return prior;
6554
+ const stacked = stackParagraphs(note.paragraphs, width(), measurer, report);
6555
+ const box = { id: note.id, yPx: 0, heightPx: stacked.heightPx, paragraphs: stacked.boxes };
6556
+ cache.set(key, box);
6557
+ return box;
6558
+ });
6559
+ };
6560
+ }
6561
+
5330
6562
  // docx/layout/wrap.ts
5331
6563
  var SIDE_DISTANCE_PX = 12;
5332
6564
  var MIN_SIDE_WIDTH_PX = 48;
@@ -5380,20 +6612,117 @@ function lineBoxesFor(exclusions, topPx, columnLeftPx, columnWidthPx) {
5380
6612
  // docx/layout/section-flow.ts
5381
6613
  var SectionFlow = class {
5382
6614
  constructor(section, pages, measurer, note, sectionIndex = 0, exclusions, continueAt, balance) {
6615
+ this.section = section;
5383
6616
  this.exclusions = exclusions;
5384
6617
  this.balance = balance;
6618
+ const noteColumns = section.footnoteColumns ?? (section.modernFootnoteSeparator ? section.columns ?? { count: 1, gapPx: 0 } : void 0);
6619
+ if (!noteColumns && !section.legacyFootnoteColumns && (section.columns?.count ?? 1) > 1 && section.blocks.some(
6620
+ (block) => block.kind === "paragraph" ? !!block.footnotes?.length : block.rows.some(
6621
+ (row) => row.cells.some(
6622
+ (cell) => cellParagraphs(cell).some((paragraph) => !!paragraph.footnotes?.length)
6623
+ )
6624
+ )
6625
+ ))
6626
+ note(
6627
+ "Multi-column footnotes use a page-wide area; native per-column footnote balancing is not yet modeled."
6628
+ );
6629
+ const sources = /* @__PURE__ */ new Map();
6630
+ for (const block of section.blocks) {
6631
+ const paragraphs = block.kind === "paragraph" ? [block] : block.rows.flatMap((row) => row.cells.flatMap(cellParagraphs));
6632
+ for (const paragraph of paragraphs)
6633
+ for (const source of paragraph.footnotes ?? []) sources.set(source.id, source);
6634
+ }
6635
+ const reflowCache = /* @__PURE__ */ new Map();
6636
+ const reflow = (box, width) => {
6637
+ const source = sources.get(box.id);
6638
+ if (!source) return box;
6639
+ const ids = new Set(box.paragraphs.map((paragraph) => paragraph.blockId));
6640
+ const key = JSON.stringify([box.id, width, [...ids], box.sourceTokenStarts]);
6641
+ const cached = reflowCache.get(key);
6642
+ if (cached) return { ...cached, continued: !!box.continued };
6643
+ const paragraphs = source.paragraphs.filter((paragraph) => ids.has(paragraph.id)).map(
6644
+ (paragraph) => box.sourceTokenStarts?.[paragraph.id] ? { ...paragraph, spacingBeforeTwips: NO_TWIPS } : paragraph
6645
+ );
6646
+ const stacked = stackParagraphs(
6647
+ paragraphs,
6648
+ width,
6649
+ measurer,
6650
+ note,
6651
+ 0,
6652
+ new Map(Object.entries(box.sourceTokenStarts ?? {}))
6653
+ );
6654
+ const result = { ...box, yPx: 0, heightPx: stacked.heightPx, paragraphs: stacked.boxes };
6655
+ reflowCache.set(key, result);
6656
+ return result;
6657
+ };
5385
6658
  this.blocks = section.blocks;
5386
6659
  this.measurer = measurer;
5387
6660
  this.note = note;
6661
+ const separatorCache = /* @__PURE__ */ new Map();
5388
6662
  this.cursor = new PageCursor(
5389
6663
  pages,
5390
6664
  section.page,
5391
6665
  section.columns ?? { count: 1, gapPx: 0 },
5392
6666
  sectionIndex,
5393
6667
  continueAt,
5394
- balance
6668
+ balance,
6669
+ note,
6670
+ (page, continued) => {
6671
+ const paragraphs = section.footnoteSeparators?.[continued && !section.modernFootnoteSeparator ? "continuationSeparator" : "separator"];
6672
+ if (!paragraphs) return void 0;
6673
+ const width = page.widthPx - page.marginLeftPx - page.marginRightPx;
6674
+ const key = `${width}:${continued}`;
6675
+ const cached = separatorCache.get(key);
6676
+ if (cached) return cached;
6677
+ const adapted = paragraphs.map((paragraph) => {
6678
+ const probe = section.legacyFootnoteColumns ? layoutParagraph(
6679
+ {
6680
+ ...paragraph,
6681
+ runs: paragraph.runs.map(
6682
+ (run) => run.object?.noteSeparator ? { ...run, object: { ...run.object, widthPx: 0 } } : run
6683
+ )
6684
+ },
6685
+ width,
6686
+ measurer,
6687
+ note
6688
+ ) : void 0;
6689
+ return {
6690
+ ...paragraph,
6691
+ runs: paragraph.runs.map(
6692
+ (run, index) => run.object?.noteSeparator ? {
6693
+ ...run,
6694
+ object: {
6695
+ ...run.object,
6696
+ widthPx: section.legacyFootnoteColumns ? Math.min(
6697
+ run.object.noteSeparator === "continuationSeparator" ? width : 192,
6698
+ Math.max(
6699
+ 0,
6700
+ width - (probe?.lines.flatMap((line2) => line2.fragments).find(
6701
+ (fragment) => fragment.runIndex === index && fragment.object?.noteSeparator
6702
+ )?.xPx ?? 0)
6703
+ )
6704
+ ) : run.object.noteSeparator === "continuationSeparator" ? width : Math.min(192, width)
6705
+ }
6706
+ } : run
6707
+ )
6708
+ };
6709
+ });
6710
+ const stacked = stackParagraphs(adapted, width, measurer, note);
6711
+ const result = { heightPx: stacked.heightPx, paragraphs: stacked.boxes };
6712
+ separatorCache.set(key, result);
6713
+ return result;
6714
+ },
6715
+ noteColumns,
6716
+ reflow,
6717
+ section.legacyFootnoteColumns
6718
+ );
6719
+ this.referenceFootnotes = createReferenceFootnotes(
6720
+ () => this.cursor.footnoteWidthPx,
6721
+ measurer,
6722
+ note
5395
6723
  );
5396
6724
  }
6725
+ section;
5397
6726
  exclusions;
5398
6727
  balance;
5399
6728
  cursor;
@@ -5403,6 +6732,7 @@ var SectionFlow = class {
5403
6732
  measurer;
5404
6733
  note;
5405
6734
  paragraphCache = /* @__PURE__ */ new Map();
6735
+ referenceFootnotes;
5406
6736
  firstRowHeightCache = /* @__PURE__ */ new Map();
5407
6737
  paragraphLayout(index) {
5408
6738
  const key = `${index}:${this.cursor.columnWidthPx}`;
@@ -5477,7 +6807,17 @@ var SectionFlow = class {
5477
6807
  for (let index = 0; index < this.blocks.length; index++) {
5478
6808
  const block = expectDefined(this.blocks[index], "flow block index");
5479
6809
  if (block.kind === "table") {
5480
- placeTable(this.cursor, block, this.measurer, this.note);
6810
+ placeTable(
6811
+ this.cursor,
6812
+ block,
6813
+ this.measurer,
6814
+ this.note,
6815
+ block.rows.some(
6816
+ (row) => row.cells.some(
6817
+ (cell) => cellParagraphs(cell).some((paragraph) => paragraph.footnotes?.length)
6818
+ )
6819
+ ) ? this.referenceFootnotes : void 0
6820
+ );
5481
6821
  if (this.balance?.pageIndex === this.cursor.page.index && !this.cursor.columnContentFits)
5482
6822
  this.balanceValid = false;
5483
6823
  continue;
@@ -5485,19 +6825,7 @@ var SectionFlow = class {
5485
6825
  if (block.afterTableSectionBreak) this.cursor.endBalance();
5486
6826
  const spacingBeforePx = this.spacingBeforeFor(index);
5487
6827
  const layout = this.wrappedLayout(index, spacingBeforePx) ?? this.paragraphLayout(index);
5488
- if (block.footnotes?.length)
5489
- this.cursor.holdFootnotes(
5490
- block.id,
5491
- block.footnotes.map((note) => {
5492
- const stacked = stackParagraphs(
5493
- note.paragraphs,
5494
- this.cursor.columnWidthPx,
5495
- this.measurer,
5496
- this.note
5497
- );
5498
- return { id: note.id, yPx: 0, heightPx: stacked.heightPx, paragraphs: stacked.boxes };
5499
- })
5500
- );
6828
+ const footnotes = (lines, includeUnanchored) => this.referenceFootnotes(block, lines, includeUnanchored);
5501
6829
  const requiredTogetherPx = block.keepNext ? this.requiredKeepHeight(index) : block.keepLines ? spacingBeforePx + layout.contentHeightPx + layout.spacingAfterPx : 0;
5502
6830
  if (requiredTogetherPx > this.cursor.columnHeightPx && requiredTogetherPx <= this.cursor.physicalColumnHeightPx)
5503
6831
  this.balanceValid = false;
@@ -5506,7 +6834,9 @@ var SectionFlow = class {
5506
6834
  {
5507
6835
  paragraph: block,
5508
6836
  layout,
6837
+ footnotes,
5509
6838
  spacingBeforePx,
6839
+ ...this.section.modernFootnoteSeparator || this.section.legacyFootnoteColumns ? { trimLeadingColumnBreak: true } : {},
5510
6840
  requiredTogetherPx,
5511
6841
  reflow: (token) => layoutParagraph(
5512
6842
  block,
@@ -5522,6 +6852,7 @@ var SectionFlow = class {
5522
6852
  if (this.balance?.pageIndex === this.cursor.page.index && this.cursor.usedColumnHeightPx > this.cursor.columnHeightPx)
5523
6853
  this.balanceValid = false;
5524
6854
  }
6855
+ this.cursor.finishFootnotes();
5525
6856
  }
5526
6857
  };
5527
6858
 
@@ -5564,8 +6895,16 @@ function insertParityBlank(pages, section) {
5564
6895
  const nextNumber = pages.length + 1;
5565
6896
  const wanted = section.break === "evenPage" ? 0 : 1;
5566
6897
  if (nextNumber % 2 === wanted) return;
6898
+ const {
6899
+ footnotes: _footnotes,
6900
+ footnoteSeparator: _separator,
6901
+ footnoteHeightPx: _noteHeight,
6902
+ footnoteColumnAreas: _noteColumnAreas,
6903
+ floats: _floats,
6904
+ ...geometry
6905
+ } = previous;
5567
6906
  pages.push({
5568
- ...previous,
6907
+ ...geometry,
5569
6908
  index: pages.length,
5570
6909
  pageInSection: previous.pageInSection + 1,
5571
6910
  columns: previous.columns.map((column) => ({ ...column, blocks: [] }))
@@ -5579,7 +6918,12 @@ function alignVertically(pages, section, note) {
5579
6918
  return;
5580
6919
  }
5581
6920
  for (const page of pages) {
5582
- const available = page.heightPx - page.marginTopPx - page.marginBottomPx;
6921
+ const footnoteHeight = page.footnoteColumnAreas?.length ? Math.max(
6922
+ ...page.footnoteColumnAreas.map(
6923
+ (area) => area.heightPx + (area.separator?.heightPx ?? FOOTNOTE_SEPARATOR_PX)
6924
+ )
6925
+ ) : page.footnotes?.length ? (page.footnoteSeparator?.heightPx ?? FOOTNOTE_SEPARATOR_PX) + (page.footnoteHeightPx ?? page.footnotes.reduce((sum, footnote) => sum + footnote.heightPx, 0)) : 0;
6926
+ const available = page.heightPx - page.marginTopPx - page.marginBottomPx - footnoteHeight;
5583
6927
  const used = Math.max(
5584
6928
  0,
5585
6929
  ...page.columns.flatMap((column) => column.blocks.map((block) => block.yPx + block.heightPx))
@@ -5694,13 +7038,13 @@ function cssHex(value) {
5694
7038
  const hex = value?.replace(/^#/, "");
5695
7039
  return hex && /^[0-9a-f]{6}$/i.test(hex) ? `#${hex}` : void 0;
5696
7040
  }
5697
- function border(side, theme) {
7041
+ function border(side, theme, preserveSingleWidth = false) {
5698
7042
  if (!side?.style || side.style === "none" || side.style === "nil") return void 0;
5699
7043
  const style = side.style.startsWith("double") ? "double" : /dot/i.test(side.style) ? "dotted" : /dash/i.test(side.style) ? "dashed" : "solid";
5700
7044
  const themed = side.themeColor && theme ? resolveThemeColorReference({ token: side.themeColor }, theme) : void 0;
5701
7045
  const hex = cssHex(side.color);
5702
7046
  const widthPx = Math.max(
5703
- style === "double" ? 3 : 1,
7047
+ style === "double" ? 3 : preserveSingleWidth && style === "solid" ? 0 : 1,
5704
7048
  (side.sizeEighthPoints ?? 4) / 8 * 96 / 72
5705
7049
  );
5706
7050
  return { widthPx, style, color: themed ?? hex ?? "#000000" };
@@ -5713,7 +7057,7 @@ function rowLayout(props) {
5713
7057
  ...props.header ? { isHeader: true } : {}
5714
7058
  };
5715
7059
  }
5716
- function adaptTable(table, model, adaptParagraph) {
7060
+ function adaptTable(table, model, adaptParagraph, _nested = false) {
5717
7061
  const grid = table.grid?.map(twipsToPx2);
5718
7062
  const columnCount = grid?.length ?? Math.max(1, ...table.rows.map((row) => row.length));
5719
7063
  const gridWidth = (start, span) => grid ? grid.slice(start, start + span).reduce((sum, width) => sum + width, 0) : void 0;
@@ -5755,7 +7099,7 @@ function adaptTable(table, model, adaptParagraph) {
5755
7099
  );
5756
7100
  const borders = {};
5757
7101
  for (const side of ["top", "right", "bottom", "left"]) {
5758
- const resolved = border(visuals.borders?.[side], model.theme);
7102
+ const resolved = border(visuals.borders?.[side], model.theme, true);
5759
7103
  if (resolved) borders[side] = resolved;
5760
7104
  }
5761
7105
  if (cell.verticalMerge === "continue") delete borders.top;
@@ -5772,6 +7116,11 @@ function adaptTable(table, model, adaptParagraph) {
5772
7116
  const fill = cssHex(visuals.shadingFill);
5773
7117
  return {
5774
7118
  paragraphs: cell.paragraphs.map(adaptParagraph),
7119
+ ...cell.sourceBlocks ? {
7120
+ blocks: cellSourceBlocks(cell).map(
7121
+ (block) => block.type === "paragraph" ? adaptParagraph(block) : adaptTable(block, model, adaptParagraph, true)
7122
+ )
7123
+ } : {},
5775
7124
  ...width !== void 0 ? { widthPx: width } : {},
5776
7125
  ...grid && xPx !== void 0 ? { xPx } : {},
5777
7126
  padding,
@@ -5951,7 +7300,13 @@ function adaptDocumentModel(model, note = () => {
5951
7300
  const script = formatting.verticalAlign === "superscript" || noteText !== void 0 && formatting.verticalAlign === void 0 ? "super" : formatting.verticalAlign === "subscript" ? "sub" : void 0;
5952
7301
  const image = run.image;
5953
7302
  if (image?.unsupported === "Text box") reportOnce(TEXT_BOX_NOTE);
5954
- const object = image && !image.anchored ? {
7303
+ const object = run.noteSeparator ? {
7304
+ partName: "",
7305
+ contentType: "",
7306
+ widthPx: 192,
7307
+ heightPx: 1,
7308
+ noteSeparator: run.noteSeparator
7309
+ } : image && !image.anchored ? {
5955
7310
  partName: image.partName,
5956
7311
  contentType: image.contentType,
5957
7312
  widthPx: image.widthPx,
@@ -5959,8 +7314,10 @@ function adaptDocumentModel(model, note = () => {
5959
7314
  ...image.chart ? { chart: docxChartPaint(image.chart, image.widthPx, image.heightPx, theme) } : {}
5960
7315
  } : void 0;
5961
7316
  return {
7317
+ sourceLength: reviewSourceLength(run),
5962
7318
  // Hidden text (`w:vanish`) takes no space when printed, as in Word by default.
5963
7319
  text: image || formatting.vanish ? "" : formatting.caps ? text2.toUpperCase() : text2,
7320
+ ...run.noteReference?.kind === "footnote" ? { footnoteReferenceId: run.noteReference.id } : {},
5964
7321
  ...object ? { object } : {},
5965
7322
  ...definedProps({
5966
7323
  bold: formatting.bold,
@@ -6059,6 +7416,10 @@ function adaptDocumentModel(model, note = () => {
6059
7416
  if (block.type === "paragraph") return adaptParagraph(block);
6060
7417
  reportOnce(TABLE_ROW_NOTE);
6061
7418
  reportOnce(VERTICAL_MERGE_NOTE);
7419
+ if (block.rows.some((row) => row.some((cell) => cell.nestedTables?.length)))
7420
+ reportOnce(
7421
+ "Nested tables are projected as read-only cell paragraphs in Print Layout; vertical merge and repeated header geometry are not rendered."
7422
+ );
6062
7423
  return adaptTable(block, model, adaptParagraph);
6063
7424
  }
6064
7425
  const blocks = [
@@ -6068,7 +7429,25 @@ function adaptDocumentModel(model, note = () => {
6068
7429
  groupParagraphBorders(blocks, betweenBorders);
6069
7430
  const folded = foldDropCaps(model.blocks, blocks);
6070
7431
  if (folded.size) reportOnce(DROP_CAP_NOTE);
7432
+ if (Object.values(model.footnoteSeparators ?? {}).some(
7433
+ (note2) => note2.blocks.some((block) => block.type === "table")
7434
+ ))
7435
+ reportOnce(
7436
+ "Tables in custom footnote separators are preserved but are not rendered in Print Layout."
7437
+ );
7438
+ const footnoteSeparators = model.footnoteSeparators ? Object.fromEntries(
7439
+ Object.entries(model.footnoteSeparators).map(([kind, note2]) => [
7440
+ kind,
7441
+ note2.blocks.filter((block) => block.type === "paragraph").map((paragraph) => adaptParagraph(paragraph))
7442
+ ])
7443
+ ) : void 0;
6071
7444
  const sections = model.sections;
7445
+ const modernFootnoteSeparator = model.compatibilityMode === 15;
7446
+ const legacyFootnoteColumns = model.compatibilityMode === 12 || model.compatibilityMode === 14;
7447
+ if (!modernFootnoteSeparator && !legacyFootnoteColumns && model.sections?.some((section) => section.footnoteColumns !== void 0))
7448
+ reportOnce(
7449
+ "Footnote column settings are preserved, but this compatibility mode has not been verified against native Word; Print Layout uses the existing page-wide fallback."
7450
+ );
6072
7451
  if (!sections || !sections.length) {
6073
7452
  return {
6074
7453
  sections: [
@@ -6081,6 +7460,9 @@ function adaptDocumentModel(model, note = () => {
6081
7460
  marginBottomPx: model.page.marginBottom,
6082
7461
  marginLeftPx: model.page.marginLeft
6083
7462
  },
7463
+ ...footnoteSeparators ? { footnoteSeparators } : {},
7464
+ ...modernFootnoteSeparator ? { modernFootnoteSeparator: true } : {},
7465
+ ...legacyFootnoteColumns ? { legacyFootnoteColumns: true } : {},
6084
7466
  blocks: blocks.filter((block) => !folded.has(block))
6085
7467
  }
6086
7468
  ]
@@ -6094,8 +7476,34 @@ function adaptDocumentModel(model, note = () => {
6094
7476
  const end = Math.max(start, endIndex);
6095
7477
  const slice = blocks.slice(start, end);
6096
7478
  start = end;
7479
+ if (legacyFootnoteColumns && section.footnoteColumns)
7480
+ reportOnce(
7481
+ "Independent footnote column counts are preserved but ignored in measured compatibility modes 12 and 14; Print Layout attaches notes to body columns."
7482
+ );
7483
+ const footnoteWidth = twipsToPx3(section.pageWidthTwips) - twipsToPx3(section.marginLeftTwips) - twipsToPx3(section.marginRightTwips);
7484
+ if (modernFootnoteSeparator && section.footnoteColumns && (section.footnoteColumns > 45 || footnoteWidth <= 48 * (section.footnoteColumns - 1)))
7485
+ reportOnce(
7486
+ "Footnote columns exceeding the available page width or 45 rendered columns use one column in Print Layout; the saved count is preserved."
7487
+ );
6097
7488
  const sectionStart = index === 0 ? void 0 : sectionBreak(section.type, reportOnce);
6098
7489
  return {
7490
+ ...footnoteSeparators ? { footnoteSeparators } : {},
7491
+ ...modernFootnoteSeparator ? { modernFootnoteSeparator: true } : {},
7492
+ ...legacyFootnoteColumns ? { legacyFootnoteColumns: true } : {},
7493
+ ...section.footnoteColumns !== void 0 && modernFootnoteSeparator ? {
7494
+ footnoteColumns: {
7495
+ count: section.footnoteColumns && (section.footnoteColumns > 45 || footnoteWidth <= 48 * (section.footnoteColumns - 1)) ? 1 : Math.max(1, section.footnoteColumns || section.columns.count),
7496
+ gapPx: section.footnoteColumns ? 48 : twipsToPx3(section.columns.spacingTwips ?? twips(720)),
7497
+ ...!section.footnoteColumns && !section.columns.equalWidth && section.columns.widths?.length ? {
7498
+ widths: section.columns.widths.map((column) => ({
7499
+ widthPx: twipsToPx3(column.widthTwips),
7500
+ gapPx: twipsToPx3(
7501
+ column.spacingTwips ?? section.columns.spacingTwips ?? twips(720)
7502
+ )
7503
+ }))
7504
+ } : {}
7505
+ }
7506
+ } : {},
6099
7507
  page: {
6100
7508
  widthPx: twipsToPx3(section.pageWidthTwips),
6101
7509
  heightPx: twipsToPx3(section.pageHeightTwips),
@@ -6277,4 +7685,4 @@ function cssFontStack(family) {
6277
7685
  );
6278
7686
  }
6279
7687
 
6280
- export { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE_PT, DEFAULT_TAB_STOP_PX, FLOAT_WRAP_NOTE, NO_TWIPS, PageCursor, SINGLE_LINE_SPACING_UNITS, adaptDocumentModel, adjustForWidowOrphan, appendBreakMarker, createFakeMeasurer, cssFontStack, fieldDisplayText, floatPosition, fontMetrics, headerFooterForPage, isEastAsianChar, layoutDocument, layoutDocumentModel, layoutParagraph, layoutRow, layoutSections, ligatureCss, pageNumberValues, pageNumbers, paragraphFloats, placeParagraph, placeTab, placeTable, positionFloats, ptToPx, pxToTwips, sectionPageCounts, splitRowAtHeight, suppressesSpacing, tokenizeRun, twipsToPx, widowControlEnabled };
7688
+ export { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE_PT, DEFAULT_TAB_STOP_PX, FLOAT_WRAP_NOTE, NO_TWIPS, PageCursor, SINGLE_LINE_SPACING_UNITS, adaptDocumentModel, adjustForWidowOrphan, appendBreakMarker, cellVerticalOffset, createFakeMeasurer, cssFontStack, fieldDisplayText, floatPosition, fontMetrics, headerFooterForPage, isEastAsianChar, layoutDocument, layoutDocumentModel, layoutParagraph, layoutRow, layoutSections, ligatureCss, pageNumberValues, pageNumbers, paragraphFloats, placeParagraph, placeTab, placeTable, positionFloats, ptToPx, pxToTwips, sectionPageCounts, splitRowAtHeight, suppressesSpacing, tokenizeRun, twipsToPx, widowControlEnabled };