@beyondwork/docx-react-component 1.0.67 → 1.0.70
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 -932
- 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 -4797
- 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,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 6 — `ai.attachExplanation` live-with-adapter primitive.
|
|
3
|
+
*
|
|
4
|
+
* Attaches an agent-authored explanation to a semantic scope by routing
|
|
5
|
+
* through Layer-06's `attachScopeMetadata` writer — the same pipeline
|
|
6
|
+
* `runtime.workflow.attachMetadata` graduated against. The explanation
|
|
7
|
+
* persists as a `WorkflowMetadataEntry` with a stable `metadataId`
|
|
8
|
+
* prefix (`ai.explanation`) and the caller-supplied text +
|
|
9
|
+
* explanationId in `value`.
|
|
10
|
+
*
|
|
11
|
+
* Determinism (S3): given identical (scopeId, explanationText,
|
|
12
|
+
* explanationId) inputs, the emitted entry is identical. The
|
|
13
|
+
* explanationId + createdAtUtc are caller-supplied so consumers that
|
|
14
|
+
* want deterministic output (tests, replay) can pin them.
|
|
15
|
+
*
|
|
16
|
+
* Scope coverage (coord-06 §13c shipped 2026-04-23): both overlay
|
|
17
|
+
* (workflow) scopes AND derived paragraph / heading / list-item
|
|
18
|
+
* scopes are valid targets. Derived scopeIds (e.g. `para:<paraId>`,
|
|
19
|
+
* `heading:<paraId>`, `li:<paraId>`) resolve against the canonical
|
|
20
|
+
* document via `resolveDerivedScopeAnchorFromCanonical`; the stored
|
|
21
|
+
* entry's anchor is the resolver's range output, and the result
|
|
22
|
+
* carries `resolvedFrom: "derived"`. Non-paragraph-like scopeIds
|
|
23
|
+
* (fields, comment threads, revisions, table-kind) still return
|
|
24
|
+
* `attached: false`.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type {
|
|
28
|
+
AttachScopeMetadataResult,
|
|
29
|
+
MetadataWriterRuntime,
|
|
30
|
+
} from "../workflow/metadata-writer.ts";
|
|
31
|
+
import { attachScopeMetadata } from "../workflow/metadata-writer.ts";
|
|
32
|
+
|
|
33
|
+
/** Stable metadataId prefix for AI-attached explanations. */
|
|
34
|
+
export const AI_EXPLANATION_METADATA_ID = "ai.explanation" as const;
|
|
35
|
+
|
|
36
|
+
export interface AttachExplanationInput {
|
|
37
|
+
readonly scopeId: string;
|
|
38
|
+
readonly explanation: string;
|
|
39
|
+
/** Optional stable id — defaults to `explanation-<scopeId>` when omitted. */
|
|
40
|
+
readonly explanationId?: string;
|
|
41
|
+
/** Optional ISO UTC stamp — defaults to `new Date(0).toISOString()` for determinism. */
|
|
42
|
+
readonly createdAtUtc?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type AttachExplanationResult =
|
|
46
|
+
| {
|
|
47
|
+
readonly attached: true;
|
|
48
|
+
readonly explanationId: string;
|
|
49
|
+
readonly entryId: string;
|
|
50
|
+
/**
|
|
51
|
+
* Coord-06 §13c — `"overlay"` when the scope was on the workflow
|
|
52
|
+
* overlay, `"derived"` when it was a paragraph / heading /
|
|
53
|
+
* list-item scopeId resolved from the canonical document.
|
|
54
|
+
*/
|
|
55
|
+
readonly resolvedFrom: "overlay" | "derived";
|
|
56
|
+
}
|
|
57
|
+
| {
|
|
58
|
+
readonly attached: false;
|
|
59
|
+
readonly explanationId: string;
|
|
60
|
+
/**
|
|
61
|
+
* `scope-not-resolvable:<scopeId>` — the scopeId is neither on
|
|
62
|
+
* the workflow overlay nor a paragraph-like derived id the
|
|
63
|
+
* canonical walk can resolve. Pre-§13c this was always
|
|
64
|
+
* `scope-not-in-overlay`; the broader prefix reflects the
|
|
65
|
+
* post-§13c two-stage resolution.
|
|
66
|
+
*/
|
|
67
|
+
readonly reason: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export function attachExplanation(
|
|
71
|
+
runtime: MetadataWriterRuntime,
|
|
72
|
+
input: AttachExplanationInput,
|
|
73
|
+
): AttachExplanationResult {
|
|
74
|
+
const explanationId = input.explanationId ?? `explanation-${input.scopeId}`;
|
|
75
|
+
const createdAtUtc = input.createdAtUtc ?? new Date(0).toISOString();
|
|
76
|
+
const writerResult: AttachScopeMetadataResult = attachScopeMetadata(runtime, {
|
|
77
|
+
scopeId: input.scopeId,
|
|
78
|
+
metadataId: AI_EXPLANATION_METADATA_ID,
|
|
79
|
+
value: {
|
|
80
|
+
explanationId,
|
|
81
|
+
text: input.explanation,
|
|
82
|
+
createdAtUtc,
|
|
83
|
+
},
|
|
84
|
+
// `inherit` persistence is the right default: explanations that
|
|
85
|
+
// need to export through to docx do so via the standard
|
|
86
|
+
// workflow-metadata export path; callers wanting `external`
|
|
87
|
+
// (side-channel only) pass through `attachScopeMetadata` directly.
|
|
88
|
+
});
|
|
89
|
+
if (writerResult.status === "attached") {
|
|
90
|
+
return {
|
|
91
|
+
attached: true,
|
|
92
|
+
explanationId,
|
|
93
|
+
entryId: writerResult.entryId,
|
|
94
|
+
resolvedFrom: writerResult.resolvedFrom,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
attached: false,
|
|
99
|
+
explanationId,
|
|
100
|
+
reason: `scope-not-resolvable:${writerResult.scopeId}`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 5 — `ScopeActionAudit` producer + telemetry emission.
|
|
3
|
+
*
|
|
4
|
+
* Every mutating replacement-scope action emits exactly one audit on the
|
|
5
|
+
* `scope` channel (S5 of layer-08 architecture). This module is the
|
|
6
|
+
* single producer — callers must not compose audit bundles locally and
|
|
7
|
+
* emit directly; they compose here so the shape + emission site stay
|
|
8
|
+
* honest.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { TelemetryBus } from "../debug/telemetry-bus.ts";
|
|
12
|
+
import type {
|
|
13
|
+
ReplacementScope,
|
|
14
|
+
RuntimeOperationPlan,
|
|
15
|
+
ScopeActionAudit,
|
|
16
|
+
SemanticScope,
|
|
17
|
+
ValidationResult,
|
|
18
|
+
} from "./semantic-scope-types.ts";
|
|
19
|
+
|
|
20
|
+
export interface EmitScopeActionAuditInputs {
|
|
21
|
+
readonly actionId: string;
|
|
22
|
+
readonly actorId: string;
|
|
23
|
+
readonly origin: "ui" | "agent" | "host";
|
|
24
|
+
readonly documentHashBefore: string;
|
|
25
|
+
readonly documentHashAfter?: string;
|
|
26
|
+
readonly targetScopeSnapshot: SemanticScope;
|
|
27
|
+
readonly proposed: ReplacementScope;
|
|
28
|
+
readonly plan: RuntimeOperationPlan;
|
|
29
|
+
readonly validation: ValidationResult;
|
|
30
|
+
readonly emittedAtUtc: string;
|
|
31
|
+
readonly bus?: TelemetryBus;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function buildScopeActionAudit(
|
|
35
|
+
inputs: EmitScopeActionAuditInputs,
|
|
36
|
+
): ScopeActionAudit {
|
|
37
|
+
return {
|
|
38
|
+
actionId: inputs.actionId,
|
|
39
|
+
actorId: inputs.actorId,
|
|
40
|
+
origin: inputs.origin,
|
|
41
|
+
documentHashBefore: inputs.documentHashBefore,
|
|
42
|
+
...(inputs.documentHashAfter
|
|
43
|
+
? { documentHashAfter: inputs.documentHashAfter }
|
|
44
|
+
: {}),
|
|
45
|
+
targetScopeSnapshot: inputs.targetScopeSnapshot,
|
|
46
|
+
proposed: inputs.proposed,
|
|
47
|
+
compiledOperations: Object.freeze(
|
|
48
|
+
inputs.plan.steps.map((step) => ({
|
|
49
|
+
kind: step.kind,
|
|
50
|
+
summary: step.summary,
|
|
51
|
+
})),
|
|
52
|
+
),
|
|
53
|
+
validation: inputs.validation,
|
|
54
|
+
emittedAtUtc: inputs.emittedAtUtc,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Build + emit one audit event on the `scope` telemetry channel. Returns
|
|
60
|
+
* the bundle so callers can surface it in their apply-result response.
|
|
61
|
+
*/
|
|
62
|
+
export function emitScopeActionAudit(
|
|
63
|
+
inputs: EmitScopeActionAuditInputs,
|
|
64
|
+
): ScopeActionAudit {
|
|
65
|
+
const audit = buildScopeActionAudit(inputs);
|
|
66
|
+
inputs.bus?.emitLazy("scope", () => ({
|
|
67
|
+
type: "scope.action_audit",
|
|
68
|
+
payload: audit,
|
|
69
|
+
}));
|
|
70
|
+
return audit;
|
|
71
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 3 — scope-bundle compiler.
|
|
3
|
+
*
|
|
4
|
+
* Wraps a compiled `SemanticScope` with its neighborhood (prev / next /
|
|
5
|
+
* parent / siblings) + evidence (review overlap, workflow overlap,
|
|
6
|
+
* formatting summary) into a single `ScopeBundle` sized for an agent turn
|
|
7
|
+
* budget (S7). The bundle is the primary unit an AI-API consumer reads.
|
|
8
|
+
*
|
|
9
|
+
* Cost: `neighborhoodFor` is O(n) per call. When composing many bundles
|
|
10
|
+
* over the same scope enumeration, pass `scopes` through explicitly so the
|
|
11
|
+
* enumeration runs once. A scope-id → index cache is a Slice 4+ follow-up.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { CanonicalDocument, StylesCatalog } from "../../model/canonical-document.ts";
|
|
15
|
+
import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
|
|
16
|
+
import type {
|
|
17
|
+
WorkflowMetadataEntry,
|
|
18
|
+
WorkflowOverlay,
|
|
19
|
+
} from "./_scope-dependencies.ts";
|
|
20
|
+
|
|
21
|
+
import { buildParagraphIndexMap, compileScope } from "./compile-scope.ts";
|
|
22
|
+
import type { EnumeratedScope } from "./enumerate-scopes.ts";
|
|
23
|
+
import { enumerateScopes } from "./enumerate-scopes.ts";
|
|
24
|
+
import { composeEvidence } from "./evidence.ts";
|
|
25
|
+
import type {
|
|
26
|
+
ScopeBundle,
|
|
27
|
+
ScopeBundleNeighborhood,
|
|
28
|
+
SemanticScope,
|
|
29
|
+
} from "./semantic-scope-types.ts";
|
|
30
|
+
|
|
31
|
+
export interface ScopeBundleInputs {
|
|
32
|
+
readonly document: Pick<CanonicalDocument, "content" | "docId" | "styles" | "review"> | CanonicalDocumentEnvelope;
|
|
33
|
+
readonly overlay?: WorkflowOverlay | null;
|
|
34
|
+
readonly nowUtc: string;
|
|
35
|
+
/** Pre-enumerated scopes; computed when absent. */
|
|
36
|
+
readonly scopes?: readonly EnumeratedScope[];
|
|
37
|
+
/**
|
|
38
|
+
* Workflow-metadata entries to project into the bundle's evidence as
|
|
39
|
+
* `aiExplanations` + `aiIssues`. When absent, those fields are
|
|
40
|
+
* omitted. Closes the adversarial-close read-side join: explanations
|
|
41
|
+
* + issues written via `ai.attachExplanation` / `ai.createIssue`
|
|
42
|
+
* become readable through `getScopeBundle` without the caller having
|
|
43
|
+
* to walk the metadata snapshot.
|
|
44
|
+
*/
|
|
45
|
+
readonly workflowMetadataEntries?: readonly WorkflowMetadataEntry[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* S7 cap — the bundle is sized for an agent turn, so we clamp the
|
|
50
|
+
* `siblingScopeIds` list to avoid O(n) bloat on top-level paragraphs in a
|
|
51
|
+
* 500-scope document. Prev/next always carry the immediate neighbors; the
|
|
52
|
+
* sibling list is truncated lexicographically after the self-position.
|
|
53
|
+
*/
|
|
54
|
+
const SIBLING_CAP = 20;
|
|
55
|
+
|
|
56
|
+
function neighborhoodFor(
|
|
57
|
+
handle: SemanticScope["handle"],
|
|
58
|
+
scopes: readonly EnumeratedScope[],
|
|
59
|
+
): ScopeBundleNeighborhood {
|
|
60
|
+
const siblings: string[] = [];
|
|
61
|
+
let previousScopeId: string | undefined;
|
|
62
|
+
let nextScopeId: string | undefined;
|
|
63
|
+
|
|
64
|
+
const parentScopeId = handle.parentScopeId;
|
|
65
|
+
const parentKey = parentScopeId ?? null;
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < scopes.length; i += 1) {
|
|
68
|
+
const entry = scopes[i]!;
|
|
69
|
+
if (entry.handle.scopeId === handle.scopeId) {
|
|
70
|
+
for (let p = i - 1; p >= 0; p -= 1) {
|
|
71
|
+
const cand = scopes[p]!;
|
|
72
|
+
if ((cand.handle.parentScopeId ?? null) === parentKey) {
|
|
73
|
+
previousScopeId = cand.handle.scopeId;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (let n = i + 1; n < scopes.length; n += 1) {
|
|
78
|
+
const cand = scopes[n]!;
|
|
79
|
+
if ((cand.handle.parentScopeId ?? null) === parentKey) {
|
|
80
|
+
nextScopeId = cand.handle.scopeId;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (
|
|
87
|
+
(entry.handle.parentScopeId ?? null) === parentKey &&
|
|
88
|
+
entry.handle.scopeId !== handle.scopeId
|
|
89
|
+
) {
|
|
90
|
+
if (siblings.length < SIBLING_CAP) {
|
|
91
|
+
siblings.push(entry.handle.scopeId);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
...(previousScopeId ? { previousScopeId } : {}),
|
|
98
|
+
...(nextScopeId ? { nextScopeId } : {}),
|
|
99
|
+
...(parentScopeId ? { parentScopeId } : {}),
|
|
100
|
+
...(siblings.length > 0 ? { siblingScopeIds: siblings } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Compile a scope bundle for one `SemanticScope`. Callers typically
|
|
106
|
+
* produce `scope` via `compileScope(entry, catalog)` and thread the same
|
|
107
|
+
* `document` + `overlay` through here.
|
|
108
|
+
*/
|
|
109
|
+
export function compileScopeBundle(
|
|
110
|
+
scope: SemanticScope,
|
|
111
|
+
inputs: ScopeBundleInputs,
|
|
112
|
+
): ScopeBundle {
|
|
113
|
+
const scopes =
|
|
114
|
+
inputs.scopes ??
|
|
115
|
+
enumerateScopes(inputs.document, { overlay: inputs.overlay ?? null });
|
|
116
|
+
const neighborhood = neighborhoodFor(scope.handle, scopes);
|
|
117
|
+
const evidence = composeEvidence({
|
|
118
|
+
scope,
|
|
119
|
+
document: inputs.document,
|
|
120
|
+
overlay: inputs.overlay,
|
|
121
|
+
scopes,
|
|
122
|
+
...(inputs.workflowMetadataEntries
|
|
123
|
+
? { workflowMetadataEntries: inputs.workflowMetadataEntries }
|
|
124
|
+
: {}),
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
scope,
|
|
128
|
+
neighborhood,
|
|
129
|
+
evidence,
|
|
130
|
+
generatedAtUtc: inputs.nowUtc,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Convenience wrapper — resolves a scope by id, compiles it, and returns
|
|
136
|
+
* its bundle. Returns null when the scope id does not enumerate.
|
|
137
|
+
*
|
|
138
|
+
* The `document` on `inputs` is the primary Layer 03 cascade input — when
|
|
139
|
+
* present, the compiler delegates formatting resolution to Layer 03 (see
|
|
140
|
+
* `compileScope` + `_formatting-seam.ts`). A bare `catalog` remains
|
|
141
|
+
* accepted for back-compat but is ignored by the seam.
|
|
142
|
+
*/
|
|
143
|
+
export function compileScopeBundleById(
|
|
144
|
+
scopeId: string,
|
|
145
|
+
inputs: ScopeBundleInputs & { readonly catalog?: StylesCatalog },
|
|
146
|
+
): ScopeBundle | null {
|
|
147
|
+
const scopes =
|
|
148
|
+
inputs.scopes ??
|
|
149
|
+
enumerateScopes(inputs.document, { overlay: inputs.overlay ?? null });
|
|
150
|
+
const entry = scopes.find((e) => e.handle.scopeId === scopeId);
|
|
151
|
+
if (!entry) return null;
|
|
152
|
+
const fullDoc =
|
|
153
|
+
"styles" in inputs.document && "content" in inputs.document
|
|
154
|
+
? (inputs.document as CanonicalDocument)
|
|
155
|
+
: undefined;
|
|
156
|
+
const compiled = compileScope(entry, {
|
|
157
|
+
...(fullDoc ? { document: fullDoc } : {}),
|
|
158
|
+
...(inputs.overlay !== undefined ? { overlay: inputs.overlay } : {}),
|
|
159
|
+
paragraphIndexByBlockIndex: buildParagraphIndexMap(inputs.document),
|
|
160
|
+
});
|
|
161
|
+
if (!compiled) return null;
|
|
162
|
+
return compileScopeBundle(compiled, { ...inputs, scopes });
|
|
163
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope compile dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* Takes an `EnumeratedScope` and dispatches to the matching kind compiler.
|
|
5
|
+
* Callers may thread a `CompileScopeOptions` bundle carrying:
|
|
6
|
+
*
|
|
7
|
+
* - `document` — full canonical document; enables Layer 03
|
|
8
|
+
* `resolveEffectiveFormatting` delegation for
|
|
9
|
+
* paragraph-like kinds (paragraphStyleId / outlineLevel
|
|
10
|
+
* / numbering.label honour the style cascade).
|
|
11
|
+
* - `overlay` — workflow overlay; the dispatcher computes overlay-
|
|
12
|
+
* scope overlap and threads `SemanticScopeWorkflow`
|
|
13
|
+
* into every paragraph-like and table-like compile.
|
|
14
|
+
* Identity-posture kinds (field, comment-thread,
|
|
15
|
+
* revision) override this in their kind file because
|
|
16
|
+
* the kind's identity implies its own mode.
|
|
17
|
+
* - `paragraphIndexByBlockIndex` — map from the all-children
|
|
18
|
+
* `blockIndex` used by the scope walker to the
|
|
19
|
+
* paragraph-type index Layer 03's synthesis uses
|
|
20
|
+
* (`paragraph-${N}`). Built once per document by
|
|
21
|
+
* `buildParagraphIndexMap`.
|
|
22
|
+
* - `positionMap` — precomputed `ScopePositionMap`. Reused across
|
|
23
|
+
* all compiles in a single pass so we only walk the
|
|
24
|
+
* document once for offset arithmetic.
|
|
25
|
+
*
|
|
26
|
+
* Kinds not yet implemented (note, image, scope, composite — 4 of 13)
|
|
27
|
+
* return `null`; the caller decides how to handle. `enumerate-scopes`
|
|
28
|
+
* already skips emitting these, so the null branch is a belt-and-braces
|
|
29
|
+
* guard for forward compatibility.
|
|
30
|
+
*
|
|
31
|
+
* Back-compat: the legacy `(entry, catalog)` signature still compiles —
|
|
32
|
+
* a bare `StylesCatalog` is accepted and ignored (it carried no cascade
|
|
33
|
+
* information the seam consumes directly). Callers are encouraged to
|
|
34
|
+
* migrate to `(entry, options)` to get Layer 03 cascade-accurate output.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import type {
|
|
38
|
+
CanonicalDocument,
|
|
39
|
+
StylesCatalog,
|
|
40
|
+
} from "../../model/canonical-document.ts";
|
|
41
|
+
import type { WorkflowOverlay } from "./_scope-dependencies.ts";
|
|
42
|
+
import type {
|
|
43
|
+
CanonicalDocumentEnvelope,
|
|
44
|
+
} from "../../core/state/editor-state.ts";
|
|
45
|
+
|
|
46
|
+
import type { EnumeratedScope } from "./enumerate-scopes.ts";
|
|
47
|
+
import {
|
|
48
|
+
buildScopePositionMap,
|
|
49
|
+
type ScopePositionMap,
|
|
50
|
+
} from "./position-map.ts";
|
|
51
|
+
import { resolveScopeRange } from "./scope-range.ts";
|
|
52
|
+
import type {
|
|
53
|
+
SemanticScope,
|
|
54
|
+
SemanticScopeWorkflow,
|
|
55
|
+
} from "./semantic-scope-types.ts";
|
|
56
|
+
import { resolveWorkflowOverlap } from "./workflow-overlap.ts";
|
|
57
|
+
|
|
58
|
+
import { compileCommentThreadScope } from "./scope-kinds/comment-thread.ts";
|
|
59
|
+
import { compileFieldScope } from "./scope-kinds/field.ts";
|
|
60
|
+
import { compileHeadingScope } from "./scope-kinds/heading.ts";
|
|
61
|
+
import { compileListItemScope } from "./scope-kinds/list-item.ts";
|
|
62
|
+
import { compileParagraphScope } from "./scope-kinds/paragraph.ts";
|
|
63
|
+
import { compileRevisionScope } from "./scope-kinds/revision.ts";
|
|
64
|
+
import { compileTableScope } from "./scope-kinds/table.ts";
|
|
65
|
+
import { compileTableCellScope } from "./scope-kinds/table-cell.ts";
|
|
66
|
+
import { compileTableRowScope } from "./scope-kinds/table-row.ts";
|
|
67
|
+
|
|
68
|
+
export interface CompileScopeOptions {
|
|
69
|
+
readonly document?: CanonicalDocument;
|
|
70
|
+
readonly overlay?: WorkflowOverlay | null;
|
|
71
|
+
readonly paragraphIndexByBlockIndex?: ReadonlyMap<number, number>;
|
|
72
|
+
/**
|
|
73
|
+
* `blockIndex → sectionIndex` precomputed via
|
|
74
|
+
* `buildSectionIndexByBlockIndex`. When present, paragraph-like kinds
|
|
75
|
+
* project `layout.sectionIndex` (coord-08 §12). When absent, the
|
|
76
|
+
* dispatcher computes it lazily from `options.document`. Callers that
|
|
77
|
+
* compile many scopes against the same document should hoist.
|
|
78
|
+
*/
|
|
79
|
+
readonly sectionIndexByBlockIndex?: ReadonlyMap<number, number>;
|
|
80
|
+
readonly positionMap?: ScopePositionMap;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isCompileScopeOptions(
|
|
84
|
+
v: unknown,
|
|
85
|
+
): v is CompileScopeOptions {
|
|
86
|
+
if (v === null || v === undefined) return true;
|
|
87
|
+
if (typeof v !== "object") return false;
|
|
88
|
+
return (
|
|
89
|
+
"document" in v ||
|
|
90
|
+
"overlay" in v ||
|
|
91
|
+
"paragraphIndexByBlockIndex" in v ||
|
|
92
|
+
"sectionIndexByBlockIndex" in v ||
|
|
93
|
+
"positionMap" in v
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Walk the document once to build a `blockIndex → sectionIndex` map.
|
|
99
|
+
* Section index is derived by counting `section_break` blocks that
|
|
100
|
+
* appear BEFORE the current block — every `section_break` advances the
|
|
101
|
+
* counter for the next block, matching OOXML's "blocks belong to the
|
|
102
|
+
* section whose properties live at the *next* section_break (or
|
|
103
|
+
* `finalSectionProperties` for the trailing section)" convention.
|
|
104
|
+
*
|
|
105
|
+
* Blocks before the first `section_break` report `sectionIndex = 0`.
|
|
106
|
+
* Callers use this for `SemanticScopeLayout.sectionIndex` projection
|
|
107
|
+
* (coord-08 §12). L04's `page-graph` carries its own per-page section
|
|
108
|
+
* indexing; this helper stays on L08's side because the per-block
|
|
109
|
+
* answer is a pure canonical-tree walk that doesn't require the
|
|
110
|
+
* layout facet.
|
|
111
|
+
*/
|
|
112
|
+
export function buildSectionIndexByBlockIndex(
|
|
113
|
+
document:
|
|
114
|
+
| Pick<CanonicalDocument, "content">
|
|
115
|
+
| CanonicalDocumentEnvelope,
|
|
116
|
+
): Map<number, number> {
|
|
117
|
+
const envelope = document as CanonicalDocumentEnvelope;
|
|
118
|
+
const root =
|
|
119
|
+
"content" in envelope
|
|
120
|
+
? envelope.content
|
|
121
|
+
: (document as unknown as { children: readonly { type: string }[] });
|
|
122
|
+
const out = new Map<number, number>();
|
|
123
|
+
let sectionIndex = 0;
|
|
124
|
+
for (let i = 0; i < root.children.length; i += 1) {
|
|
125
|
+
out.set(i, sectionIndex);
|
|
126
|
+
const child = root.children[i];
|
|
127
|
+
if (child && child.type === "section_break") {
|
|
128
|
+
sectionIndex += 1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Walk the document once to build a `blockIndex → paragraphIndex` map.
|
|
136
|
+
* Paragraph-type indexing matches Layer 03's `paragraph-${N}` blockId
|
|
137
|
+
* synthesis (see `src/runtime/formatting/document-lookup.ts`). Callers
|
|
138
|
+
* that compile many scopes over the same document should build this
|
|
139
|
+
* once and reuse.
|
|
140
|
+
*/
|
|
141
|
+
export function buildParagraphIndexMap(
|
|
142
|
+
document:
|
|
143
|
+
| Pick<CanonicalDocument, "content">
|
|
144
|
+
| CanonicalDocumentEnvelope,
|
|
145
|
+
): Map<number, number> {
|
|
146
|
+
const envelope = document as CanonicalDocumentEnvelope;
|
|
147
|
+
const root =
|
|
148
|
+
"content" in envelope
|
|
149
|
+
? envelope.content
|
|
150
|
+
: (document as unknown as { children: readonly { type: string }[] });
|
|
151
|
+
const out = new Map<number, number>();
|
|
152
|
+
let paragraphIndex = 0;
|
|
153
|
+
for (let i = 0; i < root.children.length; i += 1) {
|
|
154
|
+
const child = root.children[i];
|
|
155
|
+
if (child && child.type === "paragraph") {
|
|
156
|
+
out.set(i, paragraphIndex);
|
|
157
|
+
paragraphIndex += 1;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function workflowFor(
|
|
164
|
+
entry: EnumeratedScope,
|
|
165
|
+
overlay: WorkflowOverlay | null | undefined,
|
|
166
|
+
positionMap: ScopePositionMap | undefined,
|
|
167
|
+
): SemanticScopeWorkflow | undefined {
|
|
168
|
+
if (!overlay || !positionMap) return undefined;
|
|
169
|
+
// Review-store kinds carry identity-derived posture in their kind
|
|
170
|
+
// file (comment-thread = "comment", revision = "suggest"), so we
|
|
171
|
+
// skip the overlap path for them. All structural kinds — including
|
|
172
|
+
// marker-backed paragraphs that hosts classify as "clause" — get
|
|
173
|
+
// the proper overlap merge, which means outer `view` / `comment`
|
|
174
|
+
// scopes correctly override inner `edit` scopes.
|
|
175
|
+
const isIdentityKind =
|
|
176
|
+
entry.kind === "comment-thread" || entry.kind === "revision";
|
|
177
|
+
if (isIdentityKind) return undefined;
|
|
178
|
+
const range = resolveScopeRange(entry, entry.handle, positionMap);
|
|
179
|
+
return resolveWorkflowOverlap({
|
|
180
|
+
overlay,
|
|
181
|
+
positionMap,
|
|
182
|
+
range,
|
|
183
|
+
// Intentionally do NOT pass selfScopeIds — a marker-backed scope's
|
|
184
|
+
// own overlay entry carries the authoritative mode for its own
|
|
185
|
+
// range, and outer overlap scopes merge on top via the most-
|
|
186
|
+
// restrictive rule. Filtering self would drop the scope's own
|
|
187
|
+
// mode signal and misrepresent its posture.
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function compileScope(
|
|
192
|
+
entry: EnumeratedScope,
|
|
193
|
+
optionsOrCatalog?: CompileScopeOptions | StylesCatalog,
|
|
194
|
+
): SemanticScope | null {
|
|
195
|
+
const options: CompileScopeOptions = isCompileScopeOptions(optionsOrCatalog)
|
|
196
|
+
? (optionsOrCatalog ?? {})
|
|
197
|
+
: {};
|
|
198
|
+
const blockIndex = "blockIndex" in entry ? entry.blockIndex : -1;
|
|
199
|
+
const paragraphIndex =
|
|
200
|
+
options.paragraphIndexByBlockIndex?.get(blockIndex);
|
|
201
|
+
// Lazy section-index map: build once per dispatcher call when the
|
|
202
|
+
// caller didn't hoist + we have a document to walk. Derived scopes
|
|
203
|
+
// without a blockIndex (e.g. comment-thread/revision identity kinds)
|
|
204
|
+
// skip the projection via the `blockIndex >= 0` check below.
|
|
205
|
+
let sectionIndexMap = options.sectionIndexByBlockIndex;
|
|
206
|
+
if (!sectionIndexMap && options.document && blockIndex >= 0) {
|
|
207
|
+
sectionIndexMap = buildSectionIndexByBlockIndex(options.document);
|
|
208
|
+
}
|
|
209
|
+
const sectionIndex =
|
|
210
|
+
blockIndex >= 0 ? sectionIndexMap?.get(blockIndex) : undefined;
|
|
211
|
+
const paragraphLikeOpts: {
|
|
212
|
+
document?: CanonicalDocument;
|
|
213
|
+
paragraphIndex?: number;
|
|
214
|
+
sectionIndex?: number;
|
|
215
|
+
} = {};
|
|
216
|
+
if (options.document) paragraphLikeOpts.document = options.document;
|
|
217
|
+
if (typeof paragraphIndex === "number") {
|
|
218
|
+
paragraphLikeOpts.paragraphIndex = paragraphIndex;
|
|
219
|
+
}
|
|
220
|
+
if (typeof sectionIndex === "number") {
|
|
221
|
+
paragraphLikeOpts.sectionIndex = sectionIndex;
|
|
222
|
+
}
|
|
223
|
+
// Compute positionMap + workflow only when overlay is threaded. This
|
|
224
|
+
// keeps hot-path unit tests (without overlay) allocation-free.
|
|
225
|
+
let positionMap = options.positionMap;
|
|
226
|
+
if (!positionMap && options.overlay && options.document) {
|
|
227
|
+
positionMap = buildScopePositionMap(options.document);
|
|
228
|
+
}
|
|
229
|
+
const workflow = workflowFor(entry, options.overlay, positionMap);
|
|
230
|
+
|
|
231
|
+
switch (entry.kind) {
|
|
232
|
+
case "paragraph":
|
|
233
|
+
return compileParagraphScope(entry, {
|
|
234
|
+
...paragraphLikeOpts,
|
|
235
|
+
...(workflow ? { workflow } : {}),
|
|
236
|
+
});
|
|
237
|
+
case "heading":
|
|
238
|
+
return compileHeadingScope(entry, {
|
|
239
|
+
...paragraphLikeOpts,
|
|
240
|
+
...(workflow ? { workflow } : {}),
|
|
241
|
+
});
|
|
242
|
+
case "list-item":
|
|
243
|
+
return compileListItemScope(entry, {
|
|
244
|
+
...paragraphLikeOpts,
|
|
245
|
+
...(workflow ? { workflow } : {}),
|
|
246
|
+
});
|
|
247
|
+
case "table":
|
|
248
|
+
return compileTableScope(entry, workflow ? { workflow } : {});
|
|
249
|
+
case "table-row":
|
|
250
|
+
return compileTableRowScope(entry, workflow ? { workflow } : {});
|
|
251
|
+
case "table-cell":
|
|
252
|
+
return compileTableCellScope(entry, workflow ? { workflow } : {});
|
|
253
|
+
case "field":
|
|
254
|
+
return compileFieldScope(entry);
|
|
255
|
+
case "comment-thread":
|
|
256
|
+
return compileCommentThreadScope(entry);
|
|
257
|
+
case "revision":
|
|
258
|
+
return compileRevisionScope(entry);
|
|
259
|
+
default:
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
}
|