@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,150 @@
1
+ import { useCallback, useEffect } from "react";
2
+ import type { Dispatch, SetStateAction } from "react";
3
+
4
+ import { createCanvasBackend } from "../../runtime/layout/index.ts";
5
+ import type { RuntimeRenderSnapshot } from "../../api/public-types.ts";
6
+ import {
7
+ incrementInvalidationCounter,
8
+ recordPerfSample,
9
+ } from "../editor-surface/perf-probe.ts";
10
+
11
+ import type { ActiveParagraphLayout } from "./paragraph-layout.ts";
12
+ import type { PageChromeModel } from "./page-chrome.ts";
13
+ import type { PageShellMetrics } from "./page-shell-metrics.ts";
14
+
15
+ export interface UseWorkspaceSideEffectsOptions {
16
+ layoutFacet?: import("../../runtime/layout/index.ts").WordReviewEditorLayoutFacet;
17
+ activeParagraphLayout: ActiveParagraphLayout | null;
18
+ pageChromeModel: PageChromeModel;
19
+ pageShellMetrics: PageShellMetrics;
20
+ isPageWorkspace: boolean;
21
+ activeStoryKind: RuntimeRenderSnapshot["activeStory"]["kind"];
22
+ setLayoutToolsOpen: Dispatch<SetStateAction<boolean>>;
23
+ showDrawerReviewRail: boolean;
24
+ setReviewRailOpen: Dispatch<SetStateAction<boolean>>;
25
+ onOpenHeaderStory?: () => void;
26
+ onOpenFooterStory?: () => void;
27
+ onDismissSelectionToolbar?: () => void;
28
+ }
29
+
30
+ export interface WorkspaceSideEffectsResult {
31
+ dismissSelectionToolbar: () => void;
32
+ runWithSelectionToolbarDismiss: (action?: () => void) => () => void;
33
+ }
34
+
35
+ /**
36
+ * Bundle the small, observation-only or external-side-effect hooks the
37
+ * review workspace needs:
38
+ *
39
+ * - Perf sample + invalidation counter on each chrome recompute.
40
+ * - Auto-open the layout-tools panel when the workspace enters a
41
+ * non-main story (header / footer / footnotes canvas mode).
42
+ * - Deprecation shim for the legacy `onOpenHeaderStory` /
43
+ * `onOpenFooterStory` props.
44
+ * - Escape-key close when the review rail is rendered as a drawer.
45
+ * - Font-load-gated canvas-backend swap for the layout facet's
46
+ * measurement provider.
47
+ * - Selection-toolbar dismiss callbacks.
48
+ *
49
+ * Every hook is an isolated effect + callback — no shared state. They
50
+ * live in one module because the parent workspace would otherwise carry
51
+ * six separately-declared effects for side-effects that individually
52
+ * don't warrant their own module.
53
+ */
54
+ export function useWorkspaceSideEffects(
55
+ options: UseWorkspaceSideEffectsOptions,
56
+ ): WorkspaceSideEffectsResult {
57
+ const {
58
+ layoutFacet,
59
+ activeParagraphLayout,
60
+ pageChromeModel,
61
+ pageShellMetrics,
62
+ isPageWorkspace,
63
+ activeStoryKind,
64
+ setLayoutToolsOpen,
65
+ showDrawerReviewRail,
66
+ setReviewRailOpen,
67
+ onOpenHeaderStory,
68
+ onOpenFooterStory,
69
+ onDismissSelectionToolbar,
70
+ } = options;
71
+
72
+ useEffect(() => {
73
+ recordPerfSample("workspace.chrome");
74
+ incrementInvalidationCounter("workspace.chrome.recomputes");
75
+ }, [activeParagraphLayout, pageChromeModel, pageShellMetrics]);
76
+
77
+ useEffect(() => {
78
+ if (isPageWorkspace && activeStoryKind !== "main") {
79
+ setLayoutToolsOpen(true);
80
+ }
81
+ }, [isPageWorkspace, activeStoryKind, setLayoutToolsOpen]);
82
+
83
+ // P8.11 — deprecation shim for the legacy `onOpenHeaderStory` /
84
+ // `onOpenFooterStory` props. Per-page chrome bands route clicks via
85
+ // `onOpenStory` + `runtime.openStory` directly; the workspace-level
86
+ // bands that consumed these callbacks are gone. Kept optional for one
87
+ // release so existing hosts compile; a mount-time console.warn nudges
88
+ // them toward `onOpenStory`.
89
+ useEffect(() => {
90
+ if (onOpenHeaderStory) {
91
+ // eslint-disable-next-line no-console
92
+ console.warn(
93
+ "[docx-react-component] `onOpenHeaderStory` is deprecated. Per-page header bands route clicks via runtime.openStory directly. (P8)",
94
+ );
95
+ }
96
+ if (onOpenFooterStory) {
97
+ // eslint-disable-next-line no-console
98
+ console.warn(
99
+ "[docx-react-component] `onOpenFooterStory` is deprecated. Per-page footer bands route clicks via runtime.openStory directly. (P8)",
100
+ );
101
+ }
102
+ // Mount-once: we only want to nudge hosts at startup, not per render.
103
+ // eslint-disable-next-line react-hooks/exhaustive-deps
104
+ }, []);
105
+
106
+ useEffect(() => {
107
+ if (!showDrawerReviewRail || typeof window === "undefined") {
108
+ return;
109
+ }
110
+
111
+ const handleKeyDown = (event: KeyboardEvent) => {
112
+ if (event.key !== "Escape") {
113
+ return;
114
+ }
115
+ setReviewRailOpen(false);
116
+ };
117
+
118
+ window.addEventListener("keydown", handleKeyDown);
119
+ return () => {
120
+ window.removeEventListener("keydown", handleKeyDown);
121
+ };
122
+ }, [showDrawerReviewRail, setReviewRailOpen]);
123
+
124
+ useEffect(() => {
125
+ if (!layoutFacet) return;
126
+ const facet = layoutFacet;
127
+ const fontSet = document.fonts;
128
+ if (!fontSet?.ready) {
129
+ facet.swapMeasurementProvider(createCanvasBackend());
130
+ return;
131
+ }
132
+ void fontSet.ready.then(() => {
133
+ facet.swapMeasurementProvider(createCanvasBackend());
134
+ });
135
+ }, [layoutFacet]);
136
+
137
+ const dismissSelectionToolbar = useCallback(() => {
138
+ onDismissSelectionToolbar?.();
139
+ }, [onDismissSelectionToolbar]);
140
+
141
+ const runWithSelectionToolbarDismiss = useCallback(
142
+ (action?: () => void) => () => {
143
+ dismissSelectionToolbar();
144
+ action?.();
145
+ },
146
+ [dismissSelectionToolbar],
147
+ );
148
+
149
+ return { dismissSelectionToolbar, runWithSelectionToolbarDismiss };
150
+ }
@@ -1149,6 +1149,31 @@
1149
1149
  }
