@beyondwork/docx-react-component 1.0.29 → 1.0.31

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 (383) hide show
  1. package/package.json +65 -96
  2. package/src/README.md +85 -0
  3. package/src/api/README.md +26 -0
  4. package/src/api/public-types.ts +1952 -0
  5. package/src/api/session-state.ts +62 -0
  6. package/src/compare/diff-engine.ts +623 -0
  7. package/src/compare/export-redlines.ts +280 -0
  8. package/src/compare/index.ts +25 -0
  9. package/src/compare/snapshot.ts +97 -0
  10. package/src/component-inventory.md +99 -0
  11. package/src/core/README.md +10 -0
  12. package/src/core/commands/README.md +3 -0
  13. package/{dist/chunk-TJBP2K4T.js → src/core/commands/formatting-commands.ts} +536 -196
  14. package/src/core/commands/image-commands.ts +373 -0
  15. package/src/core/commands/index.ts +1879 -0
  16. package/src/core/commands/list-commands.ts +565 -0
  17. package/src/core/commands/paragraph-layout-commands.ts +339 -0
  18. package/src/core/commands/review-commands.ts +108 -0
  19. package/{dist/core/commands/section-layout-commands.cjs → src/core/commands/section-layout-commands.ts} +340 -137
  20. package/src/core/commands/structural-helpers.ts +309 -0
  21. package/{dist/core/commands/style-commands.cjs → src/core/commands/style-commands.ts} +113 -65
  22. package/src/core/commands/table-structure-commands.ts +854 -0
  23. package/{dist/chunk-UZXBISGO.js → src/core/commands/text-commands.ts} +142 -86
  24. package/src/core/schema/README.md +3 -0
  25. package/src/core/schema/text-schema.ts +516 -0
  26. package/src/core/search/search-text.ts +357 -0
  27. package/src/core/selection/README.md +3 -0
  28. package/src/core/selection/mapping.ts +289 -0
  29. package/src/core/selection/review-anchors.ts +183 -0
  30. package/src/core/state/README.md +3 -0
  31. package/src/core/state/editor-state.ts +892 -0
  32. package/src/core/state/text-transaction.ts +869 -0
  33. package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
  34. package/src/formats/xlsx/io/parse-sheet.ts +459 -0
  35. package/src/formats/xlsx/io/parse-styles.ts +59 -0
  36. package/src/formats/xlsx/io/parse-workbook.ts +75 -0
  37. package/src/formats/xlsx/io/serialize-shared-strings.ts +72 -0
  38. package/src/formats/xlsx/io/serialize-sheet.ts +333 -0
  39. package/src/formats/xlsx/io/serialize-styles.ts +98 -0
  40. package/src/formats/xlsx/io/serialize-workbook.ts +429 -0
  41. package/src/formats/xlsx/io/xlsx-session.ts +314 -0
  42. package/src/formats/xlsx/model/cell.ts +189 -0
  43. package/src/formats/xlsx/model/sheet.ts +326 -0
  44. package/src/formats/xlsx/model/styles.ts +118 -0
  45. package/src/formats/xlsx/model/workbook.ts +453 -0
  46. package/src/formats/xlsx/runtime/cell-commands.ts +567 -0
  47. package/src/formats/xlsx/runtime/sheet-commands.ts +206 -0
  48. package/src/formats/xlsx/runtime/workbook-runtime.ts +177 -0
  49. package/src/formats/xlsx/runtime/workbook-transaction.ts +822 -0
  50. package/src/index.ts +142 -0
  51. package/src/io/README.md +10 -0
  52. package/src/io/docx-session.ts +3175 -0
  53. package/src/io/export/README.md +3 -0
  54. package/src/io/export/export-session.ts +220 -0
  55. package/src/io/export/minimal-docx.ts +115 -0
  56. package/src/io/export/reattach-preserved-parts.ts +54 -0
  57. package/src/io/export/serialize-comments.ts +947 -0
  58. package/src/io/export/serialize-footnotes.ts +394 -0
  59. package/src/io/export/serialize-headers-footers.ts +368 -0
  60. package/src/io/export/serialize-main-document.ts +1342 -0
  61. package/src/io/export/serialize-numbering.ts +218 -0
  62. package/src/io/export/serialize-revisions.ts +389 -0
  63. package/src/io/export/serialize-runtime-revisions.ts +463 -0
  64. package/src/io/export/serialize-tables.ts +174 -0
  65. package/src/io/export/split-review-boundaries.ts +356 -0
  66. package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
  67. package/src/io/export/table-properties-xml.ts +318 -0
  68. package/src/io/normalize/README.md +3 -0
  69. package/src/io/normalize/normalize-text.ts +670 -0
  70. package/src/io/ooxml/README.md +3 -0
  71. package/src/io/ooxml/highlight-colors.ts +39 -0
  72. package/src/io/ooxml/numbering-sentinels.ts +44 -0
  73. package/src/io/ooxml/parse-comments.ts +852 -0
  74. package/src/io/ooxml/parse-complex-content.ts +287 -0
  75. package/src/io/ooxml/parse-fields.ts +834 -0
  76. package/src/io/ooxml/parse-footnotes.ts +952 -0
  77. package/src/io/ooxml/parse-headers-footers.ts +1212 -0
  78. package/src/io/ooxml/parse-inline-media.ts +461 -0
  79. package/src/io/ooxml/parse-main-document.ts +2947 -0
  80. package/src/io/ooxml/parse-numbering.ts +747 -0
  81. package/src/io/ooxml/parse-revisions.ts +1045 -0
  82. package/src/io/ooxml/parse-settings.ts +184 -0
  83. package/src/io/ooxml/parse-shapes.ts +296 -0
  84. package/src/io/ooxml/parse-styles.ts +639 -0
  85. package/src/io/ooxml/parse-tables.ts +627 -0
  86. package/src/io/ooxml/parse-theme.ts +346 -0
  87. package/src/io/ooxml/part-manifest.ts +136 -0
  88. package/src/io/ooxml/revision-boundaries.ts +475 -0
  89. package/src/io/ooxml/workflow-payload.ts +544 -0
  90. package/src/io/opc/README.md +3 -0
  91. package/src/io/opc/corrupt-package.ts +166 -0
  92. package/src/io/opc/docx-package.ts +74 -0
  93. package/src/io/opc/package-reader.ts +325 -0
  94. package/src/io/opc/package-writer.ts +273 -0
  95. package/src/io/source-package-provenance.ts +241 -0
  96. package/{dist/chunk-RMH72RZI.js → src/legal/bookmarks.ts} +130 -44
  97. package/src/legal/cross-references.ts +414 -0
  98. package/src/legal/defined-terms.ts +203 -0
  99. package/src/legal/index.ts +32 -0
  100. package/src/legal/signature-blocks.ts +259 -0
  101. package/src/model/README.md +3 -0
  102. package/src/model/canonical-document.ts +2722 -0
  103. package/src/model/cds-1.0.0.ts +212 -0
  104. package/src/model/snapshot.ts +760 -0
  105. package/src/preservation/README.md +3 -0
  106. package/src/preservation/markup-compatibility.ts +48 -0
  107. package/src/preservation/opaque-fragment-store.ts +89 -0
  108. package/src/preservation/opaque-region.ts +233 -0
  109. package/src/preservation/package-preservation.ts +113 -0
  110. package/src/preservation/preserved-part-manifest.ts +56 -0
  111. package/src/preservation/relationship-retention.ts +57 -0
  112. package/src/preservation/store.ts +255 -0
  113. package/src/review/README.md +16 -0
  114. package/src/review/store/README.md +3 -0
  115. package/src/review/store/comment-anchors.ts +70 -0
  116. package/src/review/store/comment-remapping.ts +154 -0
  117. package/src/review/store/comment-store.ts +349 -0
  118. package/src/review/store/comment-thread.ts +109 -0
  119. package/src/review/store/revision-actions.ts +423 -0
  120. package/src/review/store/revision-store.ts +323 -0
  121. package/src/review/store/revision-types.ts +182 -0
  122. package/src/review/store/runtime-comment-store.ts +43 -0
  123. package/src/runtime/README.md +3 -0
  124. package/src/runtime/ai-action-policy.ts +764 -0
  125. package/src/runtime/context-analytics.ts +824 -0
  126. package/src/runtime/document-layout.ts +332 -0
  127. package/src/runtime/document-locations.ts +521 -0
  128. package/src/runtime/document-navigation.ts +616 -0
  129. package/src/runtime/document-outline.ts +440 -0
  130. package/src/runtime/document-runtime.ts +4055 -0
  131. package/src/runtime/document-search.ts +145 -0
  132. package/src/runtime/event-refresh-hints.ts +137 -0
  133. package/src/runtime/numbering-prefix.ts +244 -0
  134. package/src/runtime/page-layout-estimation.ts +305 -0
  135. package/src/runtime/read-only-diagnostics-runtime.ts +241 -0
  136. package/src/runtime/resolved-numbering-geometry.ts +293 -0
  137. package/src/runtime/review-runtime.ts +44 -0
  138. package/src/runtime/revision-runtime.ts +107 -0
  139. package/src/runtime/session-capabilities.ts +192 -0
  140. package/src/runtime/story-context.ts +164 -0
  141. package/src/runtime/story-targeting.ts +162 -0
  142. package/src/runtime/suggestions-snapshot.ts +137 -0
  143. package/src/runtime/surface-projection.ts +1553 -0
  144. package/src/runtime/table-commands.ts +173 -0
  145. package/src/runtime/table-schema.ts +309 -0
  146. package/src/runtime/table-style-resolver.ts +409 -0
  147. package/src/runtime/view-state.ts +493 -0
  148. package/src/runtime/virtualized-rendering.ts +258 -0
  149. package/src/runtime/workflow-markup.ts +393 -0
  150. package/src/ui/README.md +30 -0
  151. package/src/ui/WordReviewEditor.tsx +5268 -0
  152. package/src/ui/browser-export.ts +52 -0
  153. package/src/ui/comments/README.md +3 -0
  154. package/src/ui/compatibility/README.md +3 -0
  155. package/src/ui/editor-command-bag.ts +127 -0
  156. package/src/ui/editor-runtime-boundary.ts +1558 -0
  157. package/src/ui/editor-shell-view.tsx +144 -0
  158. package/src/ui/editor-surface/README.md +3 -0
  159. package/src/ui/editor-surface-controller.tsx +66 -0
  160. package/src/ui/headless/comment-decoration-model.ts +124 -0
  161. package/src/ui/headless/preserve-editor-selection.ts +5 -0
  162. package/src/ui/headless/revision-decoration-model.ts +128 -0
  163. package/src/ui/headless/selection-helpers.ts +54 -0
  164. package/src/ui/headless/selection-tool-context.ts +19 -0
  165. package/src/ui/headless/selection-tool-resolver.ts +752 -0
  166. package/src/ui/headless/selection-tool-types.ts +129 -0
  167. package/src/ui/headless/selection-toolbar-model.ts +11 -0
  168. package/src/ui/headless/use-editor-keyboard.ts +103 -0
  169. package/src/ui/review/README.md +3 -0
  170. package/src/ui/runtime-shortcut-dispatch.ts +365 -0
  171. package/src/ui/runtime-snapshot-selectors.ts +197 -0
  172. package/src/ui/shared/revision-filters.ts +31 -0
  173. package/src/ui/status/README.md +3 -0
  174. package/src/ui/theme/README.md +3 -0
  175. package/src/ui/toolbar/README.md +3 -0
  176. package/src/ui/workflow-surface-blocked-rails.ts +94 -0
  177. package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
  178. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
  179. package/src/ui-tailwind/chrome/responsive-chrome.ts +46 -0
  180. package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
  181. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +64 -0
  182. package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
  183. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +121 -0
  184. package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
  185. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +30 -0
  186. package/src/ui-tailwind/chrome/tw-page-ruler.tsx +365 -0
  187. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
  188. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
  189. package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
  190. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +303 -0
  191. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
  192. package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
  193. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
  194. package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +186 -0
  195. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +139 -0
  196. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +250 -0
  197. package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
  198. package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
  199. package/src/ui-tailwind/editor-surface/perf-probe.ts +179 -0
  200. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +189 -0
  201. package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
  202. package/src/ui-tailwind/editor-surface/pm-decorations.ts +411 -0
  203. package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
  204. package/src/ui-tailwind/editor-surface/pm-schema.ts +927 -0
  205. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +567 -0
  206. package/src/ui-tailwind/editor-surface/search-plugin.ts +168 -0
  207. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +63 -0
  208. package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
  209. package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
  210. package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +129 -0
  211. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +58 -0
  212. package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
  213. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +1047 -0
  214. package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
  215. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +503 -0
  216. package/src/ui-tailwind/index.ts +62 -0
  217. package/src/ui-tailwind/page-chrome-model.ts +27 -0
  218. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +406 -0
  219. package/src/ui-tailwind/review/tw-health-panel.tsx +149 -0
  220. package/src/ui-tailwind/review/tw-review-rail.tsx +130 -0
  221. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
  222. package/src/ui-tailwind/status/tw-status-bar.tsx +65 -0
  223. package/{dist → src}/ui-tailwind/theme/editor-theme.css +58 -40
  224. package/src/ui-tailwind/toolbar/toolbar-layout.ts +47 -0
  225. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +52 -0
  226. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +1478 -0
  227. package/src/ui-tailwind/tw-review-workspace.tsx +1587 -0
  228. package/src/validation/README.md +3 -0
  229. package/src/validation/compatibility-engine.ts +878 -0
  230. package/src/validation/compatibility-report.ts +161 -0
  231. package/src/validation/diagnostics.ts +204 -0
  232. package/src/validation/docx-comment-proof.ts +720 -0
  233. package/src/validation/import-diagnostics.ts +128 -0
  234. package/src/validation/low-priority-word-surfaces.ts +373 -0
  235. package/dist/canonical-document-BLEbzL2J.d.cts +0 -844
  236. package/dist/canonical-document-BLEbzL2J.d.ts +0 -844
  237. package/dist/chunk-2FJS5GZM.js +0 -763
  238. package/dist/chunk-2FJS5GZM.js.map +0 -1
  239. package/dist/chunk-2OQBZS3F.js +0 -446
  240. package/dist/chunk-2OQBZS3F.js.map +0 -1
  241. package/dist/chunk-2S7W4KFO.js +0 -127
  242. package/dist/chunk-2S7W4KFO.js.map +0 -1
  243. package/dist/chunk-2TG72QSW.js +0 -3874
  244. package/dist/chunk-2TG72QSW.js.map +0 -1
  245. package/dist/chunk-36QNIZBO.js +0 -532
  246. package/dist/chunk-36QNIZBO.js.map +0 -1
  247. package/dist/chunk-4AQOYAW4.js +0 -3069
  248. package/dist/chunk-4AQOYAW4.js.map +0 -1
  249. package/dist/chunk-4D5EWJ3P.js +0 -77
  250. package/dist/chunk-4D5EWJ3P.js.map +0 -1
  251. package/dist/chunk-5FN54NDH.js +0 -2257
  252. package/dist/chunk-5FN54NDH.js.map +0 -1
  253. package/dist/chunk-BOYGQYRQ.js +0 -7306
  254. package/dist/chunk-BOYGQYRQ.js.map +0 -1
  255. package/dist/chunk-CN3XMECL.js +0 -212
  256. package/dist/chunk-CN3XMECL.js.map +0 -1
  257. package/dist/chunk-EBI3BX6U.js +0 -164
  258. package/dist/chunk-EBI3BX6U.js.map +0 -1
  259. package/dist/chunk-EILUG3VB.js +0 -1275
  260. package/dist/chunk-EILUG3VB.js.map +0 -1
  261. package/dist/chunk-FUDY333O.js +0 -70
  262. package/dist/chunk-FUDY333O.js.map +0 -1
  263. package/dist/chunk-GBVOWFIK.js +0 -1237
  264. package/dist/chunk-GBVOWFIK.js.map +0 -1
  265. package/dist/chunk-H4TQ3H3Y.js +0 -262
  266. package/dist/chunk-H4TQ3H3Y.js.map +0 -1
  267. package/dist/chunk-JGB3IXZO.js +0 -189
  268. package/dist/chunk-JGB3IXZO.js.map +0 -1
  269. package/dist/chunk-KD2QRQPY.js +0 -4342
  270. package/dist/chunk-KD2QRQPY.js.map +0 -1
  271. package/dist/chunk-KLMXQVYK.js +0 -369
  272. package/dist/chunk-KLMXQVYK.js.map +0 -1
  273. package/dist/chunk-KZUG5KFQ.js +0 -214
  274. package/dist/chunk-KZUG5KFQ.js.map +0 -1
  275. package/dist/chunk-QDAQ4CJU.js +0 -345
  276. package/dist/chunk-QDAQ4CJU.js.map +0 -1
  277. package/dist/chunk-RMH72RZI.js.map +0 -1
  278. package/dist/chunk-SWKWQZXM.js +0 -117
  279. package/dist/chunk-SWKWQZXM.js.map +0 -1
  280. package/dist/chunk-TJBP2K4T.js.map +0 -1
  281. package/dist/chunk-TLCEAQDQ.js +0 -542
  282. package/dist/chunk-TLCEAQDQ.js.map +0 -1
  283. package/dist/chunk-UZXBISGO.js.map +0 -1
  284. package/dist/chunk-WGBAKP3Q.js +0 -3220
  285. package/dist/chunk-WGBAKP3Q.js.map +0 -1
  286. package/dist/compare/index.cjs +0 -5475
  287. package/dist/compare/index.cjs.map +0 -1
  288. package/dist/compare/index.d.cts +0 -114
  289. package/dist/compare/index.d.ts +0 -114
  290. package/dist/compare/index.js +0 -731
  291. package/dist/compare/index.js.map +0 -1
  292. package/dist/core/commands/formatting-commands.cjs +0 -828
  293. package/dist/core/commands/formatting-commands.cjs.map +0 -1
  294. package/dist/core/commands/formatting-commands.d.cts +0 -63
  295. package/dist/core/commands/formatting-commands.d.ts +0 -63
  296. package/dist/core/commands/formatting-commands.js +0 -37
  297. package/dist/core/commands/formatting-commands.js.map +0 -1
  298. package/dist/core/commands/image-commands.cjs +0 -2023
  299. package/dist/core/commands/image-commands.cjs.map +0 -1
  300. package/dist/core/commands/image-commands.d.cts +0 -58
  301. package/dist/core/commands/image-commands.d.ts +0 -58
  302. package/dist/core/commands/image-commands.js +0 -18
  303. package/dist/core/commands/image-commands.js.map +0 -1
  304. package/dist/core/commands/section-layout-commands.cjs.map +0 -1
  305. package/dist/core/commands/section-layout-commands.d.cts +0 -62
  306. package/dist/core/commands/section-layout-commands.d.ts +0 -62
  307. package/dist/core/commands/section-layout-commands.js +0 -21
  308. package/dist/core/commands/section-layout-commands.js.map +0 -1
  309. package/dist/core/commands/style-commands.cjs.map +0 -1
  310. package/dist/core/commands/style-commands.d.cts +0 -13
  311. package/dist/core/commands/style-commands.d.ts +0 -13
  312. package/dist/core/commands/style-commands.js +0 -9
  313. package/dist/core/commands/style-commands.js.map +0 -1
  314. package/dist/core/commands/table-structure-commands.cjs +0 -1883
  315. package/dist/core/commands/table-structure-commands.cjs.map +0 -1
  316. package/dist/core/commands/table-structure-commands.d.cts +0 -59
  317. package/dist/core/commands/table-structure-commands.d.ts +0 -59
  318. package/dist/core/commands/table-structure-commands.js +0 -12
  319. package/dist/core/commands/table-structure-commands.js.map +0 -1
  320. package/dist/core/commands/text-commands.cjs +0 -2391
  321. package/dist/core/commands/text-commands.cjs.map +0 -1
  322. package/dist/core/commands/text-commands.d.cts +0 -24
  323. package/dist/core/commands/text-commands.d.ts +0 -24
  324. package/dist/core/commands/text-commands.js +0 -28
  325. package/dist/core/commands/text-commands.js.map +0 -1
  326. package/dist/core/selection/mapping.cjs +0 -200
  327. package/dist/core/selection/mapping.cjs.map +0 -1
  328. package/dist/core/selection/mapping.d.cts +0 -2
  329. package/dist/core/selection/mapping.d.ts +0 -2
  330. package/dist/core/selection/mapping.js +0 -31
  331. package/dist/core/selection/mapping.js.map +0 -1
  332. package/dist/core/state/editor-state.cjs +0 -2278
  333. package/dist/core/state/editor-state.cjs.map +0 -1
  334. package/dist/core/state/editor-state.d.cts +0 -2
  335. package/dist/core/state/editor-state.d.ts +0 -2
  336. package/dist/core/state/editor-state.js +0 -26
  337. package/dist/core/state/editor-state.js.map +0 -1
  338. package/dist/index.cjs +0 -38553
  339. package/dist/index.cjs.map +0 -1
  340. package/dist/index.d.cts +0 -15
  341. package/dist/index.d.ts +0 -15
  342. package/dist/index.js +0 -7856
  343. package/dist/index.js.map +0 -1
  344. package/dist/io/docx-session.cjs +0 -16236
  345. package/dist/io/docx-session.cjs.map +0 -1
  346. package/dist/io/docx-session.d.cts +0 -21
  347. package/dist/io/docx-session.d.ts +0 -21
  348. package/dist/io/docx-session.js +0 -18
  349. package/dist/io/docx-session.js.map +0 -1
  350. package/dist/legal/index.cjs +0 -3900
  351. package/dist/legal/index.cjs.map +0 -1
  352. package/dist/legal/index.d.cts +0 -86
  353. package/dist/legal/index.d.ts +0 -86
  354. package/dist/legal/index.js +0 -616
  355. package/dist/legal/index.js.map +0 -1
  356. package/dist/public-types-7ZL_94cz.d.ts +0 -1573
  357. package/dist/public-types-CeMaDueh.d.cts +0 -1573
  358. package/dist/public-types.cjs +0 -19
  359. package/dist/public-types.cjs.map +0 -1
  360. package/dist/public-types.d.cts +0 -2
  361. package/dist/public-types.d.ts +0 -2
  362. package/dist/public-types.js +0 -1
  363. package/dist/public-types.js.map +0 -1
  364. package/dist/runtime/document-runtime.cjs +0 -11140
  365. package/dist/runtime/document-runtime.cjs.map +0 -1
  366. package/dist/runtime/document-runtime.d.cts +0 -231
  367. package/dist/runtime/document-runtime.d.ts +0 -231
  368. package/dist/runtime/document-runtime.js +0 -21
  369. package/dist/runtime/document-runtime.js.map +0 -1
  370. package/dist/structural-helpers-CilgOVhh.d.cts +0 -10
  371. package/dist/structural-helpers-q0Gd-eBN.d.ts +0 -10
  372. package/dist/ui-tailwind/editor-surface/search-plugin.cjs +0 -313
  373. package/dist/ui-tailwind/editor-surface/search-plugin.cjs.map +0 -1
  374. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +0 -67
  375. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +0 -67
  376. package/dist/ui-tailwind/editor-surface/search-plugin.js +0 -23
  377. package/dist/ui-tailwind/editor-surface/search-plugin.js.map +0 -1
  378. package/dist/ui-tailwind/index.cjs +0 -4833
  379. package/dist/ui-tailwind/index.cjs.map +0 -1
  380. package/dist/ui-tailwind/index.d.cts +0 -617
  381. package/dist/ui-tailwind/index.d.ts +0 -617
  382. package/dist/ui-tailwind/index.js +0 -575
  383. package/dist/ui-tailwind/index.js.map +0 -1
