@beyondwork/docx-react-component 1.0.29 → 1.0.30
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.
- package/package.json +65 -96
- package/src/README.md +85 -0
- package/src/api/README.md +26 -0
- package/src/api/public-types.ts +1952 -0
- package/src/api/session-state.ts +62 -0
- package/src/compare/diff-engine.ts +623 -0
- package/src/compare/export-redlines.ts +280 -0
- package/src/compare/index.ts +25 -0
- package/src/compare/snapshot.ts +97 -0
- package/src/component-inventory.md +99 -0
- package/src/core/README.md +10 -0
- package/src/core/commands/README.md +3 -0
- package/{dist/chunk-TJBP2K4T.js → src/core/commands/formatting-commands.ts} +536 -196
- package/src/core/commands/image-commands.ts +373 -0
- package/src/core/commands/index.ts +1879 -0
- package/src/core/commands/list-commands.ts +565 -0
- package/src/core/commands/paragraph-layout-commands.ts +339 -0
- package/src/core/commands/review-commands.ts +108 -0
- package/{dist/core/commands/section-layout-commands.cjs → src/core/commands/section-layout-commands.ts} +340 -137
- package/src/core/commands/structural-helpers.ts +309 -0
- package/{dist/core/commands/style-commands.cjs → src/core/commands/style-commands.ts} +113 -65
- package/src/core/commands/table-structure-commands.ts +854 -0
- package/{dist/chunk-UZXBISGO.js → src/core/commands/text-commands.ts} +142 -86
- package/src/core/schema/README.md +3 -0
- package/src/core/schema/text-schema.ts +516 -0
- package/src/core/search/search-text.ts +357 -0
- package/src/core/selection/README.md +3 -0
- package/src/core/selection/mapping.ts +289 -0
- package/src/core/selection/review-anchors.ts +183 -0
- package/src/core/state/README.md +3 -0
- package/src/core/state/editor-state.ts +892 -0
- package/src/core/state/text-transaction.ts +869 -0
- package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
- package/src/formats/xlsx/io/parse-sheet.ts +459 -0
- package/src/formats/xlsx/io/parse-styles.ts +59 -0
- package/src/formats/xlsx/io/parse-workbook.ts +75 -0
- package/src/formats/xlsx/io/serialize-shared-strings.ts +72 -0
- package/src/formats/xlsx/io/serialize-sheet.ts +333 -0
- package/src/formats/xlsx/io/serialize-styles.ts +98 -0
- package/src/formats/xlsx/io/serialize-workbook.ts +429 -0
- package/src/formats/xlsx/io/xlsx-session.ts +314 -0
- package/src/formats/xlsx/model/cell.ts +189 -0
- package/src/formats/xlsx/model/sheet.ts +326 -0
- package/src/formats/xlsx/model/styles.ts +118 -0
- package/src/formats/xlsx/model/workbook.ts +453 -0
- package/src/formats/xlsx/runtime/cell-commands.ts +567 -0
- package/src/formats/xlsx/runtime/sheet-commands.ts +206 -0
- package/src/formats/xlsx/runtime/workbook-runtime.ts +177 -0
- package/src/formats/xlsx/runtime/workbook-transaction.ts +822 -0
- package/src/index.ts +142 -0
- package/src/io/README.md +10 -0
- package/src/io/docx-session.ts +3175 -0
- package/src/io/export/README.md +3 -0
- package/src/io/export/export-session.ts +220 -0
- package/src/io/export/minimal-docx.ts +115 -0
- package/src/io/export/reattach-preserved-parts.ts +54 -0
- package/src/io/export/serialize-comments.ts +947 -0
- package/src/io/export/serialize-footnotes.ts +394 -0
- package/src/io/export/serialize-headers-footers.ts +368 -0
- package/src/io/export/serialize-main-document.ts +1342 -0
- package/src/io/export/serialize-numbering.ts +218 -0
- package/src/io/export/serialize-revisions.ts +389 -0
- package/src/io/export/serialize-runtime-revisions.ts +463 -0
- package/src/io/export/serialize-tables.ts +174 -0
- package/src/io/export/split-review-boundaries.ts +356 -0
- package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
- package/src/io/export/table-properties-xml.ts +318 -0
- package/src/io/normalize/README.md +3 -0
- package/src/io/normalize/normalize-text.ts +670 -0
- package/src/io/ooxml/README.md +3 -0
- package/src/io/ooxml/highlight-colors.ts +39 -0
- package/src/io/ooxml/numbering-sentinels.ts +44 -0
- package/src/io/ooxml/parse-comments.ts +852 -0
- package/src/io/ooxml/parse-complex-content.ts +287 -0
- package/src/io/ooxml/parse-fields.ts +834 -0
- package/src/io/ooxml/parse-footnotes.ts +952 -0
- package/src/io/ooxml/parse-headers-footers.ts +1212 -0
- package/src/io/ooxml/parse-inline-media.ts +461 -0
- package/src/io/ooxml/parse-main-document.ts +2947 -0
- package/src/io/ooxml/parse-numbering.ts +747 -0
- package/src/io/ooxml/parse-revisions.ts +1045 -0
- package/src/io/ooxml/parse-settings.ts +184 -0
- package/src/io/ooxml/parse-shapes.ts +296 -0
- package/src/io/ooxml/parse-styles.ts +639 -0
- package/src/io/ooxml/parse-tables.ts +627 -0
- package/src/io/ooxml/parse-theme.ts +346 -0
- package/src/io/ooxml/part-manifest.ts +136 -0
- package/src/io/ooxml/revision-boundaries.ts +475 -0
- package/src/io/ooxml/workflow-payload.ts +544 -0
- package/src/io/opc/README.md +3 -0
- package/src/io/opc/corrupt-package.ts +166 -0
- package/src/io/opc/docx-package.ts +74 -0
- package/src/io/opc/package-reader.ts +325 -0
- package/src/io/opc/package-writer.ts +273 -0
- package/src/io/source-package-provenance.ts +241 -0
- package/{dist/chunk-RMH72RZI.js → src/legal/bookmarks.ts} +130 -44
- package/src/legal/cross-references.ts +414 -0
- package/src/legal/defined-terms.ts +203 -0
- package/src/legal/index.ts +32 -0
- package/src/legal/signature-blocks.ts +259 -0
- package/src/model/README.md +3 -0
- package/src/model/canonical-document.ts +2722 -0
- package/src/model/cds-1.0.0.ts +212 -0
- package/src/model/snapshot.ts +760 -0
- package/src/preservation/README.md +3 -0
- package/src/preservation/markup-compatibility.ts +48 -0
- package/src/preservation/opaque-fragment-store.ts +89 -0
- package/src/preservation/opaque-region.ts +233 -0
- package/src/preservation/package-preservation.ts +113 -0
- package/src/preservation/preserved-part-manifest.ts +56 -0
- package/src/preservation/relationship-retention.ts +57 -0
- package/src/preservation/store.ts +255 -0
- package/src/review/README.md +16 -0
- package/src/review/store/README.md +3 -0
- package/src/review/store/comment-anchors.ts +70 -0
- package/src/review/store/comment-remapping.ts +154 -0
- package/src/review/store/comment-store.ts +349 -0
- package/src/review/store/comment-thread.ts +109 -0
- package/src/review/store/revision-actions.ts +423 -0
- package/src/review/store/revision-store.ts +323 -0
- package/src/review/store/revision-types.ts +182 -0
- package/src/review/store/runtime-comment-store.ts +43 -0
- package/src/runtime/README.md +3 -0
- package/src/runtime/ai-action-policy.ts +764 -0
- package/src/runtime/context-analytics.ts +824 -0
- package/src/runtime/document-layout.ts +332 -0
- package/src/runtime/document-locations.ts +521 -0
- package/src/runtime/document-navigation.ts +616 -0
- package/src/runtime/document-outline.ts +440 -0
- package/src/runtime/document-runtime.ts +4055 -0
- package/src/runtime/document-search.ts +145 -0
- package/src/runtime/event-refresh-hints.ts +137 -0
- package/src/runtime/numbering-prefix.ts +244 -0
- package/src/runtime/page-layout-estimation.ts +305 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +241 -0
- package/src/runtime/resolved-numbering-geometry.ts +293 -0
- package/src/runtime/review-runtime.ts +44 -0
- package/src/runtime/revision-runtime.ts +107 -0
- package/src/runtime/session-capabilities.ts +192 -0
- package/src/runtime/story-context.ts +164 -0
- package/src/runtime/story-targeting.ts +162 -0
- package/src/runtime/suggestions-snapshot.ts +137 -0
- package/src/runtime/surface-projection.ts +1553 -0
- package/src/runtime/table-commands.ts +173 -0
- package/src/runtime/table-schema.ts +309 -0
- package/src/runtime/table-style-resolver.ts +409 -0
- package/src/runtime/view-state.ts +493 -0
- package/src/runtime/virtualized-rendering.ts +258 -0
- package/src/runtime/workflow-markup.ts +393 -0
- package/src/ui/README.md +30 -0
- package/src/ui/WordReviewEditor.tsx +5268 -0
- package/src/ui/browser-export.ts +52 -0
- package/src/ui/comments/README.md +3 -0
- package/src/ui/compatibility/README.md +3 -0
- package/src/ui/editor-command-bag.ts +127 -0
- package/src/ui/editor-runtime-boundary.ts +1558 -0
- package/src/ui/editor-shell-view.tsx +144 -0
- package/src/ui/editor-surface/README.md +3 -0
- package/src/ui/editor-surface-controller.tsx +66 -0
- package/src/ui/headless/comment-decoration-model.ts +124 -0
- package/src/ui/headless/preserve-editor-selection.ts +5 -0
- package/src/ui/headless/revision-decoration-model.ts +128 -0
- package/src/ui/headless/selection-helpers.ts +54 -0
- package/src/ui/headless/selection-tool-context.ts +19 -0
- package/src/ui/headless/selection-tool-resolver.ts +752 -0
- package/src/ui/headless/selection-tool-types.ts +129 -0
- package/src/ui/headless/selection-toolbar-model.ts +11 -0
- package/src/ui/headless/use-editor-keyboard.ts +103 -0
- package/src/ui/review/README.md +3 -0
- package/src/ui/runtime-shortcut-dispatch.ts +365 -0
- package/src/ui/runtime-snapshot-selectors.ts +197 -0
- package/src/ui/shared/revision-filters.ts +31 -0
- package/src/ui/status/README.md +3 -0
- package/src/ui/theme/README.md +3 -0
- package/src/ui/toolbar/README.md +3 -0
- package/src/ui/workflow-surface-blocked-rails.ts +94 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +64 -0
- package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +121 -0
- package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +30 -0
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +365 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +298 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +186 -0
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +139 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +200 -0
- package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
- package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +179 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +189 -0
- package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +411 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
- package/src/ui-tailwind/editor-surface/pm-schema.ts +927 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +567 -0
- package/src/ui-tailwind/editor-surface/search-plugin.ts +168 -0
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +65 -0
- package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
- package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +129 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +58 -0
- package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +1047 -0
- package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +503 -0
- package/src/ui-tailwind/index.ts +62 -0
- package/src/ui-tailwind/page-chrome-model.ts +27 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +406 -0
- package/src/ui-tailwind/review/tw-health-panel.tsx +149 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +122 -0
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
- package/src/ui-tailwind/status/tw-status-bar.tsx +65 -0
- package/{dist → src}/ui-tailwind/theme/editor-theme.css +58 -40
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +52 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +1133 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +1460 -0
- package/src/validation/README.md +3 -0
- package/src/validation/compatibility-engine.ts +878 -0
- package/src/validation/compatibility-report.ts +161 -0
- package/src/validation/diagnostics.ts +204 -0
- package/src/validation/docx-comment-proof.ts +720 -0
- package/src/validation/import-diagnostics.ts +128 -0
- package/src/validation/low-priority-word-surfaces.ts +373 -0
- package/dist/canonical-document-BLEbzL2J.d.cts +0 -844
- package/dist/canonical-document-BLEbzL2J.d.ts +0 -844
- package/dist/chunk-2FJS5GZM.js +0 -763
- package/dist/chunk-2FJS5GZM.js.map +0 -1
- package/dist/chunk-2OQBZS3F.js +0 -446
- package/dist/chunk-2OQBZS3F.js.map +0 -1
- package/dist/chunk-2S7W4KFO.js +0 -127
- package/dist/chunk-2S7W4KFO.js.map +0 -1
- package/dist/chunk-2TG72QSW.js +0 -3874
- package/dist/chunk-2TG72QSW.js.map +0 -1
- package/dist/chunk-36QNIZBO.js +0 -532
- package/dist/chunk-36QNIZBO.js.map +0 -1
- package/dist/chunk-4AQOYAW4.js +0 -3069
- package/dist/chunk-4AQOYAW4.js.map +0 -1
- package/dist/chunk-4D5EWJ3P.js +0 -77
- package/dist/chunk-4D5EWJ3P.js.map +0 -1
- package/dist/chunk-5FN54NDH.js +0 -2257
- package/dist/chunk-5FN54NDH.js.map +0 -1
- package/dist/chunk-BOYGQYRQ.js +0 -7306
- package/dist/chunk-BOYGQYRQ.js.map +0 -1
- package/dist/chunk-CN3XMECL.js +0 -212
- package/dist/chunk-CN3XMECL.js.map +0 -1
- package/dist/chunk-EBI3BX6U.js +0 -164
- package/dist/chunk-EBI3BX6U.js.map +0 -1
- package/dist/chunk-EILUG3VB.js +0 -1275
- package/dist/chunk-EILUG3VB.js.map +0 -1
- package/dist/chunk-FUDY333O.js +0 -70
- package/dist/chunk-FUDY333O.js.map +0 -1
- package/dist/chunk-GBVOWFIK.js +0 -1237
- package/dist/chunk-GBVOWFIK.js.map +0 -1
- package/dist/chunk-H4TQ3H3Y.js +0 -262
- package/dist/chunk-H4TQ3H3Y.js.map +0 -1
- package/dist/chunk-JGB3IXZO.js +0 -189
- package/dist/chunk-JGB3IXZO.js.map +0 -1
- package/dist/chunk-KD2QRQPY.js +0 -4342
- package/dist/chunk-KD2QRQPY.js.map +0 -1
- package/dist/chunk-KLMXQVYK.js +0 -369
- package/dist/chunk-KLMXQVYK.js.map +0 -1
- package/dist/chunk-KZUG5KFQ.js +0 -214
- package/dist/chunk-KZUG5KFQ.js.map +0 -1
- package/dist/chunk-QDAQ4CJU.js +0 -345
- package/dist/chunk-QDAQ4CJU.js.map +0 -1
- package/dist/chunk-RMH72RZI.js.map +0 -1
- package/dist/chunk-SWKWQZXM.js +0 -117
- package/dist/chunk-SWKWQZXM.js.map +0 -1
- package/dist/chunk-TJBP2K4T.js.map +0 -1
- package/dist/chunk-TLCEAQDQ.js +0 -542
- package/dist/chunk-TLCEAQDQ.js.map +0 -1
- package/dist/chunk-UZXBISGO.js.map +0 -1
- package/dist/chunk-WGBAKP3Q.js +0 -3220
- package/dist/chunk-WGBAKP3Q.js.map +0 -1
- package/dist/compare/index.cjs +0 -5475
- package/dist/compare/index.cjs.map +0 -1
- package/dist/compare/index.d.cts +0 -114
- package/dist/compare/index.d.ts +0 -114
- package/dist/compare/index.js +0 -731
- package/dist/compare/index.js.map +0 -1
- package/dist/core/commands/formatting-commands.cjs +0 -828
- package/dist/core/commands/formatting-commands.cjs.map +0 -1
- package/dist/core/commands/formatting-commands.d.cts +0 -63
- package/dist/core/commands/formatting-commands.d.ts +0 -63
- package/dist/core/commands/formatting-commands.js +0 -37
- package/dist/core/commands/formatting-commands.js.map +0 -1
- package/dist/core/commands/image-commands.cjs +0 -2023
- package/dist/core/commands/image-commands.cjs.map +0 -1
- package/dist/core/commands/image-commands.d.cts +0 -58
- package/dist/core/commands/image-commands.d.ts +0 -58
- package/dist/core/commands/image-commands.js +0 -18
- package/dist/core/commands/image-commands.js.map +0 -1
- package/dist/core/commands/section-layout-commands.cjs.map +0 -1
- package/dist/core/commands/section-layout-commands.d.cts +0 -62
- package/dist/core/commands/section-layout-commands.d.ts +0 -62
- package/dist/core/commands/section-layout-commands.js +0 -21
- package/dist/core/commands/section-layout-commands.js.map +0 -1
- package/dist/core/commands/style-commands.cjs.map +0 -1
- package/dist/core/commands/style-commands.d.cts +0 -13
- package/dist/core/commands/style-commands.d.ts +0 -13
- package/dist/core/commands/style-commands.js +0 -9
- package/dist/core/commands/style-commands.js.map +0 -1
- package/dist/core/commands/table-structure-commands.cjs +0 -1883
- package/dist/core/commands/table-structure-commands.cjs.map +0 -1
- package/dist/core/commands/table-structure-commands.d.cts +0 -59
- package/dist/core/commands/table-structure-commands.d.ts +0 -59
- package/dist/core/commands/table-structure-commands.js +0 -12
- package/dist/core/commands/table-structure-commands.js.map +0 -1
- package/dist/core/commands/text-commands.cjs +0 -2391
- package/dist/core/commands/text-commands.cjs.map +0 -1
- package/dist/core/commands/text-commands.d.cts +0 -24
- package/dist/core/commands/text-commands.d.ts +0 -24
- package/dist/core/commands/text-commands.js +0 -28
- package/dist/core/commands/text-commands.js.map +0 -1
- package/dist/core/selection/mapping.cjs +0 -200
- package/dist/core/selection/mapping.cjs.map +0 -1
- package/dist/core/selection/mapping.d.cts +0 -2
- package/dist/core/selection/mapping.d.ts +0 -2
- package/dist/core/selection/mapping.js +0 -31
- package/dist/core/selection/mapping.js.map +0 -1
- package/dist/core/state/editor-state.cjs +0 -2278
- package/dist/core/state/editor-state.cjs.map +0 -1
- package/dist/core/state/editor-state.d.cts +0 -2
- package/dist/core/state/editor-state.d.ts +0 -2
- package/dist/core/state/editor-state.js +0 -26
- package/dist/core/state/editor-state.js.map +0 -1
- package/dist/index.cjs +0 -38553
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -15
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -7856
- package/dist/index.js.map +0 -1
- package/dist/io/docx-session.cjs +0 -16236
- package/dist/io/docx-session.cjs.map +0 -1
- package/dist/io/docx-session.d.cts +0 -21
- package/dist/io/docx-session.d.ts +0 -21
- package/dist/io/docx-session.js +0 -18
- package/dist/io/docx-session.js.map +0 -1
- package/dist/legal/index.cjs +0 -3900
- package/dist/legal/index.cjs.map +0 -1
- package/dist/legal/index.d.cts +0 -86
- package/dist/legal/index.d.ts +0 -86
- package/dist/legal/index.js +0 -616
- package/dist/legal/index.js.map +0 -1
- package/dist/public-types-7ZL_94cz.d.ts +0 -1573
- package/dist/public-types-CeMaDueh.d.cts +0 -1573
- package/dist/public-types.cjs +0 -19
- package/dist/public-types.cjs.map +0 -1
- package/dist/public-types.d.cts +0 -2
- package/dist/public-types.d.ts +0 -2
- package/dist/public-types.js +0 -1
- package/dist/public-types.js.map +0 -1
- package/dist/runtime/document-runtime.cjs +0 -11140
- package/dist/runtime/document-runtime.cjs.map +0 -1
- package/dist/runtime/document-runtime.d.cts +0 -231
- package/dist/runtime/document-runtime.d.ts +0 -231
- package/dist/runtime/document-runtime.js +0 -21
- package/dist/runtime/document-runtime.js.map +0 -1
- package/dist/structural-helpers-CilgOVhh.d.cts +0 -10
- package/dist/structural-helpers-q0Gd-eBN.d.ts +0 -10
- package/dist/ui-tailwind/editor-surface/search-plugin.cjs +0 -313
- package/dist/ui-tailwind/editor-surface/search-plugin.cjs.map +0 -1
- package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +0 -67
- package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +0 -67
- package/dist/ui-tailwind/editor-surface/search-plugin.js +0 -23
- package/dist/ui-tailwind/editor-surface/search-plugin.js.map +0 -1
- package/dist/ui-tailwind/index.cjs +0 -4833
- package/dist/ui-tailwind/index.cjs.map +0 -1
- package/dist/ui-tailwind/index.d.cts +0 -617
- package/dist/ui-tailwind/index.d.ts +0 -617
- package/dist/ui-tailwind/index.js +0 -575
- package/dist/ui-tailwind/index.js.map +0 -1
|
@@ -1,34 +1,99 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ProseMirror formatting commands for the editor surface schema.
|
|
3
|
+
*
|
|
4
|
+
* Each command follows the standard ProseMirror command signature:
|
|
5
|
+
* (state, dispatch?) => boolean
|
|
6
|
+
*
|
|
7
|
+
* Toggle commands use the ProseMirror toggleMark helper.
|
|
8
|
+
* Set commands for value-bearing marks (font, size, color) apply the mark
|
|
9
|
+
* over the current selection, or remove it when the value is null.
|
|
10
|
+
* The setAlignment command sets the `alignment` attr on paragraph nodes
|
|
11
|
+
* that intersect the current selection.
|
|
12
|
+
*
|
|
13
|
+
* These commands operate on the `editorSchema` live surface. In the
|
|
14
|
+
* current architecture the runtime is the canonical document authority;
|
|
15
|
+
* these commands are designed to be used with the PM view's `dispatch`
|
|
16
|
+
* so that mark changes are reflected on the live surface immediately.
|
|
17
|
+
*/
|
|
18
|
+
|
|
2
19
|
import { toggleMark } from "prosemirror-commands";
|
|
3
|
-
|
|
20
|
+
import type { Command } from "prosemirror-state";
|
|
21
|
+
import type { MarkType, Schema } from "prosemirror-model";
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
FormattingBreadcrumbItem,
|
|
25
|
+
FormattingAlignment,
|
|
26
|
+
FormattingStateSnapshot,
|
|
27
|
+
PersistedEditorSnapshot,
|
|
28
|
+
RuntimeRenderSnapshot,
|
|
29
|
+
SurfaceBlockSnapshot,
|
|
30
|
+
SurfaceInlineSegment,
|
|
31
|
+
SurfaceTableCellSnapshot,
|
|
32
|
+
} from "../../api/public-types";
|
|
33
|
+
import type {
|
|
34
|
+
BlockNode,
|
|
35
|
+
DocumentRootNode,
|
|
36
|
+
InlineNode,
|
|
37
|
+
ParagraphNode,
|
|
38
|
+
TextMark,
|
|
39
|
+
TextNode,
|
|
40
|
+
} from "../../model/canonical-document.ts";
|
|
41
|
+
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Toggle commands (boolean marks – no attrs)
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
export function makeToggleBold(schema: Schema): Command {
|
|
4
47
|
return toggleMark(schema.marks.bold);
|
|
5
48
|
}
|
|
6
|
-
|
|
49
|
+
|
|
50
|
+
export function makeToggleItalic(schema: Schema): Command {
|
|
7
51
|
return toggleMark(schema.marks.italic);
|
|
8
52
|
}
|
|
9
|
-
|
|
53
|
+
|
|
54
|
+
export function makeToggleUnderline(schema: Schema): Command {
|
|
10
55
|
return toggleMark(schema.marks.underline);
|
|
11
56
|
}
|
|
12
|
-
|
|
57
|
+
|
|
58
|
+
export function makeToggleStrikethrough(schema: Schema): Command {
|
|
13
59
|
return toggleMark(schema.marks.strikethrough);
|
|
14
60
|
}
|
|
15
|
-
|
|
61
|
+
|
|
62
|
+
export function makeToggleSuperscript(schema: Schema): Command {
|
|
16
63
|
return toggleMark(schema.marks.superscript);
|
|
17
64
|
}
|
|
18
|
-
|
|
65
|
+
|
|
66
|
+
export function makeToggleSubscript(schema: Schema): Command {
|
|
19
67
|
return toggleMark(schema.marks.subscript);
|
|
20
68
|
}
|
|
21
|
-
|
|
69
|
+
|
|
70
|
+
export function makeToggleSmallCaps(schema: Schema): Command {
|
|
22
71
|
return toggleMark(schema.marks.small_caps);
|
|
23
72
|
}
|
|
24
|
-
|
|
73
|
+
|
|
74
|
+
export function makeToggleAllCaps(schema: Schema): Command {
|
|
25
75
|
return toggleMark(schema.marks.all_caps);
|
|
26
76
|
}
|
|
27
|
-
|
|
77
|
+
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Set commands (value-bearing marks)
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Apply or remove a value-bearing mark over the current selection.
|
|
84
|
+
* When `value` is null the mark is removed; otherwise it is added with the
|
|
85
|
+
* given attribute key set to `value`.
|
|
86
|
+
*/
|
|
87
|
+
function makeSetValueMark(
|
|
88
|
+
markType: MarkType,
|
|
89
|
+
attrKey: string,
|
|
90
|
+
value: string | number | null,
|
|
91
|
+
): Command {
|
|
28
92
|
return (state, dispatch) => {
|
|
29
93
|
const { from, to, empty } = state.selection;
|
|
30
94
|
if (empty) return false;
|
|
31
95
|
if (!dispatch) return true;
|
|
96
|
+
|
|
32
97
|
const tr = state.tr;
|
|
33
98
|
if (value === null) {
|
|
34
99
|
tr.removeMark(from, to, markType);
|
|
@@ -40,42 +105,70 @@ function makeSetValueMark(markType, attrKey, value) {
|
|
|
40
105
|
return true;
|
|
41
106
|
};
|
|
42
107
|
}
|
|
43
|
-
|
|
108
|
+
|
|
109
|
+
export function makeSetFontFamily(schema: Schema, family: string | null): Command {
|
|
44
110
|
return makeSetValueMark(schema.marks.font_family, "family", family);
|
|
45
111
|
}
|
|
46
|
-
|
|
112
|
+
|
|
113
|
+
export function makeSetFontSize(schema: Schema, size: number | null): Command {
|
|
47
114
|
return makeSetValueMark(schema.marks.font_size, "size", size);
|
|
48
115
|
}
|
|
49
|
-
|
|
116
|
+
|
|
117
|
+
export function makeSetTextColor(schema: Schema, color: string | null): Command {
|
|
50
118
|
return makeSetValueMark(schema.marks.text_color, "color", color);
|
|
51
119
|
}
|
|
52
|
-
|
|
120
|
+
|
|
121
|
+
export function makeSetHighlight(schema: Schema, color: string | null): Command {
|
|
53
122
|
return makeSetValueMark(schema.marks.highlight, "color", color);
|
|
54
123
|
}
|
|
55
|
-
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Paragraph alignment
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
export type Alignment = "left" | "center" | "right" | "justify";
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Set the `alignment` attribute on every paragraph node that intersects
|
|
133
|
+
* the current selection. Pass `null` to clear the alignment.
|
|
134
|
+
*/
|
|
135
|
+
export function makeSetAlignment(schema: Schema, alignment: Alignment | null): Command {
|
|
56
136
|
return (state, dispatch) => {
|
|
57
137
|
const { from, to } = state.selection;
|
|
58
138
|
if (!dispatch) return true;
|
|
139
|
+
|
|
59
140
|
const tr = state.tr;
|
|
60
141
|
let applied = false;
|
|
61
142
|
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
62
143
|
if (node.type === schema.nodes.paragraph) {
|
|
63
|
-
tr.setNodeMarkup(pos,
|
|
144
|
+
tr.setNodeMarkup(pos, undefined, { ...node.attrs, alignment });
|
|
64
145
|
applied = true;
|
|
65
146
|
}
|
|
66
147
|
});
|
|
148
|
+
|
|
67
149
|
if (!applied) return false;
|
|
68
150
|
dispatch(tr);
|
|
69
151
|
return true;
|
|
70
152
|
};
|
|
71
153
|
}
|
|
72
|
-
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Mark query helpers
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Returns true if every character in the selection has the given mark active.
|
|
161
|
+
* When the selection is collapsed, checks the stored marks at the cursor.
|
|
162
|
+
*/
|
|
163
|
+
export function isMarkActive(schema: Schema, markName: keyof typeof schema.marks, state: import("prosemirror-state").EditorState): boolean {
|
|
73
164
|
const markType = schema.marks[markName];
|
|
74
165
|
if (!markType) return false;
|
|
166
|
+
|
|
75
167
|
const { from, to, empty } = state.selection;
|
|
76
168
|
if (empty) {
|
|
77
169
|
return Boolean(markType.isInSet(state.storedMarks ?? state.selection.$from.marks()));
|
|
78
170
|
}
|
|
171
|
+
|
|
79
172
|
let active = true;
|
|
80
173
|
state.doc.nodesBetween(from, to, (node) => {
|
|
81
174
|
if (node.isText && !markType.isInSet(node.marks)) {
|
|
@@ -85,116 +178,180 @@ function isMarkActive(schema, markName, state) {
|
|
|
85
178
|
});
|
|
86
179
|
return active;
|
|
87
180
|
}
|
|
88
|
-
|
|
181
|
+
|
|
182
|
+
type CanonicalDocumentEnvelope = PersistedEditorSnapshot["canonicalDocument"];
|
|
183
|
+
type ParagraphSurfaceBlock = Extract<SurfaceBlockSnapshot, { kind: "paragraph" }>;
|
|
184
|
+
type ToggleFormattingMark =
|
|
185
|
+
| "bold"
|
|
186
|
+
| "italic"
|
|
187
|
+
| "underline"
|
|
188
|
+
| "strikethrough"
|
|
189
|
+
| "superscript"
|
|
190
|
+
| "subscript";
|
|
191
|
+
type FormattingOperation =
|
|
192
|
+
| { type: "toggle"; mark: ToggleFormattingMark }
|
|
193
|
+
| { type: "set-font-family"; fontFamily: string | null }
|
|
194
|
+
| { type: "set-font-size"; size: number | null }
|
|
195
|
+
| { type: "set-text-color"; color: string | null }
|
|
196
|
+
| { type: "set-highlight-color"; color: string | null }
|
|
197
|
+
| { type: "set-alignment"; alignment: FormattingAlignment }
|
|
198
|
+
| { type: "indent" }
|
|
199
|
+
| { type: "outdent" };
|
|
200
|
+
|
|
201
|
+
export interface FormattingMutationResult {
|
|
202
|
+
document: CanonicalDocumentEnvelope;
|
|
203
|
+
selection: RuntimeRenderSnapshot["selection"];
|
|
204
|
+
changed: boolean;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const DEFAULT_FORMATTING_STATE: FormattingStateSnapshot = {
|
|
89
208
|
bold: false,
|
|
90
209
|
italic: false,
|
|
91
210
|
underline: false,
|
|
92
211
|
strikethrough: false,
|
|
93
212
|
superscript: false,
|
|
94
213
|
subscript: false,
|
|
95
|
-
breadcrumb: []
|
|
214
|
+
breadcrumb: [],
|
|
96
215
|
};
|
|
97
|
-
|
|
98
|
-
|
|
216
|
+
|
|
217
|
+
const INDENT_STEP_TWIPS = 720;
|
|
218
|
+
|
|
219
|
+
export function getFormattingStateFromRenderSnapshot(
|
|
220
|
+
snapshot: RuntimeRenderSnapshot,
|
|
221
|
+
): FormattingStateSnapshot {
|
|
99
222
|
const surface = snapshot.surface;
|
|
100
223
|
if (!surface) {
|
|
101
224
|
return { ...DEFAULT_FORMATTING_STATE };
|
|
102
225
|
}
|
|
103
|
-
|
|
104
|
-
|
|
226
|
+
|
|
227
|
+
const paragraphs = collectParagraphSurfaces(surface.blocks).filter((paragraph) =>
|
|
228
|
+
selectionTouchesRange(
|
|
105
229
|
snapshot.selection.anchor,
|
|
106
230
|
snapshot.selection.head,
|
|
107
231
|
paragraph.from,
|
|
108
|
-
paragraph.to
|
|
109
|
-
)
|
|
232
|
+
paragraph.to,
|
|
233
|
+
),
|
|
110
234
|
);
|
|
111
235
|
const textSegments = collectFormattingTextSegments(paragraphs, snapshot.selection);
|
|
236
|
+
|
|
112
237
|
return {
|
|
113
|
-
bold: textSegments.length > 0
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
238
|
+
bold: textSegments.length > 0
|
|
239
|
+
? textSegments.every((segment) => segmentHasMark(segment, "bold"))
|
|
240
|
+
: false,
|
|
241
|
+
italic: textSegments.length > 0
|
|
242
|
+
? textSegments.every((segment) => segmentHasMark(segment, "italic"))
|
|
243
|
+
: false,
|
|
244
|
+
underline: textSegments.length > 0
|
|
245
|
+
? textSegments.every((segment) => segmentHasMark(segment, "underline"))
|
|
246
|
+
: false,
|
|
247
|
+
strikethrough: textSegments.length > 0
|
|
248
|
+
? textSegments.every((segment) => segmentHasMark(segment, "strikethrough"))
|
|
249
|
+
: false,
|
|
250
|
+
superscript: textSegments.length > 0
|
|
251
|
+
? textSegments.every((segment) => segmentHasMark(segment, "superscript"))
|
|
252
|
+
: false,
|
|
253
|
+
subscript: textSegments.length > 0
|
|
254
|
+
? textSegments.every((segment) => segmentHasMark(segment, "subscript"))
|
|
255
|
+
: false,
|
|
119
256
|
fontFamily: getConsistentValue(textSegments, (segment) => segment.markAttrs?.fontFamily),
|
|
120
257
|
fontSize: getConsistentValue(textSegments, (segment) => {
|
|
121
258
|
const size = segment.markAttrs?.fontSize;
|
|
122
|
-
return typeof size === "number" ? size / 2 :
|
|
259
|
+
return typeof size === "number" ? size / 2 : undefined;
|
|
123
260
|
}),
|
|
124
|
-
textColor: getConsistentValue(
|
|
125
|
-
|
|
126
|
-
(segment) => toPublicColor(segment.markAttrs?.textColor)
|
|
261
|
+
textColor: getConsistentValue(textSegments, (segment) =>
|
|
262
|
+
toPublicColor(segment.markAttrs?.textColor),
|
|
127
263
|
),
|
|
128
264
|
highlightColor: getConsistentValue(
|
|
129
265
|
textSegments,
|
|
130
266
|
(segment) => toPublicColor(segment.markAttrs?.backgroundColor) ?? null,
|
|
131
267
|
{
|
|
132
|
-
emptyFallback: null
|
|
133
|
-
}
|
|
268
|
+
emptyFallback: null,
|
|
269
|
+
},
|
|
134
270
|
),
|
|
135
|
-
alignment: getConsistentValue(
|
|
136
|
-
|
|
137
|
-
(paragraph) => toPublicAlignment(paragraph.alignment)
|
|
271
|
+
alignment: getConsistentValue(paragraphs, (paragraph) =>
|
|
272
|
+
toPublicAlignment(paragraph.alignment),
|
|
138
273
|
),
|
|
139
274
|
paragraphStyleId: getConsistentValue(paragraphs, (paragraph) => paragraph.styleId),
|
|
140
|
-
breadcrumb: getSelectionBreadcrumb(surface.blocks, snapshot.selection)
|
|
275
|
+
breadcrumb: getSelectionBreadcrumb(surface.blocks, snapshot.selection),
|
|
141
276
|
};
|
|
142
277
|
}
|
|
143
|
-
|
|
278
|
+
|
|
279
|
+
function getSelectionBreadcrumb(
|
|
280
|
+
blocks: SurfaceBlockSnapshot[],
|
|
281
|
+
selection: RuntimeRenderSnapshot["selection"],
|
|
282
|
+
): FormattingBreadcrumbItem[] {
|
|
144
283
|
const paths = collectSelectionBreadcrumbPaths(blocks, selection);
|
|
145
284
|
if (paths.length === 0) {
|
|
146
285
|
return [];
|
|
147
286
|
}
|
|
287
|
+
|
|
148
288
|
let commonLength = paths[0]?.length ?? 0;
|
|
149
289
|
for (let pathIndex = 1; pathIndex < paths.length; pathIndex += 1) {
|
|
150
290
|
const currentPath = paths[pathIndex] ?? [];
|
|
151
291
|
commonLength = Math.min(commonLength, currentPath.length);
|
|
292
|
+
|
|
152
293
|
let compareIndex = 0;
|
|
153
|
-
while (
|
|
294
|
+
while (
|
|
295
|
+
compareIndex < commonLength &&
|
|
296
|
+
breadcrumbItemsEqual(paths[0]![compareIndex]!, currentPath[compareIndex]!)
|
|
297
|
+
) {
|
|
154
298
|
compareIndex += 1;
|
|
155
299
|
}
|
|
156
300
|
commonLength = compareIndex;
|
|
157
301
|
}
|
|
158
|
-
|
|
302
|
+
|
|
303
|
+
return paths[0]!.slice(0, commonLength);
|
|
159
304
|
}
|
|
160
|
-
|
|
305
|
+
|
|
306
|
+
function collectSelectionBreadcrumbPaths(
|
|
307
|
+
blocks: SurfaceBlockSnapshot[],
|
|
308
|
+
selection: RuntimeRenderSnapshot["selection"],
|
|
309
|
+
path: FormattingBreadcrumbItem[] = [],
|
|
310
|
+
output: FormattingBreadcrumbItem[][] = [],
|
|
311
|
+
): FormattingBreadcrumbItem[][] {
|
|
161
312
|
for (let blockIndex = 0; blockIndex < blocks.length; blockIndex += 1) {
|
|
162
313
|
const block = blocks[blockIndex];
|
|
163
314
|
if (!block) {
|
|
164
315
|
continue;
|
|
165
316
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
317
|
+
|
|
318
|
+
if (
|
|
319
|
+
!selectionTouchesRange(
|
|
320
|
+
selection.anchor,
|
|
321
|
+
selection.head,
|
|
322
|
+
block.from,
|
|
323
|
+
block.to,
|
|
324
|
+
)
|
|
325
|
+
) {
|
|
172
326
|
continue;
|
|
173
327
|
}
|
|
328
|
+
|
|
174
329
|
if (block.kind === "paragraph") {
|
|
175
330
|
output.push([
|
|
176
331
|
...path,
|
|
177
332
|
{
|
|
178
|
-
kind: "paragraph",
|
|
333
|
+
kind: "paragraph" as const,
|
|
179
334
|
label: block.styleId ? `Paragraph (${block.styleId})` : "Paragraph",
|
|
180
335
|
from: block.from,
|
|
181
|
-
to: block.to
|
|
182
|
-
}
|
|
336
|
+
to: block.to,
|
|
337
|
+
},
|
|
183
338
|
]);
|
|
184
339
|
continue;
|
|
185
340
|
}
|
|
341
|
+
|
|
186
342
|
if (block.kind === "opaque_block") {
|
|
187
343
|
output.push([
|
|
188
344
|
...path,
|
|
189
345
|
{
|
|
190
|
-
kind: "opaque_block",
|
|
346
|
+
kind: "opaque_block" as const,
|
|
191
347
|
label: block.label,
|
|
192
348
|
from: block.from,
|
|
193
|
-
to: block.to
|
|
194
|
-
}
|
|
349
|
+
to: block.to,
|
|
350
|
+
},
|
|
195
351
|
]);
|
|
196
352
|
continue;
|
|
197
353
|
}
|
|
354
|
+
|
|
198
355
|
if (block.kind === "sdt_block") {
|
|
199
356
|
collectSelectionBreadcrumbPaths(
|
|
200
357
|
block.children,
|
|
@@ -202,63 +359,72 @@ function collectSelectionBreadcrumbPaths(blocks, selection, path = [], output =
|
|
|
202
359
|
[
|
|
203
360
|
...path,
|
|
204
361
|
{
|
|
205
|
-
kind: "sdt_block",
|
|
362
|
+
kind: "sdt_block" as const,
|
|
206
363
|
label: block.alias ?? block.tag ?? block.sdtType ?? "Content control",
|
|
207
364
|
from: block.from,
|
|
208
|
-
to: block.to
|
|
209
|
-
}
|
|
365
|
+
to: block.to,
|
|
366
|
+
},
|
|
210
367
|
],
|
|
211
|
-
output
|
|
368
|
+
output,
|
|
212
369
|
);
|
|
213
370
|
continue;
|
|
214
371
|
}
|
|
372
|
+
|
|
215
373
|
if (block.kind === "table") {
|
|
216
374
|
const tablePath = [
|
|
217
375
|
...path,
|
|
218
376
|
{
|
|
219
|
-
kind: "table",
|
|
377
|
+
kind: "table" as const,
|
|
220
378
|
label: block.styleId ? `Table (${block.styleId})` : "Table",
|
|
221
379
|
from: block.from,
|
|
222
|
-
to: block.to
|
|
223
|
-
}
|
|
380
|
+
to: block.to,
|
|
381
|
+
},
|
|
224
382
|
];
|
|
383
|
+
|
|
225
384
|
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
|
|
226
385
|
const row = block.rows[rowIndex];
|
|
227
386
|
if (!row) {
|
|
228
387
|
continue;
|
|
229
388
|
}
|
|
230
389
|
const rowRange = getTableRowRange(block, row);
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
390
|
+
if (
|
|
391
|
+
!selectionTouchesRange(
|
|
392
|
+
selection.anchor,
|
|
393
|
+
selection.head,
|
|
394
|
+
rowRange.from,
|
|
395
|
+
rowRange.to,
|
|
396
|
+
)
|
|
397
|
+
) {
|
|
237
398
|
continue;
|
|
238
399
|
}
|
|
400
|
+
|
|
239
401
|
const rowPath = [
|
|
240
402
|
...tablePath,
|
|
241
403
|
{
|
|
242
|
-
kind: "table_row",
|
|
404
|
+
kind: "table_row" as const,
|
|
243
405
|
label: `Row ${rowIndex + 1}`,
|
|
244
406
|
from: rowRange.from,
|
|
245
|
-
to: rowRange.to
|
|
246
|
-
}
|
|
407
|
+
to: rowRange.to,
|
|
408
|
+
},
|
|
247
409
|
];
|
|
410
|
+
|
|
248
411
|
for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex += 1) {
|
|
249
412
|
const cell = row.cells[cellIndex];
|
|
250
413
|
if (!cell) {
|
|
251
414
|
continue;
|
|
252
415
|
}
|
|
253
416
|
const cellRange = getTableCellRange(block, cell);
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
417
|
+
if (
|
|
418
|
+
!selectionTouchesRange(
|
|
419
|
+
selection.anchor,
|
|
420
|
+
selection.head,
|
|
421
|
+
cellRange.from,
|
|
422
|
+
cellRange.to,
|
|
423
|
+
)
|
|
424
|
+
) {
|
|
260
425
|
continue;
|
|
261
426
|
}
|
|
427
|
+
|
|
262
428
|
collectSelectionBreadcrumbPaths(
|
|
263
429
|
cell.content,
|
|
264
430
|
selection,
|
|
@@ -268,113 +434,169 @@ function collectSelectionBreadcrumbPaths(blocks, selection, path = [], output =
|
|
|
268
434
|
kind: "table_cell",
|
|
269
435
|
label: `Cell ${cellIndex + 1}`,
|
|
270
436
|
from: cellRange.from,
|
|
271
|
-
to: cellRange.to
|
|
272
|
-
}
|
|
437
|
+
to: cellRange.to,
|
|
438
|
+
},
|
|
273
439
|
],
|
|
274
|
-
output
|
|
440
|
+
output,
|
|
275
441
|
);
|
|
276
442
|
}
|
|
277
443
|
}
|
|
278
444
|
}
|
|
279
445
|
}
|
|
446
|
+
|
|
280
447
|
return output;
|
|
281
448
|
}
|
|
282
|
-
|
|
449
|
+
|
|
450
|
+
function getTableRowRange(
|
|
451
|
+
table: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
|
|
452
|
+
row: (typeof table.rows)[number],
|
|
453
|
+
): { from: number; to: number } {
|
|
283
454
|
let from = Number.POSITIVE_INFINITY;
|
|
284
455
|
let to = Number.NEGATIVE_INFINITY;
|
|
456
|
+
|
|
285
457
|
for (const cell of row.cells) {
|
|
286
458
|
const range = getTableCellRange(table, cell);
|
|
287
459
|
from = Math.min(from, range.from);
|
|
288
460
|
to = Math.max(to, range.to);
|
|
289
461
|
}
|
|
290
|
-
|
|
462
|
+
|
|
463
|
+
return Number.isFinite(from) && Number.isFinite(to)
|
|
464
|
+
? { from, to }
|
|
465
|
+
: { from: table.from, to: table.to };
|
|
291
466
|
}
|
|
292
|
-
|
|
467
|
+
|
|
468
|
+
function getTableCellRange(
|
|
469
|
+
table: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
|
|
470
|
+
cell: SurfaceTableCellSnapshot,
|
|
471
|
+
): { from: number; to: number } {
|
|
293
472
|
if (cell.content.length === 0) {
|
|
294
473
|
return { from: table.from, to: table.to };
|
|
295
474
|
}
|
|
475
|
+
|
|
296
476
|
let from = Number.POSITIVE_INFINITY;
|
|
297
477
|
let to = Number.NEGATIVE_INFINITY;
|
|
298
478
|
for (const child of cell.content) {
|
|
299
479
|
from = Math.min(from, child.from);
|
|
300
480
|
to = Math.max(to, child.to);
|
|
301
481
|
}
|
|
302
|
-
|
|
482
|
+
|
|
483
|
+
return Number.isFinite(from) && Number.isFinite(to)
|
|
484
|
+
? { from, to }
|
|
485
|
+
: { from: table.from, to: table.to };
|
|
303
486
|
}
|
|
304
|
-
|
|
305
|
-
|
|
487
|
+
|
|
488
|
+
function breadcrumbItemsEqual(
|
|
489
|
+
left: FormattingBreadcrumbItem,
|
|
490
|
+
right: FormattingBreadcrumbItem,
|
|
491
|
+
): boolean {
|
|
492
|
+
return (
|
|
493
|
+
left.kind === right.kind &&
|
|
494
|
+
left.label === right.label &&
|
|
495
|
+
left.from === right.from &&
|
|
496
|
+
left.to === right.to
|
|
497
|
+
);
|
|
306
498
|
}
|
|
307
|
-
|
|
499
|
+
|
|
500
|
+
export function applyFormattingOperationToDocument(
|
|
501
|
+
document: CanonicalDocumentEnvelope,
|
|
502
|
+
snapshot: RuntimeRenderSnapshot,
|
|
503
|
+
operation: FormattingOperation,
|
|
504
|
+
): FormattingMutationResult {
|
|
308
505
|
const surface = snapshot.surface;
|
|
309
506
|
if (!surface) {
|
|
310
507
|
return {
|
|
311
508
|
document,
|
|
312
509
|
selection: snapshot.selection,
|
|
313
|
-
changed: false
|
|
510
|
+
changed: false,
|
|
314
511
|
};
|
|
315
512
|
}
|
|
513
|
+
|
|
316
514
|
const nextDocument = structuredClone(document);
|
|
317
|
-
const root = nextDocument.content;
|
|
515
|
+
const root = nextDocument.content as DocumentRootNode;
|
|
318
516
|
let changed = false;
|
|
319
517
|
const selectionFrom = Math.min(snapshot.selection.anchor, snapshot.selection.head);
|
|
320
518
|
const selectionTo = Math.max(snapshot.selection.anchor, snapshot.selection.head);
|
|
519
|
+
|
|
321
520
|
if (operation.type === "set-alignment" || operation.type === "indent" || operation.type === "outdent") {
|
|
322
521
|
visitParagraphBindings(root.children, surface.blocks, (paragraph, paragraphSurface) => {
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
522
|
+
if (
|
|
523
|
+
!selectionTouchesRange(
|
|
524
|
+
snapshot.selection.anchor,
|
|
525
|
+
snapshot.selection.head,
|
|
526
|
+
paragraphSurface.from,
|
|
527
|
+
paragraphSurface.to,
|
|
528
|
+
)
|
|
529
|
+
) {
|
|
329
530
|
return;
|
|
330
531
|
}
|
|
331
|
-
|
|
532
|
+
|
|
533
|
+
const paragraphChanged =
|
|
534
|
+
operation.type === "set-alignment"
|
|
535
|
+
? applyAlignment(paragraph, operation.alignment)
|
|
536
|
+
: applyIndentation(paragraph, operation.type === "indent" ? 1 : -1);
|
|
332
537
|
changed = changed || paragraphChanged;
|
|
333
538
|
});
|
|
539
|
+
|
|
334
540
|
return {
|
|
335
541
|
document: changed ? nextDocument : document,
|
|
336
542
|
selection: snapshot.selection,
|
|
337
|
-
changed
|
|
543
|
+
changed,
|
|
338
544
|
};
|
|
339
545
|
}
|
|
546
|
+
|
|
340
547
|
if (selectionFrom === selectionTo) {
|
|
341
548
|
return {
|
|
342
549
|
document,
|
|
343
550
|
selection: snapshot.selection,
|
|
344
|
-
changed: false
|
|
551
|
+
changed: false,
|
|
345
552
|
};
|
|
346
553
|
}
|
|
554
|
+
|
|
347
555
|
const nextMarks = resolveMarkUpdater(snapshot, operation);
|
|
556
|
+
|
|
348
557
|
visitParagraphBindings(root.children, surface.blocks, (paragraph, paragraphSurface) => {
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
558
|
+
if (
|
|
559
|
+
!rangesOverlap(
|
|
560
|
+
selectionFrom,
|
|
561
|
+
selectionTo,
|
|
562
|
+
paragraphSurface.from,
|
|
563
|
+
paragraphSurface.to,
|
|
564
|
+
)
|
|
565
|
+
) {
|
|
355
566
|
return;
|
|
356
567
|
}
|
|
568
|
+
|
|
357
569
|
const transformed = transformInlineNodes(
|
|
358
570
|
paragraph.children,
|
|
359
571
|
paragraphSurface.from,
|
|
360
572
|
selectionFrom,
|
|
361
573
|
selectionTo,
|
|
362
|
-
nextMarks
|
|
574
|
+
nextMarks,
|
|
363
575
|
);
|
|
364
576
|
if (!transformed.changed) {
|
|
365
577
|
return;
|
|
366
578
|
}
|
|
579
|
+
|
|
367
580
|
paragraph.children = transformed.nodes;
|
|
368
581
|
changed = true;
|
|
369
582
|
});
|
|
583
|
+
|
|
370
584
|
return {
|
|
371
585
|
document: changed ? nextDocument : document,
|
|
372
586
|
selection: snapshot.selection,
|
|
373
|
-
changed
|
|
587
|
+
changed,
|
|
374
588
|
};
|
|
375
589
|
}
|
|
376
|
-
|
|
590
|
+
|
|
591
|
+
function resolveMarkUpdater(
|
|
592
|
+
snapshot: RuntimeRenderSnapshot,
|
|
593
|
+
operation: Exclude<
|
|
594
|
+
FormattingOperation,
|
|
595
|
+
{ type: "set-alignment" } | { type: "indent" } | { type: "outdent" }
|
|
596
|
+
>,
|
|
597
|
+
): (marks?: TextMark[]) => TextMark[] | undefined {
|
|
377
598
|
const formatting = getFormattingStateFromRenderSnapshot(snapshot);
|
|
599
|
+
|
|
378
600
|
switch (operation.type) {
|
|
379
601
|
case "toggle":
|
|
380
602
|
return (marks) => toggleMarks(marks, operation.mark, !formatting[operation.mark]);
|
|
@@ -388,49 +610,65 @@ function resolveMarkUpdater(snapshot, operation) {
|
|
|
388
610
|
return (marks) => setMarkValue(marks, "backgroundColor", sanitizeColor(operation.color));
|
|
389
611
|
}
|
|
390
612
|
}
|
|
391
|
-
|
|
613
|
+
|
|
614
|
+
function applyAlignment(
|
|
615
|
+
paragraph: ParagraphNode,
|
|
616
|
+
alignment: FormattingAlignment,
|
|
617
|
+
): boolean {
|
|
392
618
|
const nextAlignment = alignment === "justify" ? "both" : alignment;
|
|
393
619
|
if (paragraph.alignment === nextAlignment) {
|
|
394
620
|
return false;
|
|
395
621
|
}
|
|
622
|
+
|
|
396
623
|
paragraph.alignment = nextAlignment;
|
|
397
624
|
return true;
|
|
398
625
|
}
|
|
399
|
-
|
|
626
|
+
|
|
627
|
+
function applyIndentation(paragraph: ParagraphNode, delta: -1 | 1): boolean {
|
|
400
628
|
if (paragraph.numbering) {
|
|
401
629
|
const nextLevel = clamp(paragraph.numbering.level + delta, 0, 8);
|
|
402
630
|
if (nextLevel === paragraph.numbering.level) {
|
|
403
631
|
return false;
|
|
404
632
|
}
|
|
633
|
+
|
|
405
634
|
paragraph.numbering = {
|
|
406
635
|
...paragraph.numbering,
|
|
407
|
-
level: nextLevel
|
|
636
|
+
level: nextLevel,
|
|
408
637
|
};
|
|
409
638
|
return true;
|
|
410
639
|
}
|
|
640
|
+
|
|
411
641
|
const currentLeft = paragraph.indentation?.left ?? 0;
|
|
412
642
|
const nextLeft = Math.max(0, currentLeft + delta * INDENT_STEP_TWIPS);
|
|
413
643
|
if (nextLeft === currentLeft) {
|
|
414
644
|
return false;
|
|
415
645
|
}
|
|
646
|
+
|
|
416
647
|
const nextIndentation = {
|
|
417
|
-
...paragraph.indentation ?? {}
|
|
648
|
+
...(paragraph.indentation ?? {}),
|
|
418
649
|
};
|
|
419
650
|
if (nextLeft > 0) {
|
|
420
651
|
nextIndentation.left = nextLeft;
|
|
421
652
|
paragraph.indentation = nextIndentation;
|
|
422
653
|
} else if (paragraph.indentation) {
|
|
423
654
|
delete nextIndentation.left;
|
|
424
|
-
paragraph.indentation =
|
|
655
|
+
paragraph.indentation =
|
|
656
|
+
Object.keys(nextIndentation).length > 0 ? nextIndentation : undefined;
|
|
425
657
|
}
|
|
658
|
+
|
|
426
659
|
return true;
|
|
427
660
|
}
|
|
428
|
-
|
|
661
|
+
|
|
662
|
+
function collectParagraphSurfaces(
|
|
663
|
+
blocks: SurfaceBlockSnapshot[],
|
|
664
|
+
output: ParagraphSurfaceBlock[] = [],
|
|
665
|
+
): ParagraphSurfaceBlock[] {
|
|
429
666
|
for (const block of blocks) {
|
|
430
667
|
if (block.kind === "paragraph") {
|
|
431
668
|
output.push(block);
|
|
432
669
|
continue;
|
|
433
670
|
}
|
|
671
|
+
|
|
434
672
|
if (block.kind === "table") {
|
|
435
673
|
for (const row of block.rows) {
|
|
436
674
|
for (const cell of row.cells) {
|
|
@@ -439,45 +677,72 @@ function collectParagraphSurfaces(blocks, output = []) {
|
|
|
439
677
|
}
|
|
440
678
|
continue;
|
|
441
679
|
}
|
|
680
|
+
|
|
442
681
|
if (block.kind === "sdt_block") {
|
|
443
682
|
collectParagraphSurfaces(block.children, output);
|
|
444
683
|
}
|
|
445
684
|
}
|
|
685
|
+
|
|
446
686
|
return output;
|
|
447
687
|
}
|
|
448
|
-
|
|
688
|
+
|
|
689
|
+
function collectFormattingTextSegments(
|
|
690
|
+
paragraphs: ParagraphSurfaceBlock[],
|
|
691
|
+
selection: RuntimeRenderSnapshot["selection"],
|
|
692
|
+
): Array<Extract<SurfaceInlineSegment, { kind: "text" }>> {
|
|
449
693
|
const caret = selection.anchor;
|
|
450
694
|
const isCollapsed = selection.isCollapsed;
|
|
451
695
|
const selectionFrom = Math.min(selection.anchor, selection.head);
|
|
452
696
|
const selectionTo = Math.max(selection.anchor, selection.head);
|
|
453
|
-
const segments = [];
|
|
697
|
+
const segments: Array<Extract<SurfaceInlineSegment, { kind: "text" }>> = [];
|
|
698
|
+
|
|
454
699
|
for (const paragraph of paragraphs) {
|
|
455
700
|
for (const segment of paragraph.segments) {
|
|
456
701
|
if (segment.kind !== "text") {
|
|
457
702
|
continue;
|
|
458
703
|
}
|
|
459
|
-
|
|
704
|
+
|
|
705
|
+
if (
|
|
706
|
+
isCollapsed
|
|
707
|
+
? segmentContainsCaret(segment, caret)
|
|
708
|
+
: rangesOverlap(selectionFrom, selectionTo, segment.from, segment.to)
|
|
709
|
+
) {
|
|
460
710
|
segments.push(segment);
|
|
461
711
|
}
|
|
462
712
|
}
|
|
463
713
|
}
|
|
714
|
+
|
|
464
715
|
if (!isCollapsed || segments.length > 0) {
|
|
465
716
|
return segments;
|
|
466
717
|
}
|
|
718
|
+
|
|
467
719
|
for (const paragraph of paragraphs) {
|
|
468
720
|
const fallback = paragraph.segments.find(
|
|
469
|
-
(segment)
|
|
721
|
+
(segment): segment is Extract<SurfaceInlineSegment, { kind: "text" }> =>
|
|
722
|
+
segment.kind === "text" && segment.to === caret,
|
|
470
723
|
);
|
|
471
724
|
if (fallback) {
|
|
472
725
|
return [fallback];
|
|
473
726
|
}
|
|
474
727
|
}
|
|
728
|
+
|
|
475
729
|
return [];
|
|
476
730
|
}
|
|
477
|
-
|
|
478
|
-
|
|
731
|
+
|
|
732
|
+
function segmentContainsCaret(
|
|
733
|
+
segment: Extract<SurfaceInlineSegment, { kind: "text" }>,
|
|
734
|
+
caret: number,
|
|
735
|
+
): boolean {
|
|
736
|
+
return (
|
|
737
|
+
segment.from <= caret &&
|
|
738
|
+
(caret < segment.to || (segment.to === caret && segment.to > segment.from))
|
|
739
|
+
);
|
|
479
740
|
}
|
|
480
|
-
|
|
741
|
+
|
|
742
|
+
function segmentHasMark(
|
|
743
|
+
segment: Extract<SurfaceInlineSegment, { kind: "text" }>,
|
|
744
|
+
mark: ToggleFormattingMark,
|
|
745
|
+
): boolean {
|
|
481
746
|
const marks = segment.marks ?? [];
|
|
482
747
|
if (mark === "superscript") {
|
|
483
748
|
return marks.includes("superscript");
|
|
@@ -487,12 +752,21 @@ function segmentHasMark(segment, mark) {
|
|
|
487
752
|
}
|
|
488
753
|
return marks.includes(mark);
|
|
489
754
|
}
|
|
490
|
-
|
|
755
|
+
|
|
756
|
+
function getConsistentValue<TItem, TValue>(
|
|
757
|
+
items: readonly TItem[],
|
|
758
|
+
getter: (item: TItem) => TValue,
|
|
759
|
+
options: {
|
|
760
|
+
emptyFallback?: TValue;
|
|
761
|
+
} = {},
|
|
762
|
+
): TValue | undefined {
|
|
491
763
|
if (items.length === 0) {
|
|
492
764
|
return options.emptyFallback;
|
|
493
765
|
}
|
|
494
|
-
|
|
766
|
+
|
|
767
|
+
let value: TValue | undefined = undefined;
|
|
495
768
|
let initialized = false;
|
|
769
|
+
|
|
496
770
|
for (const item of items) {
|
|
497
771
|
const next = getter(item);
|
|
498
772
|
if (!initialized) {
|
|
@@ -500,23 +774,32 @@ function getConsistentValue(items, getter, options = {}) {
|
|
|
500
774
|
initialized = true;
|
|
501
775
|
continue;
|
|
502
776
|
}
|
|
777
|
+
|
|
503
778
|
if (next !== value) {
|
|
504
|
-
return
|
|
779
|
+
return undefined;
|
|
505
780
|
}
|
|
506
781
|
}
|
|
782
|
+
|
|
507
783
|
return value;
|
|
508
784
|
}
|
|
509
|
-
|
|
785
|
+
|
|
786
|
+
function visitParagraphBindings(
|
|
787
|
+
blocks: BlockNode[],
|
|
788
|
+
surfaceBlocks: SurfaceBlockSnapshot[],
|
|
789
|
+
visitor: (paragraph: ParagraphNode, surface: ParagraphSurfaceBlock) => void,
|
|
790
|
+
): void {
|
|
510
791
|
for (let index = 0; index < Math.min(blocks.length, surfaceBlocks.length); index += 1) {
|
|
511
792
|
const block = blocks[index];
|
|
512
793
|
const surface = surfaceBlocks[index];
|
|
513
794
|
if (!block || !surface) {
|
|
514
795
|
continue;
|
|
515
796
|
}
|
|
797
|
+
|
|
516
798
|
if (block.type === "paragraph" && surface.kind === "paragraph") {
|
|
517
799
|
visitor(block, surface);
|
|
518
800
|
continue;
|
|
519
801
|
}
|
|
802
|
+
|
|
520
803
|
if (block.type === "table" && surface.kind === "table") {
|
|
521
804
|
for (let rowIndex = 0; rowIndex < Math.min(block.rows.length, surface.rows.length); rowIndex += 1) {
|
|
522
805
|
const row = block.rows[rowIndex];
|
|
@@ -524,26 +807,41 @@ function visitParagraphBindings(blocks, surfaceBlocks, visitor) {
|
|
|
524
807
|
if (!row || !surfaceRow) {
|
|
525
808
|
continue;
|
|
526
809
|
}
|
|
527
|
-
|
|
810
|
+
|
|
811
|
+
for (
|
|
812
|
+
let cellIndex = 0;
|
|
813
|
+
cellIndex < Math.min(row.cells.length, surfaceRow.cells.length);
|
|
814
|
+
cellIndex += 1
|
|
815
|
+
) {
|
|
528
816
|
const cell = row.cells[cellIndex];
|
|
529
817
|
const surfaceCell = surfaceRow.cells[cellIndex];
|
|
530
818
|
if (!cell || !surfaceCell) {
|
|
531
819
|
continue;
|
|
532
820
|
}
|
|
821
|
+
|
|
533
822
|
visitParagraphBindings(cell.children, surfaceCell.content, visitor);
|
|
534
823
|
}
|
|
535
824
|
}
|
|
536
825
|
continue;
|
|
537
826
|
}
|
|
827
|
+
|
|
538
828
|
if (block.type === "sdt" && surface.kind === "sdt_block") {
|
|
539
829
|
visitParagraphBindings(block.children, surface.children, visitor);
|
|
540
830
|
}
|
|
541
831
|
}
|
|
542
832
|
}
|
|
543
|
-
|
|
833
|
+
|
|
834
|
+
function transformInlineNodes(
|
|
835
|
+
nodes: InlineNode[],
|
|
836
|
+
start: number,
|
|
837
|
+
selectionFrom: number,
|
|
838
|
+
selectionTo: number,
|
|
839
|
+
updateMarks: (marks?: TextMark[]) => TextMark[] | undefined,
|
|
840
|
+
): { nodes: InlineNode[]; changed: boolean; nextPosition: number } {
|
|
544
841
|
let changed = false;
|
|
545
842
|
let position = start;
|
|
546
|
-
const nextNodes = [];
|
|
843
|
+
const nextNodes: InlineNode[] = [];
|
|
844
|
+
|
|
547
845
|
for (const node of nodes) {
|
|
548
846
|
if (node.type === "text") {
|
|
549
847
|
const transformed = transformTextNode(
|
|
@@ -551,141 +849,178 @@ function transformInlineNodes(nodes, start, selectionFrom, selectionTo, updateMa
|
|
|
551
849
|
position,
|
|
552
850
|
selectionFrom,
|
|
553
851
|
selectionTo,
|
|
554
|
-
updateMarks
|
|
852
|
+
updateMarks,
|
|
555
853
|
);
|
|
556
854
|
nextNodes.push(...transformed.nodes);
|
|
557
855
|
position = transformed.nextPosition;
|
|
558
856
|
changed = changed || transformed.changed;
|
|
559
857
|
continue;
|
|
560
858
|
}
|
|
859
|
+
|
|
561
860
|
if (node.type === "hyperlink") {
|
|
562
861
|
const transformed = transformInlineNodes(
|
|
563
|
-
node.children,
|
|
862
|
+
node.children as InlineNode[],
|
|
564
863
|
position,
|
|
565
864
|
selectionFrom,
|
|
566
865
|
selectionTo,
|
|
567
|
-
updateMarks
|
|
866
|
+
updateMarks,
|
|
568
867
|
);
|
|
569
868
|
nextNodes.push(
|
|
570
|
-
transformed.changed
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
869
|
+
transformed.changed
|
|
870
|
+
? {
|
|
871
|
+
...node,
|
|
872
|
+
children: transformed.nodes as typeof node.children,
|
|
873
|
+
}
|
|
874
|
+
: node,
|
|
574
875
|
);
|
|
575
876
|
position = transformed.nextPosition;
|
|
576
877
|
changed = changed || transformed.changed;
|
|
577
878
|
continue;
|
|
578
879
|
}
|
|
880
|
+
|
|
579
881
|
nextNodes.push(node);
|
|
580
882
|
position += inlineNodeLength(node);
|
|
581
883
|
}
|
|
884
|
+
|
|
582
885
|
return {
|
|
583
886
|
nodes: nextNodes,
|
|
584
887
|
changed,
|
|
585
|
-
nextPosition: position
|
|
888
|
+
nextPosition: position,
|
|
586
889
|
};
|
|
587
890
|
}
|
|
588
|
-
|
|
891
|
+
|
|
892
|
+
function transformTextNode(
|
|
893
|
+
node: TextNode,
|
|
894
|
+
start: number,
|
|
895
|
+
selectionFrom: number,
|
|
896
|
+
selectionTo: number,
|
|
897
|
+
updateMarks: (marks?: TextMark[]) => TextMark[] | undefined,
|
|
898
|
+
): { nodes: TextNode[]; changed: boolean; nextPosition: number } {
|
|
589
899
|
const characters = Array.from(node.text);
|
|
590
900
|
const end = start + characters.length;
|
|
591
901
|
const overlapFrom = Math.max(selectionFrom, start);
|
|
592
902
|
const overlapTo = Math.min(selectionTo, end);
|
|
903
|
+
|
|
593
904
|
if (overlapFrom >= overlapTo) {
|
|
594
905
|
return {
|
|
595
906
|
nodes: [node],
|
|
596
907
|
changed: false,
|
|
597
|
-
nextPosition: end
|
|
908
|
+
nextPosition: end,
|
|
598
909
|
};
|
|
599
910
|
}
|
|
911
|
+
|
|
600
912
|
const localFrom = overlapFrom - start;
|
|
601
913
|
const localTo = overlapTo - start;
|
|
602
|
-
const nextNodes = [];
|
|
914
|
+
const nextNodes: TextNode[] = [];
|
|
915
|
+
|
|
603
916
|
if (localFrom > 0) {
|
|
604
917
|
nextNodes.push(createTextNode(characters.slice(0, localFrom).join(""), node.marks));
|
|
605
918
|
}
|
|
919
|
+
|
|
606
920
|
const transformedMarks = updateMarks(node.marks);
|
|
607
921
|
nextNodes.push(
|
|
608
|
-
createTextNode(characters.slice(localFrom, localTo).join(""), transformedMarks)
|
|
922
|
+
createTextNode(characters.slice(localFrom, localTo).join(""), transformedMarks),
|
|
609
923
|
);
|
|
924
|
+
|
|
610
925
|
if (localTo < characters.length) {
|
|
611
926
|
nextNodes.push(createTextNode(characters.slice(localTo).join(""), node.marks));
|
|
612
927
|
}
|
|
928
|
+
|
|
613
929
|
return {
|
|
614
930
|
nodes: nextNodes.filter((candidate) => candidate.text.length > 0),
|
|
615
931
|
changed: !marksEqual(node.marks, transformedMarks) || localFrom > 0 || localTo < characters.length,
|
|
616
|
-
nextPosition: end
|
|
932
|
+
nextPosition: end,
|
|
617
933
|
};
|
|
618
934
|
}
|
|
619
|
-
|
|
935
|
+
|
|
936
|
+
function createTextNode(text: string, marks?: TextMark[]): TextNode {
|
|
620
937
|
return {
|
|
621
938
|
type: "text",
|
|
622
939
|
text,
|
|
623
|
-
...marks && marks.length > 0 ? { marks: cloneMarks(marks) } : {}
|
|
940
|
+
...(marks && marks.length > 0 ? { marks: cloneMarks(marks) } : {}),
|
|
624
941
|
};
|
|
625
942
|
}
|
|
626
|
-
|
|
943
|
+
|
|
944
|
+
function toggleMarks(
|
|
945
|
+
marks: TextMark[] | undefined,
|
|
946
|
+
mark: ToggleFormattingMark,
|
|
947
|
+
enabled: boolean,
|
|
948
|
+
): TextMark[] | undefined {
|
|
627
949
|
const nextMarks = cloneMarks(marks);
|
|
950
|
+
|
|
628
951
|
if (mark === "superscript" || mark === "subscript") {
|
|
629
|
-
const
|
|
952
|
+
const filtered: TextMark[] = nextMarks.filter((candidate) => candidate.type !== "position");
|
|
630
953
|
if (enabled) {
|
|
631
|
-
|
|
954
|
+
filtered.push({
|
|
632
955
|
type: "position",
|
|
633
|
-
val: mark === "superscript" ? 1 : -1
|
|
956
|
+
val: mark === "superscript" ? 1 : -1,
|
|
634
957
|
});
|
|
635
958
|
}
|
|
636
|
-
return
|
|
959
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
637
960
|
}
|
|
961
|
+
|
|
638
962
|
const filtered = nextMarks.filter((candidate) => candidate.type !== mark);
|
|
639
963
|
if (enabled) {
|
|
640
964
|
filtered.push({ type: mark });
|
|
641
965
|
}
|
|
642
|
-
return filtered.length > 0 ? filtered :
|
|
966
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
643
967
|
}
|
|
644
|
-
|
|
968
|
+
|
|
969
|
+
function setMarkValue(
|
|
970
|
+
marks: TextMark[] | undefined,
|
|
971
|
+
markType: "fontFamily" | "fontSize" | "textColor" | "backgroundColor",
|
|
972
|
+
value: string | number | null,
|
|
973
|
+
): TextMark[] | undefined {
|
|
645
974
|
const nextMarks = cloneMarks(marks).filter((candidate) => {
|
|
646
975
|
if (markType === "backgroundColor") {
|
|
647
976
|
return candidate.type !== "backgroundColor" && candidate.type !== "highlight";
|
|
648
977
|
}
|
|
649
978
|
return candidate.type !== markType;
|
|
650
979
|
});
|
|
980
|
+
|
|
651
981
|
if (value !== null) {
|
|
652
982
|
switch (markType) {
|
|
653
983
|
case "fontFamily":
|
|
654
|
-
nextMarks.push({ type: "fontFamily", val: value });
|
|
984
|
+
nextMarks.push({ type: "fontFamily", val: value as string });
|
|
655
985
|
break;
|
|
656
986
|
case "fontSize":
|
|
657
|
-
nextMarks.push({ type: "fontSize", val: value });
|
|
987
|
+
nextMarks.push({ type: "fontSize", val: value as number });
|
|
658
988
|
break;
|
|
659
989
|
case "textColor":
|
|
660
|
-
nextMarks.push({ type: "textColor", color: value });
|
|
990
|
+
nextMarks.push({ type: "textColor", color: value as string });
|
|
661
991
|
break;
|
|
662
992
|
case "backgroundColor":
|
|
663
|
-
nextMarks.push({ type: "backgroundColor", color: value });
|
|
993
|
+
nextMarks.push({ type: "backgroundColor", color: value as string });
|
|
664
994
|
break;
|
|
665
995
|
}
|
|
666
996
|
}
|
|
667
|
-
|
|
997
|
+
|
|
998
|
+
return nextMarks.length > 0 ? nextMarks : undefined;
|
|
668
999
|
}
|
|
669
|
-
|
|
1000
|
+
|
|
1001
|
+
function cloneMarks(marks?: TextMark[]): TextMark[] {
|
|
670
1002
|
return marks ? marks.map((mark) => ({ ...mark })) : [];
|
|
671
1003
|
}
|
|
672
|
-
|
|
1004
|
+
|
|
1005
|
+
function marksEqual(left?: TextMark[], right?: TextMark[]): boolean {
|
|
673
1006
|
if (!left?.length && !right?.length) {
|
|
674
1007
|
return true;
|
|
675
1008
|
}
|
|
676
1009
|
if (!left || !right || left.length !== right.length) {
|
|
677
1010
|
return false;
|
|
678
1011
|
}
|
|
1012
|
+
|
|
679
1013
|
return left.every((mark, index) => JSON.stringify(mark) === JSON.stringify(right[index]));
|
|
680
1014
|
}
|
|
681
|
-
|
|
1015
|
+
|
|
1016
|
+
function inlineNodeLength(node: InlineNode): number {
|
|
682
1017
|
switch (node.type) {
|
|
683
1018
|
case "text":
|
|
684
1019
|
return Array.from(node.text).length;
|
|
685
1020
|
case "hyperlink":
|
|
686
|
-
return node.children.reduce(
|
|
687
|
-
(total, child) => total + inlineNodeLength(child),
|
|
688
|
-
0
|
|
1021
|
+
return node.children.reduce< number >(
|
|
1022
|
+
(total, child) => total + inlineNodeLength(child as InlineNode),
|
|
1023
|
+
0,
|
|
689
1024
|
);
|
|
690
1025
|
case "hard_break":
|
|
691
1026
|
case "column_break":
|
|
@@ -701,16 +1036,19 @@ function inlineNodeLength(node) {
|
|
|
701
1036
|
case "vml_shape":
|
|
702
1037
|
return 1;
|
|
703
1038
|
case "field":
|
|
704
|
-
return node.children.reduce(
|
|
705
|
-
(total, child) => total + inlineNodeLength(child),
|
|
706
|
-
0
|
|
1039
|
+
return node.children.reduce<number>(
|
|
1040
|
+
(total, child) => total + inlineNodeLength(child as InlineNode),
|
|
1041
|
+
0,
|
|
707
1042
|
);
|
|
708
1043
|
case "bookmark_start":
|
|
709
1044
|
case "bookmark_end":
|
|
710
1045
|
return 0;
|
|
711
1046
|
}
|
|
712
1047
|
}
|
|
713
|
-
|
|
1048
|
+
|
|
1049
|
+
function toPublicAlignment(
|
|
1050
|
+
alignment: ParagraphNode["alignment"] | undefined,
|
|
1051
|
+
): FormattingAlignment | undefined {
|
|
714
1052
|
switch (alignment) {
|
|
715
1053
|
case "both":
|
|
716
1054
|
case "distribute":
|
|
@@ -720,34 +1058,49 @@ function toPublicAlignment(alignment) {
|
|
|
720
1058
|
case "right":
|
|
721
1059
|
return alignment;
|
|
722
1060
|
default:
|
|
723
|
-
return
|
|
1061
|
+
return undefined;
|
|
724
1062
|
}
|
|
725
1063
|
}
|
|
726
|
-
|
|
1064
|
+
|
|
1065
|
+
function toPublicColor(color: string | undefined): string | undefined {
|
|
727
1066
|
if (!color) {
|
|
728
|
-
return
|
|
1067
|
+
return undefined;
|
|
729
1068
|
}
|
|
730
|
-
|
|
1069
|
+
|
|
1070
|
+
return /^[0-9A-F]{3,8}$/iu.test(color)
|
|
1071
|
+
? `#${color.toUpperCase()}`
|
|
1072
|
+
: color;
|
|
731
1073
|
}
|
|
732
|
-
|
|
1074
|
+
|
|
1075
|
+
function sanitizeFontFamily(fontFamily: string | null): string | null {
|
|
733
1076
|
const normalized = fontFamily?.trim();
|
|
734
1077
|
return normalized ? normalized : null;
|
|
735
1078
|
}
|
|
736
|
-
|
|
1079
|
+
|
|
1080
|
+
function sanitizeFontSize(size: number | null): number | null {
|
|
737
1081
|
if (typeof size !== "number" || !Number.isFinite(size) || size <= 0) {
|
|
738
1082
|
return null;
|
|
739
1083
|
}
|
|
1084
|
+
|
|
740
1085
|
return Math.round(size * 2);
|
|
741
1086
|
}
|
|
742
|
-
|
|
1087
|
+
|
|
1088
|
+
function sanitizeColor(color: string | null): string | null {
|
|
743
1089
|
const normalized = color?.trim();
|
|
744
1090
|
if (!normalized) {
|
|
745
1091
|
return null;
|
|
746
1092
|
}
|
|
1093
|
+
|
|
747
1094
|
const raw = normalized.startsWith("#") ? normalized.slice(1) : normalized;
|
|
748
1095
|
return /^[0-9A-F]{3,8}$/iu.test(raw) ? raw.toUpperCase() : null;
|
|
749
1096
|
}
|
|
750
|
-
|
|
1097
|
+
|
|
1098
|
+
function selectionTouchesRange(
|
|
1099
|
+
anchor: number,
|
|
1100
|
+
head: number,
|
|
1101
|
+
rangeFrom: number,
|
|
1102
|
+
rangeTo: number,
|
|
1103
|
+
): boolean {
|
|
751
1104
|
const selectionFrom = Math.min(anchor, head);
|
|
752
1105
|
const selectionTo = Math.max(anchor, head);
|
|
753
1106
|
if (selectionFrom === selectionTo) {
|
|
@@ -755,7 +1108,13 @@ function selectionTouchesRange(anchor, head, rangeFrom, rangeTo) {
|
|
|
755
1108
|
}
|
|
756
1109
|
return rangesOverlap(selectionFrom, selectionTo, rangeFrom, rangeTo);
|
|
757
1110
|
}
|
|
758
|
-
|
|
1111
|
+
|
|
1112
|
+
function rangesOverlap(
|
|
1113
|
+
leftFrom: number,
|
|
1114
|
+
leftTo: number,
|
|
1115
|
+
rightFrom: number,
|
|
1116
|
+
rightTo: number,
|
|
1117
|
+
): boolean {
|
|
759
1118
|
if (leftFrom === leftTo) {
|
|
760
1119
|
return leftFrom >= rightFrom && leftFrom <= rightTo;
|
|
761
1120
|
}
|
|
@@ -764,26 +1123,7 @@ function rangesOverlap(leftFrom, leftTo, rightFrom, rightTo) {
|
|
|
764
1123
|
}
|
|
765
1124
|
return leftFrom < rightTo && leftTo > rightFrom;
|
|
766
1125
|
}
|
|
767
|
-
|
|
1126
|
+
|
|
1127
|
+
function clamp(value: number, min: number, max: number): number {
|
|
768
1128
|
return Math.min(max, Math.max(min, value));
|
|
769
1129
|
}
|
|
770
|
-
|
|
771
|
-
export {
|
|
772
|
-
makeToggleBold,
|
|
773
|
-
makeToggleItalic,
|
|
774
|
-
makeToggleUnderline,
|
|
775
|
-
makeToggleStrikethrough,
|
|
776
|
-
makeToggleSuperscript,
|
|
777
|
-
makeToggleSubscript,
|
|
778
|
-
makeToggleSmallCaps,
|
|
779
|
-
makeToggleAllCaps,
|
|
780
|
-
makeSetFontFamily,
|
|
781
|
-
makeSetFontSize,
|
|
782
|
-
makeSetTextColor,
|
|
783
|
-
makeSetHighlight,
|
|
784
|
-
makeSetAlignment,
|
|
785
|
-
isMarkActive,
|
|
786
|
-
getFormattingStateFromRenderSnapshot,
|
|
787
|
-
applyFormattingOperationToDocument
|
|
788
|
-
};
|
|
789
|
-
//# sourceMappingURL=chunk-TJBP2K4T.js.map
|