@beyondwork/docx-react-component 1.0.67 → 1.0.70

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 (384) hide show
  1. package/README.md +75 -932
  2. package/package.json +26 -27
  3. package/src/api/anchor-conversion.ts +43 -0
  4. package/src/api/editor-state-types.ts +2 -1
  5. package/src/api/public-types.ts +504 -101
  6. package/src/api/session-state.ts +4 -0
  7. package/src/api/v3/README.md +91 -0
  8. package/src/api/v3/_create.ts +146 -0
  9. package/src/api/v3/_layer-metadata.ts +362 -0
  10. package/src/api/v3/_mocks.ts +84 -0
  11. package/src/api/v3/_runtime-handle.ts +162 -0
  12. package/src/api/v3/_ux-response.ts +73 -0
  13. package/src/api/v3/ai/_metadata-audit.ts +225 -0
  14. package/src/api/v3/ai/attach.ts +235 -0
  15. package/src/api/v3/ai/bundle.ts +132 -0
  16. package/src/api/v3/ai/explain.ts +144 -0
  17. package/src/api/v3/ai/export.ts +54 -0
  18. package/src/api/v3/ai/inspect.ts +118 -0
  19. package/src/api/v3/ai/policy.ts +77 -0
  20. package/src/api/v3/ai/replacement.ts +341 -0
  21. package/src/api/v3/ai/resolve.ts +133 -0
  22. package/src/api/v3/index.ts +79 -0
  23. package/src/api/v3/runtime/chart.ts +310 -0
  24. package/src/api/v3/runtime/clipboard.ts +81 -0
  25. package/src/api/v3/runtime/collab.ts +331 -0
  26. package/src/api/v3/runtime/content.ts +236 -0
  27. package/src/api/v3/runtime/document.ts +282 -0
  28. package/src/api/v3/runtime/formatting.ts +186 -0
  29. package/src/api/v3/runtime/geometry.ts +349 -0
  30. package/src/api/v3/runtime/layout.ts +108 -0
  31. package/src/api/v3/runtime/review.ts +129 -0
  32. package/src/api/v3/runtime/search.ts +74 -0
  33. package/src/api/v3/runtime/table.ts +63 -0
  34. package/src/api/v3/runtime/workflow.ts +434 -0
  35. package/src/api/v3/ui/_context.ts +86 -0
  36. package/src/api/v3/ui/_create.ts +65 -0
  37. package/src/api/v3/ui/_types.ts +520 -0
  38. package/src/api/v3/ui/chrome-composition.ts +342 -0
  39. package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
  40. package/src/api/v3/ui/chrome.ts +476 -0
  41. package/src/api/v3/ui/debug.ts +124 -0
  42. package/src/api/v3/ui/index.ts +64 -0
  43. package/src/api/v3/ui/overlays-visibility.ts +170 -0
  44. package/src/api/v3/ui/overlays.ts +427 -0
  45. package/src/api/v3/ui/scope.ts +71 -0
  46. package/src/api/v3/ui/session.ts +100 -0
  47. package/src/api/v3/ui/surface.ts +170 -0
  48. package/src/api/v3/ui/viewport.ts +303 -0
  49. package/src/core/commands/index.ts +28 -6
  50. package/src/core/commands/list-commands.ts +3 -2
  51. package/src/core/commands/section-layout-commands.ts +9 -8
  52. package/src/core/schema/text-schema.ts +16 -0
  53. package/src/core/selection/mapping.ts +33 -72
  54. package/src/core/state/editor-state.ts +96 -189
  55. package/src/index.ts +23 -4
  56. package/src/io/chart-preview-resolver.ts +1 -1
  57. package/src/io/docx-session.ts +36 -4797
  58. package/src/io/export/build-app-properties-xml.ts +1 -1
  59. package/src/io/export/serialize-comments.ts +1 -1
  60. package/src/io/export/serialize-headers-footers.ts +6 -1
  61. package/src/io/export/serialize-main-document.ts +45 -0
  62. package/src/io/export/serialize-run-formatting.ts +17 -2
  63. package/src/io/export/twip.ts +1 -1
  64. package/src/io/normalize/normalize-text.ts +27 -20
  65. package/src/io/ooxml/chart/parse-series.ts +1 -1
  66. package/src/io/ooxml/chart/resolve-color.ts +2 -2
  67. package/src/io/ooxml/chart/types.ts +1 -1
  68. package/src/io/ooxml/classify-embedding.ts +83 -33
  69. package/src/io/ooxml/parse-fill.ts +1 -1
  70. package/src/io/ooxml/parse-main-document.ts +71 -1
  71. package/src/io/ooxml/parse-object.ts +14 -10
  72. package/src/io/ooxml/parse-run-formatting.ts +47 -1
  73. package/src/io/ooxml/property-grab-bag.ts +2 -2
  74. package/src/io/ooxml/units.ts +11 -0
  75. package/src/io/ooxml/workflow-payload.ts +282 -7
  76. package/src/model/anchor.ts +85 -0
  77. package/src/model/canonical-document.ts +351 -15
  78. package/src/model/chart-types.ts +1 -1
  79. package/src/model/layout/index.ts +83 -0
  80. package/src/model/layout/page-graph-types.ts +181 -0
  81. package/src/model/layout/page-layout-snapshot.ts +105 -0
  82. package/src/model/layout/resolved-layout-types.ts +47 -0
  83. package/src/model/layout/runtime-page-graph-types.ts +102 -0
  84. package/src/model/paragraph-scope-ids.ts +72 -0
  85. package/src/model/review/comment-types.ts +112 -0
  86. package/src/model/review/index.ts +2 -0
  87. package/src/model/review/revision-types.ts +215 -0
  88. package/src/model/snapshot.ts +32 -0
  89. package/src/review/store/comment-store.ts +21 -47
  90. package/src/review/store/revision-types.ts +40 -198
  91. package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
  92. package/src/runtime/collab/runtime-collab-sync.ts +13 -3
  93. package/src/runtime/collab-session.ts +1 -1
  94. package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
  95. package/src/runtime/debug/event-ring-buffer.ts +64 -0
  96. package/src/runtime/debug/probability-sampler.ts +18 -0
  97. package/src/runtime/debug/runtime-debug-facet.ts +67 -0
  98. package/src/runtime/debug/stage-tokens.ts +31 -0
  99. package/src/runtime/debug/telemetry-bus.ts +271 -0
  100. package/src/runtime/debug/types.ts +275 -0
  101. package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
  102. package/src/runtime/document-layout.ts +8 -6
  103. package/src/runtime/document-runtime.ts +843 -1141
  104. package/src/runtime/document-search.ts +1 -1
  105. package/src/runtime/edit-ops/index.ts +1 -1
  106. package/src/runtime/external-send-runtime.ts +1 -1
  107. package/src/runtime/formatting/document-lookup.ts +235 -0
  108. package/src/runtime/formatting/field/registry.ts +41 -0
  109. package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
  110. package/src/runtime/formatting/font-resolution.ts +83 -0
  111. package/src/runtime/formatting/formatting-context.ts +903 -0
  112. package/src/runtime/formatting/formatting-types.ts +157 -0
  113. package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
  114. package/src/runtime/formatting/index.ts +125 -0
  115. package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
  116. package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
  117. package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
  118. package/src/runtime/formatting/projector.ts +75 -0
  119. package/src/runtime/formatting/resolve-effective.ts +407 -0
  120. package/src/runtime/formatting/revision-display.ts +105 -0
  121. package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
  122. package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
  123. package/src/runtime/formatting/telemetry-bridge.ts +106 -0
  124. package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
  125. package/src/runtime/geometry/caret-geometry.ts +164 -0
  126. package/src/runtime/geometry/geometry-facet.ts +364 -0
  127. package/src/runtime/geometry/geometry-types.ts +256 -0
  128. package/src/runtime/geometry/hit-test.ts +125 -0
  129. package/src/runtime/geometry/index.ts +71 -0
  130. package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
  131. package/src/runtime/geometry/invalidation.ts +35 -0
  132. package/src/runtime/geometry/object-handles.ts +77 -0
  133. package/src/runtime/geometry/overlay-rects.ts +85 -0
  134. package/src/runtime/geometry/project-anchors.ts +100 -0
  135. package/src/runtime/geometry/project-fragments.ts +216 -0
  136. package/src/runtime/geometry/projector.ts +129 -0
  137. package/src/runtime/geometry/replacement-envelope.ts +130 -0
  138. package/src/runtime/geometry/viewport.ts +218 -0
  139. package/src/runtime/layout/compat-input-ledger.ts +211 -0
  140. package/src/runtime/layout/index.ts +6 -1
  141. package/src/runtime/layout/inert-layout-facet.ts +12 -7
  142. package/src/runtime/layout/layout-engine-instance.ts +189 -11
  143. package/src/runtime/layout/layout-engine-version.ts +450 -1
  144. package/src/runtime/layout/layout-facet-types.ts +60 -0
  145. package/src/runtime/layout/layout-measurement-provider.ts +13 -0
  146. package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
  147. package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
  148. package/src/runtime/layout/page-graph.ts +62 -209
  149. package/src/runtime/layout/page-story-resolver.ts +7 -12
  150. package/src/runtime/layout/paginated-layout-engine.ts +186 -11
  151. package/src/runtime/layout/project-block-fragments.ts +11 -0
  152. package/src/runtime/layout/projector.ts +90 -0
  153. package/src/runtime/layout/public-facet.ts +187 -442
  154. package/src/runtime/layout/resolved-formatting-state.ts +158 -26
  155. package/src/runtime/layout/table-render-plan.ts +1 -1
  156. package/src/runtime/prerender/cache-envelope.ts +6 -1
  157. package/src/runtime/prerender/prerender-document.ts +18 -23
  158. package/src/runtime/render/decoration-resolver.ts +1 -1
  159. package/src/runtime/render/render-frame-types.ts +20 -0
  160. package/src/runtime/render/render-kernel.ts +94 -25
  161. package/src/runtime/scopes/_formatting-seam.ts +262 -0
  162. package/src/runtime/scopes/_scope-dependencies.ts +49 -0
  163. package/src/runtime/scopes/action-validation.ts +356 -0
  164. package/src/runtime/scopes/attach-explanation.ts +102 -0
  165. package/src/runtime/scopes/audit-bundle.ts +71 -0
  166. package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
  167. package/src/runtime/scopes/compile-scope.ts +262 -0
  168. package/src/runtime/scopes/compiler-service.ts +431 -0
  169. package/src/runtime/scopes/create-issue.ts +107 -0
  170. package/src/runtime/scopes/enumerate-scopes.ts +543 -0
  171. package/src/runtime/scopes/evidence.ts +233 -0
  172. package/src/runtime/scopes/index.ts +150 -0
  173. package/src/runtime/scopes/position-map.ts +214 -0
  174. package/src/runtime/scopes/preservation-boundary.ts +91 -0
  175. package/src/runtime/scopes/projector.ts +49 -0
  176. package/src/runtime/scopes/replaceability.ts +87 -0
  177. package/src/runtime/scopes/replacement/apply.ts +228 -0
  178. package/src/runtime/scopes/replacement/compile.ts +59 -0
  179. package/src/runtime/scopes/replacement/propose.ts +42 -0
  180. package/src/runtime/scopes/resolve-reference.ts +347 -0
  181. package/src/runtime/scopes/review-bundle.ts +141 -0
  182. package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
  183. package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
  184. package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
  185. package/src/runtime/scopes/scope-kinds/field.ts +65 -0
  186. package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
  187. package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
  188. package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
  189. package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
  190. package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
  191. package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
  192. package/src/runtime/scopes/scope-kinds/table.ts +55 -0
  193. package/src/runtime/scopes/scope-range.ts +208 -0
  194. package/src/runtime/scopes/semantic-scope-types.ts +454 -0
  195. package/src/runtime/scopes/workflow-overlap.ts +92 -0
  196. package/src/runtime/selection/index.ts +1 -1
  197. package/src/runtime/structure-ops/fragment-insert.ts +1 -1
  198. package/src/runtime/structure-ops/index.ts +1 -1
  199. package/src/runtime/surface-projection.ts +232 -262
  200. package/src/runtime/units.ts +4 -2
  201. package/src/runtime/workflow/coordinator.ts +1348 -0
  202. package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
  203. package/src/runtime/workflow/index.ts +25 -0
  204. package/src/runtime/workflow/markup-mode-policy.ts +98 -0
  205. package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
  206. package/src/runtime/workflow/metadata-persistence.ts +306 -0
  207. package/src/runtime/workflow/metadata-writer.ts +123 -0
  208. package/src/runtime/workflow/overlay-store.ts +690 -0
  209. package/src/runtime/workflow/projector.ts +127 -0
  210. package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
  211. package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
  212. package/src/runtime/workflow/rail/types.ts +198 -0
  213. package/src/runtime/workflow/scope-rail-composer.ts +39 -0
  214. package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
  215. package/src/runtime/workflow/scope-writer.ts +188 -0
  216. package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
  217. package/src/runtime/workflow/visibility-policy.ts +129 -0
  218. package/src/session/_sync-legacy.ts +66 -0
  219. package/src/session/export/embedded-reconstitute.ts +104 -0
  220. package/src/session/export/export-diagnostics.ts +85 -0
  221. package/src/session/export/export-validation.ts +110 -0
  222. package/src/session/export/index.ts +34 -0
  223. package/src/session/export/preservation-reattach.ts +30 -0
  224. package/src/session/export/serialize-dispatch.ts +165 -0
  225. package/src/session/export/stateful-export-pipeline.ts +432 -0
  226. package/src/session/export/stateful-export.ts +684 -0
  227. package/src/session/import/canonical-assembly.ts +227 -0
  228. package/src/session/import/diagnostics-session.ts +54 -0
  229. package/src/session/import/embedded-discovery.ts +225 -0
  230. package/src/session/import/embedded-offload.ts +337 -0
  231. package/src/session/import/import-diagnostics.ts +69 -0
  232. package/src/session/import/loader-types.ts +313 -0
  233. package/src/session/import/loader.ts +1834 -0
  234. package/src/session/import/normalize.ts +195 -0
  235. package/src/session/import/package-parts.ts +217 -0
  236. package/src/session/import/package-read.ts +195 -0
  237. package/src/session/import/parse-orchestration.ts +105 -0
  238. package/src/session/import/part-constants.ts +70 -0
  239. package/src/session/import/part-discovery.ts +94 -0
  240. package/src/session/import/preservation-index.ts +46 -0
  241. package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
  242. package/src/session/import/review-import.ts +508 -0
  243. package/src/session/import/styles-consolidation.ts +281 -0
  244. package/src/session/import/workflow-scope-import.ts +256 -0
  245. package/src/session/index.ts +37 -0
  246. package/src/session/session-state.ts +69 -0
  247. package/src/session/session.ts +532 -0
  248. package/src/session/shared/protection.ts +228 -0
  249. package/src/session/shared/session-utils.ts +82 -0
  250. package/src/session/types.ts +499 -0
  251. package/src/shell/chart-snapshots.ts +96 -0
  252. package/src/shell/media-previews.ts +85 -0
  253. package/src/shell/overlay-anchor-bridge.ts +53 -0
  254. package/src/shell/paste-adapter.ts +23 -0
  255. package/src/shell/ref-commands.ts +1697 -0
  256. package/src/shell/ref-utilities.ts +48 -0
  257. package/src/shell/search.ts +51 -0
  258. package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
  259. package/src/shell/ui-subscriber-channels.ts +81 -0
  260. package/src/shell/use-collab-sync.ts +116 -0
  261. package/src/ui/WordReviewEditor.tsx +496 -2051
  262. package/src/ui/editor-shell-view.tsx +30 -1
  263. package/src/ui/editor-surface-controller.tsx +49 -1
  264. package/src/ui/headless/revision-decoration-model.ts +83 -0
  265. package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
  266. package/src/ui/headless/scoped-chrome-policy.ts +2 -2
  267. package/src/ui/headless/selection-tool-context.ts +1 -1
  268. package/src/ui/headless/selection-tool-resolver.ts +1 -1
  269. package/src/ui/runtime-shortcut-dispatch.ts +46 -1
  270. package/src/ui/ui-controller-factory.ts +221 -0
  271. package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
  272. package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
  273. package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
  274. package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
  275. package/src/ui-tailwind/chart/render/area.tsx +3 -3
  276. package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
  277. package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
  278. package/src/ui-tailwind/chart/render/combo.tsx +2 -2
  279. package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
  280. package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
  281. package/src/ui-tailwind/chart/render/line.tsx +3 -3
  282. package/src/ui-tailwind/chart/render/pie.tsx +6 -6
  283. package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
  284. package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
  285. package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
  286. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
  287. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
  288. package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
  289. package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
  290. package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
  291. package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
  292. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
  293. package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
  294. package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
  295. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
  296. package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
  297. package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
  298. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
  299. package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
  300. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
  301. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
  302. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
  303. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
  304. package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
  305. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
  306. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
  307. package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
  308. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
  309. package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
  310. package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
  311. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
  312. package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
  313. package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
  314. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
  315. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
  316. package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
  317. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
  318. package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
  319. package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
  320. package/src/ui-tailwind/debug/README.md +57 -0
  321. package/src/ui-tailwind/debug/index.ts +3 -0
  322. package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
  323. package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
  324. package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
  325. package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
  326. package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
  327. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
  328. package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
  329. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
  330. package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
  331. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
  332. package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
  333. package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
  334. package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
  335. package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
  336. package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
  337. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
  338. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
  339. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
  340. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
  341. package/src/ui-tailwind/index.ts +0 -5
  342. package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
  343. package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
  344. package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
  345. package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
  346. package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
  347. package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
  348. package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
  349. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
  350. package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
  351. package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
  352. package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
  353. package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
  354. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
  355. package/src/ui-tailwind/review-workspace/types.ts +408 -0
  356. package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
  357. package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
  358. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
  359. package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
  360. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
  361. package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
  362. package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
  363. package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
  364. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
  365. package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
  366. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
  367. package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
  368. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
  369. package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
  370. package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
  371. package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
  372. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
  373. package/src/ui-tailwind/theme/editor-theme.css +25 -0
  374. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
  375. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
  376. package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
  377. package/src/ui-tailwind/ui-api-context.tsx +43 -0
  378. package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
  379. package/src/validation/compatibility-engine.ts +6 -6
  380. package/src/runtime/styles-cascade.ts +0 -33
  381. package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
  382. /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
  383. /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
  384. /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Layer 03 — effective-formatting types.