@@ -0,0 +1,303 @@
1
+ import React, { useEffect, useRef, useState, type CSSProperties, type FocusEventHandler, type Ref } from "react";
2
+
3
+ import { GripHorizontal } from "lucide-react";
4
+
5
+ import type { RuntimeContextAnalyticsSnapshot } from "../../api/public-types";
6
+ import type { ActiveSelectionToolModel } from "../../ui/headless/selection-tool-types";
7
+ import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
8
+ import { TwContextAnalyticsSummary } from "./tw-context-analytics-summary";
9
+ import { TwSelectionToolBlocked } from "./tw-selection-tool-blocked";
10
+ import { TwSelectionToolComment } from "./tw-selection-tool-comment";
11
+ import { TwSelectionToolFormatting } from "./tw-selection-tool-formatting";
12
+ import { TwSelectionToolStructure } from "./tw-selection-tool-structure";
13
+ import { TwSelectionToolSuggestion } from "./tw-selection-tool-suggestion";
14
+ import { TwSelectionToolWorkflow } from "./tw-selection-tool-workflow";
15
+
16
+ export interface SelectionToolPlacement {
17
+ placement: "right" | "left" | "above" | "below";
18
+ style: CSSProperties;
19
+ }
20
+
21
+ export interface TwSelectionToolHostProps {
22
+ tool: ActiveSelectionToolModel | null;
23
+ contextAnalytics?: RuntimeContextAnalyticsSnapshot | null;
24
+ placement: SelectionToolPlacement | null;
25
+ rootRef?: Ref<HTMLDivElement>;
26
+ onFocusCapture?: FocusEventHandler<HTMLDivElement>;
27
+ onBlurCapture?: FocusEventHandler<HTMLDivElement>;
28
+ onToggleBold?: () => void;
29
+ onToggleItalic?: () => void;
30
+ onToggleUnderline?: () => void;
31
+ onSetTextColor?: (color: string) => void;
32
+ onSetHighlightColor?: (color: string | null) => void;
33
+ onAddComment?: () => void;
34
+ onAcceptSuggestion?: () => void;
35
+ onRejectSuggestion?: () => void;
36
+ onEditSuggestion?: () => void;
37
+ onSetTableStyle?: (styleId: string) => void;
38
+ onAddRowBefore?: () => void;
39
+ onAddRowAfter?: () => void;
40
+ onAddColumnBefore?: () => void;
41
+ onAddColumnAfter?: () => void;
42
+ onDeleteRow?: () => void;
43
+ onDeleteColumn?: () => void;
44
+ onDeleteTable?: () => void;
45
+ onMergeCells?: () => void;
46
+ onSplitCell?: () => void;
47
+ onSetCellBackground?: (color: string) => void;
48
+ onSetImageLayout?: (
49
+ mediaId: string,
50
+ dimensions: { widthEmu: number; heightEmu: number },
51
+ ) => void;
52
+ onSetImageFrame?: (
53
+ mediaId: string,
54
+ offsets: { horizontalOffsetEmu?: number; verticalOffsetEmu?: number },
55
+ ) => void;
56
+ onRestartNumbering?: () => void;
57
+ onContinueNumbering?: () => void;
58
+ }
59
+
60
+ export function TwSelectionToolHost(props: TwSelectionToolHostProps) {
61
+ if (!props.tool) {
62
+ return null;
63
+ }
64
+
65
+ const [isDetached, setIsDetached] = useState(false);
66
+ const [detachedOffset, setDetachedOffset] = useState({ x: 0, y: 0 });
67
+ const dragStateRef = useRef<{
68
+ startX: number;
69
+ startY: number;
70
+ originX: number;
71
+ originY: number;
72
+ } | null>(null);
73
+ const supportsTopMenuControls = isTopMenuKind(props.tool.kind);
74
+
75
+ useEffect(() => {
76
+ setIsDetached(false);
77
+ setDetachedOffset({ x: 0, y: 0 });
78
+ dragStateRef.current = null;
79
+ }, [props.tool.kind]);
80
+
81
+ useEffect(() => {
82
+ if (!supportsTopMenuControls || typeof window === "undefined") {
83
+ return;
84
+ }
85
+
86
+ const handleMouseMove = (event: MouseEvent) => {
87
+ if (!dragStateRef.current) {
88
+ return;
89
+ }
90
+ setDetachedOffset({
91
+ x: dragStateRef.current.originX + (event.clientX - dragStateRef.current.startX),
92
+ y: dragStateRef.current.originY + (event.clientY - dragStateRef.current.startY),
93
+ });
94
+ };
95
+
96
+ const handleMouseUp = () => {
97
+ dragStateRef.current = null;
98
+ };
99
+
100
+ window.addEventListener("mousemove", handleMouseMove);
101
+ window.addEventListener("mouseup", handleMouseUp);
102
+ return () => {
103
+ window.removeEventListener("mousemove", handleMouseMove);
104
+ window.removeEventListener("mouseup", handleMouseUp);
105
+ };
106
+ }, [supportsTopMenuControls]);
107
+
108
+ const overlayTestId = getOverlayTestId(props.tool.kind, Boolean(props.placement));
109
+ const toolContent = renderTool(props, props.tool);
110
+ const content = toolContent ? (
111
+ <div
112
+ ref={props.rootRef}
113
+ onFocusCapture={props.onFocusCapture}
114
+ onBlurCapture={props.onBlurCapture}
115
+ className="flex flex-col gap-1.5"
116
+ >
117
+ {props.contextAnalytics ? (
118
+ <TwContextAnalyticsSummary
119
+ snapshot={props.contextAnalytics}
120
+ compact
121
+ testId="selection-context-analytics"
122
+ />
123
+ ) : null}
124
+ {toolContent}
125
+ </div>
126
+ ) : null;
127
+ const wrappedContent = content && supportsTopMenuControls ? (
128
+ <div className="flex flex-col gap-1">
129
+ <div className="inline-flex items-center gap-1.5 self-center rounded-lg border border-border/70 bg-canvas/94 px-1.5 py-1 shadow-[0_8px_20px_-18px_var(--color-shadow-strong)]">
130
+ <button
131
+ type="button"
132
+ aria-label={isDetached ? "Drag floating menu" : "Drag to float menu"}
133
+ data-testid="selection-tool-drag-handle"
134
+ className="inline-flex h-6 items-center justify-center rounded-md border border-transparent px-1.5 text-tertiary transition-colors hover:border-border/60 hover:bg-surface hover:text-primary"
135
+ onMouseDown={(event) => {
136
+ preserveEditorSelectionMouseDown(event);
137
+ setIsDetached(true);
138
+ dragStateRef.current = {
139
+ startX: event.clientX,
140
+ startY: event.clientY,
141
+ originX: isDetached ? detachedOffset.x : 0,
142
+ originY: isDetached ? detachedOffset.y : 0,
143
+ };
144
+ }}
145
+ >
146
+ <GripHorizontal className="h-3 w-3" />
147
+ </button>
148
+ <span className="text-[9px] font-semibold uppercase tracking-[0.12em] text-tertiary">
149
+ {getTopMenuLabel(props.tool.kind)}
150
+ </span>
151
+ <span className="rounded-full bg-surface px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-[0.08em] text-secondary">
152
+ {isDetached ? "Floating" : "Docked"}
153
+ </span>
154
+ <button
155
+ type="button"
156
+ aria-label={isDetached ? "Dock menu" : "Float menu"}
157
+ aria-pressed={isDetached}
158
+ data-testid="selection-tool-attach-toggle"
159
+ className="inline-flex h-6 items-center rounded-md border border-border/60 px-2 text-[10px] font-medium text-secondary transition-colors hover:bg-surface hover:text-primary"
160
+ onMouseDown={preserveEditorSelectionMouseDown}
161
+ onClick={() => {
162
+ setIsDetached((current) => !current);
163
+ }}
164
+ >
165
+ {isDetached ? "Dock menu" : "Float menu"}
166
+ </button>
167
+ </div>
168
+ {content}
169
+ </div>
170
+ ) : content;
171
+
172
+ if (!wrappedContent) {
173
+ return null;
174
+ }
175
+
176
+ if (isDetached) {
177
+ return (
178
+ <div className="pointer-events-none absolute inset-0 z-20" data-testid={overlayTestId}>
179
+ <div
180
+ className="pointer-events-auto absolute"
181
+ data-placement="detached"
182
+ style={{
183
+ left: `calc(50% + ${detachedOffset.x}px)`,
184
+ top: `${12 + detachedOffset.y}px`,
185
+ transform: "translateX(-50%)",
186
+ }}
187
+ >
188
+ {wrappedContent}
189
+ </div>
190
+ </div>
191
+ );
192
+ }
193
+
194
+ if (props.placement) {
195
+ return (
196
+ <div className="pointer-events-none absolute inset-0 z-20" data-testid={overlayTestId}>
197
+ <div
198
+ className="pointer-events-auto absolute"
199
+ data-placement={props.placement.placement}
200
+ style={props.placement.style}
201
+ >
202
+ {wrappedContent}
203
+ </div>
204
+ </div>
205
+ );
206
+ }
207
+
208
+ return (
209
+ <div
210
+ className="pointer-events-none absolute inset-x-0 top-0 z-20 flex justify-center px-4 pt-3"
211
+ data-testid={overlayTestId}
212
+ >
213
+ <div className="pointer-events-auto" data-placement="fallback">
214
+ {wrappedContent}
215
+ </div>
216
+ </div>
217
+ );
218
+ }
219
+
220
+ function renderTool(
221
+ props: TwSelectionToolHostProps,
222
+ tool: ActiveSelectionToolModel,
223
+ ): React.ReactNode {
224
+ switch (tool.kind) {
225
+ case "formatting-inline":
226
+ return (
227
+ <TwSelectionToolFormatting
228
+ model={tool}
229
+ onToggleBold={props.onToggleBold}
230
+ onToggleItalic={props.onToggleItalic}
231
+ onToggleUnderline={props.onToggleUnderline}
232
+ onSetTextColor={props.onSetTextColor}
233
+ onSetHighlightColor={props.onSetHighlightColor}
234
+ onAddComment={props.onAddComment}
235
+ />
236
+ );
237
+ case "suggestion-review":
238
+ return (
239
+ <TwSelectionToolSuggestion
240
+ model={tool}
241
+ onAccept={props.onAcceptSuggestion}
242
+ onReject={props.onRejectSuggestion}
243
+ onEditSuggestion={props.onEditSuggestion}
244
+ onAddComment={props.onAddComment}
245
+ />
246
+ );
247
+ case "structure-context":
248
+ return (
249
+ <TwSelectionToolStructure
250
+ model={tool}
251
+ onSetTableStyle={props.onSetTableStyle}
252
+ onAddRowBefore={props.onAddRowBefore}
253
+ onAddRowAfter={props.onAddRowAfter}
254
+ onAddColumnBefore={props.onAddColumnBefore}
255
+ onAddColumnAfter={props.onAddColumnAfter}
256
+ onDeleteRow={props.onDeleteRow}
257
+ onDeleteColumn={props.onDeleteColumn}
258
+ onDeleteTable={props.onDeleteTable}
259
+ onMergeCells={props.onMergeCells}
260
+ onSplitCell={props.onSplitCell}
261
+ onSetCellBackground={props.onSetCellBackground}
262
+ onSetImageLayout={props.onSetImageLayout}
263
+ onSetImageFrame={props.onSetImageFrame}
264
+ onRestartNumbering={props.onRestartNumbering}
265
+ onContinueNumbering={props.onContinueNumbering}
266
+ />
267
+ );
268
+ case "comment-thread":
269
+ return <TwSelectionToolComment model={tool} onAddComment={props.onAddComment} />;
270
+ case "workflow-task":
271
+ return <TwSelectionToolWorkflow model={tool} />;
272
+ case "blocked-explainer":
273
+ return <TwSelectionToolBlocked model={tool} />;
274
+ }
275
+ }
276
+
277
+ function getOverlayTestId(kind: ActiveSelectionToolModel["kind"], hasPlacement: boolean): string {
278
+ switch (kind) {
279
+ case "suggestion-review":
280
+ return hasPlacement ? "suggestion-card-overlay" : "suggestion-card-fallback";
281
+ case "formatting-inline":
282
+ return hasPlacement ? "selection-toolbar-overlay" : "selection-toolbar-fallback";
283
+ default:
284
+ return hasPlacement ? "selection-tool-overlay" : "selection-tool-fallback";
285
+ }
286
+ }
287
+
288
+ function isTopMenuKind(kind: ActiveSelectionToolModel["kind"]): boolean {
289
+ return kind === "formatting-inline" || kind === "suggestion-review" || kind === "workflow-task";
290
+ }
291
+
292
+ function getTopMenuLabel(kind: ActiveSelectionToolModel["kind"]): string {
293
+ switch (kind) {
294
+ case "formatting-inline":
295
+ return "Formatting";
296
+ case "suggestion-review":
297
+ return "Suggestion";
298
+ case "workflow-task":
299
+ return "Workflow";
300
+ default:
301
+ return "Menu";
302
+ }
303
+ }
@@ -0,0 +1,116 @@
1
+ import React from "react";
2
+
3
+ import type { StructureContextSelectionToolModel } from "../../ui/headless/selection-tool-types";
4
+ import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
5
+ import { TwImageContextToolbar } from "./tw-image-context-toolbar";
6
+ import { TwObjectContextToolbar } from "./tw-object-context-toolbar";
7
+ import { TwTableContextToolbar } from "./tw-table-context-toolbar";
8
+
9
+ export interface TwSelectionToolStructureProps {
10
+ model: StructureContextSelectionToolModel;
11
+ onSetTableStyle?: (styleId: string) => void;
12
+ onAddRowBefore?: () => void;
13
+ onAddRowAfter?: () => void;
14
+ onAddColumnBefore?: () => void;
15
+ onAddColumnAfter?: () => void;
16
+ onDeleteRow?: () => void;
17
+ onDeleteColumn?: () => void;
18
+ onDeleteTable?: () => void;
19
+ onMergeCells?: () => void;
20
+ onSplitCell?: () => void;
21
+ onSetCellBackground?: (color: string) => void;
22
+ onSetImageLayout?: (
23
+ mediaId: string,
24
+ dimensions: { widthEmu: number; heightEmu: number },
25
+ ) => void;
26
+ onSetImageFrame?: (
27
+ mediaId: string,
28
+ offsets: { horizontalOffsetEmu?: number; verticalOffsetEmu?: number },
29
+ ) => void;
30
+ onRestartNumbering?: () => void;
31
+ onContinueNumbering?: () => void;
32
+ }
33
+
34
+ export function TwSelectionToolStructure(props: TwSelectionToolStructureProps) {
35
+ switch (props.model.structureKind) {
36
+ case "image":
37
+ return props.model.activeImage ? (
38
+ <TwImageContextToolbar
39
+ activeImage={props.model.activeImage}
40
+ disabled={!props.model.canMutate}
41
+ onSetImageLayout={props.onSetImageLayout}
42
+ onSetImageFrame={props.onSetImageFrame}
43
+ />
44
+ ) : null;
45
+ case "object":
46
+ // Shapes and text boxes are shipped as informational-only structure tools
47
+ // until there is a real runtime-backed object mutation path.
48
+ return props.model.activeObject ? (
49
+ <TwObjectContextToolbar activeObject={props.model.activeObject} />
50
+ ) : null;
51
+ case "table":
52
+ return (
53
+ <TwTableContextToolbar
54
+ disabled={!props.model.canMutate}
55
+ tableContext={props.model.activeTable ?? null}
56
+ tableStyles={props.model.tableStyles ?? []}
57
+ onSetTableStyle={props.onSetTableStyle}
58
+ onAddRowBefore={props.onAddRowBefore}
59
+ onAddRowAfter={props.onAddRowAfter}
60
+ onAddColumnBefore={props.onAddColumnBefore}
61
+ onAddColumnAfter={props.onAddColumnAfter}
62
+ onDeleteRow={props.onDeleteRow}
63
+ onDeleteColumn={props.onDeleteColumn}
64
+ onDeleteTable={props.onDeleteTable}
65
+ onMergeCells={props.onMergeCells}
66
+ onSplitCell={props.onSplitCell}
67
+ onSetCellBackground={props.onSetCellBackground}
68
+ />
69
+ );
70
+ case "list":
71
+ return (
72
+ <div
73
+ data-testid="list-context-toolbar"
74
+ className="flex flex-wrap items-center gap-1.5 rounded-lg border border-border bg-canvas px-2.5 py-1.5 shadow-sm"
75
+ >
76
+ <span className="text-[9px] font-semibold uppercase tracking-[0.12em] text-tertiary">
77
+ List
78
+ </span>
79
+ <ToolbarButton
80
+ ariaLabel="Continue numbering"
81
+ disabled={!props.model.canMutate || !props.onContinueNumbering}
82
+ onClick={props.onContinueNumbering}
83
+ >
84
+ Continue
85
+ </ToolbarButton>
86
+ <ToolbarButton
87
+ ariaLabel="Restart numbering"
88
+ disabled={!props.model.canMutate || !props.onRestartNumbering}
89
+ onClick={props.onRestartNumbering}
90
+ >
91
+ Restart
92
+ </ToolbarButton>
93
+ </div>
94
+ );
95
+ }
96
+ }
97
+
98
+ function ToolbarButton(props: {
99
+ ariaLabel: string;
100
+ disabled: boolean;
101
+ onClick?: () => void;
102
+ children: React.ReactNode;
103
+ }) {
104
+ return (
105
+ <button
106
+ type="button"
107
+ aria-label={props.ariaLabel}
108
+ disabled={props.disabled}
109
+ onMouseDown={preserveEditorSelectionMouseDown}
110
+ onClick={props.onClick}
111
+ className="inline-flex h-7 items-center rounded-md border border-border px-2 text-[11px] font-medium text-secondary transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-40"
112
+ >
113
+ {props.children}
114
+ </button>
115
+ );
116
+ }
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import type { FocusEventHandler } from "react";
3
+
4
+ import type { SuggestionReviewSelectionToolModel } from "../../ui/headless/selection-tool-types";
5
+ import { TwSuggestionCard } from "./tw-suggestion-card";
6
+
7
+ export interface TwSelectionToolSuggestionProps {
8
+ model: SuggestionReviewSelectionToolModel;
9
+ onFocusCapture?: FocusEventHandler<HTMLDivElement>;
10
+ onBlurCapture?: FocusEventHandler<HTMLDivElement>;
11
+ onAccept?: () => void;
12
+ onReject?: () => void;
13
+ onEditSuggestion?: () => void;
14
+ onAddComment?: () => void;
15
+ }
16
+
17
+ export function TwSelectionToolSuggestion(props: TwSelectionToolSuggestionProps) {
18
+ return (
19
+ <TwSuggestionCard
20
+ model={props.model}
21
+ onFocusCapture={props.onFocusCapture}
22
+ onBlurCapture={props.onBlurCapture}
23
+ onAccept={props.onAccept}
24
+ onReject={props.onReject}
25
+ onEditSuggestion={props.onEditSuggestion}
26
+ onAddComment={props.onAddComment}
27
+ />
28
+ );
29
+ }
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+
3
+ import type { WorkflowTaskSelectionToolModel } from "../../ui/headless/selection-tool-types";
4
+
5
+ export interface TwSelectionToolWorkflowProps {
6
+ model: WorkflowTaskSelectionToolModel;
7
+ }
8
+
9
+ export function TwSelectionToolWorkflow(props: TwSelectionToolWorkflowProps) {
10
+ return (
11
+ <div
12
+ data-testid="workflow-task-selection-tool"
13
+ className="max-w-[min(20rem,calc(100vw-1.5rem))] rounded-lg border border-border bg-canvas px-2.5 py-1.5 shadow-md"
14
+ >
15
+ <div className="text-[9px] font-semibold uppercase tracking-[0.12em] text-tertiary">
16
+ Workflow task
17
+ </div>
18
+ <div className="mt-0.5 text-[13px] text-primary">{props.model.workflowTitle ?? "Scoped task"}</div>
19
+ {props.model.workflowDetail ? (
20
+ <div className="mt-0.5 text-[11px] text-secondary">{props.model.workflowDetail}</div>
21
+ ) : null}
22
+ {props.model.disabledReason ? (
23
+ <div className="mt-1 text-[11px] text-tertiary">{props.model.disabledReason}</div>
24
+ ) : null}
25
+ </div>
26
+ );
27
+ }
@@ -0,0 +1,186 @@
1
+ import React, { forwardRef } from "react";
2
+ import type { FocusEventHandler } from "react";
3
+ import * as Tooltip from "@radix-ui/react-tooltip";
4
+ import { Baseline, Bold, Highlighter, Italic, MessageSquare, Underline } from "lucide-react";
5
+
6
+ import type { SelectionToolbarModel } from "../../ui/headless/selection-toolbar-model";
7
+ import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
8
+
9
+ export interface TwSelectionToolbarProps {
10
+ model: SelectionToolbarModel;
11
+ disabledReason?: string;
12
+ onFocusCapture?: FocusEventHandler<HTMLDivElement>;
13
+ onBlurCapture?: FocusEventHandler<HTMLDivElement>;
14
+ onToggleBold?: () => void;
15
+ onToggleItalic?: () => void;
16
+ onToggleUnderline?: () => void;
17
+ onSetTextColor?: (color: string) => void;
18
+ onSetHighlightColor?: (color: string | null) => void;
19
+ onAddComment?: () => void;
20
+ }
21
+
22
+ const focusRingClass =
23
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-canvas";
24
+
25
+ export const TwSelectionToolbar = forwardRef<HTMLDivElement, TwSelectionToolbarProps>(function TwSelectionToolbar(props, ref) {
26
+ const { model } = props;
27
+ const addCommentDisabled = !model.canAddComment;
28
+ const formattingDisabled = !model.canToggleFormatting;
29
+ const contextLabel = summarizeSelectionContext(model);
30
+ const tooltipLabel = addCommentDisabled
31
+ ? props.disabledReason ?? "Select text within one paragraph to add a DOCX comment"
32
+ : "Add comment";
33
+
34
+ return (
35
+ <div
36
+ ref={ref}
37
+ data-testid="selection-toolbar"
38
+ className="inline-flex max-w-[min(22rem,calc(100vw-1.5rem))] items-center gap-1 rounded-lg border border-border/80 bg-canvas px-1 py-1 shadow-md ring-1 ring-border/70"
39
+ role="toolbar"
40
+ aria-label="Selection actions"
41
+ onFocusCapture={props.onFocusCapture}
42
+ onBlurCapture={props.onBlurCapture}
43
+ >
44
+ <ToolbarActionButton
45
+ icon={<Bold className="h-3.5 w-3.5" />}
46
+ label="Bold selection"
47
+ pressed={model.boldActive}
48
+ disabled={formattingDisabled}
49
+ onClick={props.onToggleBold}
50
+ />
51
+ <ToolbarActionButton
52
+ icon={<Italic className="h-3.5 w-3.5" />}
53
+ label="Italic selection"
54
+ pressed={model.italicActive}
55
+ disabled={formattingDisabled}
56
+ onClick={props.onToggleItalic}
57
+ />
58
+ <ToolbarActionButton
59
+ icon={<Underline className="h-3.5 w-3.5" />}
60
+ label="Underline selection"
61
+ pressed={model.underlineActive}
62
+ disabled={formattingDisabled}
63
+ onClick={props.onToggleUnderline}
64
+ />
65
+ <ToolbarActionButton
66
+ icon={<Baseline className="h-3.5 w-3.5" />}
67
+ label="Text color blue"
68
+ pressed={false}
69
+ disabled={formattingDisabled}
70
+ onClick={() => props.onSetTextColor?.("#1660a8")}
71
+ />
72
+ <ToolbarActionButton
73
+ icon={<Highlighter className="h-3.5 w-3.5" />}
74
+ label="Highlight yellow"
75
+ pressed={false}
76
+ disabled={formattingDisabled}
77
+ onClick={() => props.onSetHighlightColor?.("#ffff00")}
78
+ />
79
+
80
+ <div className="mx-0.5 h-4 w-px bg-border" />
81
+
82
+ <Tooltip.Root>
83
+ <Tooltip.Trigger asChild>
84
+ <button
85
+ type="button"
86
+ aria-label="Add comment from selection"
87
+ disabled={addCommentDisabled}
88
+ onMouseDown={preserveEditorSelectionMouseDown}
89
+ onClick={props.onAddComment}
90
+ className={`inline-flex h-6 w-6 items-center justify-center rounded-md transition-colors text-accent hover:bg-surface disabled:cursor-not-allowed disabled:opacity-30 ${focusRingClass}`}
91
+ >
92
+ <MessageSquare className="h-3 w-3" />
93
+ </button>
94
+ </Tooltip.Trigger>
95
+ <Tooltip.Portal>
96
+ <Tooltip.Content
97
+ className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50"
98
+ sideOffset={6}
99
+ >
100
+ {tooltipLabel}
101
+ </Tooltip.Content>
102
+ </Tooltip.Portal>
103
+ </Tooltip.Root>
104
+
105
+ {model.previewText ? (
106
+ <>
107
+ <div className="mx-0.5 h-4 w-px bg-border" />
108
+ <span className="max-w-[7rem] truncate text-[10px] text-secondary">
109
+ {model.previewText}
110
+ </span>
111
+ </>
112
+ ) : null}
113
+
114
+ {contextLabel ? (
115
+ <>
116
+ {!model.previewText ? <div className="mx-0.5 h-4 w-px bg-border" /> : null}
117
+ <span
118
+ className={`min-w-0 max-w-[9rem] truncate rounded-full px-1.5 py-0.5 text-[9px] font-medium tracking-[0.08em] ${
119
+ model.badges.some((badge) => badge.tone === "accent")
120
+ ? "bg-canvas text-accent ring-1 ring-accent/25"
121
+ : "bg-surface text-tertiary"
122
+ }`}
123
+ >
124
+ {contextLabel}
125
+ </span>
126
+ </>
127
+ ) : null}
128
+ </div>
129
+ );
130
+ });
131
+
132
+ function summarizeSelectionContext(model: SelectionToolbarModel): string | null {
133
+ if (model.badges.length === 0) {
134
+ return null;
135
+ }
136
+
137
+ const accentBadges = model.badges.filter((badge) => badge.tone === "accent");
138
+ const source = accentBadges.length > 0 ? accentBadges : model.badges;
139
+ const labels = source.slice(0, 2).map((badge) => badge.label.trim()).filter(Boolean);
140
+ if (labels.length === 0) {
141
+ return null;
142
+ }
143
+
144
+ const summary = labels.join(" · ");
145
+ return summary.length > 30 ? `${summary.slice(0, 27)}...` : summary;
146
+ }
147
+
148
+ interface ToolbarActionButtonProps {
149
+ icon: React.ReactNode;
150
+ label: string;
151
+ pressed: boolean;
152
+ disabled: boolean;
153
+ onClick?: () => void;
154
+ }
155
+
156
+ function ToolbarActionButton(props: ToolbarActionButtonProps) {
157
+ return (
158
+ <Tooltip.Root>
159
+ <Tooltip.Trigger asChild>
160
+ <button
161
+ type="button"
162
+ aria-label={props.label}
163
+ aria-pressed={props.pressed}
164
+ disabled={props.disabled}
165
+ onMouseDown={preserveEditorSelectionMouseDown}
166
+ onClick={props.onClick}
167
+ className={`inline-flex h-6 w-6 items-center justify-center rounded-md transition-colors disabled:cursor-not-allowed disabled:opacity-30 ${
168
+ props.pressed
169
+ ? "bg-canvas text-accent ring-1 ring-accent/30 shadow-sm"
170
+ : "text-secondary hover:bg-surface"
171
+ } ${focusRingClass}`}
172
+ >
173
+ {props.icon}
174
+ </button>
175
+ </Tooltip.Trigger>
176
+ <Tooltip.Portal>
177
+ <Tooltip.Content
178
+ className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50"
179
+ sideOffset={6}
180
+ >
181
+ {props.label}
182
+ </Tooltip.Content>
183
+ </Tooltip.Portal>
184
+ </Tooltip.Root>
185
+ );
186
+ }