1150
1150
  }
1151
1151
 
1152
+ /*
1153
+ * U3 fix — font-smoothing baseline for the entire editor shell.
1154
+ *
1155
+ * Previously `-webkit-font-smoothing` / `-moz-osx-font-smoothing` /
1156
+ * `text-rendering` lived ONLY on `.wre-page-surface` and
1157
+ * `.wre-canvas-surface`, so chrome elements (shell header, toolbar,
1158
+ * rails, status bar, overlays) inherited smoothing from the host
1159
+ * `body` — which consumers may not set. Embedding the editor in a
1160
+ * host without `-webkit-font-smoothing: antialiased` left chrome text
1161
+ * rendering with subpixel/default AA while the document surface was
1162
+ * antialiased, producing the visible mismatch the U3 report flagged.
1163
+ *
1164
+ * Declaring the tokens on `.wre-editor` (the single shell-root class
1165
+ * every surface below is nested under) makes smoothing the editor's
1166
+ * own baseline instead of a host concern. The inner
1167
+ * `.wre-page-surface` / `.wre-canvas-surface` rules are kept so
1168
+ * headless-service / Playwright captures still see explicit
1169
+ * declarations on the document surface.
1170
+ */
1171
+ .wre-editor {
1172
+ -webkit-font-smoothing: antialiased;
1173
+ -moz-osx-font-smoothing: grayscale;
1174
+ text-rendering: optimizeLegibility;
1175
+ }
1176
+
1152
1177
  /*
1153
1178
  * §6.23 — Scrollbar grammar (Lane 6c.S10)
1154
1179
  * Thin track, thumb low-contrast until hover. Consistent across
@@ -45,11 +45,11 @@ import type {
45
45
  ReviewQueueSnapshot,
46
46
  ScopeRailPosture,
47
47
  } from "../../api/public-types";
48
- import type { SessionCapabilities } from "../../runtime/session-capabilities";
48
+ import type { SessionCapabilities } from "../../api/public-types";
49
49
  import type { ScopedChromePolicy } from "../../ui/headless/scoped-chrome-policy";
50
50
  import type { ToolbarChromeItemId } from "../../ui/headless/chrome-registry";
51
51
  import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
52
- import { ROLE_ACTION_SETS } from "../chrome/role-action-sets";
52
+ import { ROLE_ACTION_SETS } from "../../ui/headless/role-action-sets";
53
53
  import { TwScopePostureMenu } from "./tw-scope-posture-menu";
54
54
 
55
55
  /**
@@ -61,7 +61,7 @@ import type {
61
61
  WorkspaceMode,
62
62
  ZoomLevel,
63
63
  } from "../../api/public-types";
64
- import type { SessionCapabilities } from "../../runtime/session-capabilities";
64
+ import type { SessionCapabilities } from "../../api/public-types";
65
65
  import {
66
66
  getToolbarChromePlacement,
67
67
  isChromeItemOwnedByRoleRegion,
@@ -70,12 +70,7 @@ import {
70
70
  type ScopedChromePolicy,
71
71
  } from "../../ui/headless/scoped-chrome-policy";
72
72
  import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
73
- import { TwHealthPanel } from "../review/tw-health-panel";
74
- import {
75
- TwRoleActionRegion,
76
- type MarkupDisplayMode,
77
- type WorkflowWorkItemSnapshot,
78
- } from "./tw-role-action-region";
73
+ import { type MarkupDisplayMode } from "./tw-role-action-region";
79
74
  import { TwDetachHandle } from "../chrome/tw-detach-handle";
80
75
  import { TwToolbarIconButton } from "./tw-toolbar-icon-button";
81
76
 
@@ -137,15 +132,15 @@ export interface TwToolbarProps {
137
132
 
138
133
  // ───── R1: role-scoped inline action region (spec §6.4) ──────────────
139
134
  /**
140
- * Active editor role. When supplied, the toolbar renders the inline
141
- * `TwRoleActionRegion` between the left formatting cluster and the
142
- * right view cluster. Omit to keep the pre-R1 layout.
135
+ * Active editor role. Since Chrome Closure Pass Task 1 (2026-04-22) the
136
+ * role-action region renders inside `<TwContextBand>` the toolbar
137
+ * itself no longer mounts `<TwRoleActionRegion>`. The `role` prop is
138
+ * retained here only so the formatting cluster can defer items owned
139
+ * by the role-region via `isChromeItemOwnedByRoleRegion`.
143
140
  */