3
+ *
4
+ * Output shapes of `resolveEffectiveFormatting`. Each type represents the
5
+ * post-cascade result for a given node kind — what the caller sees after
6
+ * the four-tier cascade + theme concretization + revision-display posture
7
+ * + (for paragraphs) resolved numbering have all been applied.
8
+ *
9
+ * Architecture reference: `docs/architecture/03-formatting-semantics.md`
10
+ * §"Entry point signature" + §"Contracts" F1–F6.
11
+ */
12
+
13
+ import type {
14
+ CanonicalParagraphFormatting,
15
+ CanonicalRunFormatting,
16
+ } from "../../model/canonical-document.ts";
17
+ import type { ResolvedTableStyleResolution } from "./table-style-resolver.ts";
18
+
19
+ /**
20
+ * Resolved paragraph formatting. Extends the canonical shape with:
21
+ *
22
+ * - `numbering` — resolved numbering marker + geometry when the paragraph
23
+ * has `paragraph.numbering?: { numberingInstanceId, level }`. Populated
24
+ * by the entry's `"paragraph"` branch when a numbering context is
25
+ * available (either `opts.numberingPrefixResolver` or a freshly built
26
+ * one).
27
+ * - `paragraphMarkRun` — the paragraph-mark rPr cascade, concretized
28
+ * with theme colors when a `ThemeColorResolver` is threaded through
29
+ * `opts.themeResolver`. Mirrors the canonical
30
+ * `paragraphMarkRunProperties` field but carries post-cascade values
31
+ * (bold/italic resolved, colorHex populated from theme slots, etc.).
32
+ *
33
+ * Extends rather than aliases `CanonicalParagraphFormatting` so callers
34
+ * can discriminate "post-cascade effective" from "raw canonical" at the
35
+ * type level — contract F1 is violated when render-path code consumes
36
+ * raw canonical values and re-does the cascade inline.
37
+ */
38
+ export interface EffectiveParagraphFormatting extends CanonicalParagraphFormatting {
39
+ readonly numbering?: EffectiveNumbering;
40
+ readonly paragraphMarkRun?: EffectiveRunFormatting;
41
+ }
42
+
43
+ /**
44
+ * Resolved run formatting. Extends the canonical run shape with
45
+ * `revisionDisplay` — populated when `opts.revisionMarkupMode` is set
46
+ * AND the run has an attached revision (insertion/deletion/formatting/
47
+ * property-change/move).
48
+ *
49
+ * `colorHex` is post-concretization: theme slots have already been
50
+ * mapped through `ThemeColorResolver.resolveWordThemeColor` when a
51
+ * theme resolver is available. Raw `colorThemeSlot` / `colorThemeTint`
52
+ * / `colorThemeShade` fields are preserved for round-trip on export.
53
+ */
54
+ export interface EffectiveRunFormatting extends CanonicalRunFormatting {
55
+ readonly revisionDisplay?: RevisionDisplayFlags;
56
+ }
57
+
58
+ export type EffectiveTableFormatting = ResolvedTableStyleResolution;
59
+
60
+ /**
61
+ * Resolved numbering output for a paragraph with numbering context.
62
+ *
63
+ * - `marker` — the formatted marker glyph (e.g. `"1."`, `"a)"`,
64
+ * `"•"`). Produced by `NumberingPrefixResolver.resolve`.
65
+ * - `level` — 0-indexed list depth (matches `<w:ilvl w:val>`).
66
+ * - `markerRunFormatting` — rPr cascade for the marker glyph (ECMA-376
67
+ * §17.9: docDefaults → paragraph-style chain → paragraph-mark rPr →
68
+ * level rPr).
69
+ * - `indentation` — merged indent + tab geometry from level def +
70
+ * paragraph overrides. Consumers (layout, render) read this instead
71
+ * of reading numbering level + paragraph indentation separately.
72
+ * - `pictureBulletRef` — relationship id for picture-bullet glyph
73
+ * when the numbering format is `"bullet"` with a pic mode.
74
+ */
75
+ export interface EffectiveNumbering {
76
+ readonly marker?: string;
77
+ readonly level?: number;
78
+ readonly markerRunFormatting?: CanonicalRunFormatting;
79
+ readonly indentation?: {
80
+ readonly left?: number;
81
+ readonly hanging?: number;
82
+ readonly firstLine?: number;
83
+ readonly tab?: number;
84
+ };
85
+ readonly pictureBulletRef?: string;
86
+ }
87
+
88
+ /**
89
+ * Field-display output. `displayText` is the rendered string (e.g.
90
+ * `"1"` / `"3"` for PAGE, `"Heading 1"` for STYLEREF).
91
+ *
92
+ * - `"resolved"` — text populated, safe to render.
93
+ * - `"unresolved"` — field exists but resolution deferred (e.g. no
94
+ * page graph yet; PAGE/NUMPAGES in prerender).
95
+ * - `"unresolvable"` — permanent failure (e.g. REF to a missing
96
+ * bookmark; STYLEREF to a non-existent style).
97
+ */
98
+ export interface EffectiveFieldDisplay {
99
+ readonly displayText?: string;
100
+ readonly refreshStatus: "resolved" | "unresolved" | "unresolvable";
101
+ }
102
+
103
+ /**
104
+ * Revision-display posture flags applied per run. Owned by layer 03's
105
+ * `applyRevisionDisplay(run, revision, markupMode)`. Architecture
106
+ * reference: contract F6.
107
+ *
108
+ * `markupMode` echoes the input so consumers can branch without
109
+ * re-reading opts. Other flags are posture hints — consumers decide the
110
+ * visual vocabulary (CSS class, inline style, decoration).
111
+ */
112
+ export interface RevisionDisplayFlags {
113
+ readonly markupMode: "clean" | "simple" | "all";
114
+ /** Hide the run entirely (e.g. open deletion in "clean" mode). */
115
+ readonly hidden?: boolean;
116
+ /** Render with strikethrough (deletion in "all" mode). */
117
+ readonly strikethrough?: boolean;
118
+ /** Render with insertion-underline (insertion in "all" mode). */
119
+ readonly insertionUnderline?: boolean;
120
+ /** Render de-emphasized (all revision kinds in "simple" mode). */
121
+ readonly deemphasize?: boolean;
122
+ /** Author color for change-bar / inline marker rendering. */
123
+ readonly authorColor?: string;
124
+ }
125
+
126
+ /**
127
+ * Discriminated union of per-node effective-formatting outputs. The
128
+ * entry dispatches by `nodeRef.kind` and returns the matching variant.
129
+ */
130
+ export type EffectiveFormatting =
131
+ | {
132
+ readonly kind: "paragraph";
133
+ readonly paragraph: EffectiveParagraphFormatting;
134
+ }
135
+ | {
136
+ readonly kind: "run";
137
+ readonly run: EffectiveRunFormatting;
138
+ }
139
+ | {
140
+ readonly kind: "table";
141
+ readonly table: EffectiveTableFormatting;
142
+ }
143
+ | {
144
+ readonly kind: "table-cell";
145
+ readonly paragraph: EffectiveParagraphFormatting;
146
+ readonly run: EffectiveRunFormatting;
147
+ }
148
+ | {
149
+ readonly kind: "field";
150
+ readonly run: EffectiveRunFormatting;
151
+ readonly field: EffectiveFieldDisplay;
152
+ }
153
+ | {
154
+ readonly kind: "drawing-frame";
155
+ /** Resolved run-level formatting at the inline anchor. */
156
+ readonly run: EffectiveRunFormatting;
157
+ };
@@ -33,8 +33,8 @@
33
33
  import type {
34
34
  CanonicalRunFormatting,
35
35
  StylesCatalog,
36
- } from "../model/canonical-document.ts";
37
- import { ThemeColorResolver } from "./theme-color-resolver.ts";
36
+ } from "../../model/canonical-document.ts";
37
+ import { ThemeColorResolver } from "./theme-color.ts";
38
38
  import {
39
39
  resolveEffectiveRunFormatting,
40
40
  type RunResolveInput,
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Layer 03 — Formatting Semantics.
3
+ *
4
+ * Canonical entry point is `resolveEffectiveFormatting`. Sub-resolvers
5
+ * (paragraph, table, theme-color, hyperlink-color, font-family) are
6
+ * re-exported here so consumers can migrate off the legacy
7
+ * `src/runtime/*-resolver.ts` paths; the legacy files remain as
8
+ * `@deprecated` shims until Slice 4.
9
+ */
10
+
11
+ export {
12
+ resolveEffectiveFormatting,
13
+ type NodeRef,
14
+ type ResolveEffectiveFormattingOptions,
15
+ } from "./resolve-effective.ts";
16
+
17
+ // Production orchestrator — the real hot-path boundary. `resolveEffectiveFormatting`
18
+ // above is a thin façade over this context for external/test callers that prefer
19
+ // a `doc + nodeRef` API. Every in-repo production consumer goes through the
20
+ // context directly for amortized per-document resolver construction.
21
+ export {
22
+ createFormattingContext,
23
+ type FormattingContext,
24
+ type FormattingContextOptions,
25
+ type ProjectedRunMarks,
26
+ type ProjectedSurfaceMark,
27
+ type NumberingResolution,
28
+ type RunResolvedProperty,
29
+ type RunProvenance,
30
+ } from "./formatting-context.ts";
31
+
32
+ export type {
33
+ EffectiveFormatting,
34
+ EffectiveParagraphFormatting,
35
+ EffectiveRunFormatting,
36
+ EffectiveTableFormatting,
37
+ EffectiveNumbering,
38
+ EffectiveFieldDisplay,
39
+ RevisionDisplayFlags,
40
+ } from "./formatting-types.ts";
41
+
42
+ // ── Sub-resolvers ─────────────────────────────────────────────────────────
43
+ export {
44
+ resolveParagraphStyleChain,
45
+ resolveCharacterStyleChain,
46
+ resolveEffectiveParagraphFormatting,
47
+ resolveEffectiveRunFormatting,
48
+ resolveNumberingMarkerRunFormatting,
49
+ resolveTableCellTextFormatting,
50
+ getNextStyleId,
51
+ type ParagraphResolveInput,
52
+ type RunResolveInput,
53
+ type MarkerResolveInput,
54
+ } from "./paragraph-style-resolver.ts";
55
+
56
+ export {
57
+ resolveTableStyleResolution,
58
+ type ResolvedTableCellStyle,
59
+ type ResolvedTableRowStyle,
60
+ type ResolvedTableLevelProperties,
61
+ type ResolvedTableStyleResolution,
62
+ } from "./table-style-resolver.ts";
63
+
64
+ export { resolveRunFontFamily } from "./font-resolution.ts";
65
+
66
+ export {
67
+ applyThemeTintShade,
68
+ ThemeColorResolver,
69
+ concretizeThemeColors,
70
+ type DrawingMlColorMod,
71
+ } from "./theme-color.ts";
72
+
73
+ export { resolveHyperlinkRunFormatting } from "./hyperlink-color.ts";
74
+
75
+ export { mergeRun, mergeParagraph } from "./style-cascade.ts";
76
+
77
+ // ── Numbering (Slice 3) ───────────────────────────────────────────────────
78
+ export {
79
+ createNumberingPrefixResolver,
80
+ formatCounter,
81
+ isSupportedNumberingFormat,
82
+ type NumberingPrefixResolver,
83
+ type NumberingPrefixResult,
84
+ } from "./numbering/prefix.ts";
85
+
86
+ export {
87
+ resolveNumberingDefinitionSet,
88
+ DEFAULT_NUMBERING_START_AT,
89
+ type ResolvedNumberingGeometry,
90
+ type ResolvedNumberingDefinitionSet,
91
+ } from "./numbering/geometry.ts";
92
+
93
+ // ── Fields (Slice 3) ──────────────────────────────────────────────────────
94
+ export {
95
+ createFieldResolver,
96
+ type FieldResolver,
97
+ type FieldResolverInput,
98
+ type ResolvedField,
99
+ type DocumentContainerNode,
100
+ } from "./field/resolver.ts";
101
+
102
+ export { formatPageNumber } from "./field/page-number-format.ts";
103
+
104
+ export { rebuildFieldRegistry } from "./field/registry.ts";
105
+
106
+ // ── Debug projector (Slice 3) ─────────────────────────────────────────────
107
+ export {
108
+ buildFormattingDebugEntry,
109
+ type FormattingDebugEntry,
110
+ } from "./projector.ts";
111
+
112
+ // ── Revision display (Slice 4) ────────────────────────────────────────────
113
+ export {
114
+ applyRevisionDisplay,
115
+ type RevisionMarkupMode,
116
+ } from "./revision-display.ts";
117
+
118
+ // ── Telemetry bridge (Phase C3) ───────────────────────────────────────────
119
+ export {
120
+ buildFormattingTelemetryBridge,
121
+ emitRevisionDisplayModeChanged,
122
+ type FormattingTelemetryBridgeOptions,
123
+ } from "./telemetry-bridge.ts";
124
+
125
+ export type { FormattingTelemetryEvent } from "./resolve-effective.ts";
@@ -8,7 +8,7 @@ import type {
8
8
  ParagraphNode,
9
9
  ParagraphSpacing,
10
10
  TabStop,
11
- } from "../model/canonical-document.ts";
11
+ } from "../../../model/canonical-document.ts";
12
12
 
