@beyondwork/docx-react-component 1.0.66 → 1.0.69
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/README.md +75 -931
- package/package.json +26 -27
- package/src/api/anchor-conversion.ts +43 -0
- package/src/api/editor-state-types.ts +2 -1
- package/src/api/public-types.ts +504 -101
- package/src/api/session-state.ts +4 -0
- package/src/api/v3/README.md +91 -0
- package/src/api/v3/_create.ts +146 -0
- package/src/api/v3/_layer-metadata.ts +362 -0
- package/src/api/v3/_mocks.ts +84 -0
- package/src/api/v3/_runtime-handle.ts +162 -0
- package/src/api/v3/_ux-response.ts +73 -0
- package/src/api/v3/ai/_metadata-audit.ts +225 -0
- package/src/api/v3/ai/attach.ts +235 -0
- package/src/api/v3/ai/bundle.ts +132 -0
- package/src/api/v3/ai/explain.ts +144 -0
- package/src/api/v3/ai/export.ts +54 -0
- package/src/api/v3/ai/inspect.ts +118 -0
- package/src/api/v3/ai/policy.ts +77 -0
- package/src/api/v3/ai/replacement.ts +341 -0
- package/src/api/v3/ai/resolve.ts +133 -0
- package/src/api/v3/index.ts +79 -0
- package/src/api/v3/runtime/chart.ts +310 -0
- package/src/api/v3/runtime/clipboard.ts +81 -0
- package/src/api/v3/runtime/collab.ts +331 -0
- package/src/api/v3/runtime/content.ts +236 -0
- package/src/api/v3/runtime/document.ts +282 -0
- package/src/api/v3/runtime/formatting.ts +186 -0
- package/src/api/v3/runtime/geometry.ts +349 -0
- package/src/api/v3/runtime/layout.ts +108 -0
- package/src/api/v3/runtime/review.ts +129 -0
- package/src/api/v3/runtime/search.ts +74 -0
- package/src/api/v3/runtime/table.ts +63 -0
- package/src/api/v3/runtime/workflow.ts +434 -0
- package/src/api/v3/ui/_context.ts +86 -0
- package/src/api/v3/ui/_create.ts +65 -0
- package/src/api/v3/ui/_types.ts +520 -0
- package/src/api/v3/ui/chrome-composition.ts +342 -0
- package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
- package/src/api/v3/ui/chrome.ts +476 -0
- package/src/api/v3/ui/debug.ts +124 -0
- package/src/api/v3/ui/index.ts +64 -0
- package/src/api/v3/ui/overlays-visibility.ts +170 -0
- package/src/api/v3/ui/overlays.ts +427 -0
- package/src/api/v3/ui/scope.ts +71 -0
- package/src/api/v3/ui/session.ts +100 -0
- package/src/api/v3/ui/surface.ts +170 -0
- package/src/api/v3/ui/viewport.ts +303 -0
- package/src/core/commands/index.ts +28 -6
- package/src/core/commands/list-commands.ts +3 -2
- package/src/core/commands/section-layout-commands.ts +9 -8
- package/src/core/schema/text-schema.ts +16 -0
- package/src/core/selection/mapping.ts +33 -72
- package/src/core/state/editor-state.ts +96 -189
- package/src/index.ts +23 -4
- package/src/io/chart-preview-resolver.ts +1 -1
- package/src/io/docx-session.ts +36 -4795
- package/src/io/export/build-app-properties-xml.ts +1 -1
- package/src/io/export/serialize-comments.ts +1 -1
- package/src/io/export/serialize-headers-footers.ts +6 -1
- package/src/io/export/serialize-main-document.ts +45 -0
- package/src/io/export/serialize-run-formatting.ts +17 -2
- package/src/io/export/twip.ts +1 -1
- package/src/io/normalize/normalize-text.ts +27 -20
- package/src/io/ooxml/chart/parse-series.ts +1 -1
- package/src/io/ooxml/chart/resolve-color.ts +2 -2
- package/src/io/ooxml/chart/types.ts +1 -1
- package/src/io/ooxml/classify-embedding.ts +83 -33
- package/src/io/ooxml/parse-fill.ts +1 -1
- package/src/io/ooxml/parse-main-document.ts +71 -1
- package/src/io/ooxml/parse-object.ts +14 -10
- package/src/io/ooxml/parse-run-formatting.ts +47 -1
- package/src/io/ooxml/property-grab-bag.ts +2 -2
- package/src/io/ooxml/units.ts +11 -0
- package/src/io/ooxml/workflow-payload.ts +282 -7
- package/src/model/anchor.ts +85 -0
- package/src/model/canonical-document.ts +351 -15
- package/src/model/chart-types.ts +1 -1
- package/src/model/layout/index.ts +83 -0
- package/src/model/layout/page-graph-types.ts +181 -0
- package/src/model/layout/page-layout-snapshot.ts +105 -0
- package/src/model/layout/resolved-layout-types.ts +47 -0
- package/src/model/layout/runtime-page-graph-types.ts +102 -0
- package/src/model/paragraph-scope-ids.ts +72 -0
- package/src/model/review/comment-types.ts +112 -0
- package/src/model/review/index.ts +2 -0
- package/src/model/review/revision-types.ts +215 -0
- package/src/model/snapshot.ts +32 -0
- package/src/review/store/comment-store.ts +21 -47
- package/src/review/store/revision-types.ts +40 -198
- package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
- package/src/runtime/collab/runtime-collab-sync.ts +13 -3
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
- package/src/runtime/debug/event-ring-buffer.ts +64 -0
- package/src/runtime/debug/probability-sampler.ts +18 -0
- package/src/runtime/debug/runtime-debug-facet.ts +67 -0
- package/src/runtime/debug/stage-tokens.ts +31 -0
- package/src/runtime/debug/telemetry-bus.ts +271 -0
- package/src/runtime/debug/types.ts +275 -0
- package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
- package/src/runtime/document-layout.ts +8 -6
- package/src/runtime/document-runtime.ts +843 -1141
- package/src/runtime/document-search.ts +1 -1
- package/src/runtime/edit-ops/index.ts +1 -1
- package/src/runtime/external-send-runtime.ts +1 -1
- package/src/runtime/formatting/document-lookup.ts +235 -0
- package/src/runtime/formatting/field/registry.ts +41 -0
- package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
- package/src/runtime/formatting/font-resolution.ts +83 -0
- package/src/runtime/formatting/formatting-context.ts +903 -0
- package/src/runtime/formatting/formatting-types.ts +157 -0
- package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
- package/src/runtime/formatting/index.ts +125 -0
- package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
- package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
- package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
- package/src/runtime/formatting/projector.ts +75 -0
- package/src/runtime/formatting/resolve-effective.ts +407 -0
- package/src/runtime/formatting/revision-display.ts +105 -0
- package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
- package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
- package/src/runtime/formatting/telemetry-bridge.ts +106 -0
- package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
- package/src/runtime/geometry/caret-geometry.ts +164 -0
- package/src/runtime/geometry/geometry-facet.ts +364 -0
- package/src/runtime/geometry/geometry-types.ts +256 -0
- package/src/runtime/geometry/hit-test.ts +125 -0
- package/src/runtime/geometry/index.ts +71 -0
- package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
- package/src/runtime/geometry/invalidation.ts +35 -0
- package/src/runtime/geometry/object-handles.ts +77 -0
- package/src/runtime/geometry/overlay-rects.ts +85 -0
- package/src/runtime/geometry/project-anchors.ts +100 -0
- package/src/runtime/geometry/project-fragments.ts +216 -0
- package/src/runtime/geometry/projector.ts +129 -0
- package/src/runtime/geometry/replacement-envelope.ts +130 -0
- package/src/runtime/geometry/viewport.ts +218 -0
- package/src/runtime/layout/compat-input-ledger.ts +211 -0
- package/src/runtime/layout/index.ts +6 -1
- package/src/runtime/layout/inert-layout-facet.ts +12 -7
- package/src/runtime/layout/layout-engine-instance.ts +189 -11
- package/src/runtime/layout/layout-engine-version.ts +450 -1
- package/src/runtime/layout/layout-facet-types.ts +60 -0
- package/src/runtime/layout/layout-measurement-provider.ts +13 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
- package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
- package/src/runtime/layout/page-graph.ts +62 -209
- package/src/runtime/layout/page-story-resolver.ts +7 -12
- package/src/runtime/layout/paginated-layout-engine.ts +186 -11
- package/src/runtime/layout/project-block-fragments.ts +11 -0
- package/src/runtime/layout/projector.ts +90 -0
- package/src/runtime/layout/public-facet.ts +187 -442
- package/src/runtime/layout/resolved-formatting-state.ts +158 -26
- package/src/runtime/layout/table-render-plan.ts +1 -1
- package/src/runtime/prerender/cache-envelope.ts +6 -1
- package/src/runtime/prerender/prerender-document.ts +18 -23
- package/src/runtime/render/decoration-resolver.ts +1 -1
- package/src/runtime/render/render-frame-types.ts +20 -0
- package/src/runtime/render/render-kernel.ts +94 -25
- package/src/runtime/scopes/_formatting-seam.ts +262 -0
- package/src/runtime/scopes/_scope-dependencies.ts +49 -0
- package/src/runtime/scopes/action-validation.ts +356 -0
- package/src/runtime/scopes/attach-explanation.ts +102 -0
- package/src/runtime/scopes/audit-bundle.ts +71 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
- package/src/runtime/scopes/compile-scope.ts +262 -0
- package/src/runtime/scopes/compiler-service.ts +431 -0
- package/src/runtime/scopes/create-issue.ts +107 -0
- package/src/runtime/scopes/enumerate-scopes.ts +543 -0
- package/src/runtime/scopes/evidence.ts +233 -0
- package/src/runtime/scopes/index.ts +150 -0
- package/src/runtime/scopes/position-map.ts +214 -0
- package/src/runtime/scopes/preservation-boundary.ts +91 -0
- package/src/runtime/scopes/projector.ts +49 -0
- package/src/runtime/scopes/replaceability.ts +87 -0
- package/src/runtime/scopes/replacement/apply.ts +228 -0
- package/src/runtime/scopes/replacement/compile.ts +59 -0
- package/src/runtime/scopes/replacement/propose.ts +42 -0
- package/src/runtime/scopes/resolve-reference.ts +347 -0
- package/src/runtime/scopes/review-bundle.ts +141 -0
- package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
- package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
- package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
- package/src/runtime/scopes/scope-kinds/field.ts +65 -0
- package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
- package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
- package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
- package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
- package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
- package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
- package/src/runtime/scopes/scope-kinds/table.ts +55 -0
- package/src/runtime/scopes/scope-range.ts +208 -0
- package/src/runtime/scopes/semantic-scope-types.ts +454 -0
- package/src/runtime/scopes/workflow-overlap.ts +92 -0
- package/src/runtime/selection/index.ts +1 -1
- package/src/runtime/structure-ops/fragment-insert.ts +1 -1
- package/src/runtime/structure-ops/index.ts +1 -1
- package/src/runtime/surface-projection.ts +232 -262
- package/src/runtime/units.ts +4 -2
- package/src/runtime/workflow/coordinator.ts +1348 -0
- package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
- package/src/runtime/workflow/index.ts +25 -0
- package/src/runtime/workflow/markup-mode-policy.ts +98 -0
- package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
- package/src/runtime/workflow/metadata-persistence.ts +306 -0
- package/src/runtime/workflow/metadata-writer.ts +123 -0
- package/src/runtime/workflow/overlay-store.ts +690 -0
- package/src/runtime/workflow/projector.ts +127 -0
- package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
- package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
- package/src/runtime/workflow/rail/types.ts +198 -0
- package/src/runtime/workflow/scope-rail-composer.ts +39 -0
- package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
- package/src/runtime/workflow/scope-writer.ts +188 -0
- package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
- package/src/runtime/workflow/visibility-policy.ts +129 -0
- package/src/session/_sync-legacy.ts +66 -0
- package/src/session/export/embedded-reconstitute.ts +104 -0
- package/src/session/export/export-diagnostics.ts +85 -0
- package/src/session/export/export-validation.ts +110 -0
- package/src/session/export/index.ts +34 -0
- package/src/session/export/preservation-reattach.ts +30 -0
- package/src/session/export/serialize-dispatch.ts +165 -0
- package/src/session/export/stateful-export-pipeline.ts +432 -0
- package/src/session/export/stateful-export.ts +684 -0
- package/src/session/import/canonical-assembly.ts +227 -0
- package/src/session/import/diagnostics-session.ts +54 -0
- package/src/session/import/embedded-discovery.ts +225 -0
- package/src/session/import/embedded-offload.ts +337 -0
- package/src/session/import/import-diagnostics.ts +69 -0
- package/src/session/import/loader-types.ts +313 -0
- package/src/session/import/loader.ts +1834 -0
- package/src/session/import/normalize.ts +195 -0
- package/src/session/import/package-parts.ts +217 -0
- package/src/session/import/package-read.ts +195 -0
- package/src/session/import/parse-orchestration.ts +105 -0
- package/src/session/import/part-constants.ts +70 -0
- package/src/session/import/part-discovery.ts +94 -0
- package/src/session/import/preservation-index.ts +46 -0
- package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
- package/src/session/import/review-import.ts +508 -0
- package/src/session/import/styles-consolidation.ts +281 -0
- package/src/session/import/workflow-scope-import.ts +256 -0
- package/src/session/index.ts +37 -0
- package/src/session/session-state.ts +69 -0
- package/src/session/session.ts +532 -0
- package/src/session/shared/protection.ts +228 -0
- package/src/session/shared/session-utils.ts +82 -0
- package/src/session/types.ts +499 -0
- package/src/shell/chart-snapshots.ts +96 -0
- package/src/shell/media-previews.ts +85 -0
- package/src/shell/overlay-anchor-bridge.ts +53 -0
- package/src/shell/paste-adapter.ts +23 -0
- package/src/shell/ref-commands.ts +1697 -0
- package/src/shell/ref-utilities.ts +48 -0
- package/src/shell/search.ts +51 -0
- package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
- package/src/shell/ui-subscriber-channels.ts +81 -0
- package/src/shell/use-collab-sync.ts +116 -0
- package/src/ui/WordReviewEditor.tsx +496 -2051
- package/src/ui/editor-shell-view.tsx +30 -1
- package/src/ui/editor-surface-controller.tsx +49 -1
- package/src/ui/headless/revision-decoration-model.ts +83 -0
- package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
- package/src/ui/headless/scoped-chrome-policy.ts +2 -2
- package/src/ui/headless/selection-tool-context.ts +1 -1
- package/src/ui/headless/selection-tool-resolver.ts +1 -1
- package/src/ui/runtime-shortcut-dispatch.ts +46 -1
- package/src/ui/ui-controller-factory.ts +221 -0
- package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
- package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
- package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
- package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
- package/src/ui-tailwind/chart/render/area.tsx +3 -3
- package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
- package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
- package/src/ui-tailwind/chart/render/combo.tsx +2 -2
- package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
- package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
- package/src/ui-tailwind/chart/render/line.tsx +3 -3
- package/src/ui-tailwind/chart/render/pie.tsx +6 -6
- package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
- package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
- package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
- package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
- package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
- package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
- package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
- package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
- package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
- package/src/ui-tailwind/debug/README.md +57 -0
- package/src/ui-tailwind/debug/index.ts +3 -0
- package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
- package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
- package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
- package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
- package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
- package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
- package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
- package/src/ui-tailwind/index.ts +0 -5
- package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
- package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
- package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
- package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
- package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
- package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
- package/src/ui-tailwind/review-workspace/types.ts +408 -0
- package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
- package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
- package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
- package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
- package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
- package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
- package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
- package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
- package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
- package/src/ui-tailwind/theme/editor-theme.css +25 -0
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
- package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
- package/src/ui-tailwind/ui-api-context.tsx +43 -0
- package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
- package/src/validation/compatibility-engine.ts +6 -6
- package/src/runtime/styles-cascade.ts +0 -33
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
- /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
- /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
- /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-side import helpers extracted from `src/io/docx-session.ts`
|
|
3
|
+
* (slice 5e-6d). These functions translate parsed OOXML revisions +
|
|
4
|
+
* comments into the canonical review shapes and back into the runtime-
|
|
5
|
+
* facing record map — they are part of the package/session integration
|
|
6
|
+
* surface, not review-layer state management.
|
|
7
|
+
*
|
|
8
|
+
* The module is P6-clean: every cross-layer type reaches through
|
|
9
|
+
* `src/model/**`, never through `src/review/**` or `src/core/**`.
|
|
10
|
+
* Anchor mechanics used here (`createDetachedAnchor`) come from
|
|
11
|
+
* `src/model/anchor.ts`; revision / comment shapes + the pure
|
|
12
|
+
* `getRevisionActionability` predicate come from `src/model/review/`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createDetachedAnchor } from "../../model/anchor.ts";
|
|
16
|
+
import type {
|
|
17
|
+
CanonicalDocument,
|
|
18
|
+
CommentThread as CommentThreadRecord,
|
|
19
|
+
OpaqueFragmentRecord,
|
|
20
|
+
RevisionRecord as RuntimeRevisionRecord,
|
|
21
|
+
} from "../../model/canonical-document.ts";
|
|
22
|
+
import type { CommentThread } from "../../model/review/comment-types.ts";
|
|
23
|
+
import {
|
|
24
|
+
getRevisionActionability,
|
|
25
|
+
type RevisionRecord as ReviewRevisionRecord,
|
|
26
|
+
} from "../../model/review/revision-types.ts";
|
|
27
|
+
import type {
|
|
28
|
+
CommentImportDiagnostic,
|
|
29
|
+
ImportedCommentDefinition,
|
|
30
|
+
ParsedCommentsResult,
|
|
31
|
+
} from "../../io/ooxml/parse-comments.ts";
|
|
32
|
+
import type { ParsedRevisionsResult } from "../../io/ooxml/parse-revisions.ts";
|
|
33
|
+
import { serializeRuntimeRevisionsIntoStoryXml } from "../../io/export/serialize-runtime-revisions.ts";
|
|
34
|
+
|
|
35
|
+
type CanonicalDocumentEnvelope = CanonicalDocument;
|
|
36
|
+
|
|
37
|
+
export interface NormalizedImportedCommentsResult extends ParsedCommentsResult {
|
|
38
|
+
preservedDefinitions: readonly ImportedCommentDefinition[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function normalizeImportedRevisionRecords(
|
|
42
|
+
parsed: ParsedRevisionsResult,
|
|
43
|
+
content: CanonicalDocumentEnvelope["content"],
|
|
44
|
+
opaqueFragments: Record<string, OpaqueFragmentRecord>,
|
|
45
|
+
): ParsedRevisionsResult {
|
|
46
|
+
const opaqueRanges = Object.values(opaqueFragments).map((fragment) => fragment.lastKnownRange);
|
|
47
|
+
const paragraphRanges = collectCanonicalParagraphRanges(content);
|
|
48
|
+
if (opaqueRanges.length === 0) {
|
|
49
|
+
return {
|
|
50
|
+
...parsed,
|
|
51
|
+
revisions: parsed.revisions.map((revision) => {
|
|
52
|
+
if (revision.anchor.kind !== "range" || revision.metadata.preserveOnlyReason) {
|
|
53
|
+
return revision;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const preserveOnlyReason = getStructuralPreserveOnlyReason(
|
|
57
|
+
revision,
|
|
58
|
+
paragraphRanges,
|
|
59
|
+
);
|
|
60
|
+
if (!preserveOnlyReason) {
|
|
61
|
+
return revision;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...revision,
|
|
66
|
+
metadata: {
|
|
67
|
+
...revision.metadata,
|
|
68
|
+
preserveOnlyReason,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
...parsed,
|
|
77
|
+
revisions: parsed.revisions.map((revision) => {
|
|
78
|
+
const { anchor } = revision;
|
|
79
|
+
if (anchor.kind !== "range" || revision.metadata.preserveOnlyReason) {
|
|
80
|
+
return revision;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const preserveOnlyReason =
|
|
84
|
+
getStructuralPreserveOnlyReason(revision, paragraphRanges) ??
|
|
85
|
+
(opaqueRanges.some((range) => rangesIntersect(range, anchor.range))
|
|
86
|
+
? "Imported revision overlaps preserve-only OOXML and remains preserve-only."
|
|
87
|
+
: undefined);
|
|
88
|
+
|
|
89
|
+
if (!preserveOnlyReason) {
|
|
90
|
+
return revision;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
...revision,
|
|
95
|
+
metadata: {
|
|
96
|
+
...revision.metadata,
|
|
97
|
+
preserveOnlyReason,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function normalizeImportedCommentThreads(
|
|
105
|
+
parsed: ParsedCommentsResult,
|
|
106
|
+
opaqueFragments: Record<string, OpaqueFragmentRecord>,
|
|
107
|
+
revisions: readonly ReviewRevisionRecord[],
|
|
108
|
+
): NormalizedImportedCommentsResult {
|
|
109
|
+
const opaqueRanges = Object.values(opaqueFragments).map((fragment) => fragment.lastKnownRange);
|
|
110
|
+
// Use getRevisionActionability() — not the raw preserveOnlyReason flag — so
|
|
111
|
+
// Lane 7b-promoted shapes (cellIns/cellDel/cellMerge, linked-pair moves) that
|
|
112
|
+
// still carry a default preserveOnlyReason aren't treated as preserve-only
|
|
113
|
+
// for comment-anchor detachment. See revision-types.ts:192-200.
|
|
114
|
+
const preserveOnlyRevisionRanges = revisions.flatMap((revision) => {
|
|
115
|
+
if (
|
|
116
|
+
revision.anchor.kind !== "range" ||
|
|
117
|
+
getRevisionActionability(revision) !== "preserve-only"
|
|
118
|
+
) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
return [revision.anchor.range];
|
|
122
|
+
});
|
|
123
|
+
const preserveOnlyCommentIds = new Set(parsed.diagnostics.map((diagnostic) => diagnostic.commentId));
|
|
124
|
+
const additionalDiagnostics: CommentImportDiagnostic[] = [];
|
|
125
|
+
const normalizedThreads: CommentThread[] = parsed.threads.map((thread) => {
|
|
126
|
+
const { anchor } = thread;
|
|
127
|
+
if (anchor.kind !== "range") {
|
|
128
|
+
preserveOnlyCommentIds.add(thread.commentId);
|
|
129
|
+
return thread;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const opaqueOverlap = opaqueRanges.some((range) => rangesIntersect(range, anchor.range));
|
|
133
|
+
if (opaqueOverlap) {
|
|
134
|
+
preserveOnlyCommentIds.add(thread.commentId);
|
|
135
|
+
additionalDiagnostics.push({
|
|
136
|
+
commentId: thread.commentId,
|
|
137
|
+
code: "opaque_anchor_preserve_only",
|
|
138
|
+
message:
|
|
139
|
+
"Comment anchor intersects preserve-only OOXML content. Thread is visible but detached; anchor cannot be safely remapped.",
|
|
140
|
+
featureClass: "preserve-only",
|
|
141
|
+
detachedReason: "opaque-region" as const,
|
|
142
|
+
actionabilityNote: "The comment body is preserved. The anchor overlaps opaque content that the editor cannot safely modify.",
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
...thread,
|
|
146
|
+
anchor: createDetachedAnchor(anchor.range, "importAmbiguity"),
|
|
147
|
+
status: "detached",
|
|
148
|
+
metadata: {
|
|
149
|
+
...thread.metadata,
|
|
150
|
+
detachedReason: "opaque-region",
|
|
151
|
+
actionabilityNote:
|
|
152
|
+
"The comment body is preserved. The anchor overlaps opaque content that the editor cannot safely modify.",
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const preserveOnlyRevisionOverlap = preserveOnlyRevisionRanges.some((range) =>
|
|
158
|
+
rangesIntersect(range, anchor.range),
|
|
159
|
+
);
|
|
160
|
+
if (preserveOnlyRevisionOverlap) {
|
|
161
|
+
preserveOnlyCommentIds.add(thread.commentId);
|
|
162
|
+
additionalDiagnostics.push({
|
|
163
|
+
commentId: thread.commentId,
|
|
164
|
+
code: "preserve_only_revision_overlap",
|
|
165
|
+
message:
|
|
166
|
+
"Comment anchor overlaps preserve-only review markup. Thread is visible but detached; anchor cannot be safely remapped during editing.",
|
|
167
|
+
featureClass: "preserve-only",
|
|
168
|
+
detachedReason: "revision-overlap" as const,
|
|
169
|
+
actionabilityNote: "The comment body is preserved. The anchor overlaps preserve-only revision markup that the editor cannot safely modify.",
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
...thread,
|
|
173
|
+
anchor: createDetachedAnchor(anchor.range, "importAmbiguity"),
|
|
174
|
+
status: "detached",
|
|
175
|
+
metadata: {
|
|
176
|
+
...thread.metadata,
|
|
177
|
+
detachedReason: "revision-overlap",
|
|
178
|
+
actionabilityNote:
|
|
179
|
+
"The comment body is preserved. The anchor overlaps preserve-only revision markup that the editor cannot safely modify.",
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return thread;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
...parsed,
|
|
189
|
+
threads: normalizedThreads,
|
|
190
|
+
diagnostics: [...parsed.diagnostics, ...additionalDiagnostics],
|
|
191
|
+
definitions: parsed.definitions,
|
|
192
|
+
preservedDefinitions: parsed.definitions.filter((definition) =>
|
|
193
|
+
preserveOnlyCommentIds.has(
|
|
194
|
+
resolveDefinitionRootCommentId(definition, parsed.definitions),
|
|
195
|
+
),
|
|
196
|
+
),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function resolveImportedCommentThreadOnTranslation(
|
|
201
|
+
thread: CommentThread,
|
|
202
|
+
timestamp: string,
|
|
203
|
+
): CommentThread {
|
|
204
|
+
if (thread.status === "resolved") {
|
|
205
|
+
return thread;
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
...thread,
|
|
209
|
+
status: thread.status === "detached" ? "detached" : "resolved",
|
|
210
|
+
resolution: thread.resolution ?? {
|
|
211
|
+
resolvedAt: timestamp,
|
|
212
|
+
resolvedBy: thread.entries[thread.entries.length - 1]?.authorId ?? thread.createdBy,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function resolveDefinitionRootCommentId(
|
|
218
|
+
definition: ImportedCommentDefinition,
|
|
219
|
+
definitions: readonly ImportedCommentDefinition[],
|
|
220
|
+
): string {
|
|
221
|
+
if (!definition.parentParaId) {
|
|
222
|
+
return definition.commentId;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const definitionsByParaId = new Map(
|
|
226
|
+
definitions
|
|
227
|
+
.filter((candidate) => typeof candidate.paraId === "string")
|
|
228
|
+
.map((candidate) => [candidate.paraId!, candidate]),
|
|
229
|
+
);
|
|
230
|
+
const visited = new Set<string>();
|
|
231
|
+
let current: ImportedCommentDefinition | undefined = definition;
|
|
232
|
+
|
|
233
|
+
while (current?.parentParaId) {
|
|
234
|
+
if (visited.has(current.parentParaId)) {
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
visited.add(current.parentParaId);
|
|
238
|
+
const parent = definitionsByParaId.get(current.parentParaId);
|
|
239
|
+
if (!parent) {
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
current = parent;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return current?.commentId ?? definition.commentId;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function getStructuralPreserveOnlyReason(
|
|
249
|
+
revision: ReviewRevisionRecord,
|
|
250
|
+
paragraphRanges: ReadonlyArray<{ start: number; end: number }>,
|
|
251
|
+
): string | undefined {
|
|
252
|
+
const form = revision.metadata.importedRevisionForm;
|
|
253
|
+
const { anchor } = revision;
|
|
254
|
+
if (!form || anchor.kind !== "range") {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (
|
|
259
|
+
(form === "run-insertion" || form === "run-deletion") &&
|
|
260
|
+
anchor.range.from === anchor.range.to
|
|
261
|
+
) {
|
|
262
|
+
return "Imported zero-width run revision remains preserve-only.";
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (form === "paragraph-insertion" || form === "paragraph-deletion") {
|
|
266
|
+
const paragraphBoundary = paragraphRanges.find(
|
|
267
|
+
(boundary) =>
|
|
268
|
+
boundary.end === anchor.range.from ||
|
|
269
|
+
(anchor.range.from >= boundary.start &&
|
|
270
|
+
anchor.range.from <= boundary.end),
|
|
271
|
+
);
|
|
272
|
+
return paragraphBoundary
|
|
273
|
+
? undefined
|
|
274
|
+
: "Imported revision spans paragraph-level structure and remains preserve-only.";
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const paragraphBoundary = paragraphRanges.find(
|
|
278
|
+
(boundary) =>
|
|
279
|
+
anchor.range.from >= boundary.start &&
|
|
280
|
+
anchor.range.to <= boundary.end,
|
|
281
|
+
);
|
|
282
|
+
return paragraphBoundary
|
|
283
|
+
? undefined
|
|
284
|
+
: "Imported revision spans structural boundaries and remains preserve-only.";
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function collectCanonicalParagraphRanges(
|
|
288
|
+
content: CanonicalDocumentEnvelope["content"],
|
|
289
|
+
): Array<{ start: number; end: number }> {
|
|
290
|
+
const ranges: Array<{ start: number; end: number }> = [];
|
|
291
|
+
let cursor = 0;
|
|
292
|
+
let previousWasParagraph = false;
|
|
293
|
+
|
|
294
|
+
for (const block of content.children) {
|
|
295
|
+
if (block.type === "paragraph") {
|
|
296
|
+
if (previousWasParagraph) {
|
|
297
|
+
cursor += 1;
|
|
298
|
+
}
|
|
299
|
+
const start = cursor;
|
|
300
|
+
cursor += measureCanonicalParagraph(block);
|
|
301
|
+
ranges.push({ start, end: cursor });
|
|
302
|
+
previousWasParagraph = true;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
cursor += 1;
|
|
307
|
+
previousWasParagraph = false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return ranges;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function measureCanonicalParagraph(
|
|
314
|
+
paragraph: CanonicalDocumentEnvelope["content"]["children"][number] & { type: "paragraph" },
|
|
315
|
+
): number {
|
|
316
|
+
return paragraph.children.reduce<number>((size, child) => {
|
|
317
|
+
if (child.type === "text") {
|
|
318
|
+
return size + Array.from(child.text).length;
|
|
319
|
+
}
|
|
320
|
+
if (child.type === "hyperlink") {
|
|
321
|
+
return (
|
|
322
|
+
size +
|
|
323
|
+
child.children.reduce<number>((childSize, entry) => {
|
|
324
|
+
if (entry.type === "text") {
|
|
325
|
+
return childSize + Array.from(entry.text).length;
|
|
326
|
+
}
|
|
327
|
+
return childSize + 1;
|
|
328
|
+
}, 0)
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
return size + 1;
|
|
332
|
+
}, 0);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function rangesIntersect(
|
|
336
|
+
left: { from: number; to: number },
|
|
337
|
+
right: { from: number; to: number },
|
|
338
|
+
): boolean {
|
|
339
|
+
return left.from < right.to && right.from < left.to;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export function toRuntimeCommentRecords(
|
|
343
|
+
threads: readonly CommentThread[],
|
|
344
|
+
): Record<string, CommentThreadRecord> {
|
|
345
|
+
return Object.fromEntries(
|
|
346
|
+
threads.map((thread) => {
|
|
347
|
+
return [
|
|
348
|
+
thread.commentId,
|
|
349
|
+
{
|
|
350
|
+
commentId: thread.commentId,
|
|
351
|
+
body: thread.entries.map((entry) => entry.body).join("\n"),
|
|
352
|
+
anchor: thread.anchor,
|
|
353
|
+
createdBy: thread.createdBy,
|
|
354
|
+
authorId: thread.createdBy,
|
|
355
|
+
createdAt: thread.createdAt,
|
|
356
|
+
entries: thread.entries.map((entry) => ({
|
|
357
|
+
entryId: entry.entryId,
|
|
358
|
+
authorId: entry.authorId,
|
|
359
|
+
body: entry.body,
|
|
360
|
+
createdAt: entry.createdAt,
|
|
361
|
+
metadata: entry.metadata
|
|
362
|
+
? {
|
|
363
|
+
ooxmlCommentId: entry.metadata.ooxmlCommentId,
|
|
364
|
+
paraId: entry.metadata.paraId,
|
|
365
|
+
parentParaId: entry.metadata.parentParaId,
|
|
366
|
+
durableId: entry.metadata.durableId,
|
|
367
|
+
initials: entry.metadata.initials,
|
|
368
|
+
}
|
|
369
|
+
: undefined,
|
|
370
|
+
})),
|
|
371
|
+
status: thread.status,
|
|
372
|
+
resolution: thread.resolution
|
|
373
|
+
? {
|
|
374
|
+
resolvedAt: thread.resolution.resolvedAt,
|
|
375
|
+
resolvedBy: thread.resolution.resolvedBy,
|
|
376
|
+
}
|
|
377
|
+
: undefined,
|
|
378
|
+
resolvedAt: thread.resolution?.resolvedAt,
|
|
379
|
+
warningIds: [...thread.warningIds],
|
|
380
|
+
isResolved: thread.status === "resolved",
|
|
381
|
+
metadata: thread.metadata
|
|
382
|
+
? {
|
|
383
|
+
source: thread.metadata.source,
|
|
384
|
+
rootOoxmlCommentId: thread.metadata.rootOoxmlCommentId,
|
|
385
|
+
rootParaId: thread.metadata.rootParaId,
|
|
386
|
+
}
|
|
387
|
+
: undefined,
|
|
388
|
+
} satisfies CommentThreadRecord,
|
|
389
|
+
];
|
|
390
|
+
}),
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export function toRuntimeRevisionRecords(
|
|
395
|
+
revisions: readonly ReviewRevisionRecord[],
|
|
396
|
+
): Record<string, RuntimeRevisionRecord> {
|
|
397
|
+
return Object.fromEntries(
|
|
398
|
+
revisions.map((revision) => [
|
|
399
|
+
revision.revisionId,
|
|
400
|
+
{
|
|
401
|
+
changeId: revision.revisionId,
|
|
402
|
+
kind: revision.kind,
|
|
403
|
+
anchor: revision.anchor,
|
|
404
|
+
authorId: revision.authorId,
|
|
405
|
+
createdAt: revision.createdAt,
|
|
406
|
+
warningIds: [...revision.warningIds],
|
|
407
|
+
metadata: {
|
|
408
|
+
source: revision.metadata.source,
|
|
409
|
+
storyTarget: revision.metadata.storyTarget,
|
|
410
|
+
preserveOnlyReason: revision.metadata.preserveOnlyReason,
|
|
411
|
+
suggestionId: revision.metadata.suggestionId,
|
|
412
|
+
semanticKind: revision.metadata.semanticKind,
|
|
413
|
+
linkedRevisionIds: revision.metadata.linkedRevisionIds,
|
|
414
|
+
predecessorSuggestionId: revision.metadata.predecessorSuggestionId,
|
|
415
|
+
importedRevisionForm: revision.metadata.importedRevisionForm,
|
|
416
|
+
originalRevisionType: revision.metadata.originalRevisionType,
|
|
417
|
+
ooxmlRevisionId: revision.metadata.ooxmlRevisionId,
|
|
418
|
+
propertyChangeData: revision.metadata.propertyChangeData,
|
|
419
|
+
moveData: revision.metadata.moveData,
|
|
420
|
+
},
|
|
421
|
+
status: revision.status === "active" ? "open" : revision.status,
|
|
422
|
+
} satisfies RuntimeRevisionRecord,
|
|
423
|
+
]),
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export function toReviewRevisionRecords(
|
|
428
|
+
revisions: CanonicalDocumentEnvelope["review"]["revisions"],
|
|
429
|
+
): ReviewRevisionRecord[] {
|
|
430
|
+
return Object.values(revisions).map((revision) => ({
|
|
431
|
+
revisionId: revision.changeId,
|
|
432
|
+
kind: revision.kind,
|
|
433
|
+
anchor: revision.anchor,
|
|
434
|
+
authorId: revision.authorId ?? "unknown",
|
|
435
|
+
createdAt: revision.createdAt,
|
|
436
|
+
warningIds: [...(revision.warningIds ?? [])],
|
|
437
|
+
metadata: {
|
|
438
|
+
source: revision.metadata?.source ?? "runtime",
|
|
439
|
+
storyTarget: revision.metadata?.storyTarget,
|
|
440
|
+
preserveOnlyReason: revision.metadata?.preserveOnlyReason,
|
|
441
|
+
suggestionId: revision.metadata?.suggestionId,
|
|
442
|
+
semanticKind: revision.metadata?.semanticKind,
|
|
443
|
+
linkedRevisionIds: revision.metadata?.linkedRevisionIds,
|
|
444
|
+
predecessorSuggestionId: revision.metadata?.predecessorSuggestionId,
|
|
445
|
+
importedRevisionForm: revision.metadata?.importedRevisionForm,
|
|
446
|
+
originalRevisionType: revision.metadata?.originalRevisionType,
|
|
447
|
+
ooxmlRevisionId: revision.metadata?.ooxmlRevisionId,
|
|
448
|
+
propertyChangeData: revision.metadata?.propertyChangeData,
|
|
449
|
+
moveData: revision.metadata?.moveData,
|
|
450
|
+
},
|
|
451
|
+
status: revision.status === "open" ? "active" : revision.status,
|
|
452
|
+
}));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export function serializeSecondaryStoryWithRuntimeRevisions(
|
|
456
|
+
xml: string,
|
|
457
|
+
revisions: readonly ReviewRevisionRecord[],
|
|
458
|
+
label: string,
|
|
459
|
+
): string {
|
|
460
|
+
if (revisions.length === 0) {
|
|
461
|
+
return xml;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const serialized = serializeRuntimeRevisionsIntoStoryXml(xml, revisions);
|
|
465
|
+
if (serialized.skippedRevisionIds.length > 0) {
|
|
466
|
+
throw new Error(
|
|
467
|
+
`DOCX export is blocked because ${serialized.skippedRevisionIds.length} active revisions overlap unsupported serialization boundaries in ${label}.`,
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
return serialized.documentXml;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export function stripCommentMarkup(
|
|
474
|
+
documentXml: string,
|
|
475
|
+
ownedCommentIds: readonly string[],
|
|
476
|
+
): string {
|
|
477
|
+
if (ownedCommentIds.length === 0) {
|
|
478
|
+
return documentXml;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
let output = documentXml;
|
|
482
|
+
for (const commentId of ownedCommentIds) {
|
|
483
|
+
const escapedCommentId = escapeRegExp(commentId);
|
|
484
|
+
const attributePattern = `(?:w:id|id)=["']${escapedCommentId}["']`;
|
|
485
|
+
output = output
|
|
486
|
+
.replace(
|
|
487
|
+
new RegExp(`<w:commentRangeStart\\b[^>]*${attributePattern}[^>]*/>`, "gu"),
|
|
488
|
+
"",
|
|
489
|
+
)
|
|
490
|
+
.replace(
|
|
491
|
+
new RegExp(`<w:commentRangeEnd\\b[^>]*${attributePattern}[^>]*/>`, "gu"),
|
|
492
|
+
"",
|
|
493
|
+
)
|
|
494
|
+
.replace(
|
|
495
|
+
new RegExp(
|
|
496
|
+
`<w:r\\b[^>]*>(?:(?!<w:t\\b|</w:r>)[\\s\\S])*?<w:commentReference\\b[^>]*${attributePattern}[^>]*/>(?:(?!<w:t\\b|</w:r>)[\\s\\S])*?</w:r>`,
|
|
497
|
+
"gu",
|
|
498
|
+
),
|
|
499
|
+
"",
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return output;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function escapeRegExp(value: string): string {
|
|
507
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
508
|
+
}
|