144
141
  role?: EditorRole;
145
- /** Review-queue snapshot for the review role's inline prev/next/counts. */
142
+ /** Review-queue snapshot consumed only by the view-cluster change-counter chip. */
146
143
  reviewQueue?: ReviewQueueSnapshot;
147
- /** Active work item for the workflow role's inline queue. */
148
- workflowItem?: WorkflowWorkItemSnapshot | null;
149
144
  /** Markup display mode for the review role. */
150
145
  markupDisplay?: MarkupDisplayMode;
151
146
 
@@ -154,22 +149,13 @@ export interface TwToolbarProps {
154
149
  onReviewSidebarComments?: () => void;
155
150
  // Workflow + review role: scope posture
156
151
  onMarkScopePosture?: (posture: ScopeRailPosture) => void;
157
- // Review role
152
+ // Review role — inline prev/next + accept/reject stay on the toolbar for
153
+ // the view-cluster mount (queue counter chip); batch ops moved with the
154
+ // role-region to <TwContextBand> and are threaded there, not here.
158
155
  onReviewPrev?: () => void;
159
156
  onReviewNext?: () => void;
160
157
  onReviewAccept?: () => void;
161
158
  onReviewReject?: () => void;
162
- onReviewAcceptAll?: () => void;
163
- onReviewRejectAll?: () => void;
164
- onReviewMarkupMode?: (mode: MarkupDisplayMode) => void;
165
- // Workflow role
166
- onWorkflowPrev?: () => void;
167
- onWorkflowNext?: () => void;
168
- onWorkflowMarkComplete?: () => void;
169
- onWorkflowClaim?: () => void;
170
- onWorkflowSkip?: () => void;
171
- onWorkflowMarkBlocked?: () => void;
172
- onWorkflowJumpToScope?: () => void;
173
159
  /** Current chrome pin state; when supplied enables the topnav detach handle. */
174
160
  chromePins?: ChromePinsState;
175
161
  /** Called when the user detaches or re-attaches the topnav. */
@@ -208,6 +194,15 @@ export interface TwToolbarProps {
208
194
  image?: string;
209
195
  sectionBreak?: string;
210
196
  };
197
+
198
+ /**
199
+ * Phase E.3 — handoff to the management rail's Health tab. Clicking
200
+ * the signal-only health chip fires this callback so the workspace can
201
+ * open the rail via the chrome-host controller's `openRailTab` method.
202
+ * Diagnostics detail no longer lives inside a toolbar popover (audit
203
+ * §2.10); the chip surfaces severity + count only.
204
+ */
205
+ onOpenHealthRail?: () => void;
211
206
  }