13
13
  export const DEFAULT_NUMBERING_START_AT = 1;
14
14
 
@@ -3,12 +3,12 @@ import type {
3
3
  NumberingCatalog,
4
4
  NumberingLevelDefinition,
5
5
  ParagraphNode,
6
- } from "../model/canonical-document.ts";
6
+ } from "../../../model/canonical-document.ts";
7
7
  import {
8
8
  DEFAULT_NUMBERING_START_AT,
9
9
  resolveNumberingDefinitionSet,
10
10
  type ResolvedNumberingGeometry,
11
- } from "./resolved-numbering-geometry.ts";
11
+ } from "./geometry.ts";
12
12
 
13
13
  interface NumberingSequenceState {
14
14
  counters: Array<number | undefined>;
@@ -221,7 +221,43 @@ function renderLevelText(
221
221
  return rendered.trim().length > 0 ? rendered : null;
222
222
  }
223
223
 
224
- function formatCounter(value: number, format: string): string {
224
+ /**
225
+ * Formats the runtime has dedicated implementations for. Anything outside
226
+ * this set falls through to `decimal` — documented dishonestly-silent
227
+ * behavior pending ECMA-376 §17.9.7 full coverage. L03 audit
228
+ * (2026-04-22) tracks this as Task-5. When a format NOT in this set
229
+ * is requested, we still return `String(value)` so user-visible
230
+ * rendering doesn't collapse, but consumers should treat unknown
231
+ * formats as a fidelity gap.
232
+ */
233
+ const SUPPORTED_NUMBERING_FORMATS = new Set<string>([
234
+ "decimal",
235
+ "decimalZero",
236
+ "upperLetter",
237
+ "lowerLetter",
238
+ "upperRoman",
239
+ "lowerRoman",
240
+ "hex",
241
+ "ordinal",
242
+ "cardinalText",
243
+ "ordinalText",
244
+ "chicago",
245
+ "bullet",
246
+ "none",
247
+ ]);
248
+
249
+ export function isSupportedNumberingFormat(format: string): boolean {
250
+ return SUPPORTED_NUMBERING_FORMATS.has(format);
251
+ }
252
+
253
+ /**
254
+ * Internal helper exported for targeted testing. Consumers should drive
255
+ * the full `createNumberingPrefixResolver(catalog).resolveParagraph(...)`
256
+ * path in production code — this raw entry exists so parity tests can
257
+ * assert format-by-format behavior without constructing a full
258
+ * `NumberingCatalog`.
259
+ */
260
+ export function formatCounter(value: number, format: string): string {
225
261
  switch (format) {
226
262
  case "decimal":
227
263
  return String(value);
@@ -235,13 +271,60 @@ function formatCounter(value: number, format: string): string {
235
271
  return toRoman(value).toUpperCase();
236
272
  case "lowerRoman":
237
273
  return toRoman(value).toLowerCase();
274
+ case "hex":
275
+ // ECMA-376 §17.9.7: hexadecimal numbering. Uppercase matches
276
+ // Word's rendered output on round-tripped documents.
277
+ return value >= 0 ? value.toString(16).toUpperCase() : String(value);
278
+ case "ordinal":
279
+ // ECMA-376 §17.9.7: English ordinal suffix. 11/12/13 are the
280
+ // special cases that take "th" regardless of last digit.
281
+ return toOrdinal(value);
282
+ case "cardinalText":
283
+ // ECMA-376 §17.9.7: English cardinal-word numbering. Coverage is
284
+ // 1–999; values outside fall through to decimal (String(value)).
285
+ return toCardinalText(value);
286
+ case "ordinalText":
287
+ // ECMA-376 §17.9.7: English ordinal-word numbering.
288
+ return toOrdinalText(value);
289
+ case "chicago":
290
+ // ECMA-376 §17.9.7: Chicago-manual-style symbol cycle. *, †, ‡,
291
+ // §, ‖, ¶, then each doubles for the 7–12 pass, triples for
292
+ // 13–18, and so on.
293
+ return toChicago(value);
294
+ case "bullet":
295
+ // ECMA-376 §17.9.7: bullet numbering — level.text carries the
296
+ // literal glyph (or picture-bullet reference). `%1` placeholders
297
+ // must interpolate to "" so the glyph is the only visible
298
+ // output; matches the `none` behavior.
299
+ return "";
238
300
  case "none":
239
301
  return "";
240
302
  default:
303
+ // Unsupported format — fall through to decimal for visible output.
304
+ // Callers that care about fidelity should gate on
305
+ // `isSupportedNumberingFormat(format)` first.
241
306
  return String(value);
242
307
  }
243
308
  }
244
309
 
310
+ function toOrdinal(value: number): string {
311
+ if (value <= 0) return String(value);
312
+ const lastTwo = value % 100;
313
+ const lastOne = value % 10;
314
+ // Teens: 11th, 12th, 13th (not 11st/12nd/13rd).
315
+ if (lastTwo >= 11 && lastTwo <= 13) return `${value}th`;
316
+ switch (lastOne) {
317
+ case 1:
318
+ return `${value}st`;
319
+ case 2:
320
+ return `${value}nd`;
321
+ case 3:
322
+ return `${value}rd`;
323
+ default:
324
+ return `${value}th`;
325
+ }
326
+ }
327
+
245
328
  function toAlphabetic(value: number): string {
246
329
  if (value <= 0) {
247
330
  return String(value);
@@ -288,3 +371,87 @@ function toRoman(value: number): string {
288
371
  }
289
372
  return result;
290
373
  }
374
+
375
+ // ---------------------------------------------------------------------------
376
+ // ECMA-376 §17.9.7 English number-word helpers (cardinalText / ordinalText).
377
+ // Coverage is 1–999; values outside the supported range fall through to
378
+ // `String(value)` so rendered output is never empty. Callers that care
379
+ // about fidelity beyond 999 should gate on the value range before invoking
380
+ // these formats.
381
+ // ---------------------------------------------------------------------------
382
+
383
+ const ONES_CARDINAL = [
384
+ "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
385
+ "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
386
+ "seventeen", "eighteen", "nineteen",
387
+ ] as const;
388
+
389
+ const TENS_CARDINAL = [
390
+ "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty",
391
+ "ninety",
392
+ ] as const;
393
+
394
+ function toCardinalText(value: number): string {
395
+ if (!Number.isInteger(value) || value < 1 || value > 999) return String(value);
396
+ return cardinalBelowThousand(value);
397
+ }
398
+
399
+ function cardinalBelowThousand(value: number): string {
400
+ if (value < 20) return ONES_CARDINAL[value]!;
401
+ if (value < 100) {
402
+ const tens = Math.floor(value / 10);
403
+ const rest = value % 10;
404
+ return rest === 0
405
+ ? TENS_CARDINAL[tens]!
406
+ : `${TENS_CARDINAL[tens]}-${ONES_CARDINAL[rest]}`;
407
+ }
408
+ const hundreds = Math.floor(value / 100);
409
+ const rest = value % 100;
410
+ const base = `${ONES_CARDINAL[hundreds]} hundred`;
411
+ if (rest === 0) return base;
412
+ return `${base} ${cardinalBelowThousand(rest)}`;
413
+ }
414
+
415
+ // Standalone ordinal-word map for ones 1–19 where the ordinal differs from
416
+ // the cardinal (e.g. "one" → "first", not "oneth").
417
+ const ONES_ORDINAL = [
418
+ "", "first", "second", "third", "fourth", "fifth", "sixth", "seventh",
419
+ "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth",
420
+ "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth",
421
+ "nineteenth",
422
+ ] as const;
423
+
424
+ // Tens endings (20 → "twentieth", 30 → "thirtieth", …). Standalone decades
425
+ // swap their trailing `y` for `ieth`.
426
+ const TENS_ORDINAL = [
427
+ "", "", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth",
428
+ "seventieth", "eightieth", "ninetieth",
429
+ ] as const;
430
+
431
+ function toOrdinalText(value: number): string {
432
+ if (!Number.isInteger(value) || value < 1 || value > 999) return String(value);
433
+ if (value < 20) return ONES_ORDINAL[value]!;
434
+ if (value < 100) {
435
+ const tens = Math.floor(value / 10);
436
+ const rest = value % 10;
437
+ return rest === 0
438
+ ? TENS_ORDINAL[tens]!
439
+ : `${TENS_CARDINAL[tens]}-${ONES_ORDINAL[rest]}`;
440
+ }
441
+ const hundreds = Math.floor(value / 100);
442
+ const rest = value % 100;
443
+ if (rest === 0) return `${ONES_CARDINAL[hundreds]} hundredth`;
444
+ return `${ONES_CARDINAL[hundreds]} hundred ${toOrdinalText(rest)}`;
445
+ }
446
+
447
+ // ECMA-376 §17.9.7 chicago cycle. 6-symbol sequence; each pass through the
448
+ // cycle repeats the symbol once more. Value 1 → "*", 6 → "¶", 7 → "**",
449
+ // 12 → "¶¶", 13 → "***", etc. Non-positive values fall through to decimal.
450
+ const CHICAGO_GLYPHS = ["*", "†", "‡", "§", "‖", "¶"] as const;
451
+
452
+ function toChicago(value: number): string {
453
+ if (!Number.isInteger(value) || value < 1) return String(value);
454
+ const index = (value - 1) % CHICAGO_GLYPHS.length;
455
+ const repeat = Math.floor((value - 1) / CHICAGO_GLYPHS.length) + 1;
456
+ return CHICAGO_GLYPHS[index]!.repeat(repeat);
457
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Paragraph + character style chain walkers.
3
+ *
4
+ * Owns ONLY the `basedOn`-chain traversal functions
5
+ * (`resolveParagraphStyleChain`, `resolveCharacterStyleChain`) and the small
6
+ * utility `getNextStyleId`. The four-tier cascade drivers
7
+ * (`resolveEffective*Formatting`, `resolveNumberingMarkerRunFormatting`,
8
+ * `resolveTableCellTextFormatting`) and the merge primitives live in
9
+ * `./style-cascade.ts`; they are re-exported here for back-compat with
10
+ * consumers migrating off the legacy import path.
11
+ *
12
+ * Returned chains are leaf-first (most-specific style at index 0, root at
13
+ * the end). Cycles break at the first re-encounter. Dangling `basedOn`
14
+ * references stop the walk silently (the leaf is still returned).
15
+ */
16
+
17
+ import type {
18
+ CharacterStyleDefinition,
19
+ ParagraphStyleDefinition,
20
+ StylesCatalog,
21
+ } from "../../model/canonical-document.ts";
22
+
23
+ export function resolveParagraphStyleChain(
24
+ styleId: string,
25
+ catalog: StylesCatalog | undefined,
26
+ ): string[] {
27
+ const chain: string[] = [];
28
+ if (!catalog) return chain;
29
+ const visited = new Set<string>();
30
+ let current: string | undefined = styleId;
31
+ while (current && !visited.has(current)) {
32
+ visited.add(current);
33
+ const def: ParagraphStyleDefinition | undefined = catalog.paragraphs[current];
34
+ if (!def) break;
35
+ chain.push(current);
36
+ current = def.basedOn;
37
+ }
38
+ return chain;
39
+ }
40
+
41
+ export function resolveCharacterStyleChain(
42
+ styleId: string,
43
+ catalog: StylesCatalog | undefined,
44
+ ): string[] {
45
+ const chain: string[] = [];
46
+ if (!catalog) return chain;
47
+ const visited = new Set<string>();
48
+ let current: string | undefined = styleId;
49
+ while (current && !visited.has(current)) {
50
+ visited.add(current);
51
+ const def: CharacterStyleDefinition | undefined = catalog.characters[current];
52
+ if (!def) break;
53
+ chain.push(current);
54
+ current = def.basedOn;
55
+ }
56
+ return chain;
57
+ }
58
+
59
+ /**
60
+ * Return the `w:next` style ID for `styleId` — the paragraph style Word
61
+ * applies after pressing Enter at the end of a paragraph of this style.
62
+ */
63
+ export function getNextStyleId(
64
+ styleId: string,
65
+ catalog: StylesCatalog | undefined,
66
+ ): string | undefined {
67
+ return catalog?.paragraphs[styleId]?.nextStyle;
68
+ }
69
+
70
+ // ---------------------------------------------------------------------------
71
+ // Back-compat re-exports
72
+ //
73
+ // The cascade drivers + merge primitives moved to `./style-cascade.ts` in
74
+ // Phase B1 of the layer-03 refactor (completes the Slice-2 "four-tier
75
+ // cascade core extract" plan row). Re-exported here so consumers that
76
+ // import from `paragraph-style-resolver.ts` continue to compile during
77
+ // the Phase-D consumer migration.
78
+ // ---------------------------------------------------------------------------
79
+
80
+ export {
81
+ resolveEffectiveParagraphFormatting,
82
+ resolveEffectiveRunFormatting,
83
+ resolveNumberingMarkerRunFormatting,
84
+ resolveTableCellTextFormatting,
85
+ mergeParagraph,
86
+ mergeRun,
87
+ type ParagraphResolveInput,
88
+ type RunResolveInput,
89
+ type MarkerResolveInput,
90
+ } from "./style-cascade.ts";
91
+
92
+ export { resolveRunFontFamily } from "./font-resolution.ts";
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Layer 03 — formatting debug projector.
3
+ *
4
+ * Produces a `FormattingDebugEntry` for the debug-inspector snapshot when
5
+ * the `formatting` telemetry channel is on. Architecture reference:
6
+ * docs/architecture/03-formatting-semantics.md §"Projector and oracle surfaces".
7
+ *
8
+ * The projector is strict about cost: when the `formatting` channel is
9
+ * off, consumers must not call `buildFormattingDebugEntry`. The channel
10
+ * toggle lives on the telemetry bus; callers gate the call through
11
+ * `bus.isEnabled("formatting")` before paying the summary cost.
12
+ *
13
+ * Slice 3 lands the minimum-viable summary: catalog population, cascade
14
+ * cache-hit counters, and a probability-gated sample of the last N
15
+ * resolutions. Slice 4 extends it with revision-display posture counts.
16
+ */
17
+
18
+ import type { CanonicalDocument } from "../../model/canonical-document.ts";
19
+
20
+ export interface FormattingCatalogSummary {
21
+ readonly paragraphStyles: number;
22
+ readonly characterStyles: number;
23
+ readonly tableStyles: number;
24
+ readonly numberingInstances: number;
25
+ readonly numberingAbstracts: number;
26
+ readonly hasTheme: boolean;
27
+ readonly hasFontTable: boolean;
28
+ }
29
+
30
+ export interface FormattingResolutionSample {
31
+ readonly t: number;
32
+ readonly kind:
33
+ | "paragraph"
34
+ | "run"
35
+ | "table"
36
+ | "table-cell"
37
+ | "field"
38
+ | "drawing-frame";
39
+ readonly blockId: string;
40
+ readonly resolvedStyleChainDepth?: number;
41
+ }
42
+
43
+ export interface FormattingDebugEntry {
44
+ readonly schemaVersion: 1;
45
+ readonly catalog: FormattingCatalogSummary;
46
+ readonly revisionMarkupMode?: "clean" | "simple" | "all";
47
+ readonly recentSamples: readonly FormattingResolutionSample[];
48
+ }
49
+
50
+ export interface BuildFormattingDebugEntryInputs {
51
+ readonly doc: CanonicalDocument;
52
+ readonly revisionMarkupMode?: "clean" | "simple" | "all";
53
+ readonly recentSamples?: readonly FormattingResolutionSample[];
54
+ }
55
+
56
+ export function buildFormattingDebugEntry(
57
+ inputs: BuildFormattingDebugEntryInputs,
58
+ ): FormattingDebugEntry {
59
+ const { doc, revisionMarkupMode, recentSamples } = inputs;
60
+ const catalog: FormattingCatalogSummary = {
61
+ paragraphStyles: Object.keys(doc.styles.paragraphs ?? {}).length,
62
+ characterStyles: Object.keys(doc.styles.characters ?? {}).length,
63
+ tableStyles: Object.keys(doc.styles.tables ?? {}).length,
64
+ numberingInstances: Object.keys(doc.numbering?.instances ?? {}).length,
65
+ numberingAbstracts: Object.keys(doc.numbering?.abstractDefinitions ?? {}).length,
66
+ hasTheme: Boolean(doc.subParts?.canonicalTheme),
67
+ hasFontTable: Boolean(doc.fontTable),
68
+ };
69
+ return {
70
+ schemaVersion: 1,
71
+ catalog,
72
+ revisionMarkupMode,
73
+ recentSamples: recentSamples ?? [],
74
+ };
75
+ }