@a3s-lab/office 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +470 -0
  3. package/THIRD_PARTY_NOTICES.md +33 -0
  4. package/dist/0~1403.js +245 -0
  5. package/dist/0~152.js +94 -0
  6. package/dist/0~3539.js +1856 -0
  7. package/dist/0~3557.js +179 -0
  8. package/dist/0~3635.js +302 -0
  9. package/dist/0~4595.js +1162 -0
  10. package/dist/0~5050.js +308 -0
  11. package/dist/0~6552.js +787 -0
  12. package/dist/0~7048.js +2110 -0
  13. package/dist/0~7614.js +1037 -0
  14. package/dist/0~8155.js +299 -0
  15. package/dist/0~9445.js +283 -0
  16. package/dist/0~9512.js +743 -0
  17. package/dist/0~document-editor.js +10967 -0
  18. package/dist/0~markdown-editor.js +2260 -0
  19. package/dist/0~pdf-viewer.js +2156 -0
  20. package/dist/0~presentation-editor.js +8359 -0
  21. package/dist/0~rslib-runtime.js +27 -0
  22. package/dist/0~spreadsheet-editor.js +10388 -0
  23. package/dist/0~use-office-draft.js +46 -0
  24. package/dist/0~work-document-extensions.js +2470 -0
  25. package/dist/0~work-document-links.js +14 -0
  26. package/dist/0~work-document-model-codec.js +42 -0
  27. package/dist/0~work-document-page-color.js +11 -0
  28. package/dist/0~work-document-paragraph-formatting.js +425 -0
  29. package/dist/0~work-docx-bibliography.js +347 -0
  30. package/dist/0~work-docx-export.js +1151 -0
  31. package/dist/0~work-docx-import.js +3116 -0
  32. package/dist/0~work-docx-page-color.js +42 -0
  33. package/dist/0~work-office-diagnostics.js +1377 -0
  34. package/dist/0~work-pptx-export.js +1009 -0
  35. package/dist/0~work-pptx-import.js +1138 -0
  36. package/dist/0~work-presentation-charts.js +442 -0
  37. package/dist/0~work-presentation-transition.js +38 -0
  38. package/dist/0~work-presentation-visual-scale.js +38 -0
  39. package/dist/0~work-spreadsheet-formula-support.js +9 -0
  40. package/dist/1134.js +445 -0
  41. package/dist/4104.js +5786 -0
  42. package/dist/432.js +211 -0
  43. package/dist/4704.js +1364 -0
  44. package/dist/6489.js +182 -0
  45. package/dist/8715.js +3959 -0
  46. package/dist/8728.js +723 -0
  47. package/dist/9356.js +10 -0
  48. package/dist/core.d.ts +15 -0
  49. package/dist/core.js +4 -0
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +5 -0
  52. package/dist/internal/design-system/primitives/button/button.d.ts +9 -0
  53. package/dist/internal/design-system/primitives/button/icon-button.d.ts +7 -0
  54. package/dist/internal/design-system/primitives/dialog/dialog.d.ts +12 -0
  55. package/dist/internal/design-system/primitives/feedback/collection-state.d.ts +9 -0
  56. package/dist/internal/design-system/primitives/feedback/inline-notice.d.ts +10 -0
  57. package/dist/internal/design-system/primitives/feedback/state-view.d.ts +13 -0
  58. package/dist/internal/design-system/primitives/form/field.d.ts +19 -0
  59. package/dist/internal/design-system/primitives/index.d.ts +14 -0
  60. package/dist/internal/design-system/primitives/layout/split-handle.d.ts +17 -0
  61. package/dist/internal/design-system/primitives/navigation/segmented-control.d.ts +19 -0
  62. package/dist/internal/design-system/primitives/navigation/tab-navigation.d.ts +13 -0
  63. package/dist/internal/design-system/primitives/navigation/tabs.d.ts +21 -0
  64. package/dist/internal/design-system/primitives/overlay/dialog-focus-scope.d.ts +17 -0
  65. package/dist/internal/design-system/primitives/overlay/popover.d.ts +34 -0
  66. package/dist/internal/design-system/primitives/overlay/portal-root.d.ts +1 -0
  67. package/dist/internal/design-system/primitives/status/status-badge.d.ts +6 -0
  68. package/dist/internal/features/work/components/work-document-pages.d.ts +4 -0
  69. package/dist/internal/features/work/components/work-editor-agent-menus.d.ts +12 -0
  70. package/dist/internal/features/work/components/work-editor-loading-state.d.ts +3 -0
  71. package/dist/internal/features/work/editors/document-changes-panel.d.ts +9 -0
  72. package/dist/internal/features/work/editors/document-citation-source-form.d.ts +33 -0
  73. package/dist/internal/features/work/editors/document-citations-panel.d.ts +8 -0
  74. package/dist/internal/features/work/editors/document-columns-panel.d.ts +5 -0
  75. package/dist/internal/features/work/editors/document-comment-composer.d.ts +13 -0
  76. package/dist/internal/features/work/editors/document-comments-panel.d.ts +17 -0
  77. package/dist/internal/features/work/editors/document-editor-focus.d.ts +1 -0
  78. package/dist/internal/features/work/editors/document-editor-pagination.d.ts +3 -0
  79. package/dist/internal/features/work/editors/document-editor-support.d.ts +34 -0
  80. package/dist/internal/features/work/editors/document-editor.d.ts +20 -0
  81. package/dist/internal/features/work/editors/document-find-highlight.d.ts +8 -0
  82. package/dist/internal/features/work/editors/document-find-replace-panel.d.ts +10 -0
  83. package/dist/internal/features/work/editors/document-formatting-options.d.ts +113 -0
  84. package/dist/internal/features/work/editors/document-home-ribbon.d.ts +9 -0
  85. package/dist/internal/features/work/editors/document-layout-panel.d.ts +10 -0
  86. package/dist/internal/features/work/editors/document-list-gallery.d.ts +4 -0
  87. package/dist/internal/features/work/editors/document-navigation-panel.d.ts +9 -0
  88. package/dist/internal/features/work/editors/document-page-chrome-editor.d.ts +39 -0
  89. package/dist/internal/features/work/editors/document-page-chrome-panel.d.ts +5 -0
  90. package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +10 -0
  91. package/dist/internal/features/work/editors/document-page-navigation.d.ts +14 -0
  92. package/dist/internal/features/work/editors/document-page-stack.d.ts +8 -0
  93. package/dist/internal/features/work/editors/document-pagination-popover.d.ts +4 -0
  94. package/dist/internal/features/work/editors/document-paragraph-spacing-popover.d.ts +4 -0
  95. package/dist/internal/features/work/editors/document-picture-ribbon.d.ts +4 -0
  96. package/dist/internal/features/work/editors/document-ruler-tab-stops.d.ts +12 -0
  97. package/dist/internal/features/work/editors/document-ruler.d.ts +15 -0
  98. package/dist/internal/features/work/editors/document-selection-context-menu.d.ts +22 -0
  99. package/dist/internal/features/work/editors/document-selection-toolbar.d.ts +8 -0
  100. package/dist/internal/features/work/editors/document-status-bar.d.ts +19 -0
  101. package/dist/internal/features/work/editors/document-style-gallery.d.ts +4 -0
  102. package/dist/internal/features/work/editors/document-table-insert-popover.d.ts +4 -0
  103. package/dist/internal/features/work/editors/document-table-ribbon.d.ts +7 -0
  104. package/dist/internal/features/work/editors/document-task-pane.d.ts +11 -0
  105. package/dist/internal/features/work/editors/document-toolbar.d.ts +100 -0
  106. package/dist/internal/features/work/editors/document-vertical-ruler.d.ts +6 -0
  107. package/dist/internal/features/work/editors/markdown-editor-focus.d.ts +2 -0
  108. package/dist/internal/features/work/editors/markdown-editor.d.ts +16 -0
  109. package/dist/internal/features/work/editors/markdown-insert-dialog.d.ts +19 -0
  110. package/dist/internal/features/work/editors/markdown-selection-context-menu.d.ts +14 -0
  111. package/dist/internal/features/work/editors/markdown-source-commands.d.ts +41 -0
  112. package/dist/internal/features/work/editors/markdown-status.d.ts +7 -0
  113. package/dist/internal/features/work/editors/markdown-toolbar.d.ts +22 -0
  114. package/dist/internal/features/work/editors/markdown-workspace.d.ts +26 -0
  115. package/dist/internal/features/work/editors/office-checkbox.d.ts +9 -0
  116. package/dist/internal/features/work/editors/office-color-picker.d.ts +11 -0
  117. package/dist/internal/features/work/editors/office-controls.d.ts +7 -0
  118. package/dist/internal/features/work/editors/office-dialog.d.ts +35 -0
  119. package/dist/internal/features/work/editors/office-editor-extension.d.ts +86 -0
  120. package/dist/internal/features/work/editors/office-file-data.d.ts +1 -0
  121. package/dist/internal/features/work/editors/office-font-families.d.ts +187 -0
  122. package/dist/internal/features/work/editors/office-menu-keyboard.d.ts +2 -0
  123. package/dist/internal/features/work/editors/office-number-field.d.ts +21 -0
  124. package/dist/internal/features/work/editors/office-number-normalization.d.ts +9 -0
  125. package/dist/internal/features/work/editors/office-select.d.ts +19 -0
  126. package/dist/internal/features/work/editors/office-shortcuts.d.ts +1 -0
  127. package/dist/internal/features/work/editors/office-slider.d.ts +10 -0
  128. package/dist/internal/features/work/editors/office-table-dimensions.d.ts +4 -0
  129. package/dist/internal/features/work/editors/office-table-insert-popover.d.ts +7 -0
  130. package/dist/internal/features/work/editors/office-task-pane.d.ts +7 -0
  131. package/dist/internal/features/work/editors/office-text-field.d.ts +20 -0
  132. package/dist/internal/features/work/editors/office-tiptap-extensions.d.ts +2 -0
  133. package/dist/internal/features/work/editors/pdf-annotation-controller.d.ts +23 -0
  134. package/dist/internal/features/work/editors/pdf-editor-extensions.d.ts +36 -0
  135. package/dist/internal/features/work/editors/pdf-thumbnail-rail.d.ts +26 -0
  136. package/dist/internal/features/work/editors/pdf-toolbar.d.ts +23 -0
  137. package/dist/internal/features/work/editors/pdf-viewer-controller.d.ts +48 -0
  138. package/dist/internal/features/work/editors/pdf-viewer.d.ts +11 -0
  139. package/dist/internal/features/work/editors/presentation-arrangement-controller.d.ts +19 -0
  140. package/dist/internal/features/work/editors/presentation-chart-analysis-canvas.d.ts +21 -0
  141. package/dist/internal/features/work/editors/presentation-chart-axis-canvas.d.ts +33 -0
  142. package/dist/internal/features/work/editors/presentation-chart-axis-editor.d.ts +5 -0
  143. package/dist/internal/features/work/editors/presentation-chart-canvas.d.ts +5 -0
  144. package/dist/internal/features/work/editors/presentation-chart-cartesian-canvas.d.ts +3 -0
  145. package/dist/internal/features/work/editors/presentation-chart-data-label-editor.d.ts +6 -0
  146. package/dist/internal/features/work/editors/presentation-chart-data-labels.d.ts +26 -0
  147. package/dist/internal/features/work/editors/presentation-chart-layout-editor.d.ts +5 -0
  148. package/dist/internal/features/work/editors/presentation-chart-legend-canvas.d.ts +15 -0
  149. package/dist/internal/features/work/editors/presentation-chart-panel.d.ts +7 -0
  150. package/dist/internal/features/work/editors/presentation-chart-series-analysis-editor.d.ts +6 -0
  151. package/dist/internal/features/work/editors/presentation-chart-series-canvas.d.ts +15 -0
  152. package/dist/internal/features/work/editors/presentation-command-controller.d.ts +3 -0
  153. package/dist/internal/features/work/editors/presentation-command-types.d.ts +206 -0
  154. package/dist/internal/features/work/editors/presentation-comments-panel.d.ts +9 -0
  155. package/dist/internal/features/work/editors/presentation-context-menu.d.ts +11 -0
  156. package/dist/internal/features/work/editors/presentation-design-panel.d.ts +13 -0
  157. package/dist/internal/features/work/editors/presentation-editor-focus.d.ts +12 -0
  158. package/dist/internal/features/work/editors/presentation-editor-operations.d.ts +10 -0
  159. package/dist/internal/features/work/editors/presentation-editor-types.d.ts +22 -0
  160. package/dist/internal/features/work/editors/presentation-editor.d.ts +3 -0
  161. package/dist/internal/features/work/editors/presentation-keyboard-extension.d.ts +3 -0
  162. package/dist/internal/features/work/editors/presentation-player.d.ts +7 -0
  163. package/dist/internal/features/work/editors/presentation-presenter-view.d.ts +15 -0
  164. package/dist/internal/features/work/editors/presentation-selection.d.ts +21 -0
  165. package/dist/internal/features/work/editors/presentation-slide-canvas.d.ts +26 -0
  166. package/dist/internal/features/work/editors/presentation-slide-thumbnail.d.ts +18 -0
  167. package/dist/internal/features/work/editors/presentation-status-bar.d.ts +10 -0
  168. package/dist/internal/features/work/editors/presentation-text-editor.d.ts +22 -0
  169. package/dist/internal/features/work/editors/presentation-text-formatting.d.ts +3 -0
  170. package/dist/internal/features/work/editors/presentation-thumbnail-rail.d.ts +20 -0
  171. package/dist/internal/features/work/editors/presentation-toolbar.d.ts +19 -0
  172. package/dist/internal/features/work/editors/presentation-transition-panel.d.ts +9 -0
  173. package/dist/internal/features/work/editors/presentation-workspace.d.ts +38 -0
  174. package/dist/internal/features/work/editors/spreadsheet-calculation-model.d.ts +8 -0
  175. package/dist/internal/features/work/editors/spreadsheet-calculation-projection.d.ts +32 -0
  176. package/dist/internal/features/work/editors/spreadsheet-chart-axis-editor.d.ts +9 -0
  177. package/dist/internal/features/work/editors/spreadsheet-chart-draft.d.ts +17 -0
  178. package/dist/internal/features/work/editors/spreadsheet-chart-layout-editor.d.ts +13 -0
  179. package/dist/internal/features/work/editors/spreadsheet-chart-panel.d.ts +10 -0
  180. package/dist/internal/features/work/editors/spreadsheet-chart-series-style-editor.d.ts +9 -0
  181. package/dist/internal/features/work/editors/spreadsheet-clipboard-shortcuts.d.ts +9 -0
  182. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +121 -0
  183. package/dist/internal/features/work/editors/spreadsheet-conditional-comparison-fields.d.ts +7 -0
  184. package/dist/internal/features/work/editors/spreadsheet-conditional-format-model.d.ts +72 -0
  185. package/dist/internal/features/work/editors/spreadsheet-conditional-format-panel.d.ts +7 -0
  186. package/dist/internal/features/work/editors/spreadsheet-conditional-threshold-fields.d.ts +10 -0
  187. package/dist/internal/features/work/editors/spreadsheet-context-menu.d.ts +36 -0
  188. package/dist/internal/features/work/editors/spreadsheet-data-label-editor.d.ts +9 -0
  189. package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +46 -0
  190. package/dist/internal/features/work/editors/spreadsheet-editor-support.d.ts +31 -0
  191. package/dist/internal/features/work/editors/spreadsheet-editor.d.ts +16 -0
  192. package/dist/internal/features/work/editors/spreadsheet-error-bar-editor.d.ts +10 -0
  193. package/dist/internal/features/work/editors/spreadsheet-find-bar.d.ts +8 -0
  194. package/dist/internal/features/work/editors/spreadsheet-find.d.ts +9 -0
  195. package/dist/internal/features/work/editors/spreadsheet-formula-panel.d.ts +10 -0
  196. package/dist/internal/features/work/editors/spreadsheet-header-footer-fields.d.ts +5 -0
  197. package/dist/internal/features/work/editors/spreadsheet-keyboard-navigation.d.ts +18 -0
  198. package/dist/internal/features/work/editors/spreadsheet-number-format.d.ts +11 -0
  199. package/dist/internal/features/work/editors/spreadsheet-pivot-panel.d.ts +10 -0
  200. package/dist/internal/features/work/editors/spreadsheet-print-settings-panel.d.ts +6 -0
  201. package/dist/internal/features/work/editors/spreadsheet-protection-panel.d.ts +7 -0
  202. package/dist/internal/features/work/editors/spreadsheet-sheet-bar.d.ts +17 -0
  203. package/dist/internal/features/work/editors/spreadsheet-sheet-model.d.ts +13 -0
  204. package/dist/internal/features/work/editors/spreadsheet-trendline-editor.d.ts +8 -0
  205. package/dist/internal/features/work/editors/spreadsheet-workbook-panel.d.ts +16 -0
  206. package/dist/internal/features/work/editors/use-document-comments.d.ts +26 -0
  207. package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +19 -0
  208. package/dist/internal/features/work/editors/use-document-layout-fonts.d.ts +2 -0
  209. package/dist/internal/features/work/editors/use-document-page-chrome.d.ts +33 -0
  210. package/dist/internal/features/work/editors/use-document-pagination.d.ts +46 -0
  211. package/dist/internal/features/work/editors/use-markdown-source-history.d.ts +16 -0
  212. package/dist/internal/features/work/editors/use-office-draft.d.ts +10 -0
  213. package/dist/internal/features/work/editors/use-office-editor-keyboard-shortcuts.d.ts +9 -0
  214. package/dist/internal/features/work/editors/use-office-editor-runtime.d.ts +6 -0
  215. package/dist/internal/features/work/editors/use-office-editor-wheel-zoom.d.ts +19 -0
  216. package/dist/internal/features/work/editors/use-office-history.d.ts +10 -0
  217. package/dist/internal/features/work/editors/use-presentation-clipboard.d.ts +22 -0
  218. package/dist/internal/features/work/editors/use-presentation-design-commands.d.ts +33 -0
  219. package/dist/internal/features/work/editors/use-presentation-element-commands.d.ts +29 -0
  220. package/dist/internal/features/work/editors/use-presentation-geometry.d.ts +17 -0
  221. package/dist/internal/features/work/editors/use-presentation-history.d.ts +12 -0
  222. package/dist/internal/features/work/editors/use-presentation-review-commands.d.ts +22 -0
  223. package/dist/internal/features/work/editors/use-presentation-selection.d.ts +11 -0
  224. package/dist/internal/features/work/editors/use-presentation-slide-commands.d.ts +18 -0
  225. package/dist/internal/features/work/editors/use-presentation-thumbnail-visibility.d.ts +4 -0
  226. package/dist/internal/features/work/editors/use-presentation-thumbnail-window.d.ts +17 -0
  227. package/dist/internal/features/work/editors/use-presentation-transform.d.ts +53 -0
  228. package/dist/internal/features/work/editors/use-spreadsheet-calculation.d.ts +17 -0
  229. package/dist/internal/features/work/editors/use-spreadsheet-workbook-sync.d.ts +10 -0
  230. package/dist/internal/features/work/editors/work-office-chrome.d.ts +61 -0
  231. package/dist/internal/features/work/editors/work-office-ribbon-overflow.d.ts +18 -0
  232. package/dist/internal/features/work/work-agent-proposal-apply.d.ts +8 -0
  233. package/dist/internal/features/work/work-agent-proposal.d.ts +55 -0
  234. package/dist/internal/features/work/work-agent-request.d.ts +6 -0
  235. package/dist/internal/features/work/work-chart-series-analysis-context.d.ts +3 -0
  236. package/dist/internal/features/work/work-document-caption-nodes.d.ts +13 -0
  237. package/dist/internal/features/work/work-document-captions.d.ts +14 -0
  238. package/dist/internal/features/work/work-document-changes.d.ts +35 -0
  239. package/dist/internal/features/work/work-document-character-formatting.d.ts +13 -0
  240. package/dist/internal/features/work/work-document-citation-nodes.d.ts +25 -0
  241. package/dist/internal/features/work/work-document-citations.d.ts +21 -0
  242. package/dist/internal/features/work/work-document-columns.d.ts +15 -0
  243. package/dist/internal/features/work/work-document-comments.d.ts +48 -0
  244. package/dist/internal/features/work/work-document-extensions.d.ts +11 -0
  245. package/dist/internal/features/work/work-document-field-node.d.ts +12 -0
  246. package/dist/internal/features/work/work-document-fields.d.ts +15 -0
  247. package/dist/internal/features/work/work-document-file-io.d.ts +4 -0
  248. package/dist/internal/features/work/work-document-fonts.d.ts +16 -0
  249. package/dist/internal/features/work/work-document-image-layout.d.ts +29 -0
  250. package/dist/internal/features/work/work-document-incremental-layout.d.ts +17 -0
  251. package/dist/internal/features/work/work-document-layout.d.ts +5 -0
  252. package/dist/internal/features/work/work-document-line-measurement.d.ts +24 -0
  253. package/dist/internal/features/work/work-document-links.d.ts +2 -0
  254. package/dist/internal/features/work/work-document-lists.d.ts +25 -0
  255. package/dist/internal/features/work/work-document-model-codec.d.ts +3 -0
  256. package/dist/internal/features/work/work-document-model.d.ts +12 -0
  257. package/dist/internal/features/work/work-document-note-nodes.d.ts +11 -0
  258. package/dist/internal/features/work/work-document-notes.d.ts +18 -0
  259. package/dist/internal/features/work/work-document-outline.d.ts +14 -0
  260. package/dist/internal/features/work/work-document-page-break.d.ts +2 -0
  261. package/dist/internal/features/work/work-document-page-chrome-commands.d.ts +15 -0
  262. package/dist/internal/features/work/work-document-page-chrome.d.ts +19 -0
  263. package/dist/internal/features/work/work-document-page-color.d.ts +3 -0
  264. package/dist/internal/features/work/work-document-pages.d.ts +19 -0
  265. package/dist/internal/features/work/work-document-pagination-decorations.d.ts +3 -0
  266. package/dist/internal/features/work/work-document-pagination-dom.d.ts +35 -0
  267. package/dist/internal/features/work/work-document-pagination-measurement.d.ts +9 -0
  268. package/dist/internal/features/work/work-document-pagination-types.d.ts +88 -0
  269. package/dist/internal/features/work/work-document-pagination.d.ts +17 -0
  270. package/dist/internal/features/work/work-document-paragraph-formatting.d.ts +61 -0
  271. package/dist/internal/features/work/work-document-search.d.ts +11 -0
  272. package/dist/internal/features/work/work-document-section-editor.d.ts +20 -0
  273. package/dist/internal/features/work/work-document-section-node.d.ts +13 -0
  274. package/dist/internal/features/work/work-document-section.d.ts +34 -0
  275. package/dist/internal/features/work/work-document-selection-menu.d.ts +54 -0
  276. package/dist/internal/features/work/work-document-tab-node.d.ts +6 -0
  277. package/dist/internal/features/work/work-document-tab-stops.d.ts +29 -0
  278. package/dist/internal/features/work/work-document-table-cell-formatting.d.ts +46 -0
  279. package/dist/internal/features/work/work-document-table-commands.d.ts +17 -0
  280. package/dist/internal/features/work/work-document-table-pagination.d.ts +5 -0
  281. package/dist/internal/features/work/work-document-table-row.d.ts +37 -0
  282. package/dist/internal/features/work/work-document-table-sizing.d.ts +27 -0
  283. package/dist/internal/features/work/work-document-text-layout.d.ts +14 -0
  284. package/dist/internal/features/work/work-docx-bibliography.d.ts +12 -0
  285. package/dist/internal/features/work/work-docx-caption-diagnostics.d.ts +6 -0
  286. package/dist/internal/features/work/work-docx-caption-export.d.ts +4 -0
  287. package/dist/internal/features/work/work-docx-caption-fields.d.ts +5 -0
  288. package/dist/internal/features/work/work-docx-caption-import.d.ts +20 -0
  289. package/dist/internal/features/work/work-docx-change-import.d.ts +12 -0
  290. package/dist/internal/features/work/work-docx-citation-diagnostics.d.ts +3 -0
  291. package/dist/internal/features/work/work-docx-citation-export.d.ts +3 -0
  292. package/dist/internal/features/work/work-docx-citation-import.d.ts +23 -0
  293. package/dist/internal/features/work/work-docx-column-export.d.ts +14 -0
  294. package/dist/internal/features/work/work-docx-column-import.d.ts +2 -0
  295. package/dist/internal/features/work/work-docx-comment-import.d.ts +14 -0
  296. package/dist/internal/features/work/work-docx-export-formatting.d.ts +30 -0
  297. package/dist/internal/features/work/work-docx-export-image.d.ts +2 -0
  298. package/dist/internal/features/work/work-docx-export.d.ts +2 -0
  299. package/dist/internal/features/work/work-docx-field-export.d.ts +2 -0
  300. package/dist/internal/features/work/work-docx-field-import.d.ts +16 -0
  301. package/dist/internal/features/work/work-docx-field-instructions.d.ts +8 -0
  302. package/dist/internal/features/work/work-docx-image-layout-import.d.ts +12 -0
  303. package/dist/internal/features/work/work-docx-import.d.ts +50 -0
  304. package/dist/internal/features/work/work-docx-list-import.d.ts +14 -0
  305. package/dist/internal/features/work/work-docx-note-diagnostics.d.ts +3 -0
  306. package/dist/internal/features/work/work-docx-note-import.d.ts +3 -0
  307. package/dist/internal/features/work/work-docx-page-chrome-diagnostics.d.ts +3 -0
  308. package/dist/internal/features/work/work-docx-page-chrome-import.d.ts +11 -0
  309. package/dist/internal/features/work/work-docx-page-color.d.ts +2 -0
  310. package/dist/internal/features/work/work-docx-paragraph-alignment-import.d.ts +12 -0
  311. package/dist/internal/features/work/work-docx-paragraph-direction-import.d.ts +12 -0
  312. package/dist/internal/features/work/work-docx-paragraph-indent-import.d.ts +12 -0
  313. package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +12 -0
  314. package/dist/internal/features/work/work-docx-paragraph-spacing-import.d.ts +12 -0
  315. package/dist/internal/features/work/work-docx-paragraph-styles.d.ts +18 -0
  316. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +19 -0
  317. package/dist/internal/features/work/work-docx-tab-stop-import.d.ts +13 -0
  318. package/dist/internal/features/work/work-docx-table-cell-export.d.ts +4 -0
  319. package/dist/internal/features/work/work-docx-table-cell-import.d.ts +16 -0
  320. package/dist/internal/features/work/work-docx-table-row-import.d.ts +13 -0
  321. package/dist/internal/features/work/work-docx-table-sizing-export.d.ts +8 -0
  322. package/dist/internal/features/work/work-docx-table-sizing-import.d.ts +12 -0
  323. package/dist/internal/features/work/work-docx-theme.d.ts +9 -0
  324. package/dist/internal/features/work/work-file-data.d.ts +1 -0
  325. package/dist/internal/features/work/work-file-download.d.ts +3 -0
  326. package/dist/internal/features/work/work-file-io.d.ts +8 -0
  327. package/dist/internal/features/work/work-markdown-extensions.d.ts +19 -0
  328. package/dist/internal/features/work/work-markdown-file-io.d.ts +3 -0
  329. package/dist/internal/features/work/work-markdown-selection-menu.d.ts +57 -0
  330. package/dist/internal/features/work/work-office-diagnostics.d.ts +9 -0
  331. package/dist/internal/features/work/work-ooxml-package.d.ts +28 -0
  332. package/dist/internal/features/work/work-pdf-export.d.ts +23 -0
  333. package/dist/internal/features/work/work-pptx-chart-axes.d.ts +3 -0
  334. package/dist/internal/features/work/work-pptx-chart-axis-diagnostics.d.ts +5 -0
  335. package/dist/internal/features/work/work-pptx-chart-data-labels.d.ts +12 -0
  336. package/dist/internal/features/work/work-pptx-chart-import.d.ts +11 -0
  337. package/dist/internal/features/work/work-pptx-chart-layout-style.d.ts +15 -0
  338. package/dist/internal/features/work/work-pptx-chart-series-analysis.d.ts +13 -0
  339. package/dist/internal/features/work/work-pptx-chart-xy.d.ts +3 -0
  340. package/dist/internal/features/work/work-pptx-comments.d.ts +17 -0
  341. package/dist/internal/features/work/work-pptx-export.d.ts +4 -0
  342. package/dist/internal/features/work/work-pptx-groups.d.ts +19 -0
  343. package/dist/internal/features/work/work-pptx-import.d.ts +6 -0
  344. package/dist/internal/features/work/work-pptx-layout-export.d.ts +13 -0
  345. package/dist/internal/features/work/work-pptx-layout-import.d.ts +30 -0
  346. package/dist/internal/features/work/work-pptx-style.d.ts +13 -0
  347. package/dist/internal/features/work/work-pptx-transition.d.ts +13 -0
  348. package/dist/internal/features/work/work-presentation-agent-context.d.ts +6 -0
  349. package/dist/internal/features/work/work-presentation-chart-axes.d.ts +14 -0
  350. package/dist/internal/features/work/work-presentation-charts.d.ts +37 -0
  351. package/dist/internal/features/work/work-presentation-clipboard.d.ts +26 -0
  352. package/dist/internal/features/work/work-presentation-file-io.d.ts +15 -0
  353. package/dist/internal/features/work/work-presentation-groups.d.ts +17 -0
  354. package/dist/internal/features/work/work-presentation-layouts.d.ts +13 -0
  355. package/dist/internal/features/work/work-presentation-transition.d.ts +4 -0
  356. package/dist/internal/features/work/work-presentation-visual-scale.d.ts +2 -0
  357. package/dist/internal/features/work/work-repository.d.ts +4 -0
  358. package/dist/internal/features/work/work-spreadsheet-agent-context.d.ts +15 -0
  359. package/dist/internal/features/work/work-spreadsheet-chart-axis.d.ts +42 -0
  360. package/dist/internal/features/work/work-spreadsheet-chart-layout.d.ts +29 -0
  361. package/dist/internal/features/work/work-spreadsheet-chart-legend-svg.d.ts +18 -0
  362. package/dist/internal/features/work/work-spreadsheet-chart-series-layout.d.ts +24 -0
  363. package/dist/internal/features/work/work-spreadsheet-chart-series-style.d.ts +29 -0
  364. package/dist/internal/features/work/work-spreadsheet-chart-svg-utils.d.ts +7 -0
  365. package/dist/internal/features/work/work-spreadsheet-chart-svg.d.ts +3 -0
  366. package/dist/internal/features/work/work-spreadsheet-chart-types.d.ts +147 -0
  367. package/dist/internal/features/work/work-spreadsheet-chart-validation.d.ts +2 -0
  368. package/dist/internal/features/work/work-spreadsheet-charts.d.ts +17 -0
  369. package/dist/internal/features/work/work-spreadsheet-combination-chart-svg.d.ts +9 -0
  370. package/dist/internal/features/work/work-spreadsheet-comments.d.ts +7 -0
  371. package/dist/internal/features/work/work-spreadsheet-conditional-canvas.d.ts +5 -0
  372. package/dist/internal/features/work/work-spreadsheet-conditional-colors.d.ts +9 -0
  373. package/dist/internal/features/work/work-spreadsheet-conditional-comparisons.d.ts +4 -0
  374. package/dist/internal/features/work/work-spreadsheet-conditional-data-bar.d.ts +8 -0
  375. package/dist/internal/features/work/work-spreadsheet-conditional-format.d.ts +10 -0
  376. package/dist/internal/features/work/work-spreadsheet-conditional-icons.d.ts +107 -0
  377. package/dist/internal/features/work/work-spreadsheet-conditional-values.d.ts +19 -0
  378. package/dist/internal/features/work/work-spreadsheet-data-label-svg.d.ts +27 -0
  379. package/dist/internal/features/work/work-spreadsheet-error-bar-svg.d.ts +5 -0
  380. package/dist/internal/features/work/work-spreadsheet-error-bars.d.ts +8 -0
  381. package/dist/internal/features/work/work-spreadsheet-formula-analysis.d.ts +30 -0
  382. package/dist/internal/features/work/work-spreadsheet-formula-support.d.ts +1 -0
  383. package/dist/internal/features/work/work-spreadsheet-formulas.d.ts +19 -0
  384. package/dist/internal/features/work/work-spreadsheet-header-footer.d.ts +14 -0
  385. package/dist/internal/features/work/work-spreadsheet-line-chart-svg.d.ts +10 -0
  386. package/dist/internal/features/work/work-spreadsheet-page-breaks.d.ts +4 -0
  387. package/dist/internal/features/work/work-spreadsheet-page-setup.d.ts +26 -0
  388. package/dist/internal/features/work/work-spreadsheet-pivot-engine.d.ts +21 -0
  389. package/dist/internal/features/work/work-spreadsheet-pivot-values.d.ts +7 -0
  390. package/dist/internal/features/work/work-spreadsheet-pivots.d.ts +27 -0
  391. package/dist/internal/features/work/work-spreadsheet-protection.d.ts +55 -0
  392. package/dist/internal/features/work/work-spreadsheet-ranges.d.ts +25 -0
  393. package/dist/internal/features/work/work-spreadsheet-trendline-svg.d.ts +9 -0
  394. package/dist/internal/features/work/work-spreadsheet-trendlines.d.ts +11 -0
  395. package/dist/internal/features/work/work-spreadsheet-xy-chart-axes-svg.d.ts +10 -0
  396. package/dist/internal/features/work/work-templates.d.ts +4 -0
  397. package/dist/internal/features/work/work-types.d.ts +513 -0
  398. package/dist/internal/features/work/work-xlsx-chart-axes.d.ts +4 -0
  399. package/dist/internal/features/work/work-xlsx-chart-diagnostics.d.ts +3 -0
  400. package/dist/internal/features/work/work-xlsx-chart-layout.d.ts +16 -0
  401. package/dist/internal/features/work/work-xlsx-chart-series-style.d.ts +6 -0
  402. package/dist/internal/features/work/work-xlsx-chart-values.d.ts +10 -0
  403. package/dist/internal/features/work/work-xlsx-charts.d.ts +32 -0
  404. package/dist/internal/features/work/work-xlsx-conditional-format-diagnostics.d.ts +6 -0
  405. package/dist/internal/features/work/work-xlsx-conditional-format-write.d.ts +11 -0
  406. package/dist/internal/features/work/work-xlsx-conditional-format.d.ts +29 -0
  407. package/dist/internal/features/work/work-xlsx-defined-names.d.ts +4 -0
  408. package/dist/internal/features/work/work-xlsx-drawing-geometry.d.ts +27 -0
  409. package/dist/internal/features/work/work-xlsx-formula-diagnostics.d.ts +3 -0
  410. package/dist/internal/features/work/work-xlsx-formulas.d.ts +40 -0
  411. package/dist/internal/features/work/work-xlsx-header-footer.d.ts +12 -0
  412. package/dist/internal/features/work/work-xlsx-images.d.ts +17 -0
  413. package/dist/internal/features/work/work-xlsx-interop.d.ts +39 -0
  414. package/dist/internal/features/work/work-xlsx-page-breaks.d.ts +7 -0
  415. package/dist/internal/features/work/work-xlsx-page-setup-diagnostics.d.ts +2 -0
  416. package/dist/internal/features/work/work-xlsx-page-setup.d.ts +5 -0
  417. package/dist/internal/features/work/work-xlsx-pivot-diagnostics.d.ts +3 -0
  418. package/dist/internal/features/work/work-xlsx-pivot-xml.d.ts +9 -0
  419. package/dist/internal/features/work/work-xlsx-pivots.d.ts +32 -0
  420. package/dist/internal/features/work/work-xlsx-protection.d.ts +24 -0
  421. package/dist/internal/features/workspace/components/workspace-context-menu.d.ts +29 -0
  422. package/dist/internal/features/workspace/components/workspace-text-control-selection.d.ts +7 -0
  423. package/dist/internal/kernel/office-kernel-client-types.d.ts +40 -0
  424. package/dist/internal/kernel/office-kernel-client.d.ts +4 -0
  425. package/dist/internal/kernel/office-kernel-fallback.d.ts +2 -0
  426. package/dist/internal/kernel/office-kernel-presentation-fallback.d.ts +2 -0
  427. package/dist/internal/kernel/office-kernel-protocol.d.ts +229 -0
  428. package/dist/internal/kernel/office-kernel-spreadsheet-fallback-formula.d.ts +3 -0
  429. package/dist/internal/kernel/office-kernel-spreadsheet-fallback-validation.d.ts +5 -0
  430. package/dist/internal/kernel/office-kernel-spreadsheet-fallback-value.d.ts +6 -0
  431. package/dist/internal/kernel/office-kernel-spreadsheet-fallback.d.ts +2 -0
  432. package/dist/internal/kernel/office-kernel-spreadsheet-protocol.d.ts +112 -0
  433. package/dist/internal/kernel/office-kernel-spreadsheet-session-fallback.d.ts +8 -0
  434. package/dist/internal/kernel/office-kernel-text-fallback.d.ts +10 -0
  435. package/dist/internal/kernel/office-kernel-version.d.ts +1 -0
  436. package/dist/internal/kernel/office-kernel.worker.d.ts +1 -0
  437. package/dist/internal/keyboard-shortcuts.d.ts +2 -0
  438. package/dist/internal/state/app-state.d.ts +8 -0
  439. package/dist/noto-naskh-arabic-regular.ttf +0 -0
  440. package/dist/noto-naskh-arabic.LICENSE.txt +94 -0
  441. package/dist/noto-sans-hans-regular.otf +0 -0
  442. package/dist/noto-sans-hans.LICENSE.txt +94 -0
  443. package/dist/noto-sans-hebrew-regular.ttf +0 -0
  444. package/dist/noto-sans-hebrew.LICENSE.txt +94 -0
  445. package/dist/noto-sans-regular.ttf +0 -0
  446. package/dist/noto-sans.LICENSE.txt +94 -0
  447. package/dist/office-kernel.wasm +0 -0
  448. package/dist/office-kernel.worker.js +14605 -0
  449. package/dist/office-surface.d.ts +10 -0
  450. package/dist/pdfium.LICENSE.txt +196 -0
  451. package/dist/pdfium.wasm +0 -0
  452. package/dist/pptxgen.LICENSE.txt +21 -0
  453. package/dist/pptxgen.bundle.js +11244 -0
  454. package/dist/react.d.ts +51 -0
  455. package/dist/react.js +1 -0
  456. package/dist/styles.css +17435 -0
  457. package/dist/styles.js +0 -0
  458. package/dist/vue.d.ts +282 -0
  459. package/dist/vue.js +231 -0
  460. package/dist/web-component.d.ts +98 -0
  461. package/dist/web-component.js +335 -0
  462. package/docs/browser-editor-architecture.md +947 -0
  463. package/package.json +165 -0