212
207
 
213
208
  export interface ToolbarInteractionPolicy {
@@ -593,39 +588,16 @@ export function TwToolbar(props: TwToolbarProps) {
593
588
  ) : null}
594
589
  </div>
595
590
 
596
- {/* R1: role-scoped inline action region (spec §6.4) */}
597
- {props.role ? (
598
- <TwRoleActionRegion
599
- role={props.role}
600
- policy={scopedChromePolicy}
601
- compactMode={isCompact}
602
- reviewQueue={props.reviewQueue}
603
- workflowItem={props.workflowItem}
604
- markupDisplay={props.markupDisplay}
605
- canAddComment={canAddComment}
606
- showTrackedChanges={props.showTrackedChanges}
607
- capabilities={caps}
608
- onAddComment={props.onAddComment}
609
- onShowTrackedChangesChange={props.onShowTrackedChangesChange}
610
- onReviewSidebarTrackedChanges={props.onReviewSidebarTrackedChanges}
611
- onReviewSidebarComments={props.onReviewSidebarComments}
612
- onMarkScopePosture={props.onMarkScopePosture}
613
- onReviewPrev={props.onReviewPrev}
614
- onReviewNext={props.onReviewNext}
615
- onReviewAccept={props.onReviewAccept}
616
- onReviewReject={props.onReviewReject}
617
- onReviewAcceptAll={props.onReviewAcceptAll}
618
- onReviewRejectAll={props.onReviewRejectAll}
619
- onReviewMarkupMode={props.onReviewMarkupMode}
620
- onWorkflowPrev={props.onWorkflowPrev}
621
- onWorkflowNext={props.onWorkflowNext}
622
- onWorkflowMarkComplete={props.onWorkflowMarkComplete}
623
- onWorkflowClaim={props.onWorkflowClaim}
624
- onWorkflowSkip={props.onWorkflowSkip}
625
- onWorkflowMarkBlocked={props.onWorkflowMarkBlocked}
626
- onWorkflowJumpToScope={props.onWorkflowJumpToScope}
627
- />
628
- ) : null}
591
+ {/*
592
+ * Chrome Closure Pass · Task 1 (designsystem.md §6.3) — the
593
+ * role-action region used to render here as the toolbar's center
594
+ * subregion. It now lives inside `TwContextBand` (rendered as a
595
+ * sibling above the toolbar) so the workspace row is
596
+ * [shell] · [TwContextBand carrying role actions] · [TwToolbar]
597
+ * The toolbar still consumes `props.role` above for
598
+ * `isChromeItemOwnedByRoleRegion` deferral so it does not
599
+ * duplicate controls the band already exposes (§6.2 "Do not").
600
+ */}
629
601
 
