@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,869 @@
1
+ import { createSelectionSnapshot, type CanonicalDocumentEnvelope, type SelectionSnapshot } from "./editor-state.ts";
2
+ import type { TransactionMapping } from "../selection/mapping.ts";
3
+ import {
4
+ cloneParagraphProperties,
5
+ cloneStoryUnit,
6
+ createPlainText,
7
+ parseTextStory,
8
+ serializeTextStory,
9
+ type ParagraphProperties,
10
+ type StoryUnit,
11
+ type TextStory,
12
+ } from "../schema/text-schema.ts";
13
+ import { createEditorSurfaceSnapshot } from "../../runtime/surface-projection.ts";
14
+ import type { DocumentRootNode, ParagraphNode, SdtNode, TableNode } from "../../model/canonical-document.ts";
15
+
16
+ export type TextInsertion =
17
+ | {
18
+ type: "text";
19
+ text: string;
20
+ }
21
+ | {
22
+ type: "tab";
23
+ }
24
+ | {
25
+ type: "hard_break";
26
+ }
27
+ | {
28
+ type: "paragraph_break";
29
+ };
30
+
31
+ export type TextTransactionIntent =
32
+ | {
33
+ type: "replace";
34
+ range?: {
35
+ from: number;
36
+ to: number;
37
+ };
38
+ insertion: TextInsertion[];
39
+ }
40
+ | {
41
+ type: "delete_backward";
42
+ }
43
+ | {
44
+ type: "delete_forward";
45
+ };
46
+
47
+ export interface TextTransactionResult {
48
+ document: CanonicalDocumentEnvelope;
49
+ selection: SelectionSnapshot;
50
+ mapping: TransactionMapping;
51
+ storyText: string;
52
+ }
53
+
54
+ export class TextTransactionError extends Error {
55
+ readonly code: "invalid_selection" | "unsupported_content";
56
+
57
+ constructor(
58
+ code: TextTransactionError["code"],
59
+ message: string,
60
+ ) {
61
+ super(message);
62
+ this.name = "TextTransactionError";
63
+ this.code = code;
64
+ }
65
+ }
66
+
67
+ export function applyTextTransaction(
68
+ document: CanonicalDocumentEnvelope,
69
+ selection: SelectionSnapshot,
70
+ intent: TextTransactionIntent,
71
+ options: {
72
+ timestamp: string;
73
+ },
74
+ ): TextTransactionResult {
75
+ const topLevelParagraphResult = tryApplyTopLevelParagraphTransaction(
76
+ document,
77
+ selection,
78
+ intent,
79
+ options,
80
+ );
81
+ if (topLevelParagraphResult) {
82
+ return topLevelParagraphResult;
83
+ }
84
+
85
+ const sdtScopedResult = tryApplyTopLevelSdtParagraphTransaction(
86
+ document,
87
+ selection,
88
+ intent,
89
+ options,
90
+ );
91
+ if (sdtScopedResult) {
92
+ return sdtScopedResult;
93
+ }
94
+
95
+ const tableScopedResult = tryApplyTableParagraphTransaction(
96
+ document,
97
+ selection,
98
+ intent,
99
+ options,
100
+ );
101
+ if (tableScopedResult) {
102
+ return tableScopedResult;
103
+ }
104
+
105
+ return applyLinearTextTransaction(document, selection, intent, options);
106
+ }
107
+
108
+ function applyLinearTextTransaction(
109
+ document: CanonicalDocumentEnvelope,
110
+ selection: SelectionSnapshot,
111
+ intent: TextTransactionIntent,
112
+ options: {
113
+ timestamp: string;
114
+ },
115
+ ): TextTransactionResult {
116
+ const story = parseTextStory(document.content);
117
+ const normalizedRange = resolveRange(selection, story.size, intent);
118
+ const insertionUnits = createInsertionUnits(intent, story, normalizedRange.from);
119
+
120
+ ensureEditableRange(story.units.slice(normalizedRange.from, normalizedRange.to));
121
+
122
+ const nextUnits = [
123
+ ...story.units.slice(0, normalizedRange.from).map(cloneStoryUnit),
124
+ ...insertionUnits.map(cloneStoryUnit),
125
+ ...story.units.slice(normalizedRange.to).map(cloneStoryUnit),
126
+ ];
127
+
128
+ const nextStory: TextStory = {
129
+ firstParagraph: cloneParagraphProperties(story.firstParagraph),
130
+ units: normalizeStoryUnits(nextUnits),
131
+ size: 0,
132
+ };
133
+ nextStory.size = nextStory.units.length;
134
+
135
+ const caret = normalizedRange.from + insertionUnits.length;
136
+
137
+ return {
138
+ document: {
139
+ ...document,
140
+ updatedAt: options.timestamp,
141
+ content: serializeTextStory(nextStory),
142
+ },
143
+ selection: createSelectionSnapshot(caret, caret),
144
+ mapping: {
145
+ steps: [
146
+ {
147
+ from: normalizedRange.from,
148
+ to: normalizedRange.to,
149
+ insertSize: insertionUnits.length,
150
+ },
151
+ ],
152
+ metadata: {
153
+ affectsComments: true,
154
+ affectsRevisions: true,
155
+ ...(containsParagraphBoundaryChange(story, normalizedRange, insertionUnits)
156
+ ? { invalidatesStructures: true }
157
+ : {}),
158
+ },
159
+ },
160
+ storyText: createPlainText(nextStory),
161
+ };
162
+ }
163
+
164
+ function tryApplyTableParagraphTransaction(
165
+ document: CanonicalDocumentEnvelope,
166
+ selection: SelectionSnapshot,
167
+ intent: TextTransactionIntent,
168
+ options: {
169
+ timestamp: string;
170
+ },
171
+ ): TextTransactionResult | null {
172
+ const scope = resolveTableParagraphScope(document, selection);
173
+ if (!scope) {
174
+ return null;
175
+ }
176
+ if (scope === "unsupported") {
177
+ throw new TextTransactionError(
178
+ "unsupported_content",
179
+ "Text transactions inside table structures are only supported when the selection stays within one paragraph-backed table cell.",
180
+ );
181
+ }
182
+ const localDocument: CanonicalDocumentEnvelope = {
183
+ ...document,
184
+ content: {
185
+ type: "doc",
186
+ children: [scope.paragraph],
187
+ },
188
+ };
189
+ const localSelection = createSelectionSnapshot(
190
+ selection.anchor - scope.paragraphStart,
191
+ selection.head - scope.paragraphStart,
192
+ );
193
+ const localResult = applyLinearTextTransaction(
194
+ localDocument,
195
+ localSelection,
196
+ localizeTextTransactionIntent(intent, scope.paragraphStart),
197
+ options,
198
+ );
199
+ const nextParagraphBlocks = (localResult.document.content as DocumentRootNode).children;
200
+ const nextRoot: DocumentRootNode = {
201
+ ...scope.root,
202
+ children: scope.root.children.map((child, blockIndex) => {
203
+ if (blockIndex !== scope.tableBlockIndex) {
204
+ return child;
205
+ }
206
+
207
+ const table = child as TableNode;
208
+ return {
209
+ ...table,
210
+ rows: table.rows.map((row, rowIndex) => {
211
+ if (rowIndex !== scope.rowIndex) {
212
+ return row;
213
+ }
214
+
215
+ return {
216
+ ...row,
217
+ cells: row.cells.map((cell, cellIndex) => {
218
+ if (cellIndex !== scope.cellIndex) {
219
+ return cell;
220
+ }
221
+
222
+ return {
223
+ ...cell,
224
+ children: [
225
+ ...cell.children.slice(0, scope.childIndex),
226
+ ...nextParagraphBlocks,
227
+ ...cell.children.slice(scope.childIndex + 1),
228
+ ],
229
+ };
230
+ }),
231
+ };
232
+ }),
233
+ };
234
+ }),
235
+ };
236
+
237
+ return {
238
+ document: {
239
+ ...document,
240
+ updatedAt: options.timestamp,
241
+ content: nextRoot,
242
+ },
243
+ selection: createSelectionSnapshot(
244
+ localResult.selection.anchor + scope.paragraphStart,
245
+ localResult.selection.head + scope.paragraphStart,
246
+ ),
247
+ mapping: {
248
+ ...localResult.mapping,
249
+ steps: localResult.mapping.steps.map((step) => ({
250
+ ...step,
251
+ from: step.from + scope.paragraphStart,
252
+ to: step.to + scope.paragraphStart,
253
+ })),
254
+ },
255
+ storyText: localResult.storyText,
256
+ };
257
+ }
258
+
259
+ function tryApplyTopLevelSdtParagraphTransaction(
260
+ document: CanonicalDocumentEnvelope,
261
+ selection: SelectionSnapshot,
262
+ intent: TextTransactionIntent,
263
+ options: {
264
+ timestamp: string;
265
+ },
266
+ ): TextTransactionResult | null {
267
+ const scope = resolveTopLevelSdtParagraphScope(document, selection);
268
+ if (!scope) {
269
+ return null;
270
+ }
271
+
272
+ const localDocument: CanonicalDocumentEnvelope = {
273
+ ...document,
274
+ content: {
275
+ type: "doc",
276
+ children: [scope.paragraph],
277
+ },
278
+ };
279
+ const localSelection = createSelectionSnapshot(
280
+ selection.anchor - scope.paragraphStart,
281
+ selection.head - scope.paragraphStart,
282
+ );
283
+ const localResult = applyLinearTextTransaction(
284
+ localDocument,
285
+ localSelection,
286
+ localizeTextTransactionIntent(intent, scope.paragraphStart),
287
+ options,
288
+ );
289
+ const nextParagraphBlocks = (localResult.document.content as DocumentRootNode).children;
290
+ const nextRoot: DocumentRootNode = {
291
+ ...scope.root,
292
+ children: scope.root.children.map((child, blockIndex) => {
293
+ if (blockIndex !== scope.blockIndex) {
294
+ return child;
295
+ }
296
+ return replaceParagraphInSdt(child as SdtNode, scope.childPath, nextParagraphBlocks);
297
+ }),
298
+ };
299
+
300
+ return {
301
+ document: {
302
+ ...document,
303
+ updatedAt: options.timestamp,
304
+ content: nextRoot,
305
+ },
306
+ selection: createSelectionSnapshot(
307
+ localResult.selection.anchor + scope.paragraphStart,
308
+ localResult.selection.head + scope.paragraphStart,
309
+ ),
310
+ mapping: {
311
+ ...localResult.mapping,
312
+ steps: localResult.mapping.steps.map((step) => ({
313
+ ...step,
314
+ from: step.from + scope.paragraphStart,
315
+ to: step.to + scope.paragraphStart,
316
+ })),
317
+ },
318
+ storyText: localResult.storyText,
319
+ };
320
+ }
321
+
322
+ function tryApplyTopLevelParagraphTransaction(
323
+ document: CanonicalDocumentEnvelope,
324
+ selection: SelectionSnapshot,
325
+ intent: TextTransactionIntent,
326
+ options: {
327
+ timestamp: string;
328
+ },
329
+ ): TextTransactionResult | null {
330
+ const scope = resolveTopLevelParagraphScope(document, selection);
331
+ if (!scope) {
332
+ return null;
333
+ }
334
+ if (
335
+ selection.isCollapsed &&
336
+ ((intent.type === "delete_backward" && selection.anchor === scope.paragraphStart) ||
337
+ (intent.type === "delete_forward" && selection.anchor === scope.paragraphEnd))
338
+ ) {
339
+ return null;
340
+ }
341
+
342
+ const localDocument: CanonicalDocumentEnvelope = {
343
+ ...document,
344
+ content: {
345
+ type: "doc",
346
+ children: [scope.paragraph],
347
+ },
348
+ };
349
+ const localSelection = createSelectionSnapshot(
350
+ selection.anchor - scope.paragraphStart,
351
+ selection.head - scope.paragraphStart,
352
+ );
353
+ const localResult = applyLinearTextTransaction(
354
+ localDocument,
355
+ localSelection,
356
+ localizeTextTransactionIntent(intent, scope.paragraphStart),
357
+ options,
358
+ );
359
+ const nextParagraphBlocks = (localResult.document.content as DocumentRootNode).children;
360
+ const nextRoot: DocumentRootNode = {
361
+ ...scope.root,
362
+ children: [
363
+ ...scope.root.children.slice(0, scope.blockIndex),
364
+ ...nextParagraphBlocks,
365
+ ...scope.root.children.slice(scope.blockIndex + 1),
366
+ ],
367
+ };
368
+
369
+ return {
370
+ document: {
371
+ ...document,
372
+ updatedAt: options.timestamp,
373
+ content: nextRoot,
374
+ },
375
+ selection: createSelectionSnapshot(
376
+ localResult.selection.anchor + scope.paragraphStart,
377
+ localResult.selection.head + scope.paragraphStart,
378
+ ),
379
+ mapping: {
380
+ ...localResult.mapping,
381
+ steps: localResult.mapping.steps.map((step) => ({
382
+ ...step,
383
+ from: step.from + scope.paragraphStart,
384
+ to: step.to + scope.paragraphStart,
385
+ })),
386
+ },
387
+ storyText: localResult.storyText,
388
+ };
389
+ }
390
+
391
+ function resolveTableParagraphScope(
392
+ document: CanonicalDocumentEnvelope,
393
+ selection: SelectionSnapshot,
394
+ ):
395
+ | {
396
+ root: DocumentRootNode;
397
+ tableBlockIndex: number;
398
+ rowIndex: number;
399
+ cellIndex: number;
400
+ childIndex: number;
401
+ paragraph: ParagraphNode;
402
+ paragraphStart: number;
403
+ }
404
+ | "unsupported"
405
+ | null {
406
+ const root = document.content as DocumentRootNode;
407
+ if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
408
+ return null;
409
+ }
410
+
411
+ const surface = createEditorSurfaceSnapshot(document, selection);
412
+ const selectionFrom = Math.min(selection.anchor, selection.head);
413
+ const selectionTo = Math.max(selection.anchor, selection.head);
414
+
415
+ for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
416
+ const block = root.children[blockIndex];
417
+ const surfaceBlock = surface.blocks[blockIndex];
418
+ if (block?.type !== "table" || surfaceBlock?.kind !== "table") {
419
+ continue;
420
+ }
421
+
422
+ const insideTable = selectionFallsWithinSurfaceRange(
423
+ selectionFrom,
424
+ selectionTo,
425
+ surfaceBlock.from,
426
+ surfaceBlock.to,
427
+ );
428
+ if (!insideTable) {
429
+ continue;
430
+ }
431
+
432
+ for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
433
+ const row = block.rows[rowIndex];
434
+ const surfaceRow = surfaceBlock.rows[rowIndex];
435
+ if (!row || !surfaceRow) {
436
+ continue;
437
+ }
438
+
439
+ for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex += 1) {
440
+ const cell = row.cells[cellIndex];
441
+ const surfaceCell = surfaceRow.cells[cellIndex];
442
+ if (!cell || !surfaceCell) {
443
+ continue;
444
+ }
445
+
446
+ for (
447
+ let childIndex = 0;
448
+ childIndex < Math.min(cell.children.length, surfaceCell.content.length);
449
+ childIndex += 1
450
+ ) {
451
+ const child = cell.children[childIndex];
452
+ const surfaceChild = surfaceCell.content[childIndex];
453
+ if (child?.type !== "paragraph" || surfaceChild?.kind !== "paragraph") {
454
+ continue;
455
+ }
456
+
457
+ const insideParagraph = selectionFallsWithinSurfaceRange(
458
+ selectionFrom,
459
+ selectionTo,
460
+ surfaceChild.from,
461
+ surfaceChild.to,
462
+ );
463
+ if (!insideParagraph) {
464
+ continue;
465
+ }
466
+
467
+ return {
468
+ root,
469
+ tableBlockIndex: blockIndex,
470
+ rowIndex,
471
+ cellIndex,
472
+ childIndex,
473
+ paragraph: child,
474
+ paragraphStart: surfaceChild.from,
475
+ };
476
+ }
477
+ }
478
+ }
479
+
480
+ return "unsupported";
481
+ }
482
+
483
+ return null;
484
+ }
485
+
486
+ function resolveTopLevelParagraphScope(
487
+ document: CanonicalDocumentEnvelope,
488
+ selection: SelectionSnapshot,
489
+ ):
490
+ | {
491
+ root: DocumentRootNode;
492
+ blockIndex: number;
493
+ paragraph: ParagraphNode;
494
+ paragraphStart: number;
495
+ paragraphEnd: number;
496
+ }
497
+ | null {
498
+ const root = document.content as DocumentRootNode;
499
+ if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
500
+ return null;
501
+ }
502
+
503
+ const surface = createEditorSurfaceSnapshot(document, selection);
504
+ const selectionFrom = Math.min(selection.anchor, selection.head);
505
+ const selectionTo = Math.max(selection.anchor, selection.head);
506
+
507
+ for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
508
+ const block = root.children[blockIndex];
509
+ const surfaceBlock = surface.blocks[blockIndex];
510
+ if (block?.type !== "paragraph" || surfaceBlock?.kind !== "paragraph") {
511
+ continue;
512
+ }
513
+
514
+ const insideParagraph = selectionFallsWithinSurfaceRange(
515
+ selectionFrom,
516
+ selectionTo,
517
+ surfaceBlock.from,
518
+ surfaceBlock.to,
519
+ );
520
+ const isCollapsedParagraphTailBeforeTable =
521
+ selectionFrom === selectionTo &&
522
+ selectionFrom === surfaceBlock.to &&
523
+ root.children[blockIndex + 1]?.type === "table";
524
+ if (!insideParagraph && !isCollapsedParagraphTailBeforeTable) {
525
+ continue;
526
+ }
527
+
528
+ return {
529
+ root,
530
+ blockIndex,
531
+ paragraph: block,
532
+ paragraphStart: surfaceBlock.from,
533
+ paragraphEnd: surfaceBlock.to,
534
+ };
535
+ }
536
+
537
+ return null;
538
+ }
539
+
540
+ function resolveTopLevelSdtParagraphScope(
541
+ document: CanonicalDocumentEnvelope,
542
+ selection: SelectionSnapshot,
543
+ ):
544
+ | {
545
+ root: DocumentRootNode;
546
+ blockIndex: number;
547
+ childPath: number[];
548
+ paragraph: ParagraphNode;
549
+ paragraphStart: number;
550
+ }
551
+ | null {
552
+ const root = document.content as DocumentRootNode;
553
+ if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
554
+ return null;
555
+ }
556
+
557
+ const surface = createEditorSurfaceSnapshot(document, selection);
558
+ const selectionFrom = Math.min(selection.anchor, selection.head);
559
+ const selectionTo = Math.max(selection.anchor, selection.head);
560
+
561
+ for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
562
+ const block = root.children[blockIndex];
563
+ const surfaceBlock = surface.blocks[blockIndex];
564
+ if (block?.type !== "sdt" || surfaceBlock?.kind !== "sdt_block") {
565
+ continue;
566
+ }
567
+
568
+ const nested = resolveParagraphInSdtChildren(
569
+ block.children,
570
+ surfaceBlock.children,
571
+ selectionFrom,
572
+ selectionTo,
573
+ [],
574
+ );
575
+ if (nested) {
576
+ return {
577
+ root,
578
+ blockIndex,
579
+ childPath: nested.childPath,
580
+ paragraph: nested.paragraph,
581
+ paragraphStart: nested.paragraphStart,
582
+ };
583
+ }
584
+ }
585
+
586
+ return null;
587
+ }
588
+
589
+ function resolveParagraphInSdtChildren(
590
+ blocks: readonly DocumentRootNode["children"][number][],
591
+ surfaceBlocks: readonly {
592
+ kind: string;
593
+ from: number;
594
+ to: number;
595
+ children?: readonly { kind: string; from: number; to: number; children?: readonly unknown[] }[];
596
+ }[],
597
+ selectionFrom: number,
598
+ selectionTo: number,
599
+ path: number[],
600
+ ):
601
+ | {
602
+ childPath: number[];
603
+ paragraph: ParagraphNode;
604
+ paragraphStart: number;
605
+ }
606
+ | null {
607
+ for (let index = 0; index < Math.min(blocks.length, surfaceBlocks.length); index += 1) {
608
+ const block = blocks[index];
609
+ const surfaceBlock = surfaceBlocks[index];
610
+ if (!block || !surfaceBlock) {
611
+ continue;
612
+ }
613
+
614
+ if (block.type === "paragraph" && surfaceBlock.kind === "paragraph") {
615
+ const insideParagraph = selectionFallsWithinSurfaceRange(
616
+ selectionFrom,
617
+ selectionTo,
618
+ surfaceBlock.from,
619
+ surfaceBlock.to,
620
+ );
621
+ if (insideParagraph) {
622
+ return {
623
+ childPath: [...path, index],
624
+ paragraph: block,
625
+ paragraphStart: surfaceBlock.from,
626
+ };
627
+ }
628
+ continue;
629
+ }
630
+
631
+ if (block.type === "sdt" && surfaceBlock.kind === "sdt_block") {
632
+ const nested = resolveParagraphInSdtChildren(
633
+ block.children,
634
+ (surfaceBlock.children ?? []) as {
635
+ kind: string;
636
+ from: number;
637
+ to: number;
638
+ children?: readonly { kind: string; from: number; to: number; children?: readonly unknown[] }[];
639
+ }[],
640
+ selectionFrom,
641
+ selectionTo,
642
+ [...path, index],
643
+ );
644
+ if (nested) {
645
+ return nested;
646
+ }
647
+ }
648
+ }
649
+
650
+ return null;
651
+ }
652
+
653
+ function replaceParagraphInSdt(
654
+ sdt: SdtNode,
655
+ childPath: number[],
656
+ nextParagraphBlocks: DocumentRootNode["children"],
657
+ ): SdtNode {
658
+ if (childPath.length === 0) {
659
+ return sdt;
660
+ }
661
+
662
+ const [childIndex, ...restPath] = childPath;
663
+ return {
664
+ ...sdt,
665
+ children: sdt.children.map((child, index) => {
666
+ if (index !== childIndex) {
667
+ return child;
668
+ }
669
+ if (restPath.length === 0) {
670
+ return nextParagraphBlocks[0] ?? child;
671
+ }
672
+ if (child.type === "sdt") {
673
+ return replaceParagraphInSdt(child, restPath, nextParagraphBlocks);
674
+ }
675
+ return child;
676
+ }),
677
+ };
678
+ }
679
+
680
+ function selectionFallsWithinSurfaceRange(
681
+ selectionFrom: number,
682
+ selectionTo: number,
683
+ rangeFrom: number,
684
+ rangeTo: number,
685
+ ): boolean {
686
+ if (rangeFrom === rangeTo) {
687
+ return selectionFrom === rangeFrom && selectionTo === rangeTo;
688
+ }
689
+
690
+ return (
691
+ selectionFrom >= rangeFrom &&
692
+ selectionTo <= rangeTo &&
693
+ selectionFrom < rangeTo
694
+ );
695
+ }
696
+
697
+ function resolveRange(
698
+ selection: SelectionSnapshot,
699
+ storySize: number,
700
+ intent: TextTransactionIntent,
701
+ ): { from: number; to: number } {
702
+ const from = Math.max(0, Math.min(selection.anchor, selection.head));
703
+ const to = Math.max(0, Math.max(selection.anchor, selection.head));
704
+
705
+ if (from > storySize || to > storySize) {
706
+ throw new TextTransactionError(
707
+ "invalid_selection",
708
+ `Selection ${from}-${to} exceeds story size ${storySize}.`,
709
+ );
710
+ }
711
+
712
+ if (intent.type === "replace") {
713
+ if (intent.range) {
714
+ const explicitFrom = Math.max(0, Math.min(intent.range.from, intent.range.to));
715
+ const explicitTo = Math.max(0, Math.max(intent.range.from, intent.range.to));
716
+ if (explicitFrom > storySize || explicitTo > storySize) {
717
+ throw new TextTransactionError(
718
+ "invalid_selection",
719
+ `Explicit range ${explicitFrom}-${explicitTo} exceeds story size ${storySize}.`,
720
+ );
721
+ }
722
+
723
+ return {
724
+ from: explicitFrom,
725
+ to: explicitTo,
726
+ };
727
+ }
728
+
729
+ return { from, to };
730
+ }
731
+
732
+ if (from !== to) {
733
+ return { from, to };
734
+ }
735
+
736
+ if (intent.type === "delete_backward") {
737
+ return {
738
+ from: Math.max(0, from - 1),
739
+ to: from,
740
+ };
741
+ }
742
+
743
+ return {
744
+ from,
745
+ to: Math.min(storySize, from + 1),
746
+ };
747
+ }
748
+
749
+ function localizeTextTransactionIntent(
750
+ intent: TextTransactionIntent,
751
+ offset: number,
752
+ ): TextTransactionIntent {
753
+ if (intent.type !== "replace" || !intent.range) {
754
+ return intent;
755
+ }
756
+
757
+ return {
758
+ ...intent,
759
+ range: {
760
+ from: intent.range.from - offset,
761
+ to: intent.range.to - offset,
762
+ },
763
+ };
764
+ }
765
+
766
+ function createInsertionUnits(
767
+ intent: TextTransactionIntent,
768
+ story: TextStory,
769
+ position: number,
770
+ ): StoryUnit[] {
771
+ if (intent.type !== "replace") {
772
+ return [];
773
+ }
774
+
775
+ const inheritedProps = resolveParagraphPropertiesAtPosition(story, position);
776
+
777
+ return intent.insertion.flatMap((entry) => {
778
+ switch (entry.type) {
779
+ case "text":
780
+ return Array.from(entry.text).map<StoryUnit>((character) => ({
781
+ kind: "text",
782
+ value: character,
783
+ }));
784
+ case "tab":
785
+ return [{ kind: "tab" }];
786
+ case "hard_break":
787
+ return [{ kind: "hard_break" }];
788
+ case "paragraph_break":
789
+ return [
790
+ {
791
+ kind: "paragraph_break",
792
+ nextParagraph: cloneParagraphProperties(inheritedProps),
793
+ },
794
+ ];
795
+ }
796
+ });
797
+ }
798
+
799
+ function resolveParagraphPropertiesAtPosition(
800
+ story: TextStory,
801
+ position: number,
802
+ ): ParagraphProperties {
803
+ let current = cloneParagraphProperties(story.firstParagraph);
804
+
805
+ for (let index = 0; index < Math.min(position, story.units.length); index += 1) {
806
+ const unit = story.units[index];
807
+ if (unit.kind === "paragraph_break") {
808
+ current = cloneParagraphProperties(unit.nextParagraph);
809
+ } else if (unit.kind === "opaque_block" && unit.nextParagraph) {
810
+ current = cloneParagraphProperties(unit.nextParagraph);
811
+ }
812
+ }
813
+
814
+ return current;
815
+ }
816
+
817
+ function normalizeStoryUnits(units: StoryUnit[]): StoryUnit[] {
818
+ if (units.length === 0) {
819
+ return [];
820
+ }
821
+
822
+ const normalized: StoryUnit[] = [];
823
+
824
+ for (const unit of units) {
825
+ if (
826
+ unit.kind === "paragraph_break" &&
827
+ normalized[normalized.length - 1]?.kind === "paragraph_break"
828
+ ) {
829
+ normalized.push({
830
+ kind: "paragraph_break",
831
+ nextParagraph: cloneParagraphProperties(unit.nextParagraph),
832
+ });
833
+ continue;
834
+ }
835
+
836
+ normalized.push(cloneStoryUnit(unit));
837
+ }
838
+
839
+ return normalized;
840
+ }
841
+
842
+ function ensureEditableRange(units: StoryUnit[]): void {
843
+ const protectedUnit = units.find(
844
+ (unit) => unit.kind === "opaque_inline" || unit.kind === "opaque_block" || unit.kind === "image",
845
+ );
846
+
847
+ if (!protectedUnit) {
848
+ return;
849
+ }
850
+
851
+ throw new TextTransactionError(
852
+ "unsupported_content",
853
+ `Text transaction crosses protected ${protectedUnit.kind} content.`,
854
+ );
855
+ }
856
+
857
+ function containsParagraphBoundaryChange(
858
+ story: TextStory,
859
+ range: { from: number; to: number },
860
+ insertionUnits: StoryUnit[],
861
+ ): boolean {
862
+ if (insertionUnits.some((unit) => unit.kind === "paragraph_break")) {
863
+ return true;
864
+ }
865
+
866
+ return story.units
867
+ .slice(range.from, range.to)
868
+ .some((unit) => unit.kind === "paragraph_break");
869
+ }