@@ -0,0 +1,2260 @@
1
+ import { __webpack_require__ } from "./0~rslib-runtime.js";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { EditorContent, useEditor } from "@tiptap/react";
4
+ import { useCallback, useDeferredValue, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
5
+ import { Extension } from "@tiptap/core";
6
+ import { TaskItem, TaskList } from "@tiptap/extension-list";
7
+ import extension_image from "@tiptap/extension-image";
8
+ import extension_placeholder from "@tiptap/extension-placeholder";
9
+ import { TableKit } from "@tiptap/extension-table";
10
+ import { Markdown } from "@tiptap/markdown";
11
+ import starter_kit from "@tiptap/starter-kit";
12
+ import { Bold, Code2, Columns2, Image, Italic, Link2, List, ListChecks, ListOrdered, Minus, PencilLine, Quote, Redo2, Strikethrough, Table2, Undo2, Unlink } from "lucide-react";
13
+ import { mergeOfficeTiptapExtensions, documentPlainTextAsHtml, customSelectionMenuItems } from "./0~5050.js";
14
+ import { OfficeSelect, isWorkspaceContextMenuKeyboardEvent, WorkOfficeZoomControls, WorkOfficeStatusBar, Dialog, WorkOfficeRibbon, workspaceContextMenuPosition, WorkspaceContextMenu, WorkOfficeRibbonGroup, WorkOfficeRibbonButton, WorkOfficePreviewBar } from "./0~4595.js";
15
+ import { button_Button, stepOfficeZoom, useOfficeEditorWheelZoom, office_text_field_OfficeTextField } from "./0~9512.js";
16
+ import { normalizeDocumentHref, DOCUMENT_LINK_VALIDATION_MESSAGE } from "./0~work-document-links.js";
17
+ import { WorkEditorLoadingState } from "./432.js";
18
+ var markdown_editor_namespaceObject = {};
19
+ __webpack_require__.r(markdown_editor_namespaceObject);
20
+ __webpack_require__.d(markdown_editor_namespaceObject, {
21
+ MarkdownEditor: ()=>MarkdownEditor,
22
+ markdownTaskCheckboxLabel: ()=>markdownTaskCheckboxLabel
23
+ });
24
+ const TEXT_CONTROL_MIRROR_PROPERTIES = [
25
+ 'box-sizing',
26
+ 'width',
27
+ 'height',
28
+ 'padding-top',
29
+ 'padding-right',
30
+ 'padding-bottom',
31
+ 'padding-left',
32
+ 'border-top-width',
33
+ 'border-right-width',
34
+ 'border-bottom-width',
35
+ 'border-left-width',
36
+ 'border-top-style',
37
+ 'border-right-style',
38
+ 'border-bottom-style',
39
+ 'border-left-style',
40
+ 'font-family',
41
+ 'font-size',
42
+ 'font-style',
43
+ 'font-weight',
44
+ 'font-variant',
45
+ 'font-stretch',
46
+ 'line-height',
47
+ 'letter-spacing',
48
+ 'text-align',
49
+ 'text-indent',
50
+ 'text-transform',
51
+ 'word-spacing',
52
+ 'tab-size',
53
+ 'direction',
54
+ 'writing-mode',
55
+ 'white-space',
56
+ 'overflow-wrap',
57
+ 'word-break',
58
+ 'scrollbar-gutter'
59
+ ];
60
+ function workspaceTextControlSelectionBounds(control) {
61
+ const { selectionEnd, selectionStart } = control;
62
+ if (selectionEnd <= selectionStart) return null;
63
+ const ownerDocument = control.ownerDocument;
64
+ const view = ownerDocument.defaultView;
65
+ if (!view || !ownerDocument.body) return null;
66
+ const controlBounds = control.getBoundingClientRect();
67
+ if (controlBounds.width <= 0 || controlBounds.height <= 0) return null;
68
+ const computedStyle = view.getComputedStyle(control);
69
+ const mirror = ownerDocument.createElement('div');
70
+ mirror.setAttribute('aria-hidden', 'true');
71
+ mirror.style.position = 'fixed';
72
+ mirror.style.left = `${controlBounds.left}px`;
73
+ mirror.style.top = `${controlBounds.top}px`;
74
+ mirror.style.margin = '0';
75
+ mirror.style.overflow = 'hidden';
76
+ mirror.style.pointerEvents = 'none';
77
+ mirror.style.visibility = 'hidden';
78
+ for (const property of TEXT_CONTROL_MIRROR_PROPERTIES)mirror.style.setProperty(property, computedStyle.getPropertyValue(property));
79
+ const text = ownerDocument.createTextNode(`${control.value}\u200b`);
80
+ mirror.append(text);
81
+ ownerDocument.body.append(mirror);
82
+ mirror.scrollLeft = control.scrollLeft;
83
+ mirror.scrollTop = control.scrollTop;
84
+ const range = ownerDocument.createRange();
85
+ range.setStart(text, selectionStart);
86
+ range.setEnd(text, selectionEnd);
87
+ const selectionBounds = range.getBoundingClientRect();
88
+ mirror.remove();
89
+ return visibleSelectionBounds(selectionBounds, controlBounds);
90
+ }
91
+ function visibleSelectionBounds(selection, control) {
92
+ const left = Math.max(selection.left, control.left);
93
+ const top = Math.max(selection.top, control.top);
94
+ const right = Math.min(selection.right, control.right);
95
+ const bottom = Math.min(selection.bottom, control.bottom);
96
+ if (right <= left || bottom <= top) return null;
97
+ return {
98
+ left,
99
+ top,
100
+ width: right - left,
101
+ height: bottom - top
102
+ };
103
+ }
104
+ const WorkMarkdown = Extension.create({
105
+ name: 'workMarkdown',
106
+ addCommands () {
107
+ return {
108
+ setWorkMarkdown: (markdown, options = {})=>({ chain })=>chain().setMeta('addToHistory', false).setContent(markdown, {
109
+ contentType: 'markdown',
110
+ emitUpdate: options.emitUpdate ?? true
111
+ }).run()
112
+ };
113
+ }
114
+ });
115
+ function createWorkMarkdownExtensions() {
116
+ return [
117
+ starter_kit.configure({
118
+ link: {
119
+ autolink: true,
120
+ defaultProtocol: 'https',
121
+ openOnClick: false
122
+ },
123
+ underline: false
124
+ }),
125
+ TaskList,
126
+ TaskItem.configure({
127
+ nested: true,
128
+ HTMLAttributes: {
129
+ 'data-type': 'taskItem'
130
+ },
131
+ a11y: {
132
+ checkboxLabel: markdownTaskCheckboxLabel
133
+ }
134
+ }),
135
+ extension_image.configure({
136
+ allowBase64: false,
137
+ inline: true
138
+ }),
139
+ TableKit.configure({
140
+ table: {
141
+ allowTableNodeSelection: true,
142
+ resizable: false
143
+ }
144
+ }),
145
+ extension_placeholder.configure({
146
+ placeholder: '开始写 Markdown…'
147
+ }),
148
+ Markdown.configure({
149
+ indentation: {
150
+ style: 'space',
151
+ size: 2
152
+ },
153
+ markedOptions: {
154
+ gfm: true,
155
+ breaks: false,
156
+ pedantic: false
157
+ }
158
+ }),
159
+ WorkMarkdown
160
+ ];
161
+ }
162
+ function markdownTaskCheckboxLabel(node) {
163
+ const label = node.textContent.trim() || '任务';
164
+ return `${node.attrs.checked ? '已完成' : '未完成'}:${label}`;
165
+ }
166
+ const INLINE_WRAPPERS = {
167
+ bold: '**',
168
+ code: '`',
169
+ italic: '*',
170
+ strike: '~~'
171
+ };
172
+ const MARKDOWN_TABLE = "| Column 1 | Column 2 | Column 3 |\n| --- | --- | --- |\n| | | |\n| | | |";
173
+ function isMarkdownSourceCommandActive(markdown, requestedSelection, command) {
174
+ const selection = normalizeMarkdownSourceSelection(requestedSelection, markdown.length);
175
+ if (isInlineMarkdownSourceCommand(command)) return sourceSelectionHasInlineWrapper(markdown, selection, INLINE_WRAPPERS[command], command);
176
+ if ('code-block' === command) {
177
+ const selected = markdown.slice(selection.start, selection.end);
178
+ return selected.startsWith('```\n') && selected.endsWith('\n```') || markdown.slice(0, selection.start).endsWith('```\n') && markdown.slice(selection.end).startsWith('\n```');
179
+ }
180
+ if ('horizontal-rule' === command || 'table' === command) return false;
181
+ const range = selectedLineRange(markdown, selection);
182
+ const lines = markdown.slice(range.start, range.end).split('\n').filter((line)=>line.length > 0);
183
+ if (!lines.length) return false;
184
+ if (command.startsWith('heading-')) {
185
+ const level = Number(command.at(-1));
186
+ const pattern = new RegExp(`^#{${level}}\\s+`);
187
+ return lines.every((line)=>pattern.test(line));
188
+ }
189
+ if ('paragraph' === command) return lines.every((line)=>!/^#{1,6}\s+/.test(line));
190
+ if ('blockquote' === command) return lines.every((line)=>/^>\s+/.test(line));
191
+ if ('bullet-list' === command) return lines.every((line)=>/^[-+*]\s+(?!\[[ xX]\]\s+)/.test(line));
192
+ if ('ordered-list' === command) return lines.every((line)=>/^\d+[.)]\s+/.test(line));
193
+ return lines.every((line)=>/^[-+*]\s+\[[ xX]\]\s+/.test(line));
194
+ }
195
+ function applyMarkdownSourceCommand(markdown, requestedSelection, command) {
196
+ const selection = normalizeMarkdownSourceSelection(requestedSelection, markdown.length);
197
+ if (isInlineMarkdownSourceCommand(command)) return toggleInlineWrapper(markdown, selection, INLINE_WRAPPERS[command], command);
198
+ if ('horizontal-rule' === command) return insertMarkdownBlock(markdown, selection, '---', void 0, true);
199
+ if ('table' === command) return insertMarkdownBlock(markdown, selection, MARKDOWN_TABLE, {
200
+ start: 2,
201
+ end: 10
202
+ });
203
+ if ('code-block' === command) return toggleCodeBlock(markdown, selection);
204
+ return transformSelectedLines(markdown, selection, command);
205
+ }
206
+ function isInlineMarkdownSourceCommand(command) {
207
+ return Object.hasOwn(INLINE_WRAPPERS, command);
208
+ }
209
+ function replaceMarkdownSourceSelection(markdown, requestedSelection, replacement, selectedRange = {
210
+ start: 0,
211
+ end: replacement.length
212
+ }) {
213
+ const selection = normalizeMarkdownSourceSelection(requestedSelection, markdown.length);
214
+ const nextMarkdown = `${markdown.slice(0, selection.start)}${replacement}${markdown.slice(selection.end)}`;
215
+ return {
216
+ markdown: nextMarkdown,
217
+ selection: {
218
+ start: selection.start + selectedRange.start,
219
+ end: selection.start + selectedRange.end,
220
+ direction: 'none'
221
+ }
222
+ };
223
+ }
224
+ function createMarkdownLinkSourceInsert(label, source) {
225
+ return createMarkdownSourceInsert('', label, source, 1);
226
+ }
227
+ function createMarkdownImageSourceInsert(altText, source) {
228
+ return createMarkdownSourceInsert('!', altText, source, 2);
229
+ }
230
+ function findMarkdownSourceLink(markdown, requestedSelection) {
231
+ const selection = normalizeMarkdownSourceSelection(requestedSelection, markdown.length);
232
+ let cursor = 0;
233
+ while(cursor < markdown.length){
234
+ const openBracket = markdown.indexOf('[', cursor);
235
+ if (openBracket < 0) break;
236
+ cursor = openBracket + 1;
237
+ if (markdownDelimiterIsEscaped(markdown, openBracket) || markdownSourceBracketStartsImage(markdown, openBracket)) continue;
238
+ const closeBracket = markdownSourceClosingBracket(markdown, openBracket);
239
+ if (closeBracket < 0 || '(' !== markdown[closeBracket + 1]) continue;
240
+ const destination = markdownSourceLinkDestination(markdown, closeBracket + 1);
241
+ if (!destination) continue;
242
+ cursor = destination.range.end;
243
+ const range = {
244
+ start: openBracket,
245
+ end: destination.range.end
246
+ };
247
+ if (!markdownSourceSelectionTargetsRange(selection, range)) continue;
248
+ const rawLabel = markdown.slice(openBracket + 1, closeBracket);
249
+ return {
250
+ label: unescapeMarkdownLinkLabel(rawLabel),
251
+ rawLabel,
252
+ range,
253
+ source: unescapeMarkdownLinkDestination(destination.rawSource)
254
+ };
255
+ }
256
+ return null;
257
+ }
258
+ function createMarkdownSourceLinkRemoval(link) {
259
+ return {
260
+ replacement: link.rawLabel,
261
+ selectedRange: {
262
+ start: 0,
263
+ end: link.rawLabel.length
264
+ }
265
+ };
266
+ }
267
+ function createMarkdownSourceInsert(prefix, text, source, selectionStart) {
268
+ const escapedText = text.replaceAll('\\', '\\\\').replaceAll('[', '\\[').replaceAll(']', '\\]');
269
+ const destination = /\s/u.test(source) ? `<${source}>` : source.replace(/([\\()])/gu, '\\$1');
270
+ return {
271
+ replacement: `${prefix}[${escapedText}](${destination})`,
272
+ selectedRange: {
273
+ start: selectionStart,
274
+ end: selectionStart + escapedText.length
275
+ }
276
+ };
277
+ }
278
+ function markdownSourceBracketStartsImage(markdown, openBracket) {
279
+ const marker = openBracket - 1;
280
+ return marker >= 0 && '!' === markdown[marker] && !markdownDelimiterIsEscaped(markdown, marker);
281
+ }
282
+ function markdownSourceClosingBracket(markdown, openBracket) {
283
+ let depth = 1;
284
+ for(let cursor = openBracket + 1; cursor < markdown.length; cursor += 1)if (!markdownDelimiterIsEscaped(markdown, cursor)) {
285
+ if ('[' === markdown[cursor]) depth += 1;
286
+ else if (']' === markdown[cursor]) {
287
+ depth -= 1;
288
+ if (0 === depth) return cursor;
289
+ }
290
+ }
291
+ return -1;
292
+ }
293
+ function markdownSourceLinkDestination(markdown, openParenthesis) {
294
+ let cursor = openParenthesis + 1;
295
+ while(' ' === markdown[cursor] || '\t' === markdown[cursor])cursor += 1;
296
+ if (cursor >= markdown.length || '\n' === markdown[cursor]) return null;
297
+ let rawSource = '';
298
+ if ('<' === markdown[cursor]) {
299
+ const sourceStart = cursor + 1;
300
+ cursor = sourceStart;
301
+ while(cursor < markdown.length && ('>' !== markdown[cursor] || markdownDelimiterIsEscaped(markdown, cursor))){
302
+ if ('\n' === markdown[cursor]) return null;
303
+ cursor += 1;
304
+ }
305
+ if ('>' !== markdown[cursor]) return null;
306
+ rawSource = markdown.slice(sourceStart, cursor);
307
+ cursor += 1;
308
+ } else {
309
+ const sourceStart = cursor;
310
+ let depth = 0;
311
+ while(cursor < markdown.length){
312
+ const character = markdown[cursor];
313
+ if ('\n' === character) return null;
314
+ if (markdownDelimiterIsEscaped(markdown, cursor)) {
315
+ cursor += 1;
316
+ continue;
317
+ }
318
+ if ('(' === character) depth += 1;
319
+ else if (')' === character) {
320
+ if (0 === depth) break;
321
+ depth -= 1;
322
+ } else if ((' ' === character || '\t' === character) && 0 === depth) break;
323
+ cursor += 1;
324
+ }
325
+ rawSource = markdown.slice(sourceStart, cursor);
326
+ }
327
+ if (!rawSource) return null;
328
+ while(' ' === markdown[cursor] || '\t' === markdown[cursor])cursor += 1;
329
+ if (')' !== markdown[cursor]) {
330
+ cursor = markdownSourceLinkTitleEnd(markdown, cursor);
331
+ if (cursor < 0) return null;
332
+ while(' ' === markdown[cursor] || '\t' === markdown[cursor])cursor += 1;
333
+ }
334
+ if (')' !== markdown[cursor]) return null;
335
+ return {
336
+ range: {
337
+ start: openParenthesis,
338
+ end: cursor + 1
339
+ },
340
+ rawSource
341
+ };
342
+ }
343
+ function markdownSourceLinkTitleEnd(markdown, start) {
344
+ const opener = markdown[start];
345
+ const closer = '(' === opener ? ')' : opener;
346
+ if (!closer || ![
347
+ '"',
348
+ "'",
349
+ '('
350
+ ].includes(opener ?? '')) return -1;
351
+ for(let cursor = start + 1; cursor < markdown.length; cursor += 1){
352
+ if ('\n' === markdown[cursor]) break;
353
+ if (markdown[cursor] === closer && !markdownDelimiterIsEscaped(markdown, cursor)) return cursor + 1;
354
+ }
355
+ return -1;
356
+ }
357
+ function markdownSourceSelectionTargetsRange(selection, range) {
358
+ if (selection.start === selection.end) return selection.start >= range.start && selection.start < range.end;
359
+ return selection.start >= range.start && selection.end <= range.end;
360
+ }
361
+ function unescapeMarkdownLinkLabel(label) {
362
+ return label.replace(/\\([\\[\]])/gu, '$1');
363
+ }
364
+ function unescapeMarkdownLinkDestination(source) {
365
+ return source.replace(/\\([\\()<>])/gu, '$1');
366
+ }
367
+ function toggleInlineWrapper(markdown, selection, wrapper, command) {
368
+ const selected = markdown.slice(selection.start, selection.end);
369
+ const selectedHasWrapper = selected.length >= 2 * wrapper.length && selected.startsWith(wrapper) && selected.endsWith(wrapper);
370
+ if (selectedHasWrapper) {
371
+ const replacement = selected.slice(wrapper.length, -wrapper.length);
372
+ return replaceMarkdownSourceSelection(markdown, selection, replacement);
373
+ }
374
+ const enclosingWrapper = inlineWrapperAroundSelection(markdown, selection, wrapper, command);
375
+ if (enclosingWrapper) return {
376
+ markdown: `${markdown.slice(0, enclosingWrapper.open)}${markdown.slice(enclosingWrapper.open + wrapper.length, enclosingWrapper.close)}${markdown.slice(enclosingWrapper.close + wrapper.length)}`,
377
+ selection: {
378
+ start: selection.start - wrapper.length,
379
+ end: selection.end - wrapper.length,
380
+ direction: selection.direction
381
+ }
382
+ };
383
+ const before = markdown.slice(0, selection.start);
384
+ const after = markdown.slice(selection.end);
385
+ const wrapperOutsideSelection = before.endsWith(wrapper) && after.startsWith(wrapper) && !('italic' === command && before.endsWith('**') && after.startsWith('**'));
386
+ if (wrapperOutsideSelection) return {
387
+ markdown: `${before.slice(0, -wrapper.length)}${selected}${after.slice(wrapper.length)}`,
388
+ selection: {
389
+ start: selection.start - wrapper.length,
390
+ end: selection.end - wrapper.length,
391
+ direction: selection.direction
392
+ }
393
+ };
394
+ const replacement = `${wrapper}${selected}${wrapper}`;
395
+ return replaceMarkdownSourceSelection(markdown, selection, replacement, {
396
+ start: wrapper.length,
397
+ end: wrapper.length + selected.length
398
+ });
399
+ }
400
+ function sourceSelectionHasInlineWrapper(markdown, selection, wrapper, command) {
401
+ const selected = markdown.slice(selection.start, selection.end);
402
+ const selectedHasWrapper = selected.length >= 2 * wrapper.length && selected.startsWith(wrapper) && selected.endsWith(wrapper) && !('italic' === command && selected.startsWith('**') && selected.endsWith('**'));
403
+ if (selectedHasWrapper) return true;
404
+ if (inlineWrapperAroundSelection(markdown, selection, wrapper, command)) return true;
405
+ const before = markdown.slice(0, selection.start);
406
+ const after = markdown.slice(selection.end);
407
+ return before.endsWith(wrapper) && after.startsWith(wrapper) && !('italic' === command && before.endsWith('**') && after.startsWith('**'));
408
+ }
409
+ function inlineWrapperAroundSelection(markdown, selection, wrapper, command) {
410
+ const lineStart = markdown.lastIndexOf('\n', Math.max(0, selection.start - 1)) + 1;
411
+ const followingNewline = markdown.indexOf('\n', selection.end);
412
+ const lineEnd = followingNewline < 0 ? markdown.length : followingNewline;
413
+ const delimiters = [];
414
+ for(let index = lineStart; index <= lineEnd - wrapper.length;)if (!markdown.startsWith(wrapper, index) || markdownDelimiterIsEscaped(markdown, index) || 'italic' === command && ('*' === markdown[index - 1] || '*' === markdown[index + wrapper.length])) index += 1;
415
+ else {
416
+ delimiters.push(index);
417
+ index += wrapper.length;
418
+ }
419
+ for(let index = 0; index + 1 < delimiters.length; index += 2){
420
+ const open = delimiters[index];
421
+ const close = delimiters[index + 1];
422
+ if (void 0 !== open && void 0 !== close && selection.start >= open + wrapper.length && selection.end <= close) return {
423
+ open,
424
+ close
425
+ };
426
+ }
427
+ return null;
428
+ }
429
+ function markdownDelimiterIsEscaped(markdown, index) {
430
+ let backslashes = 0;
431
+ for(let cursor = index - 1; cursor >= 0 && '\\' === markdown[cursor]; cursor -= 1)backslashes += 1;
432
+ return backslashes % 2 === 1;
433
+ }
434
+ function transformSelectedLines(markdown, selection, command) {
435
+ const range = selectedLineRange(markdown, selection);
436
+ const lines = markdown.slice(range.start, range.end).split('\n');
437
+ const nonEmptyLines = lines.filter((line)=>line.length > 0);
438
+ const everyNonEmptyLine = (pattern)=>nonEmptyLines.length > 0 && nonEmptyLines.every((line)=>pattern.test(line));
439
+ let transformed;
440
+ if (command.startsWith('heading-')) {
441
+ const level = Number(command.at(-1));
442
+ const prefix = `${'#'.repeat(level)} `;
443
+ transformed = lines.map((line)=>line ? `${prefix}${stripBlockPrefix(line)}` : prefix);
444
+ } else if ('paragraph' === command) transformed = lines.map((line)=>line.replace(/^#{1,6}\s+/, ''));
445
+ else if ('blockquote' === command) {
446
+ const remove = everyNonEmptyLine(/^>\s+/);
447
+ transformed = lines.map((line)=>remove ? line.replace(/^>\s+/, '') : line ? `> ${line}` : '> ');
448
+ } else {
449
+ const pattern = 'bullet-list' === command ? /^[-+*]\s+(?!\[[ xX]\]\s+)/ : 'ordered-list' === command ? /^\d+[.)]\s+/ : /^[-+*]\s+\[[ xX]\]\s+/;
450
+ const remove = everyNonEmptyLine(pattern);
451
+ transformed = lines.map((line, index)=>{
452
+ const text = stripListPrefix(line);
453
+ if (remove) return text;
454
+ if ('ordered-list' === command) return `${index + 1}. ${text}`;
455
+ if ('task-list' === command) return `- [ ] ${text}`;
456
+ return `- ${text}`;
457
+ });
458
+ }
459
+ const replacement = transformed.join('\n');
460
+ return {
461
+ markdown: `${markdown.slice(0, range.start)}${replacement}${markdown.slice(range.end)}`,
462
+ selection: {
463
+ start: range.start,
464
+ end: range.start + replacement.length,
465
+ direction: selection.direction
466
+ }
467
+ };
468
+ }
469
+ function toggleCodeBlock(markdown, selection) {
470
+ const selected = markdown.slice(selection.start, selection.end);
471
+ if (selected.startsWith('```\n') && selected.endsWith('\n```')) {
472
+ const replacement = selected.slice(4, -4);
473
+ return replaceMarkdownSourceSelection(markdown, selection, replacement);
474
+ }
475
+ const before = markdown.slice(0, selection.start);
476
+ const after = markdown.slice(selection.end);
477
+ if (before.endsWith('```\n') && after.startsWith('\n```')) return {
478
+ markdown: `${before.slice(0, -4)}${selected}${after.slice(4)}`,
479
+ selection: {
480
+ start: selection.start - 4,
481
+ end: selection.end - 4,
482
+ direction: selection.direction
483
+ }
484
+ };
485
+ return replaceMarkdownSourceSelection(markdown, selection, `\`\`\`\n${selected}\n\`\`\``, {
486
+ start: 4,
487
+ end: 4 + selected.length
488
+ });
489
+ }
490
+ function insertMarkdownBlock(markdown, selection, block, selectedRange, appendBlank = false) {
491
+ const before = markdown.slice(0, selection.start);
492
+ const after = markdown.slice(selection.end);
493
+ const leading = before ? before.endsWith('\n\n') ? '' : before.endsWith('\n') ? '\n' : '\n\n' : '';
494
+ const trailing = after ? after.startsWith('\n\n') ? '' : after.startsWith('\n') ? '\n' : '\n\n' : appendBlank ? '\n\n' : '';
495
+ const replacement = `${leading}${block}${trailing}`;
496
+ const blockStart = selection.start + leading.length;
497
+ return {
498
+ markdown: `${before}${replacement}${after}`,
499
+ selection: selectedRange ? {
500
+ start: blockStart + selectedRange.start,
501
+ end: blockStart + selectedRange.end,
502
+ direction: 'none'
503
+ } : {
504
+ start: selection.start + replacement.length,
505
+ end: selection.start + replacement.length,
506
+ direction: 'none'
507
+ }
508
+ };
509
+ }
510
+ function selectedLineRange(markdown, selection) {
511
+ const start = 0 === selection.start ? 0 : markdown.lastIndexOf('\n', selection.start - 1) + 1;
512
+ const inclusiveEnd = selection.end > selection.start && '\n' === markdown[selection.end - 1] ? selection.end - 1 : selection.end;
513
+ const newline = markdown.indexOf('\n', inclusiveEnd);
514
+ return {
515
+ start,
516
+ end: newline < 0 ? markdown.length : newline
517
+ };
518
+ }
519
+ function stripBlockPrefix(line) {
520
+ return line.replace(/^(?:#{1,6}\s+|[-+*]\s+(?:\[[ xX]\]\s+)?|\d+[.)]\s+|>\s+)/, '');
521
+ }
522
+ function stripListPrefix(line) {
523
+ return line.replace(/^(?:[-+*]\s+(?:\[[ xX]\]\s+)?|\d+[.)]\s+)/, '');
524
+ }
525
+ function normalizeMarkdownSourceSelection(selection, markdownLength) {
526
+ const requestedStart = Math.min(selection.start, selection.end);
527
+ const requestedEnd = Math.max(selection.start, selection.end);
528
+ return {
529
+ start: Math.max(0, Math.min(markdownLength, requestedStart)),
530
+ end: Math.max(0, Math.min(markdownLength, requestedEnd)),
531
+ direction: selection.direction
532
+ };
533
+ }
534
+ const SURROUNDING_TEXT_LIMIT = 2000;
535
+ function createWorkMarkdownSourceSelectionSnapshot(markdown, selection, content) {
536
+ const from = Math.max(0, Math.min(markdown.length, selection.start));
537
+ const to = Math.max(from, Math.min(markdown.length, selection.end));
538
+ const rawText = markdown.slice(from, to);
539
+ const text = rawText.trim();
540
+ if (!text) return null;
541
+ return {
542
+ selection: {
543
+ surface: 'source',
544
+ from,
545
+ to,
546
+ text,
547
+ rawText,
548
+ beforeText: markdown.slice(0, from).slice(-SURROUNDING_TEXT_LIMIT),
549
+ afterText: markdown.slice(to).slice(0, SURROUNDING_TEXT_LIMIT)
550
+ },
551
+ document: {
552
+ content: content.markdown === markdown ? content : {
553
+ ...content,
554
+ markdown
555
+ },
556
+ markdown,
557
+ text: markdown
558
+ }
559
+ };
560
+ }
561
+ function createWorkMarkdownVisualSelectionSnapshot(editor, content) {
562
+ const { from, to, empty } = editor.state.selection;
563
+ if (empty) return null;
564
+ const rawText = editor.state.doc.textBetween(from, to, '\n');
565
+ const text = rawText.trim();
566
+ if (!text) return null;
567
+ const markdown = editor.getMarkdown();
568
+ return {
569
+ selection: {
570
+ surface: 'visual',
571
+ from,
572
+ to,
573
+ text,
574
+ rawText,
575
+ beforeText: editor.state.doc.textBetween(0, from, '\n').slice(-SURROUNDING_TEXT_LIMIT),
576
+ afterText: editor.state.doc.textBetween(to, editor.state.doc.content.size, '\n').slice(0, SURROUNDING_TEXT_LIMIT)
577
+ },
578
+ document: {
579
+ content: content.markdown === markdown ? content : {
580
+ ...content,
581
+ markdown
582
+ },
583
+ markdown,
584
+ text: editor.state.doc.textBetween(0, editor.state.doc.content.size, '\n')
585
+ }
586
+ };
587
+ }
588
+ function createWorkMarkdownSourceSelectionAction(snapshot, getMarkdown, applyEdit) {
589
+ let from = snapshot.selection.from;
590
+ let to = snapshot.selection.to;
591
+ let expectedText = snapshot.selection.rawText;
592
+ let disposed = false;
593
+ const currentSelection = ()=>{
594
+ if (disposed) return 'editor-unavailable';
595
+ const markdown = getMarkdown();
596
+ if (markdown.slice(from, to) !== expectedText) return 'stale-selection';
597
+ return {
598
+ start: from,
599
+ end: to,
600
+ direction: 'none'
601
+ };
602
+ };
603
+ const editText = (text, placement)=>{
604
+ if ('string' != typeof text || 'replace' !== placement && !text) return {
605
+ applied: false,
606
+ reason: 'invalid-text'
607
+ };
608
+ const selection = currentSelection();
609
+ if ('string' == typeof selection) return {
610
+ applied: false,
611
+ reason: selection
612
+ };
613
+ const editSelection = 'before' === placement ? {
614
+ ...selection,
615
+ end: selection.start
616
+ } : 'after' === placement ? {
617
+ ...selection,
618
+ start: selection.end
619
+ } : selection;
620
+ const edit = replaceMarkdownSourceSelection(getMarkdown(), editSelection, text);
621
+ if (!applyEdit(edit)) return {
622
+ applied: false,
623
+ reason: 'command-rejected'
624
+ };
625
+ if ('before' === placement) {
626
+ from += text.length;
627
+ to += text.length;
628
+ } else if ('replace' === placement) {
629
+ to = from + text.length;
630
+ expectedText = text;
631
+ }
632
+ return {
633
+ applied: true
634
+ };
635
+ };
636
+ return {
637
+ context: {
638
+ ...snapshot,
639
+ commands: {
640
+ copyText: ()=>copyMarkdownSelection(snapshot.selection.rawText),
641
+ insertAfter: (text)=>editText(text, 'after'),
642
+ insertBefore: (text)=>editText(text, 'before'),
643
+ replaceText: (text)=>editText(text, 'replace')
644
+ }
645
+ },
646
+ dispose: ()=>{
647
+ disposed = true;
648
+ }
649
+ };
650
+ }
651
+ function createWorkMarkdownVisualSelectionAction(editor, snapshot) {
652
+ let from = snapshot.selection.from;
653
+ let to = snapshot.selection.to;
654
+ let stale = false;
655
+ let disposed = false;
656
+ const handleTransaction = ({ transaction })=>{
657
+ if (!transaction.docChanged || stale || disposed) return;
658
+ const mappedFrom = transaction.mapping.mapResult(from, 1);
659
+ const mappedTo = transaction.mapping.mapResult(to, -1);
660
+ from = mappedFrom.pos;
661
+ to = mappedTo.pos;
662
+ stale = mappedFrom.deletedAcross || mappedTo.deletedAcross || from > to || transaction.doc.textBetween(from, to, '\n') !== snapshot.selection.rawText;
663
+ };
664
+ editor.on('transaction', handleTransaction);
665
+ const currentRange = ()=>{
666
+ if (disposed || editor.isDestroyed) return 'editor-unavailable';
667
+ if (!editor.isEditable) return 'read-only';
668
+ if (stale || from < 0 || to < from || to > editor.state.doc.content.size || editor.state.doc.textBetween(from, to, '\n') !== snapshot.selection.rawText) return 'stale-selection';
669
+ return {
670
+ from,
671
+ to
672
+ };
673
+ };
674
+ const editText = (text, placement)=>{
675
+ if ('string' != typeof text || 'replace' !== placement && !text) return {
676
+ applied: false,
677
+ reason: 'invalid-text'
678
+ };
679
+ const range = currentRange();
680
+ if ('string' == typeof range) return {
681
+ applied: false,
682
+ reason: range
683
+ };
684
+ const editRange = 'before' === placement ? {
685
+ from: range.from,
686
+ to: range.from
687
+ } : 'after' === placement ? {
688
+ from: range.to,
689
+ to: range.to
690
+ } : range;
691
+ const applied = editor.chain().focus().setTextSelection(editRange).insertContent(documentPlainTextAsHtml(text)).run();
692
+ return applied ? {
693
+ applied: true
694
+ } : {
695
+ applied: false,
696
+ reason: 'command-rejected'
697
+ };
698
+ };
699
+ return {
700
+ context: {
701
+ ...snapshot,
702
+ commands: {
703
+ copyText: ()=>copyMarkdownSelection(snapshot.selection.rawText),
704
+ insertAfter: (text)=>editText(text, 'after'),
705
+ insertBefore: (text)=>editText(text, 'before'),
706
+ replaceText: (text)=>editText(text, 'replace')
707
+ }
708
+ },
709
+ dispose: ()=>{
710
+ if (disposed) return;
711
+ disposed = true;
712
+ editor.off('transaction', handleTransaction);
713
+ }
714
+ };
715
+ }
716
+ async function copyMarkdownSelection(text) {
717
+ try {
718
+ if ("u" < typeof navigator || !navigator.clipboard?.writeText) return false;
719
+ await navigator.clipboard.writeText(text);
720
+ return true;
721
+ } catch {
722
+ return false;
723
+ }
724
+ }
725
+ const MARKDOWN_SURFACE_FOCUS_RETRY_FRAMES = 4;
726
+ function restoreMarkdownEditingSurfaceFocus(getTarget) {
727
+ const commandTrigger = document.activeElement;
728
+ let remainingFrames = MARKDOWN_SURFACE_FOCUS_RETRY_FRAMES;
729
+ const restore = ()=>{
730
+ if (remainingFrames <= 0) return;
731
+ remainingFrames -= 1;
732
+ const target = getTarget();
733
+ if (!target?.isConnected) return void requestAnimationFrame(restore);
734
+ const activeElement = document.activeElement;
735
+ const canRestore = activeElement === commandTrigger || activeElement === target || activeElement === document.body || activeElement === document.documentElement || !activeElement?.isConnected;
736
+ if (canRestore) target.focus({
737
+ preventScroll: true
738
+ });
739
+ };
740
+ requestAnimationFrame(restore);
741
+ }
742
+ function MarkdownSelectionContextMenu({ editor, menu, createSourceAction, onClose }) {
743
+ const createAction = ()=>'source' === menu.snapshot.selection.surface ? createSourceAction(menu.snapshot) : createWorkMarkdownVisualSelectionAction(editor, menu.snapshot);
744
+ return /*#__PURE__*/ jsx(WorkspaceContextMenu, {
745
+ label: "选中文本操作",
746
+ x: menu.x,
747
+ y: menu.y,
748
+ items: customSelectionMenuItems(menu.items, createAction),
749
+ onClose: onClose
750
+ });
751
+ }
752
+ const MARKDOWN_MIN_ZOOM = 60;
753
+ const MARKDOWN_MAX_ZOOM = 180;
754
+ function MarkdownStatus({ characterCount, lineCount, saveStatus, zoom, onZoomChange }) {
755
+ return /*#__PURE__*/ jsxs(WorkOfficeStatusBar, {
756
+ className: "work-markdown-status",
757
+ controls: /*#__PURE__*/ jsx(WorkOfficeZoomControls, {
758
+ zoom: zoom,
759
+ minimum: MARKDOWN_MIN_ZOOM,
760
+ maximum: MARKDOWN_MAX_ZOOM,
761
+ decreaseLabel: "缩小内容",
762
+ increaseLabel: "放大内容",
763
+ outputLabel: "Markdown 缩放比例",
764
+ sliderLabel: "调整 Markdown 缩放比例",
765
+ onChange: onZoomChange
766
+ }),
767
+ children: [
768
+ /*#__PURE__*/ jsxs("output", {
769
+ children: [
770
+ lineCount,
771
+ " 行"
772
+ ]
773
+ }),
774
+ /*#__PURE__*/ jsxs("output", {
775
+ children: [
776
+ characterCount,
777
+ " 字符"
778
+ ]
779
+ }),
780
+ saveStatus && /*#__PURE__*/ jsx("span", {
781
+ className: "work-office-save-status",
782
+ children: saveStatus
783
+ })
784
+ ]
785
+ });
786
+ }
787
+ const MARKDOWN_IMAGE_VALIDATION_MESSAGE = '请输入完整的 http、https 或相对图片地址。';
788
+ function MarkdownInsertDialog({ request, restoreFocusTarget, onClose, onSubmit }) {
789
+ const formId = useId();
790
+ const textFieldId = useId();
791
+ const sourceFieldId = useId();
792
+ const submittedRef = useRef(false);
793
+ const [source, setSource] = useState(request.source);
794
+ const [text, setText] = useState('link' === request.kind ? request.label : request.altText);
795
+ const normalizedSource = normalizeMarkdownInsertSource(request.kind, source);
796
+ const sourceReady = null !== normalizedSource;
797
+ const sourceError = markdownInsertSourceError(request.kind, source);
798
+ const sourceErrorId = `${sourceFieldId}-error`;
799
+ const submit = (event)=>{
800
+ event.preventDefault();
801
+ if (submittedRef.current) return;
802
+ const completedSource = normalizeMarkdownInsertSource(request.kind, source);
803
+ if (!completedSource) return;
804
+ submittedRef.current = true;
805
+ onSubmit('link' === request.kind ? {
806
+ kind: 'link',
807
+ action: request.action,
808
+ label: text.trim() || completedSource,
809
+ source: completedSource
810
+ } : {
811
+ kind: 'image',
812
+ altText: text.trim(),
813
+ source: completedSource
814
+ });
815
+ };
816
+ const title = 'link' === request.kind ? 'edit' === request.action ? '编辑链接' : '添加链接' : '插入图片';
817
+ const submitLabel = 'link' === request.kind ? 'edit' === request.action ? '保存' : '添加' : '插入';
818
+ const focusText = 'link' === request.kind && !request.label.trim();
819
+ return /*#__PURE__*/ jsx(Dialog, {
820
+ title: title,
821
+ className: "work-office-dialog work-markdown-insert-dialog",
822
+ restoreFocusTarget: restoreFocusTarget,
823
+ onClose: onClose,
824
+ footer: /*#__PURE__*/ jsxs(Fragment, {
825
+ children: [
826
+ /*#__PURE__*/ jsx(button_Button, {
827
+ tone: "quiet",
828
+ onClick: onClose,
829
+ children: "取消"
830
+ }),
831
+ /*#__PURE__*/ jsx(button_Button, {
832
+ tone: "primary",
833
+ type: "submit",
834
+ form: formId,
835
+ disabled: !sourceReady,
836
+ children: submitLabel
837
+ })
838
+ ]
839
+ }),
840
+ children: /*#__PURE__*/ jsxs("form", {
841
+ id: formId,
842
+ className: "work-markdown-insert-form",
843
+ onSubmit: submit,
844
+ children: [
845
+ /*#__PURE__*/ jsxs("label", {
846
+ className: "work-office-dialog-field",
847
+ htmlFor: textFieldId,
848
+ children: [
849
+ /*#__PURE__*/ jsx("span", {
850
+ className: "work-office-dialog-field-label",
851
+ children: 'link' === request.kind ? '显示文字' : '替代文字(可选)'
852
+ }),
853
+ /*#__PURE__*/ jsx(office_text_field_OfficeTextField, {
854
+ id: textFieldId,
855
+ "aria-label": 'link' === request.kind ? '显示文字' : '替代文字(可选)',
856
+ "data-autofocus": focusText || void 0,
857
+ value: text,
858
+ onChange: (event)=>setText(event.target.value)
859
+ })
860
+ ]
861
+ }),
862
+ /*#__PURE__*/ jsxs("label", {
863
+ className: "work-office-dialog-field",
864
+ htmlFor: sourceFieldId,
865
+ children: [
866
+ /*#__PURE__*/ jsx("span", {
867
+ className: "work-office-dialog-field-label",
868
+ children: 'link' === request.kind ? '链接地址' : '图片地址'
869
+ }),
870
+ /*#__PURE__*/ jsx(office_text_field_OfficeTextField, {
871
+ id: sourceFieldId,
872
+ "aria-label": 'link' === request.kind ? '链接地址' : '图片地址',
873
+ "aria-describedby": sourceError ? sourceErrorId : void 0,
874
+ "aria-invalid": sourceError ? true : void 0,
875
+ inputMode: "url",
876
+ placeholder: "https://",
877
+ "data-autofocus": !focusText || void 0,
878
+ value: source,
879
+ onChange: (event)=>setSource(event.target.value)
880
+ }),
881
+ sourceError && /*#__PURE__*/ jsx("span", {
882
+ id: sourceErrorId,
883
+ className: "work-office-dialog-field-error",
884
+ role: "alert",
885
+ children: sourceError
886
+ })
887
+ ]
888
+ })
889
+ ]
890
+ })
891
+ });
892
+ }
893
+ function normalizeMarkdownInsertSource(kind, source) {
894
+ const value = source.trim();
895
+ if (!value || /[\u0000-\u001f\u007f\\<>]/u.test(value)) return null;
896
+ if ('link' === kind) {
897
+ const normalized = normalizeDocumentHref(value);
898
+ return normalized ? normalizeMarkdownSourceSpaces(normalized) : null;
899
+ }
900
+ if (/^https?:/iu.test(value)) {
901
+ const normalized = normalizeDocumentHref(value);
902
+ return normalized && /^https?:/iu.test(normalized) ? normalizeMarkdownSourceSpaces(normalized) : null;
903
+ }
904
+ try {
905
+ const base = new URL('https://a3s-office.invalid/');
906
+ const resolved = new URL(value, base);
907
+ const path = value.split(/[?#]/u, 1)[0] ?? '';
908
+ return resolved.protocol === base.protocol && resolved.origin === base.origin && /[^\s./]/u.test(path) ? normalizeMarkdownSourceSpaces(value) : null;
909
+ } catch {
910
+ return null;
911
+ }
912
+ }
913
+ function normalizeMarkdownSourceSpaces(source) {
914
+ return source.replace(/ /gu, '%20');
915
+ }
916
+ function markdownInsertSourceError(kind, source) {
917
+ const value = source.trim();
918
+ if (!value || 'https://' === value) return null;
919
+ if (normalizeMarkdownInsertSource(kind, value)) return null;
920
+ return 'link' === kind ? DOCUMENT_LINK_VALIDATION_MESSAGE : MARKDOWN_IMAGE_VALIDATION_MESSAGE;
921
+ }
922
+ const markdownRibbonTabs = [
923
+ {
924
+ id: 'home',
925
+ label: '开始'
926
+ },
927
+ {
928
+ id: 'insert',
929
+ label: '插入'
930
+ },
931
+ {
932
+ id: 'view',
933
+ label: '视图'
934
+ }
935
+ ];
936
+ const markdownToolbarShortcuts = {
937
+ bold: {
938
+ ariaKeyShortcuts: 'Control+B Meta+B',
939
+ label: 'Cmd/Ctrl+B'
940
+ },
941
+ italic: {
942
+ ariaKeyShortcuts: 'Control+I Meta+I',
943
+ label: 'Cmd/Ctrl+I'
944
+ },
945
+ redo: {
946
+ ariaKeyShortcuts: 'Control+Shift+Z Meta+Shift+Z Control+Y Meta+Y',
947
+ label: 'Cmd/Ctrl+Shift+Z 或 Cmd/Ctrl+Y'
948
+ },
949
+ undo: {
950
+ ariaKeyShortcuts: 'Control+Z Meta+Z',
951
+ label: 'Cmd/Ctrl+Z'
952
+ }
953
+ };
954
+ function MarkdownToolbar({ editor, fileActions, sourceEditing, canSourceRedo, canSourceUndo, viewMode, getSourceFocusTarget, getSourceSelection, onSourceCommand, onSourceRedo, onSourceReplace, onSourceUndo, onViewModeChange }) {
955
+ const [activeTab, setActiveTab] = useState('home');
956
+ const [insertDialog, setInsertDialog] = useState(null);
957
+ const sourceSelection = sourceEditing ? getSourceSelection() : null;
958
+ const sourceLink = sourceSelection ? findMarkdownSourceLink(sourceSelection.markdown, sourceSelection.selection) : null;
959
+ const commandIsActive = (command)=>sourceSelection ? isMarkdownSourceCommandActive(sourceSelection.markdown, sourceSelection.selection, command) : false;
960
+ const paragraphStyle = sourceEditing ? commandIsActive('heading-1') ? 'h1' : commandIsActive('heading-2') ? 'h2' : commandIsActive('heading-3') ? 'h3' : 'paragraph' : editor.isActive('heading', {
961
+ level: 1
962
+ }) ? 'h1' : editor.isActive('heading', {
963
+ level: 2
964
+ }) ? 'h2' : editor.isActive('heading', {
965
+ level: 3
966
+ }) ? 'h3' : 'paragraph';
967
+ const linkActive = sourceEditing ? Boolean(sourceLink) : editor.isActive('link');
968
+ const canUndo = sourceEditing ? canSourceUndo : canRunVisualEditorCommand(editor, ()=>editor.can().chain().focus().undo().run());
969
+ const canRedo = sourceEditing ? canSourceRedo : canRunVisualEditorCommand(editor, ()=>editor.can().chain().focus().redo().run());
970
+ const runCommand = (sourceCommand, visualCommand)=>{
971
+ if (sourceEditing) return void onSourceCommand(sourceCommand);
972
+ visualCommand();
973
+ };
974
+ const openLinkDialog = ()=>{
975
+ if (sourceEditing) {
976
+ const current = getSourceSelection();
977
+ if (!current) return;
978
+ const link = findMarkdownSourceLink(current.markdown, current.selection);
979
+ setInsertDialog({
980
+ surface: 'source',
981
+ target: link ? {
982
+ markdown: current.markdown,
983
+ selection: {
984
+ start: link.range.start,
985
+ end: link.range.end,
986
+ direction: 'none'
987
+ },
988
+ text: current.markdown.slice(link.range.start, link.range.end)
989
+ } : current,
990
+ request: {
991
+ kind: 'link',
992
+ action: link ? 'edit' : 'insert',
993
+ label: link?.label ?? current.text,
994
+ source: link?.source ?? 'https://'
995
+ }
996
+ });
997
+ return;
998
+ }
999
+ const editingLink = editor.isActive('link');
1000
+ if (editingLink) editor.commands.extendMarkRange('link');
1001
+ const { from, to } = editor.state.selection;
1002
+ setInsertDialog({
1003
+ surface: 'visual',
1004
+ target: {
1005
+ document: editor.state.doc,
1006
+ from,
1007
+ text: editor.state.doc.textBetween(from, to, ' '),
1008
+ to
1009
+ },
1010
+ request: {
1011
+ kind: 'link',
1012
+ action: editingLink ? 'edit' : 'insert',
1013
+ label: editor.state.selection.empty ? '' : editor.state.doc.textBetween(from, to, ' '),
1014
+ source: editingLink ? String(editor.getAttributes('link').href ?? '') : 'https://'
1015
+ }
1016
+ });
1017
+ };
1018
+ const removeLink = ()=>{
1019
+ if (sourceEditing) {
1020
+ const current = getSourceSelection();
1021
+ if (!current) return;
1022
+ const link = findMarkdownSourceLink(current.markdown, current.selection);
1023
+ if (!link) return;
1024
+ const removal = createMarkdownSourceLinkRemoval(link);
1025
+ onSourceReplace(removal.replacement, removal.selectedRange, {
1026
+ markdown: current.markdown,
1027
+ selection: {
1028
+ start: link.range.start,
1029
+ end: link.range.end,
1030
+ direction: 'none'
1031
+ },
1032
+ text: current.markdown.slice(link.range.start, link.range.end)
1033
+ });
1034
+ return;
1035
+ }
1036
+ if (!editor.isActive('link')) return;
1037
+ editor.chain().focus().extendMarkRange('link').unsetLink().run();
1038
+ };
1039
+ const openImageDialog = ()=>{
1040
+ if (sourceEditing) {
1041
+ const current = getSourceSelection();
1042
+ if (!current) return;
1043
+ setInsertDialog({
1044
+ surface: 'source',
1045
+ target: current,
1046
+ request: {
1047
+ kind: 'image',
1048
+ altText: '',
1049
+ source: 'https://'
1050
+ }
1051
+ });
1052
+ return;
1053
+ }
1054
+ const { from, to } = editor.state.selection;
1055
+ setInsertDialog({
1056
+ surface: 'visual',
1057
+ target: {
1058
+ document: editor.state.doc,
1059
+ from,
1060
+ text: editor.state.doc.textBetween(from, to, ' '),
1061
+ to
1062
+ },
1063
+ request: {
1064
+ kind: 'image',
1065
+ altText: '',
1066
+ source: 'https://'
1067
+ }
1068
+ });
1069
+ };
1070
+ const commitInsert = (result)=>{
1071
+ const dialog = insertDialog;
1072
+ if (!dialog) return;
1073
+ if ('source' === dialog.surface) {
1074
+ const insert = 'image' === result.kind ? createMarkdownImageSourceInsert(result.altText, result.source) : createMarkdownLinkSourceInsert(result.label, result.source);
1075
+ onSourceReplace(insert.replacement, insert.selectedRange, dialog.target);
1076
+ setInsertDialog(null);
1077
+ return;
1078
+ }
1079
+ if (editor.isDestroyed || !editor.state.doc.eq(dialog.target.document)) return void setInsertDialog(null);
1080
+ const chain = editor.chain().focus().setTextSelection({
1081
+ from: dialog.target.from,
1082
+ to: dialog.target.to
1083
+ });
1084
+ if ('image' === result.kind) {
1085
+ chain.setImage({
1086
+ src: result.source,
1087
+ alt: result.altText || void 0
1088
+ }).run();
1089
+ setInsertDialog(null);
1090
+ return;
1091
+ }
1092
+ if (dialog.target.text && dialog.target.text === result.label) {
1093
+ chain.setLink({
1094
+ href: result.source
1095
+ }).run();
1096
+ setInsertDialog(null);
1097
+ return;
1098
+ }
1099
+ chain.insertContent({
1100
+ type: 'text',
1101
+ text: result.label,
1102
+ marks: [
1103
+ {
1104
+ type: 'link',
1105
+ attrs: {
1106
+ href: result.source
1107
+ }
1108
+ }
1109
+ ]
1110
+ }).run();
1111
+ setInsertDialog(null);
1112
+ };
1113
+ return /*#__PURE__*/ jsxs(Fragment, {
1114
+ children: [
1115
+ /*#__PURE__*/ jsx(WorkOfficeRibbon, {
1116
+ ariaLabel: "Markdown 功能区",
1117
+ tabs: markdownRibbonTabs,
1118
+ defaultTab: "home",
1119
+ activeTab: activeTab,
1120
+ onTabChange: setActiveTab,
1121
+ fileActions: fileActions,
1122
+ className: "work-markdown-ribbon",
1123
+ toolbarClassName: "markdown-toolbar",
1124
+ panels: {
1125
+ home: /*#__PURE__*/ jsxs(Fragment, {
1126
+ children: [
1127
+ /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
1128
+ label: "撤销",
1129
+ children: [
1130
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1131
+ label: "撤销",
1132
+ shortcut: markdownToolbarShortcuts.undo,
1133
+ disabled: !canUndo,
1134
+ onClick: ()=>{
1135
+ if (sourceEditing) onSourceUndo();
1136
+ else editor.chain().focus().undo().run();
1137
+ },
1138
+ children: /*#__PURE__*/ jsx(Undo2, {
1139
+ size: 16
1140
+ })
1141
+ }),
1142
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1143
+ label: "重做",
1144
+ shortcut: markdownToolbarShortcuts.redo,
1145
+ disabled: !canRedo,
1146
+ onClick: ()=>{
1147
+ if (sourceEditing) onSourceRedo();
1148
+ else editor.chain().focus().redo().run();
1149
+ },
1150
+ children: /*#__PURE__*/ jsx(Redo2, {
1151
+ size: 16
1152
+ })
1153
+ })
1154
+ ]
1155
+ }),
1156
+ /*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
1157
+ label: "样式",
1158
+ children: /*#__PURE__*/ jsx(OfficeSelect, {
1159
+ ariaLabel: "段落样式",
1160
+ value: paragraphStyle,
1161
+ options: [
1162
+ {
1163
+ value: 'paragraph',
1164
+ label: '正文'
1165
+ },
1166
+ {
1167
+ value: 'h1',
1168
+ label: '标题 1'
1169
+ },
1170
+ {
1171
+ value: 'h2',
1172
+ label: '标题 2'
1173
+ },
1174
+ {
1175
+ value: 'h3',
1176
+ label: '标题 3'
1177
+ }
1178
+ ],
1179
+ onValueChange: (value)=>{
1180
+ if ('paragraph' === value) runCommand('paragraph', ()=>{
1181
+ editor.chain().focus().setParagraph().run();
1182
+ });
1183
+ else {
1184
+ const level = Number(value.slice(1));
1185
+ runCommand(`heading-${level}`, ()=>{
1186
+ editor.chain().focus().toggleHeading({
1187
+ level
1188
+ }).run();
1189
+ });
1190
+ }
1191
+ }
1192
+ })
1193
+ }),
1194
+ /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
1195
+ label: "文字",
1196
+ children: [
1197
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1198
+ label: "加粗",
1199
+ shortcut: markdownToolbarShortcuts.bold,
1200
+ active: sourceEditing ? commandIsActive('bold') : editor.isActive('bold'),
1201
+ onClick: ()=>runCommand('bold', ()=>{
1202
+ editor.chain().focus().toggleBold().run();
1203
+ }),
1204
+ children: /*#__PURE__*/ jsx(Bold, {
1205
+ size: 16
1206
+ })
1207
+ }),
1208
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1209
+ label: "斜体",
1210
+ shortcut: markdownToolbarShortcuts.italic,
1211
+ active: sourceEditing ? commandIsActive('italic') : editor.isActive('italic'),
1212
+ onClick: ()=>runCommand('italic', ()=>{
1213
+ editor.chain().focus().toggleItalic().run();
1214
+ }),
1215
+ children: /*#__PURE__*/ jsx(Italic, {
1216
+ size: 16
1217
+ })
1218
+ }),
1219
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1220
+ label: "删除线",
1221
+ active: sourceEditing ? commandIsActive('strike') : editor.isActive('strike'),
1222
+ onClick: ()=>runCommand('strike', ()=>{
1223
+ editor.chain().focus().toggleStrike().run();
1224
+ }),
1225
+ children: /*#__PURE__*/ jsx(Strikethrough, {
1226
+ size: 16
1227
+ })
1228
+ }),
1229
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1230
+ label: "行内代码",
1231
+ active: sourceEditing ? commandIsActive('code') : editor.isActive('code'),
1232
+ onClick: ()=>runCommand('code', ()=>{
1233
+ editor.chain().focus().toggleCode().run();
1234
+ }),
1235
+ children: /*#__PURE__*/ jsx(Code2, {
1236
+ size: 16
1237
+ })
1238
+ })
1239
+ ]
1240
+ }),
1241
+ /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
1242
+ label: "段落",
1243
+ children: [
1244
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1245
+ label: "项目列表",
1246
+ active: sourceEditing ? commandIsActive('bullet-list') : editor.isActive('bulletList'),
1247
+ onClick: ()=>runCommand('bullet-list', ()=>{
1248
+ editor.chain().focus().toggleBulletList().run();
1249
+ }),
1250
+ children: /*#__PURE__*/ jsx(List, {
1251
+ size: 16
1252
+ })
1253
+ }),
1254
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1255
+ label: "编号列表",
1256
+ active: sourceEditing ? commandIsActive('ordered-list') : editor.isActive('orderedList'),
1257
+ onClick: ()=>runCommand('ordered-list', ()=>{
1258
+ editor.chain().focus().toggleOrderedList().run();
1259
+ }),
1260
+ children: /*#__PURE__*/ jsx(ListOrdered, {
1261
+ size: 16
1262
+ })
1263
+ }),
1264
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1265
+ label: "任务列表",
1266
+ active: sourceEditing ? commandIsActive('task-list') : editor.isActive('taskList'),
1267
+ onClick: ()=>runCommand('task-list', ()=>{
1268
+ editor.chain().focus().toggleTaskList().run();
1269
+ }),
1270
+ children: /*#__PURE__*/ jsx(ListChecks, {
1271
+ size: 16
1272
+ })
1273
+ }),
1274
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1275
+ label: "引用",
1276
+ active: sourceEditing ? commandIsActive('blockquote') : editor.isActive('blockquote'),
1277
+ onClick: ()=>runCommand('blockquote', ()=>{
1278
+ editor.chain().focus().toggleBlockquote().run();
1279
+ }),
1280
+ children: /*#__PURE__*/ jsx(Quote, {
1281
+ size: 16
1282
+ })
1283
+ })
1284
+ ]
1285
+ })
1286
+ ]
1287
+ }),
1288
+ insert: /*#__PURE__*/ jsxs(Fragment, {
1289
+ children: [
1290
+ /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
1291
+ label: "链接",
1292
+ children: [
1293
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1294
+ label: linkActive ? '编辑链接' : '添加链接',
1295
+ displayLabel: true,
1296
+ active: linkActive,
1297
+ onClick: openLinkDialog,
1298
+ children: /*#__PURE__*/ jsx(Link2, {
1299
+ size: 19
1300
+ })
1301
+ }),
1302
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1303
+ label: "移除链接",
1304
+ displayLabel: true,
1305
+ disabled: !linkActive,
1306
+ onClick: removeLink,
1307
+ children: /*#__PURE__*/ jsx(Unlink, {
1308
+ size: 19
1309
+ })
1310
+ }),
1311
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1312
+ label: "插入图片",
1313
+ displayLabel: true,
1314
+ onClick: openImageDialog,
1315
+ children: /*#__PURE__*/ jsx(Image, {
1316
+ size: 19
1317
+ })
1318
+ })
1319
+ ]
1320
+ }),
1321
+ /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
1322
+ label: "内容",
1323
+ children: [
1324
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1325
+ label: "代码块",
1326
+ displayLabel: true,
1327
+ active: sourceEditing ? commandIsActive('code-block') : editor.isActive('codeBlock'),
1328
+ onClick: ()=>runCommand('code-block', ()=>{
1329
+ editor.chain().focus().toggleCodeBlock().run();
1330
+ }),
1331
+ children: /*#__PURE__*/ jsx(Code2, {
1332
+ size: 19
1333
+ })
1334
+ }),
1335
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1336
+ label: "分隔线",
1337
+ displayLabel: true,
1338
+ onClick: ()=>runCommand('horizontal-rule', ()=>{
1339
+ editor.chain().focus().setHorizontalRule().run();
1340
+ }),
1341
+ children: /*#__PURE__*/ jsx(Minus, {
1342
+ size: 19
1343
+ })
1344
+ }),
1345
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1346
+ label: "表格",
1347
+ displayLabel: true,
1348
+ onClick: ()=>runCommand('table', ()=>{
1349
+ editor.chain().focus().insertTable({
1350
+ rows: 3,
1351
+ cols: 3,
1352
+ withHeaderRow: true
1353
+ }).run();
1354
+ }),
1355
+ children: /*#__PURE__*/ jsx(Table2, {
1356
+ size: 19
1357
+ })
1358
+ })
1359
+ ]
1360
+ })
1361
+ ]
1362
+ }),
1363
+ view: /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
1364
+ label: "编辑方式",
1365
+ children: [
1366
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1367
+ label: "可视化编辑",
1368
+ visibleLabel: "可视化",
1369
+ displayLabel: true,
1370
+ active: 'visual' === viewMode,
1371
+ onClick: ()=>onViewModeChange('visual'),
1372
+ children: /*#__PURE__*/ jsx(PencilLine, {
1373
+ size: 19
1374
+ })
1375
+ }),
1376
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1377
+ label: "源码编辑",
1378
+ visibleLabel: "源码",
1379
+ displayLabel: true,
1380
+ active: 'source' === viewMode,
1381
+ onClick: ()=>onViewModeChange('source'),
1382
+ children: /*#__PURE__*/ jsx(Code2, {
1383
+ size: 19
1384
+ })
1385
+ }),
1386
+ /*#__PURE__*/ jsx(MarkdownToolbarButton, {
1387
+ label: "分屏编辑",
1388
+ visibleLabel: "分屏",
1389
+ displayLabel: true,
1390
+ active: 'split' === viewMode,
1391
+ onClick: ()=>onViewModeChange('split'),
1392
+ children: /*#__PURE__*/ jsx(Columns2, {
1393
+ size: 19
1394
+ })
1395
+ })
1396
+ ]
1397
+ })
1398
+ }
1399
+ }),
1400
+ insertDialog && /*#__PURE__*/ jsx(MarkdownInsertDialog, {
1401
+ request: insertDialog.request,
1402
+ restoreFocusTarget: ()=>'source' === insertDialog.surface ? getSourceFocusTarget() ?? editor.view.dom : editor.view.dom,
1403
+ onClose: ()=>setInsertDialog(null),
1404
+ onSubmit: commitInsert
1405
+ })
1406
+ ]
1407
+ });
1408
+ }
1409
+ function canRunVisualEditorCommand(editor, command) {
1410
+ if (editor.isDestroyed || !editor.view) return false;
1411
+ return command();
1412
+ }
1413
+ function MarkdownToolbarButton({ label, visibleLabel, shortcut, active = false, displayLabel = false, children, ...props }) {
1414
+ return /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
1415
+ ...props,
1416
+ label: label,
1417
+ visibleLabel: visibleLabel,
1418
+ title: shortcut ? `${label}(${shortcut.label})` : label,
1419
+ "aria-keyshortcuts": shortcut?.ariaKeyShortcuts,
1420
+ active: active,
1421
+ displayLabel: displayLabel,
1422
+ children: children
1423
+ });
1424
+ }
1425
+ const DEFAULT_MARKDOWN_SPLIT_PERCENT = 50;
1426
+ const MIN_MARKDOWN_SPLIT_PERCENT = 30;
1427
+ const MAX_MARKDOWN_SPLIT_PERCENT = 70;
1428
+ const MARKDOWN_SPLIT_KEYBOARD_STEP = 5;
1429
+ function proportionalMarkdownScrollTop(sourceScrollTop, sourceScrollHeight, sourceClientHeight, targetScrollHeight, targetClientHeight) {
1430
+ const sourceRange = Math.max(0, sourceScrollHeight - sourceClientHeight);
1431
+ const targetRange = Math.max(0, targetScrollHeight - targetClientHeight);
1432
+ if (!sourceRange || !targetRange) return 0;
1433
+ const progress = Math.min(1, Math.max(0, sourceScrollTop / sourceRange));
1434
+ return progress * targetRange;
1435
+ }
1436
+ function MarkdownWorkspace({ editor, markdown, mode, readOnly = false, visualReadOnly = readOnly, sourceRef, sourceSelectionRequest, onSourceChange, onSourceCommand, onSourceContextMenu, onSourceIntent, onSourceRedo, onSourceSelectionChange, onSourceUndo, onVisualContextMenu, onVisualIntent }) {
1437
+ const workspaceRef = useRef(null);
1438
+ const visualRef = useRef(null);
1439
+ const synchronizedTargetRef = useRef(null);
1440
+ const releaseFrameRef = useRef(null);
1441
+ const sourceInputTypeRef = useRef(void 0);
1442
+ const [sourcePanePercent, setSourcePanePercent] = useState(DEFAULT_MARKDOWN_SPLIT_PERCENT);
1443
+ const [resizing, setResizing] = useState(false);
1444
+ const showSource = !readOnly && 'visual' !== mode;
1445
+ const showVisual = readOnly || 'source' !== mode;
1446
+ const visualIsReadOnly = readOnly || visualReadOnly;
1447
+ const releaseScrollLock = useCallback(()=>{
1448
+ if (null !== releaseFrameRef.current) cancelAnimationFrame(releaseFrameRef.current);
1449
+ releaseFrameRef.current = requestAnimationFrame(()=>{
1450
+ synchronizedTargetRef.current = null;
1451
+ releaseFrameRef.current = null;
1452
+ });
1453
+ }, []);
1454
+ useEffect(()=>()=>{
1455
+ if (null !== releaseFrameRef.current) cancelAnimationFrame(releaseFrameRef.current);
1456
+ }, []);
1457
+ useLayoutEffect(()=>{
1458
+ if (!sourceSelectionRequest) return;
1459
+ const source = sourceRef.current;
1460
+ if (!source) return;
1461
+ source.focus({
1462
+ preventScroll: true
1463
+ });
1464
+ source.setSelectionRange(sourceSelectionRequest.start, sourceSelectionRequest.end, sourceSelectionRequest.direction);
1465
+ onSourceSelectionChange?.(sourceSelectionRequest);
1466
+ }, [
1467
+ onSourceSelectionChange,
1468
+ sourceRef,
1469
+ sourceSelectionRequest
1470
+ ]);
1471
+ const handleSourceScroll = useCallback((event)=>{
1472
+ if ('split' !== mode) return;
1473
+ if ('source' === synchronizedTargetRef.current) {
1474
+ synchronizedTargetRef.current = null;
1475
+ return;
1476
+ }
1477
+ const source = event.currentTarget;
1478
+ const target = visualRef.current;
1479
+ if (!target) return;
1480
+ synchronizedTargetRef.current = 'visual';
1481
+ target.scrollTop = proportionalMarkdownScrollTop(source.scrollTop, source.scrollHeight, source.clientHeight, target.scrollHeight, target.clientHeight);
1482
+ releaseScrollLock();
1483
+ }, [
1484
+ mode,
1485
+ releaseScrollLock
1486
+ ]);
1487
+ const handleVisualScroll = useCallback((event)=>{
1488
+ if ('split' !== mode) return;
1489
+ if ('visual' === synchronizedTargetRef.current) {
1490
+ synchronizedTargetRef.current = null;
1491
+ return;
1492
+ }
1493
+ const source = event.currentTarget;
1494
+ const target = sourceRef.current;
1495
+ if (!target) return;
1496
+ synchronizedTargetRef.current = 'source';
1497
+ target.scrollTop = proportionalMarkdownScrollTop(source.scrollTop, source.scrollHeight, source.clientHeight, target.scrollHeight, target.clientHeight);
1498
+ releaseScrollLock();
1499
+ }, [
1500
+ mode,
1501
+ releaseScrollLock
1502
+ ]);
1503
+ const resizeFromPointer = useCallback((clientX)=>{
1504
+ const workspace = workspaceRef.current;
1505
+ if (!workspace) return;
1506
+ const bounds = workspace.getBoundingClientRect();
1507
+ if (bounds.width <= 0) return;
1508
+ setSourcePanePercent(clampMarkdownSplitPercent(Math.round((clientX - bounds.left) / bounds.width * 1000) / 10));
1509
+ }, []);
1510
+ const handleResizeStart = (event)=>{
1511
+ event.preventDefault();
1512
+ event.currentTarget.setPointerCapture(event.pointerId);
1513
+ setResizing(true);
1514
+ resizeFromPointer(event.clientX);
1515
+ };
1516
+ const handleResizeMove = (event)=>{
1517
+ if (!event.currentTarget.hasPointerCapture(event.pointerId)) return;
1518
+ resizeFromPointer(event.clientX);
1519
+ };
1520
+ const handleResizeEnd = (event)=>{
1521
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
1522
+ setResizing(false);
1523
+ };
1524
+ const handleResizeKeyDown = (event)=>{
1525
+ let next = null;
1526
+ if ('ArrowLeft' === event.key) next = sourcePanePercent - MARKDOWN_SPLIT_KEYBOARD_STEP;
1527
+ else if ('ArrowRight' === event.key) next = sourcePanePercent + MARKDOWN_SPLIT_KEYBOARD_STEP;
1528
+ else if ('Home' === event.key) next = MIN_MARKDOWN_SPLIT_PERCENT;
1529
+ else if ('End' === event.key) next = MAX_MARKDOWN_SPLIT_PERCENT;
1530
+ else if ('Enter' === event.key) next = DEFAULT_MARKDOWN_SPLIT_PERCENT;
1531
+ if (null === next) return;
1532
+ event.preventDefault();
1533
+ setSourcePanePercent(clampMarkdownSplitPercent(next));
1534
+ };
1535
+ const workspaceStyle = {
1536
+ '--work-markdown-source-pane': `${sourcePanePercent}%`
1537
+ };
1538
+ return /*#__PURE__*/ jsxs("div", {
1539
+ ref: workspaceRef,
1540
+ className: `work-markdown-workspace ${mode}`,
1541
+ "data-split-resizing": resizing || void 0,
1542
+ style: workspaceStyle,
1543
+ children: [
1544
+ showSource && /*#__PURE__*/ jsxs("section", {
1545
+ "aria-label": "Markdown 源码窗格",
1546
+ className: "work-markdown-pane source",
1547
+ children: [
1548
+ 'split' === mode && /*#__PURE__*/ jsx("header", {
1549
+ className: "work-markdown-pane-label",
1550
+ children: "编辑"
1551
+ }),
1552
+ /*#__PURE__*/ jsx("textarea", {
1553
+ ref: sourceRef,
1554
+ "aria-label": "Markdown 源码",
1555
+ placeholder: "开始写 Markdown…",
1556
+ value: markdown,
1557
+ spellCheck: true,
1558
+ onBeforeInput: (event)=>{
1559
+ const inputType = event.nativeEvent.inputType;
1560
+ if ('historyUndo' === inputType) {
1561
+ event.preventDefault();
1562
+ onSourceUndo?.();
1563
+ return;
1564
+ }
1565
+ if ('historyRedo' === inputType) {
1566
+ event.preventDefault();
1567
+ onSourceRedo?.();
1568
+ return;
1569
+ }
1570
+ sourceInputTypeRef.current = inputType || void 0;
1571
+ },
1572
+ onChange: (event)=>{
1573
+ onSourceIntent?.();
1574
+ const source = event.currentTarget;
1575
+ onSourceChange(source.value, markdown_workspace_sourceSelection(source), sourceInputTypeRef.current);
1576
+ sourceInputTypeRef.current = void 0;
1577
+ },
1578
+ onFocus: onSourceIntent,
1579
+ onContextMenu: onSourceContextMenu,
1580
+ onKeyDown: (event)=>{
1581
+ if (isWorkspaceContextMenuKeyboardEvent(event) && onSourceContextMenu?.(event)) return;
1582
+ if (event.altKey || !(event.metaKey || event.ctrlKey)) return;
1583
+ const key = event.key.toLocaleLowerCase();
1584
+ if ('z' === key) {
1585
+ event.preventDefault();
1586
+ if (event.shiftKey) onSourceRedo?.();
1587
+ else onSourceUndo?.();
1588
+ return;
1589
+ }
1590
+ if ('y' === key && !event.shiftKey) {
1591
+ event.preventDefault();
1592
+ onSourceRedo?.();
1593
+ return;
1594
+ }
1595
+ if (event.shiftKey) return;
1596
+ const command = 'b' === key ? 'bold' : 'i' === key ? 'italic' : null;
1597
+ if (!command || !onSourceCommand?.(command)) return;
1598
+ event.preventDefault();
1599
+ },
1600
+ onKeyUp: (event)=>onSourceSelectionChange?.(markdown_workspace_sourceSelection(event.currentTarget)),
1601
+ onPointerDown: onSourceIntent,
1602
+ onPointerUp: (event)=>{
1603
+ onSourceIntent?.();
1604
+ onSourceSelectionChange?.(markdown_workspace_sourceSelection(event.currentTarget));
1605
+ },
1606
+ onSelect: (event)=>{
1607
+ onSourceIntent?.();
1608
+ onSourceSelectionChange?.(markdown_workspace_sourceSelection(event.currentTarget));
1609
+ },
1610
+ onScroll: handleSourceScroll
1611
+ })
1612
+ ]
1613
+ }),
1614
+ 'split' === mode && /*#__PURE__*/ jsx("hr", {
1615
+ className: "work-markdown-splitter",
1616
+ "aria-label": "调整编辑与预览宽度",
1617
+ "aria-orientation": "vertical",
1618
+ "aria-valuemin": MIN_MARKDOWN_SPLIT_PERCENT,
1619
+ "aria-valuemax": MAX_MARKDOWN_SPLIT_PERCENT,
1620
+ "aria-valuenow": sourcePanePercent,
1621
+ "aria-valuetext": `编辑窗格 ${sourcePanePercent}%`,
1622
+ tabIndex: 0,
1623
+ title: "拖动调整分栏宽度,双击恢复均分",
1624
+ onDoubleClick: ()=>setSourcePanePercent(DEFAULT_MARKDOWN_SPLIT_PERCENT),
1625
+ onKeyDown: handleResizeKeyDown,
1626
+ onPointerCancel: handleResizeEnd,
1627
+ onPointerDown: handleResizeStart,
1628
+ onPointerMove: handleResizeMove,
1629
+ onPointerUp: handleResizeEnd
1630
+ }),
1631
+ showVisual && /*#__PURE__*/ jsxs("section", {
1632
+ ref: visualRef,
1633
+ "aria-label": visualIsReadOnly ? 'Markdown 预览窗格' : 'Markdown 编辑窗格',
1634
+ className: "work-markdown-pane visual",
1635
+ "data-readonly": visualIsReadOnly ? 'true' : 'false',
1636
+ onContextMenu: onVisualContextMenu,
1637
+ onKeyDownCapture: (event)=>{
1638
+ if (!isWorkspaceContextMenuKeyboardEvent(event)) return;
1639
+ onVisualContextMenu?.(event);
1640
+ },
1641
+ onFocusCapture: onVisualIntent,
1642
+ onPointerDownCapture: onVisualIntent,
1643
+ onScroll: handleVisualScroll,
1644
+ children: [
1645
+ 'split' === mode && /*#__PURE__*/ jsx("header", {
1646
+ className: "work-markdown-pane-label",
1647
+ children: "预览"
1648
+ }),
1649
+ /*#__PURE__*/ jsx("div", {
1650
+ className: "work-markdown-canvas",
1651
+ children: /*#__PURE__*/ jsx(EditorContent, {
1652
+ editor: editor
1653
+ })
1654
+ })
1655
+ ]
1656
+ })
1657
+ ]
1658
+ });
1659
+ }
1660
+ function markdown_workspace_sourceSelection(source) {
1661
+ return {
1662
+ start: source.selectionStart,
1663
+ end: source.selectionEnd,
1664
+ direction: source.selectionDirection
1665
+ };
1666
+ }
1667
+ function clampMarkdownSplitPercent(value) {
1668
+ return Math.min(MAX_MARKDOWN_SPLIT_PERCENT, Math.max(MIN_MARKDOWN_SPLIT_PERCENT, value));
1669
+ }
1670
+ const MARKDOWN_SOURCE_HISTORY_LIMIT = 100;
1671
+ const MARKDOWN_TYPING_COALESCE_MS = 1000;
1672
+ function useMarkdownSourceHistory(initialMarkdown) {
1673
+ const historyRef = useRef({
1674
+ past: [],
1675
+ present: {
1676
+ markdown: initialMarkdown,
1677
+ selection: collapsedSelection(0)
1678
+ },
1679
+ future: [],
1680
+ typing: null
1681
+ });
1682
+ const [, setVersion] = useState(0);
1683
+ const refresh = useCallback(()=>setVersion((value)=>value + 1), []);
1684
+ const record = useCallback((edit, options = {})=>{
1685
+ const history = historyRef.current;
1686
+ const next = normalizeSnapshot(edit);
1687
+ if (next.markdown === history.present.markdown) {
1688
+ history.present = next;
1689
+ return false;
1690
+ }
1691
+ const now = Date.now();
1692
+ const coalesce = true === options.typing && canCoalesceTyping(history, next, options.inputType, now);
1693
+ if (!coalesce) history.past = [
1694
+ ...history.past.slice(-(MARKDOWN_SOURCE_HISTORY_LIMIT - 1)),
1695
+ history.present
1696
+ ];
1697
+ history.present = next;
1698
+ history.future = [];
1699
+ history.typing = options.typing ? {
1700
+ at: now,
1701
+ inputType: options.inputType
1702
+ } : null;
1703
+ refresh();
1704
+ return true;
1705
+ }, [
1706
+ refresh
1707
+ ]);
1708
+ const reset = useCallback((markdown, selection)=>{
1709
+ const next = normalizeSnapshot({
1710
+ markdown,
1711
+ selection
1712
+ });
1713
+ const history = historyRef.current;
1714
+ const changed = history.past.length > 0 || history.future.length > 0 || history.present.markdown !== next.markdown;
1715
+ historyRef.current = {
1716
+ past: [],
1717
+ present: next,
1718
+ future: [],
1719
+ typing: null
1720
+ };
1721
+ if (changed) refresh();
1722
+ }, [
1723
+ refresh
1724
+ ]);
1725
+ const updateSelection = useCallback((selection)=>{
1726
+ const history = historyRef.current;
1727
+ const normalized = normalizeSelection(selection, history.present.markdown.length);
1728
+ if (sameSelection(normalized, history.present.selection)) return;
1729
+ history.present = {
1730
+ ...history.present,
1731
+ selection: normalized
1732
+ };
1733
+ history.typing = null;
1734
+ refresh();
1735
+ }, [
1736
+ refresh
1737
+ ]);
1738
+ const undo = useCallback(()=>{
1739
+ const history = historyRef.current;
1740
+ const previous = history.past.at(-1);
1741
+ if (!previous) return null;
1742
+ history.past = history.past.slice(0, -1);
1743
+ history.future = [
1744
+ ...history.future.slice(-(MARKDOWN_SOURCE_HISTORY_LIMIT - 1)),
1745
+ history.present
1746
+ ];
1747
+ history.present = previous;
1748
+ history.typing = null;
1749
+ refresh();
1750
+ return previous;
1751
+ }, [
1752
+ refresh
1753
+ ]);
1754
+ const redo = useCallback(()=>{
1755
+ const history = historyRef.current;
1756
+ const next = history.future.at(-1);
1757
+ if (!next) return null;
1758
+ history.future = history.future.slice(0, -1);
1759
+ history.past = [
1760
+ ...history.past.slice(-(MARKDOWN_SOURCE_HISTORY_LIMIT - 1)),
1761
+ history.present
1762
+ ];
1763
+ history.present = next;
1764
+ history.typing = null;
1765
+ refresh();
1766
+ return next;
1767
+ }, [
1768
+ refresh
1769
+ ]);
1770
+ return {
1771
+ canUndo: historyRef.current.past.length > 0,
1772
+ canRedo: historyRef.current.future.length > 0,
1773
+ record,
1774
+ redo,
1775
+ reset,
1776
+ undo,
1777
+ updateSelection
1778
+ };
1779
+ }
1780
+ function canCoalesceTyping(history, next, inputType, now) {
1781
+ const typing = history.typing;
1782
+ if (!typing || now - typing.at > MARKDOWN_TYPING_COALESCE_MS) return false;
1783
+ if (!isContinuousTypingInput(typing.inputType) || !isContinuousTypingInput(inputType)) return false;
1784
+ return history.present.selection.start === history.present.selection.end && next.selection.start === next.selection.end;
1785
+ }
1786
+ function isContinuousTypingInput(inputType) {
1787
+ return !inputType || 'insertText' === inputType || 'insertCompositionText' === inputType || 'insertLineBreak' === inputType || 'deleteContentBackward' === inputType || 'deleteContentForward' === inputType;
1788
+ }
1789
+ function normalizeSnapshot(snapshot) {
1790
+ return {
1791
+ markdown: snapshot.markdown,
1792
+ selection: normalizeSelection(snapshot.selection, snapshot.markdown.length)
1793
+ };
1794
+ }
1795
+ function normalizeSelection(selection, length) {
1796
+ const start = Math.max(0, Math.min(length, selection.start));
1797
+ const end = Math.max(start, Math.min(length, selection.end));
1798
+ return {
1799
+ start,
1800
+ end,
1801
+ direction: selection.direction
1802
+ };
1803
+ }
1804
+ function collapsedSelection(position) {
1805
+ return {
1806
+ start: position,
1807
+ end: position,
1808
+ direction: 'none'
1809
+ };
1810
+ }
1811
+ function sameSelection(left, right) {
1812
+ return left.start === right.start && left.end === right.end && left.direction === right.direction;
1813
+ }
1814
+ const MARKDOWN_PREVIEW_SYNC_DELAY = 160;
1815
+ const EMPTY_MARKDOWN_EXTENSIONS = [];
1816
+ function MarkdownEditor({ content, extensions: additionalExtensions = EMPTY_MARKDOWN_EXTENSIONS, preview, saveStatus, fileActions, getSelectionMenuItems, onChange }) {
1817
+ const contentRef = useRef(content);
1818
+ const onChangeRef = useRef(onChange);
1819
+ const receivedContentRef = useRef(content);
1820
+ const appliedMarkdownRef = useRef(content.markdown);
1821
+ const emittedMarkdownRef = useRef(null);
1822
+ const sourceMarkdownRef = useRef(content.markdown);
1823
+ const initialMarkdownRef = useRef(content.markdown);
1824
+ const previewTimerRef = useRef(null);
1825
+ const sourceTextareaRef = useRef(null);
1826
+ const markdownRootRef = useRef(null);
1827
+ const [sourceMarkdown, setSourceMarkdown] = useState(content.markdown);
1828
+ const [selectionMenu, setSelectionMenu] = useState(null);
1829
+ const [sourceSelectionRequest, setSourceSelectionRequest] = useState();
1830
+ const [viewMode, setViewMode] = useState('split');
1831
+ const [zoom, setZoom] = useState(100);
1832
+ const [, setSelectionVersion] = useState(0);
1833
+ const { canRedo: canRedoSource, canUndo: canUndoSource, record: recordSourceHistory, redo: redoSourceHistory, reset: resetSourceHistory, undo: undoSourceHistory, updateSelection: updateSourceHistorySelection } = useMarkdownSourceHistory(content.markdown);
1834
+ contentRef.current = content;
1835
+ onChangeRef.current = onChange;
1836
+ const cancelPreviewSync = useCallback(()=>{
1837
+ if (null === previewTimerRef.current) return;
1838
+ clearTimeout(previewTimerRef.current);
1839
+ previewTimerRef.current = null;
1840
+ }, []);
1841
+ const extensions = useMemo(()=>mergeOfficeTiptapExtensions('MarkdownEditor', createWorkMarkdownExtensions(), additionalExtensions), [
1842
+ additionalExtensions
1843
+ ]);
1844
+ const editorProps = useMemo(()=>({
1845
+ attributes: {
1846
+ 'aria-label': 'Markdown 编辑区',
1847
+ 'aria-multiline': 'true',
1848
+ role: 'textbox',
1849
+ spellcheck: 'true'
1850
+ }
1851
+ }), []);
1852
+ const editor = useEditor({
1853
+ extensions,
1854
+ content: initialMarkdownRef.current,
1855
+ contentType: 'markdown',
1856
+ editable: !preview && 'visual' === viewMode,
1857
+ editorProps,
1858
+ onUpdate: ({ editor: current })=>{
1859
+ const markdown = current.getMarkdown();
1860
+ if (markdown === appliedMarkdownRef.current) return;
1861
+ cancelPreviewSync();
1862
+ const next = {
1863
+ ...contentRef.current,
1864
+ markdown
1865
+ };
1866
+ appliedMarkdownRef.current = markdown;
1867
+ emittedMarkdownRef.current = markdown;
1868
+ sourceMarkdownRef.current = markdown;
1869
+ contentRef.current = next;
1870
+ setSourceMarkdown(markdown);
1871
+ resetSourceHistory(markdown, textareaSelection(sourceTextareaRef.current, markdown.length));
1872
+ onChangeRef.current(next);
1873
+ },
1874
+ onSelectionUpdate: ()=>setSelectionVersion((value)=>value + 1)
1875
+ }, [
1876
+ extensions
1877
+ ]);
1878
+ const applyMarkdownToEditor = useCallback((markdown)=>{
1879
+ cancelPreviewSync();
1880
+ if (!editor || editor.isDestroyed || appliedMarkdownRef.current === markdown) return;
1881
+ appliedMarkdownRef.current = markdown;
1882
+ editor.commands.setWorkMarkdown(markdown, {
1883
+ emitUpdate: false
1884
+ });
1885
+ }, [
1886
+ cancelPreviewSync,
1887
+ editor
1888
+ ]);
1889
+ const queueMarkdownPreview = useCallback((markdown, immediate = false)=>{
1890
+ cancelPreviewSync();
1891
+ if (!editor || editor.isDestroyed || appliedMarkdownRef.current === markdown) return;
1892
+ if (immediate) return void applyMarkdownToEditor(markdown);
1893
+ previewTimerRef.current = setTimeout(()=>{
1894
+ previewTimerRef.current = null;
1895
+ applyMarkdownToEditor(markdown);
1896
+ }, MARKDOWN_PREVIEW_SYNC_DELAY);
1897
+ }, [
1898
+ applyMarkdownToEditor,
1899
+ cancelPreviewSync,
1900
+ editor
1901
+ ]);
1902
+ useEffect(()=>cancelPreviewSync, [
1903
+ cancelPreviewSync
1904
+ ]);
1905
+ useEffect(()=>{
1906
+ if (!editor) return;
1907
+ const visualEditorReadOnly = preview || 'visual' !== viewMode;
1908
+ let checkboxFrame = null;
1909
+ const applyTaskCheckboxState = ()=>{
1910
+ for (const checkbox of editor.view.dom.querySelectorAll('li[data-type="taskItem"] > label input[type="checkbox"]')){
1911
+ checkbox.disabled = visualEditorReadOnly;
1912
+ checkbox.setAttribute('aria-disabled', String(visualEditorReadOnly));
1913
+ checkbox.setAttribute('aria-label', markdownTaskCheckboxLabel({
1914
+ attrs: {
1915
+ checked: checkbox.checked
1916
+ },
1917
+ textContent: checkbox.closest('li[data-type="taskItem"]')?.textContent ?? ''
1918
+ }));
1919
+ }
1920
+ };
1921
+ const scheduleTaskCheckboxState = ()=>{
1922
+ if (null !== checkboxFrame) cancelAnimationFrame(checkboxFrame);
1923
+ checkboxFrame = requestAnimationFrame(()=>{
1924
+ checkboxFrame = null;
1925
+ applyTaskCheckboxState();
1926
+ });
1927
+ };
1928
+ const applyViewState = ()=>{
1929
+ if (editor.isDestroyed) return;
1930
+ editor.setEditable(!visualEditorReadOnly, false);
1931
+ editor.view.dom.setAttribute('aria-label', visualEditorReadOnly ? 'Markdown 预览' : 'Markdown 编辑区');
1932
+ editor.view.dom.setAttribute('aria-readonly', String(visualEditorReadOnly));
1933
+ editor.view.dom.setAttribute('role', visualEditorReadOnly ? 'document' : 'textbox');
1934
+ if (visualEditorReadOnly) {
1935
+ editor.view.dom.removeAttribute('aria-multiline');
1936
+ editor.view.dom.tabIndex = 0;
1937
+ } else {
1938
+ editor.view.dom.setAttribute('aria-multiline', 'true');
1939
+ editor.view.dom.removeAttribute('tabindex');
1940
+ }
1941
+ applyTaskCheckboxState();
1942
+ scheduleTaskCheckboxState();
1943
+ };
1944
+ applyViewState();
1945
+ editor.on('mount', applyViewState);
1946
+ editor.on('update', applyTaskCheckboxState);
1947
+ editor.on('transaction', scheduleTaskCheckboxState);
1948
+ return ()=>{
1949
+ if (null !== checkboxFrame) cancelAnimationFrame(checkboxFrame);
1950
+ editor.off('mount', applyViewState);
1951
+ editor.off('update', applyTaskCheckboxState);
1952
+ editor.off('transaction', scheduleTaskCheckboxState);
1953
+ };
1954
+ }, [
1955
+ editor,
1956
+ preview,
1957
+ viewMode
1958
+ ]);
1959
+ useEffect(()=>{
1960
+ if (!editor || receivedContentRef.current === content) return;
1961
+ receivedContentRef.current = content;
1962
+ const markdown = content.markdown;
1963
+ if (sourceMarkdownRef.current !== markdown) {
1964
+ sourceMarkdownRef.current = markdown;
1965
+ setSourceMarkdown(markdown);
1966
+ }
1967
+ if (emittedMarkdownRef.current === markdown) {
1968
+ emittedMarkdownRef.current = null;
1969
+ return;
1970
+ }
1971
+ emittedMarkdownRef.current = null;
1972
+ resetSourceHistory(markdown, textareaSelection(sourceTextareaRef.current, markdown.length));
1973
+ if (preview || 'source' !== viewMode) queueMarkdownPreview(markdown, true);
1974
+ }, [
1975
+ content,
1976
+ editor,
1977
+ preview,
1978
+ queueMarkdownPreview,
1979
+ resetSourceHistory,
1980
+ viewMode
1981
+ ]);
1982
+ const updateSource = useCallback((markdown)=>{
1983
+ if (markdown === sourceMarkdownRef.current) return;
1984
+ sourceMarkdownRef.current = markdown;
1985
+ setSourceMarkdown(markdown);
1986
+ const next = {
1987
+ ...contentRef.current,
1988
+ markdown
1989
+ };
1990
+ contentRef.current = next;
1991
+ emittedMarkdownRef.current = markdown;
1992
+ onChangeRef.current(next);
1993
+ if ('source' !== viewMode) queueMarkdownPreview(markdown);
1994
+ }, [
1995
+ queueMarkdownPreview,
1996
+ viewMode
1997
+ ]);
1998
+ const getSourceSelection = useCallback(()=>{
1999
+ const source = sourceTextareaRef.current;
2000
+ if (!source) return null;
2001
+ const selection = textareaSelection(source, sourceMarkdownRef.current.length);
2002
+ return {
2003
+ markdown: sourceMarkdownRef.current,
2004
+ selection,
2005
+ text: sourceMarkdownRef.current.slice(selection.start, selection.end)
2006
+ };
2007
+ }, []);
2008
+ const requestSourceSelection = useCallback((selection)=>{
2009
+ setSourceSelectionRequest((current)=>({
2010
+ ...selection,
2011
+ revision: (current?.revision ?? 0) + 1
2012
+ }));
2013
+ }, []);
2014
+ const applySourceEdit = useCallback((edit)=>{
2015
+ recordSourceHistory(edit);
2016
+ updateSource(edit.markdown);
2017
+ requestSourceSelection(edit.selection);
2018
+ return true;
2019
+ }, [
2020
+ recordSourceHistory,
2021
+ requestSourceSelection,
2022
+ updateSource
2023
+ ]);
2024
+ const changeSource = useCallback((markdown, selection, inputType)=>{
2025
+ const edit = {
2026
+ markdown,
2027
+ selection
2028
+ };
2029
+ if (!recordSourceHistory(edit, {
2030
+ typing: true,
2031
+ inputType
2032
+ })) return;
2033
+ updateSource(markdown);
2034
+ }, [
2035
+ recordSourceHistory,
2036
+ updateSource
2037
+ ]);
2038
+ const applySourceHistory = useCallback((edit)=>{
2039
+ if (!edit) return false;
2040
+ updateSource(edit.markdown);
2041
+ requestSourceSelection(edit.selection);
2042
+ return true;
2043
+ }, [
2044
+ requestSourceSelection,
2045
+ updateSource
2046
+ ]);
2047
+ const undoSource = useCallback(()=>applySourceHistory(undoSourceHistory()), [
2048
+ applySourceHistory,
2049
+ undoSourceHistory
2050
+ ]);
2051
+ const redoSource = useCallback(()=>applySourceHistory(redoSourceHistory()), [
2052
+ applySourceHistory,
2053
+ redoSourceHistory
2054
+ ]);
2055
+ const runSourceCommand = useCallback((command)=>{
2056
+ const current = getSourceSelection();
2057
+ if (!current) return false;
2058
+ return applySourceEdit(applyMarkdownSourceCommand(current.markdown, current.selection, command));
2059
+ }, [
2060
+ applySourceEdit,
2061
+ getSourceSelection
2062
+ ]);
2063
+ const replaceSourceSelection = useCallback((replacement, selectedRange, target)=>{
2064
+ const current = target ?? getSourceSelection();
2065
+ if (!current) return false;
2066
+ if (current.markdown !== sourceMarkdownRef.current) return false;
2067
+ return applySourceEdit(replaceMarkdownSourceSelection(current.markdown, current.selection, replacement, selectedRange));
2068
+ }, [
2069
+ applySourceEdit,
2070
+ getSourceSelection
2071
+ ]);
2072
+ const handleSourceSelectionChange = useCallback((selection)=>{
2073
+ updateSourceHistorySelection(selection);
2074
+ setSelectionVersion((value)=>value + 1);
2075
+ }, [
2076
+ updateSourceHistorySelection
2077
+ ]);
2078
+ const handleVisualIntent = useCallback(()=>{
2079
+ applyMarkdownToEditor(sourceMarkdownRef.current);
2080
+ }, [
2081
+ applyMarkdownToEditor
2082
+ ]);
2083
+ const openSourceSelectionMenu = useCallback((event)=>{
2084
+ if (!getSelectionMenuItems) return false;
2085
+ const current = getSourceSelection();
2086
+ if (!current) return false;
2087
+ const snapshot = createWorkMarkdownSourceSelectionSnapshot(current.markdown, current.selection, contentRef.current);
2088
+ if (!snapshot) return false;
2089
+ event.preventDefault();
2090
+ event.stopPropagation();
2091
+ const position = workspaceContextMenuPosition(event, workspaceTextControlSelectionBounds(event.currentTarget));
2092
+ const items = getSelectionMenuItems(snapshot);
2093
+ setSelectionMenu(items.length ? {
2094
+ x: position.x,
2095
+ y: position.y,
2096
+ snapshot,
2097
+ items
2098
+ } : null);
2099
+ return items.length > 0;
2100
+ }, [
2101
+ getSelectionMenuItems,
2102
+ getSourceSelection
2103
+ ]);
2104
+ const openVisualSelectionMenu = useCallback((event)=>{
2105
+ if (!editor || !getSelectionMenuItems) return false;
2106
+ const snapshot = createWorkMarkdownVisualSelectionSnapshot(editor, contentRef.current);
2107
+ if (!snapshot) return false;
2108
+ event.preventDefault();
2109
+ event.stopPropagation();
2110
+ const position = workspaceContextMenuPosition(event);
2111
+ const items = getSelectionMenuItems(snapshot);
2112
+ setSelectionMenu(items.length ? {
2113
+ x: position.x,
2114
+ y: position.y,
2115
+ snapshot,
2116
+ items
2117
+ } : null);
2118
+ return items.length > 0;
2119
+ }, [
2120
+ editor,
2121
+ getSelectionMenuItems
2122
+ ]);
2123
+ const createSourceSelectionAction = useCallback((snapshot)=>createWorkMarkdownSourceSelectionAction(snapshot, ()=>sourceMarkdownRef.current, applySourceEdit), [
2124
+ applySourceEdit
2125
+ ]);
2126
+ const changeViewMode = useCallback((mode)=>{
2127
+ const focusSurface = 'visual' === mode ? 'visual' : 'source';
2128
+ if ('source' !== mode) applyMarkdownToEditor(sourceMarkdownRef.current);
2129
+ setViewMode(mode);
2130
+ restoreMarkdownEditingSurfaceFocus(()=>{
2131
+ if ('source' === focusSurface) return sourceTextareaRef.current;
2132
+ return editor && !editor.isDestroyed ? editor.view.dom : null;
2133
+ });
2134
+ }, [
2135
+ applyMarkdownToEditor,
2136
+ editor
2137
+ ]);
2138
+ const deferredMarkdown = useDeferredValue(sourceMarkdown);
2139
+ const metrics = useMemo(()=>markdownMetrics(deferredMarkdown), [
2140
+ deferredMarkdown
2141
+ ]);
2142
+ const editorStyle = {
2143
+ '--work-markdown-zoom': zoom
2144
+ };
2145
+ useOfficeEditorWheelZoom({
2146
+ enabled: Boolean(editor),
2147
+ scopeRef: markdownRootRef,
2148
+ onZoomIn: ()=>setZoom((current)=>stepOfficeZoom(current, 'in', {
2149
+ minimum: 60,
2150
+ maximum: 180
2151
+ })),
2152
+ onZoomOut: ()=>setZoom((current)=>stepOfficeZoom(current, 'out', {
2153
+ minimum: 60,
2154
+ maximum: 180
2155
+ }))
2156
+ });
2157
+ if (!editor) return /*#__PURE__*/ jsx(WorkEditorLoadingState, {
2158
+ title: "正在准备 Markdown 编辑器"
2159
+ });
2160
+ if (preview) return /*#__PURE__*/ jsxs("section", {
2161
+ ref: markdownRootRef,
2162
+ className: "work-markdown-editor preview",
2163
+ style: editorStyle,
2164
+ children: [
2165
+ /*#__PURE__*/ jsx(WorkOfficePreviewBar, {
2166
+ ariaLabel: "Markdown 预览工具",
2167
+ label: "只读预览",
2168
+ detail: `${metrics.lineCount} 行`,
2169
+ fileActions: fileActions,
2170
+ className: "work-markdown-ribbon"
2171
+ }),
2172
+ /*#__PURE__*/ jsx(MarkdownWorkspace, {
2173
+ editor: editor,
2174
+ markdown: sourceMarkdown,
2175
+ mode: "visual",
2176
+ readOnly: true,
2177
+ sourceRef: sourceTextareaRef,
2178
+ onSourceChange: updateSource,
2179
+ onVisualIntent: handleVisualIntent
2180
+ }),
2181
+ /*#__PURE__*/ jsx(MarkdownStatus, {
2182
+ characterCount: metrics.characterCount,
2183
+ lineCount: metrics.lineCount,
2184
+ saveStatus: saveStatus,
2185
+ zoom: zoom,
2186
+ onZoomChange: setZoom
2187
+ })
2188
+ ]
2189
+ });
2190
+ return /*#__PURE__*/ jsxs("section", {
2191
+ ref: markdownRootRef,
2192
+ className: "work-markdown-editor",
2193
+ style: editorStyle,
2194
+ children: [
2195
+ /*#__PURE__*/ jsx(MarkdownToolbar, {
2196
+ editor: editor,
2197
+ fileActions: fileActions,
2198
+ sourceEditing: 'visual' !== viewMode,
2199
+ canSourceRedo: canRedoSource,
2200
+ canSourceUndo: canUndoSource,
2201
+ viewMode: viewMode,
2202
+ getSourceFocusTarget: ()=>sourceTextareaRef.current,
2203
+ getSourceSelection: getSourceSelection,
2204
+ onSourceCommand: runSourceCommand,
2205
+ onSourceRedo: redoSource,
2206
+ onSourceReplace: replaceSourceSelection,
2207
+ onSourceUndo: undoSource,
2208
+ onViewModeChange: changeViewMode
2209
+ }),
2210
+ /*#__PURE__*/ jsx(MarkdownWorkspace, {
2211
+ editor: editor,
2212
+ markdown: sourceMarkdown,
2213
+ mode: viewMode,
2214
+ visualReadOnly: 'split' === viewMode,
2215
+ sourceRef: sourceTextareaRef,
2216
+ sourceSelectionRequest: sourceSelectionRequest,
2217
+ onSourceChange: changeSource,
2218
+ onSourceCommand: runSourceCommand,
2219
+ onSourceContextMenu: getSelectionMenuItems ? openSourceSelectionMenu : void 0,
2220
+ onSourceRedo: redoSource,
2221
+ onSourceSelectionChange: handleSourceSelectionChange,
2222
+ onSourceUndo: undoSource,
2223
+ onVisualContextMenu: getSelectionMenuItems ? openVisualSelectionMenu : void 0,
2224
+ onVisualIntent: handleVisualIntent
2225
+ }),
2226
+ /*#__PURE__*/ jsx(MarkdownStatus, {
2227
+ characterCount: metrics.characterCount,
2228
+ lineCount: metrics.lineCount,
2229
+ saveStatus: saveStatus,
2230
+ zoom: zoom,
2231
+ onZoomChange: setZoom
2232
+ }),
2233
+ selectionMenu && /*#__PURE__*/ jsx(MarkdownSelectionContextMenu, {
2234
+ editor: editor,
2235
+ menu: selectionMenu,
2236
+ createSourceAction: createSourceSelectionAction,
2237
+ onClose: ()=>setSelectionMenu(null)
2238
+ })
2239
+ ]
2240
+ });
2241
+ }
2242
+ function textareaSelection(textarea, fallbackPosition) {
2243
+ if (!textarea) return {
2244
+ start: fallbackPosition,
2245
+ end: fallbackPosition,
2246
+ direction: 'none'
2247
+ };
2248
+ return {
2249
+ start: textarea.selectionStart,
2250
+ end: textarea.selectionEnd,
2251
+ direction: textarea.selectionDirection
2252
+ };
2253
+ }
2254
+ function markdownMetrics(markdown) {
2255
+ return {
2256
+ lineCount: markdown ? markdown.replace(/\r\n?/g, '\n').split('\n').length : 1,
2257
+ characterCount: Array.from(markdown).length
2258
+ };
2259
+ }
2260
+ export { markdown_editor_namespaceObject };