630
602
  {/* Right cluster: comment, track changes, markup, view, export */}
631
603
  <div className={`flex items-center gap-0.5 ${isCompact ? "ml-auto flex-wrap justify-end" : ""}`}>
@@ -868,47 +840,38 @@ export function TwToolbar(props: TwToolbarProps) {
868
840
 
869
841
  {showHealth ? (
870
842
  <>
871
- <Popover.Root>
872
- <Tooltip.Root>
873
- <Tooltip.Trigger asChild>
874
- <Popover.Trigger asChild>
875
- <button
876
- type="button"
877
- aria-label="Document health"
878
- onMouseDown={preserveEditorSelectionMouseDown}
879
- className={`relative inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface hover:text-primary outline-none ${focusRingClass}`}
880
- >
881
- <AlertCircle className="h-3.5 w-3.5" />
882
- {(caps?.healthIssueCount ?? 0) > 0 ? (
883
- <span className="absolute -top-0.5 -right-0.5 flex h-3 min-w-[12px] items-center justify-center rounded-full bg-tertiary text-[8px] font-medium text-white">
884
- {caps?.healthIssueCount}
885
- </span>
886
- ) : null}
887
- </button>
888
- </Popover.Trigger>
889
- </Tooltip.Trigger>
890
- <Tooltip.Portal>
891
- <Tooltip.Content className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50" sideOffset={6}>
892
- {(caps?.healthIssueCount ?? 0) > 0
893
- ? `Document health — ${caps?.healthIssueCount} issue${(caps?.healthIssueCount ?? 0) !== 1 ? "s" : ""}`
894
- : "Document health — no issues"}
895
- </Tooltip.Content>
896
- </Tooltip.Portal>
897
- </Tooltip.Root>
898
- <Popover.Portal>
899
- <Popover.Content
900
- className="w-[360px] max-h-[480px] overflow-y-auto rounded-lg bg-canvas shadow-lg ring-1 ring-border p-3 z-50"
901
- sideOffset={8}
902
- align="end"
843
+ {/*
844
+ * Phase E.3 — signal-only chip. The Radix Popover that
845
+ * previously wrapped this button is retired (audit §2.10);
846
+ * detail now lives in the rail `health` tab. Clicking the
847
+ * chip fires `onOpenHealthRail` so the workspace can pivot
848
+ * the rail via the chrome-host controller's `openRailTab`.
849
+ */}
850
+ <Tooltip.Root>
851
+ <Tooltip.Trigger asChild>
852
+ <button
853
+ type="button"
854
+ aria-label="Document health"
855
+ onMouseDown={preserveEditorSelectionMouseDown}
856
+ onClick={props.onOpenHealthRail}
857
+ className={`relative inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface hover:text-primary outline-none ${focusRingClass}`}
903
858
  >
904
- <TwHealthPanel
905
- blockedReasons={props.blockedReasons}
906
- compatibility={props.compatibility!}
907
- warnings={props.warnings!}
908
- />
909
- </Popover.Content>
910
- </Popover.Portal>
911
- </Popover.Root>
859
+ <AlertCircle className="h-3.5 w-3.5" />
860
+ {(caps?.healthIssueCount ?? 0) > 0 ? (
861
+ <span className="absolute -top-0.5 -right-0.5 flex h-3 min-w-[12px] items-center justify-center rounded-full bg-tertiary text-[8px] font-medium text-white">
862
+ {caps?.healthIssueCount}
863
+ </span>
864
+ ) : null}
865
+ </button>
866
+ </Tooltip.Trigger>
867
+ <Tooltip.Portal>
868
+ <Tooltip.Content className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50" sideOffset={6}>
869
+ {(caps?.healthIssueCount ?? 0) > 0
870
+ ? `Document health — ${caps?.healthIssueCount} issue${(caps?.healthIssueCount ?? 0) !== 1 ? "s" : ""} (opens rail)`
871
+ : "Document health — no issues"}
872
+ </Tooltip.Content>
873
+ </Tooltip.Portal>
874
+ </Tooltip.Root>
912
875
  <div className="mx-1 h-4 w-px bg-border" />
913
876
  </>
914
877
  ) : null}