@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
|
@@ -56,11 +56,12 @@ import {
|
|
|
56
56
|
type MarginPresetDefinition,
|
|
57
57
|
type ActiveMarginPreset,
|
|
58
58
|
} from "./margin-preset-catalog.ts";
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
// ScopeRailSegment type is still re-exported from this module so
|
|
60
|
+
// chrome/overlay consumers (`tw-scope-rail-layer.tsx` etc.) can
|
|
61
|
+
// continue to import segment types via `../../runtime/layout`. Rail
|
|
62
|
+
// composition itself is Layer-06 (see workflow/coordinator.ts +
|
|
63
|
+
// runtime.workflow) — the layout facet only supplies the page graph.
|
|
64
|
+
import type { ScopeRailSegment } from "../workflow/rail/compose.ts";
|
|
64
65
|
import { createEditorSurfaceSnapshot } from "../surface-projection.ts";
|
|
65
66
|
import { storyTargetKey } from "../story-targeting.ts";
|
|
66
67
|
import { MAIN_STORY_TARGET } from "../../core/selection/mapping.ts";
|
|
@@ -68,9 +69,25 @@ import {
|
|
|
68
69
|
createSelectionSnapshot,
|
|
69
70
|
type CanonicalDocumentEnvelope,
|
|
70
71
|
} from "../../core/state/editor-state.ts";
|
|
71
|
-
|
|
72
|
+
// L03 production boundary: layout delegates every table-style cascade
|
|
73
|
+
// through `FormattingContext.resolveTable` so the same hot-path entry is
|
|
74
|
+
// used in surface-projection and here. Direct imports of the table-style
|
|
75
|
+
// resolver from non-Layer-03 code are rejected by
|
|
76
|
+
// `scripts/ci-check-formatting-production-boundary.mjs`.
|
|
77
|
+
import { createFormattingContext } from "../formatting/formatting-context.ts";
|
|
78
|
+
import type { ResolvedTableStyleResolution } from "../formatting/table-style-resolver.ts";
|
|
72
79
|
import { buildTableRenderPlan } from "./table-render-plan.ts";
|
|
73
|
-
|
|
80
|
+
// Geometry helpers are no longer imported here:
|
|
81
|
+
// - `hitTest` + `getAnchorRects` moved to the geometry facet in the
|
|
82
|
+
// refactor/05 Slice 6 wrapper-deletion pass (2026-04-22).
|
|
83
|
+
// - `collectScopeRailSegmentsForQuery` is no longer needed because
|
|
84
|
+
// refactor/06 Slice 4C moved rail-segment composition to
|
|
85
|
+
// `runtime.workflow.*`; the layout facet supplies the page graph
|
|
86
|
+
// as input, not the rail output.
|
|
87
|
+
import { collectLineBoxesForRegion } from "../geometry/project-fragments.ts";
|
|
88
|
+
// `recordPerfSample` no longer imported — used only by the removed
|
|
89
|
+
// `hitTest` wrapper to emit `chrome.hit_test` samples. Geometry facet
|
|
90
|
+
// can add its own instrumentation at call site if needed.
|
|
74
91
|
import type {
|
|
75
92
|
SurfaceBlockSnapshot,
|
|
76
93
|
} from "../../api/public-types";
|
|
@@ -84,6 +101,31 @@ export type {
|
|
|
84
101
|
|
|
85
102
|
export type { ScopeRailSegment };
|
|
86
103
|
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Module-level warning emitter (D1 silent-success probes)
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
type LayoutWarningEmitter = (type: string, guard: string, inputs: Record<string, unknown>) => void;
|
|
109
|
+
let _activeLayoutWarningEmitter: LayoutWarningEmitter | undefined;
|
|
110
|
+
|
|
111
|
+
export function setActiveLayoutWarningEmitter(fn: LayoutWarningEmitter | undefined): void {
|
|
112
|
+
_activeLayoutWarningEmitter = fn;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Exported so debug-infra D1 probes at layout-semantic guards that have
|
|
117
|
+
* physically moved into `src/runtime/geometry/**` (Slice 2a+ of refactor/05)
|
|
118
|
+
* can continue to emit through the same `setActiveLayoutWarningEmitter`
|
|
119
|
+
* pipeline as the remaining in-facet probes. The emit surface is unchanged;
|
|
120
|
+
* only the call-site location moved.
|
|
121
|
+
*/
|
|
122
|
+
export function emitLayoutGuardWarning(
|
|
123
|
+
guard: string,
|
|
124
|
+
inputs: Record<string, unknown>,
|
|
125
|
+
): void {
|
|
126
|
+
_activeLayoutWarningEmitter?.(`layout.guard.return-empty`, guard, inputs);
|
|
127
|
+
}
|
|
128
|
+
|
|
87
129
|
// ---------------------------------------------------------------------------
|
|
88
130
|
// Public read model types (shape-stable, cloned at the facet boundary)
|
|
89
131
|
// ---------------------------------------------------------------------------
|
|
@@ -397,6 +439,13 @@ export interface WordReviewEditorLayoutFacet {
|
|
|
397
439
|
// Per-page semantic reads ---------------------------------------------
|
|
398
440
|
getActiveStoriesOnPage(pageIndex: number): PublicResolvedPageStories | null;
|
|
399
441
|
getDisplayPageNumber(pageIndex: number): number | null;
|
|
442
|
+
/**
|
|
443
|
+
* @deprecated Use `GeometryFacet.getLineBoxes` (refactor/05 layer 05).
|
|
444
|
+
* Both paths route through
|
|
445
|
+
* `src/runtime/geometry/project-fragments.ts::collectLineBoxesForRegion`;
|
|
446
|
+
* this wrapper is retained for back-compat and will be deleted after
|
|
447
|
+
* consumers migrate.
|
|
448
|
+
*/
|
|
400
449
|
getLineBoxes(
|
|
401
450
|
pageIndex: number,
|
|
402
451
|
options?: { region?: PublicPageRegion["kind"]; columnIndex?: number },
|
|
@@ -448,66 +497,31 @@ export interface WordReviewEditorLayoutFacet {
|
|
|
448
497
|
getMarginPresetCatalog(): readonly MarginPresetDefinition[];
|
|
449
498
|
getActiveMarginPreset(sectionIndex: number): ActiveMarginPreset | null;
|
|
450
499
|
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
/**
|
|
478
|
-
* Resolve anchor rects for a `RenderAnchorQuery`. Returns `[]` when the
|
|
479
|
-
* kernel is absent or the query does not match any anchor. Chrome
|
|
480
|
-
* surfaces that need a single rect can read `getAnchorRects(q)[0]`;
|
|
481
|
-
* selection-spanning surfaces read the full list and union as needed.
|
|
482
|
-
*/
|
|
483
|
-
getAnchorRects?(
|
|
484
|
-
query: import("../render/index.ts").RenderAnchorQuery,
|
|
485
|
-
): readonly import("../render/index.ts").RenderFrameRect[];
|
|
486
|
-
|
|
487
|
-
// Scope rail segments (R3a) -------------------------------------------
|
|
488
|
-
/**
|
|
489
|
-
* Return workflow rail segments active on a given page. Returns an empty
|
|
490
|
-
* list when the host runtime did not supply workflow data to the facet.
|
|
491
|
-
*/
|
|
492
|
-
getScopeRailSegments(
|
|
493
|
-
pageIndex: number,
|
|
494
|
-
): readonly import("../workflow-rail-segments.ts").ScopeRailSegment[];
|
|
495
|
-
/** Return every scope rail segment across the document. */
|
|
496
|
-
getAllScopeRailSegments(): readonly import("../workflow-rail-segments.ts").ScopeRailSegment[];
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Scope-card projection consumed by the chrome overlay's card layer
|
|
500
|
-
* (scope-card-overlay P1). Joins every unique scope segment with
|
|
501
|
-
* its attached issue metadata (R2 `ISSUE_METADATA_ID`), its
|
|
502
|
-
* work-item id, and its `primaryAnchorRect` via the render kernel's
|
|
503
|
-
* anchor index. P2 fields (`suggestionGroupIds`,
|
|
504
|
-
* `reviewActionCount`, `agentPending`) are defaulted to empty /
|
|
505
|
-
* zero / false in P1 and populated by later phases.
|
|
506
|
-
*
|
|
507
|
-
* Returns an empty list when no workflow rail input has been wired
|
|
508
|
-
* or when no scopes are currently on the active story.
|
|
509
|
-
*/
|
|
510
|
-
getAllScopeCardModels(): readonly import("../../api/public-types.ts").ScopeCardModel[];
|
|
500
|
+
// `getRenderFrame` + `getRenderZoom` — REMOVED from the layout facet
|
|
501
|
+
// in the refactor/05 cross-lane-coord §8.4–§8.6 pass (2026-04-22).
|
|
502
|
+
// Both are pure render-kernel passthroughs — architecturally
|
|
503
|
+
// geometry-layer concerns, not layout. Consumers must call them
|
|
504
|
+
// through `runtime.geometry.getRenderFrame` / `.getRenderZoom`.
|
|
505
|
+
// Post-deletion the layout facet exposes layout-only reads; all five
|
|
506
|
+
// UI chrome consumers (selection-anchor resolver, object-selection
|
|
507
|
+
// overlay, table-grip layer, scope-rail layer, PM surface) were
|
|
508
|
+
// migrated to `runtime.geometry` in the same pass.
|
|
509
|
+
|
|
510
|
+
// `hitTest` + `getAnchorRects` — REMOVED in the refactor/05 Slice 6
|
|
511
|
+
// wrapper-deletion pass (2026-04-22). Both operate on pixel rects
|
|
512
|
+
// projected from the render frame — pure Layer-05 concerns. Consumers
|
|
513
|
+
// must call them through `runtime.geometry.hitTest` /
|
|
514
|
+
// `runtime.geometry.getAnchorRects`. The pure helpers live at
|
|
515
|
+
// `src/runtime/geometry/hit-test.ts::resolveHitTest` and
|
|
516
|
+
// `src/runtime/geometry/project-anchors.ts::resolveAnchorRects`.
|
|
517
|
+
|
|
518
|
+
// Scope-rail / scope-card composition is Layer-06 owned (W7).
|
|
519
|
+
// Consume via `runtime.workflow.getRailSegments(pageIndex)` /
|
|
520
|
+
// `runtime.workflow.getAllRailSegments()` /
|
|
521
|
+
// `runtime.workflow.getAllScopeCardModels()`. Layer-06 Slice 4
|
|
522
|
+
// (rail-seam inversion, 2026-04-22) removed the deprecated shims
|
|
523
|
+
// that previously lived here. The layout facet supplies page-graph
|
|
524
|
+
// input only; it is not the consumer seam for workflow data.
|
|
511
525
|
|
|
512
526
|
// Measurement exposure -------------------------------------------------
|
|
513
527
|
getResolvedFormatting(blockId: string): PublicResolvedParagraphFormatting | null;
|
|
@@ -546,20 +560,6 @@ export interface WordReviewEditorLayoutFacet {
|
|
|
546
560
|
pageIndex: number,
|
|
547
561
|
): import("./table-render-plan.ts").TableRenderPlan | null;
|
|
548
562
|
|
|
549
|
-
// Table render plan (P3e consumed by the render kernel, P4) ------------
|
|
550
|
-
/**
|
|
551
|
-
* Build a `TableRenderPlan` for a table block on a given page. Returns
|
|
552
|
-
* `null` when the blockId does not resolve to a table in the current
|
|
553
|
-
* surface. The plan carries columnsTwips, bandClasses, verticalMerges,
|
|
554
|
-
* repeatedHeaderRows, and columnResizeHandles so chrome can render
|
|
555
|
-
* band-aware cell styling and place column-resize grips without
|
|
556
|
-
* walking canonical state.
|
|
557
|
-
*/
|
|
558
|
-
getTableRenderPlan(
|
|
559
|
-
blockId: string,
|
|
560
|
-
pageIndex: number,
|
|
561
|
-
): import("./table-render-plan.ts").TableRenderPlan | null;
|
|
562
|
-
|
|
563
563
|
/**
|
|
564
564
|
* Returns the Y offset (in twips from the top of the page body) where this
|
|
565
565
|
* table fragment starts on the given page. Computed by summing
|
|
@@ -612,30 +612,12 @@ export interface CreateLayoutFacetInput {
|
|
|
612
612
|
| import("../render/index.ts").RenderKernel
|
|
613
613
|
| null
|
|
614
614
|
| undefined;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
getWorkflowRailInput?: () =>
|
|
622
|
-
| Omit<
|
|
623
|
-
import("../workflow-rail-segments.ts").CollectScopeRailSegmentsInput,
|
|
624
|
-
"pageGraph"
|
|
625
|
-
>
|
|
626
|
-
| null
|
|
627
|
-
| undefined;
|
|
628
|
-
/**
|
|
629
|
-
* Optional workflow-metadata accessor for scope-card issue resolution
|
|
630
|
-
* (R2 / scope-card-overlay P1). Returns the
|
|
631
|
-
* `WorkflowMarkupSnapshot.metadata` array so `getAllScopeCardModels`
|
|
632
|
-
* can attach issue values to their scopes. Omit when the host does
|
|
633
|
-
* not push metadata entries.
|
|
634
|
-
*/
|
|
635
|
-
getWorkflowMarkupMetadata?: () =>
|
|
636
|
-
| readonly import("../../api/public-types.ts").WorkflowMetadataMarkup[]
|
|
637
|
-
| null
|
|
638
|
-
| undefined;
|
|
615
|
+
// Scope-rail input accessors (`getWorkflowRailInput`,
|
|
616
|
+
// `getWorkflowMarkupMetadata`, `getSuggestionsSnapshot`) removed by
|
|
617
|
+
// Layer-06 Slice 4. Workflow rail / scope-card composition is now
|
|
618
|
+
// owned end-to-end by the coordinator + runtime.workflow facet; the
|
|
619
|
+
// layout facet only supplies the page graph as input, it does not
|
|
620
|
+
// consume workflow data.
|
|
639
621
|
/**
|
|
640
622
|
* L7 Phase 2 — optional viewport culling hooks wired from the owning
|
|
641
623
|
* `DocumentRuntime`. When supplied, `facet.setVisibleBlockRange` /
|
|
@@ -644,15 +626,6 @@ export interface CreateLayoutFacetInput {
|
|
|
644
626
|
*/
|
|
645
627
|
setVisibleBlockRange?: (range: { start: number; end: number }) => void;
|
|
646
628
|
requestViewportRefresh?: () => void;
|
|
647
|
-
/**
|
|
648
|
-
* R3 — optional suggestions snapshot accessor. Used by
|
|
649
|
-
* `getAllScopeCardModels` to attach `SuggestionGroup` entries whose
|
|
650
|
-
* `issueId` matches the scope's issue. Omit to skip group wiring.
|
|
651
|
-
*/
|
|
652
|
-
getSuggestionsSnapshot?: () =>
|
|
653
|
-
| import("../../api/public-types.ts").SuggestionsSnapshot
|
|
654
|
-
| null
|
|
655
|
-
| undefined;
|
|
656
629
|
}
|
|
657
630
|
|
|
658
631
|
export function createLayoutFacet(
|
|
@@ -832,10 +805,20 @@ export function createLayoutFacet(
|
|
|
832
805
|
return resolveFootnoteAreaRegionBlocks(node, document);
|
|
833
806
|
}
|
|
834
807
|
if (region === "column") {
|
|
835
|
-
//
|
|
836
|
-
//
|
|
837
|
-
|
|
838
|
-
|
|
808
|
+
// Refactor/04 Slice 4 follow-up — resolve per-column fragment
|
|
809
|
+
// ids against the live `regions.columns[columnIndex].fragmentIds`
|
|
810
|
+
// populated by `buildRegions`. Single-column pages leave
|
|
811
|
+
// `regions.columns === undefined` (F01 + CCEP single-column
|
|
812
|
+
// regression preserved), so the column branch returns empty
|
|
813
|
+
// there. Out-of-range `columnIndex` also returns empty rather
|
|
814
|
+
// than wrapping or throwing — the caller's query was outside
|
|
815
|
+
// the published column count for this page.
|
|
816
|
+
return resolveColumnRegionBlocks(
|
|
817
|
+
node,
|
|
818
|
+
graph,
|
|
819
|
+
findBodyBlockById,
|
|
820
|
+
columnIndex ?? 0,
|
|
821
|
+
);
|
|
839
822
|
}
|
|
840
823
|
// endnote-area: empty per-page; document-end via getDocumentEndnoteBlocks.
|
|
841
824
|
return Object.freeze([]);
|
|
@@ -931,7 +914,10 @@ export function createLayoutFacet(
|
|
|
931
914
|
getLineBoxes(pageIndex, options) {
|
|
932
915
|
const graph = currentGraph();
|
|
933
916
|
const node = graph.pages[pageIndex];
|
|
934
|
-
if (!node)
|
|
917
|
+
if (!node) {
|
|
918
|
+
emitLayoutGuardWarning("getLineBoxes", { pageIndex });
|
|
919
|
+
return [];
|
|
920
|
+
}
|
|
935
921
|
const region = options?.region ?? "body";
|
|
936
922
|
return collectLineBoxesForRegion(
|
|
937
923
|
node,
|
|
@@ -944,7 +930,10 @@ export function createLayoutFacet(
|
|
|
944
930
|
getLineBoxesForRegion(pageIndex, region, options) {
|
|
945
931
|
const graph = currentGraph();
|
|
946
932
|
const node = graph.pages[pageIndex];
|
|
947
|
-
if (!node)
|
|
933
|
+
if (!node) {
|
|
934
|
+
emitLayoutGuardWarning("getLineBoxesForRegion", { pageIndex, region });
|
|
935
|
+
return [];
|
|
936
|
+
}
|
|
948
937
|
return collectLineBoxesForRegion(
|
|
949
938
|
node,
|
|
950
939
|
region,
|
|
@@ -956,7 +945,10 @@ export function createLayoutFacet(
|
|
|
956
945
|
getStoryRegionsOnPage(pageIndex) {
|
|
957
946
|
const graph = currentGraph();
|
|
958
947
|
const node = graph.pages[pageIndex];
|
|
959
|
-
if (!node)
|
|
948
|
+
if (!node) {
|
|
949
|
+
emitLayoutGuardWarning("getStoryRegionsOnPage", { pageIndex });
|
|
950
|
+
return [];
|
|
951
|
+
}
|
|
960
952
|
const result: PublicPageRegion[] = [];
|
|
961
953
|
// Render order: header → body → columns → footer → footnote-area.
|
|
962
954
|
if (node.regions.header) {
|
|
@@ -1089,75 +1081,20 @@ export function createLayoutFacet(
|
|
|
1089
1081
|
});
|
|
1090
1082
|
},
|
|
1091
1083
|
|
|
1092
|
-
getRenderFrame
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
getRenderZoom() {
|
|
1099
|
-
const kernel = input.renderKernel?.();
|
|
1100
|
-
if (!kernel) return null;
|
|
1101
|
-
return kernel.getZoom();
|
|
1102
|
-
},
|
|
1103
|
-
|
|
1104
|
-
hitTest(pointInRoot) {
|
|
1105
|
-
const kernel = input.renderKernel?.();
|
|
1106
|
-
if (!kernel) return null;
|
|
1107
|
-
const t0 = typeof performance !== "undefined" ? performance.now() : 0;
|
|
1108
|
-
const frame = kernel.getRenderFrame();
|
|
1109
|
-
const result = resolveHitTest(frame, pointInRoot);
|
|
1110
|
-
if (t0 > 0) recordPerfSample("chrome.hit_test", performance.now() - t0);
|
|
1111
|
-
return result;
|
|
1112
|
-
},
|
|
1113
|
-
|
|
1114
|
-
getAnchorRects(query) {
|
|
1115
|
-
const kernel = input.renderKernel?.();
|
|
1116
|
-
if (!kernel) return [];
|
|
1117
|
-
const frame = kernel.getRenderFrame();
|
|
1118
|
-
return resolveAnchorRects(frame, query);
|
|
1119
|
-
},
|
|
1120
|
-
|
|
1121
|
-
getScopeRailSegments(pageIndex) {
|
|
1122
|
-
return collectScopeRailSegmentsForQuery(
|
|
1123
|
-
input.getWorkflowRailInput?.(),
|
|
1124
|
-
currentGraph(),
|
|
1125
|
-
).filter((segment) => segment.pageIndex === pageIndex);
|
|
1126
|
-
},
|
|
1127
|
-
|
|
1128
|
-
getAllScopeRailSegments() {
|
|
1129
|
-
return collectScopeRailSegmentsForQuery(
|
|
1130
|
-
input.getWorkflowRailInput?.(),
|
|
1131
|
-
currentGraph(),
|
|
1132
|
-
);
|
|
1133
|
-
},
|
|
1134
|
-
|
|
1135
|
-
getAllScopeCardModels() {
|
|
1136
|
-
const railInput = input.getWorkflowRailInput?.();
|
|
1137
|
-
const segments = collectScopeRailSegmentsForQuery(railInput, currentGraph());
|
|
1138
|
-
if (segments.length === 0) return [];
|
|
1139
|
-
const kernel = input.renderKernel?.();
|
|
1140
|
-
const anchorIndex = kernel?.getRenderFrame?.()?.anchorIndex ?? null;
|
|
1141
|
-
const metadata = input.getWorkflowMarkupMetadata?.();
|
|
1142
|
-
const suggestions = input.getSuggestionsSnapshot?.() ?? null;
|
|
1143
|
-
// The workflow-markup entries carry BOTH issue and review-action
|
|
1144
|
-
// metadata. The projector filters to REVIEW_ACTION_METADATA_ID
|
|
1145
|
-
// internally, so we can just pass the whole list.
|
|
1146
|
-
return attachScopeCardModel({
|
|
1147
|
-
segments,
|
|
1148
|
-
scopes: railInput?.scopes ?? [],
|
|
1149
|
-
metadata: metadata ?? undefined,
|
|
1150
|
-
anchorIndex,
|
|
1151
|
-
suggestions,
|
|
1152
|
-
reviewActionMetadata: metadata ?? undefined,
|
|
1153
|
-
candidates: railInput?.candidates ?? undefined,
|
|
1154
|
-
});
|
|
1155
|
-
},
|
|
1084
|
+
// `getRenderFrame` + `getRenderZoom` — removed in refactor/05
|
|
1085
|
+
// cross-lane-coord §8 pass. Geometry concerns; call through
|
|
1086
|
+
// `runtime.geometry.getRenderFrame` / `.getRenderZoom`.
|
|
1087
|
+
// `hitTest` + `getAnchorRects` — removed in refactor/05 Slice 6
|
|
1088
|
+
// wrapper-deletion pass. Geometry concerns; call through
|
|
1089
|
+
// `runtime.geometry.hitTest` / `runtime.geometry.getAnchorRects`.
|
|
1156
1090
|
|
|
1157
1091
|
getFragmentsForPage(pageIndex) {
|
|
1158
1092
|
const graph = currentGraph();
|
|
1159
1093
|
const node = graph.pages[pageIndex];
|
|
1160
|
-
if (!node)
|
|
1094
|
+
if (!node) {
|
|
1095
|
+
emitLayoutGuardWarning("getFragmentsForPage", { pageIndex });
|
|
1096
|
+
return [];
|
|
1097
|
+
}
|
|
1161
1098
|
return graph.fragments
|
|
1162
1099
|
.filter((f) => f.pageId === node.pageId)
|
|
1163
1100
|
.map((f) => toPublicBlockFragment(f, graph));
|
|
@@ -1659,257 +1596,22 @@ function findPageForOffsetAndStory(
|
|
|
1659
1596
|
return null;
|
|
1660
1597
|
}
|
|
1661
1598
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
* the document end as a separate region whose layout sits outside
|
|
1679
|
-
* the per-page accounting.
|
|
1680
|
-
*/
|
|
1681
|
-
function collectLineBoxesForRegion(
|
|
1682
|
-
node: RuntimePageNode,
|
|
1683
|
-
region: PublicPageRegion["kind"],
|
|
1684
|
-
graph: RuntimePageGraph,
|
|
1685
|
-
columnIndex: number | undefined,
|
|
1686
|
-
): readonly RuntimeLineBoxAlias[] {
|
|
1687
|
-
if (region === "body") {
|
|
1688
|
-
return node.lineBoxes;
|
|
1689
|
-
}
|
|
1690
|
-
// P4: synthesize line boxes from the region's fragments.
|
|
1691
|
-
const regionEntry = resolveRegionEntry(node, region, columnIndex);
|
|
1692
|
-
if (!regionEntry || regionEntry.fragmentIds.length === 0) {
|
|
1693
|
-
return EMPTY_LINE_BOXES;
|
|
1694
|
-
}
|
|
1695
|
-
const fragmentsById = new Map(
|
|
1696
|
-
graph.fragments.map((f) => [f.fragmentId, f] as const),
|
|
1697
|
-
);
|
|
1698
|
-
const result: RuntimeLineBoxAlias[] = [];
|
|
1699
|
-
let cursorTwips = 0;
|
|
1700
|
-
let lineIndex = 0;
|
|
1701
|
-
for (const fragmentId of regionEntry.fragmentIds) {
|
|
1702
|
-
const fragment = fragmentsById.get(fragmentId);
|
|
1703
|
-
if (!fragment) continue;
|
|
1704
|
-
const heightTwips = Math.max(1, fragment.heightTwips);
|
|
1705
|
-
result.push({
|
|
1706
|
-
fragmentId,
|
|
1707
|
-
lineIndex: lineIndex++,
|
|
1708
|
-
baselineTwips: cursorTwips + heightTwips,
|
|
1709
|
-
heightTwips,
|
|
1710
|
-
widthTwips: regionEntry.widthTwips,
|
|
1711
|
-
});
|
|
1712
|
-
cursorTwips += heightTwips;
|
|
1713
|
-
}
|
|
1714
|
-
return result;
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
function resolveRegionEntry(
|
|
1718
|
-
node: RuntimePageNode,
|
|
1719
|
-
region: PublicPageRegion["kind"],
|
|
1720
|
-
columnIndex: number | undefined,
|
|
1721
|
-
): RuntimePageRegion | undefined {
|
|
1722
|
-
switch (region) {
|
|
1723
|
-
case "header":
|
|
1724
|
-
return node.regions.header;
|
|
1725
|
-
case "footer":
|
|
1726
|
-
return node.regions.footer;
|
|
1727
|
-
case "column": {
|
|
1728
|
-
const columns = node.regions.columns ?? [];
|
|
1729
|
-
if (columns.length === 0) return undefined;
|
|
1730
|
-
const idx = columnIndex ?? 0;
|
|
1731
|
-
return columns[idx];
|
|
1732
|
-
}
|
|
1733
|
-
case "footnote-area": {
|
|
1734
|
-
// Footnote area sits at the bottom of the body region per
|
|
1735
|
-
// OOXML. `RuntimePageRegions.footnotes` is a stable seam
|
|
1736
|
-
// declared by P4; the page-graph builder populates entries
|
|
1737
|
-
// when P8 lands. Returns the first footnote region (page
|
|
1738
|
-
// layouts allocate one block of footnotes per page; multi-
|
|
1739
|
-
// block layouts come later).
|
|
1740
|
-
const footnoteRegionList = node.regions.footnotes;
|
|
1741
|
-
if (footnoteRegionList && footnoteRegionList.length > 0) {
|
|
1742
|
-
return footnoteRegionList[0];
|
|
1743
|
-
}
|
|
1744
|
-
return undefined;
|
|
1745
|
-
}
|
|
1746
|
-
default:
|
|
1747
|
-
return undefined;
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
// Use a shared alias so the region helper doesn't import the runtime
|
|
1752
|
-
// `RuntimeLineBox` type redundantly (`lineBoxes` is already strongly typed on
|
|
1753
|
-
// `RuntimePageNode`).
|
|
1754
|
-
type RuntimeLineBoxAlias = RuntimePageNode["lineBoxes"][number];
|
|
1755
|
-
const EMPTY_LINE_BOXES: readonly RuntimeLineBoxAlias[] = Object.freeze([]);
|
|
1756
|
-
|
|
1757
|
-
/**
|
|
1758
|
-
* Join the host-supplied workflow rail input with the current page graph.
|
|
1759
|
-
* Returns an empty array when no input is available so callers can always
|
|
1760
|
-
* iterate without null-checking.
|
|
1761
|
-
*/
|
|
1762
|
-
function collectScopeRailSegmentsForQuery(
|
|
1763
|
-
input:
|
|
1764
|
-
| Omit<
|
|
1765
|
-
import("../workflow-rail-segments.ts").CollectScopeRailSegmentsInput,
|
|
1766
|
-
"pageGraph"
|
|
1767
|
-
>
|
|
1768
|
-
| null
|
|
1769
|
-
| undefined,
|
|
1770
|
-
graph: RuntimePageGraph,
|
|
1771
|
-
): ScopeRailSegment[] {
|
|
1772
|
-
if (!input) return [];
|
|
1773
|
-
return collectScopeRailSegments({ ...input, pageGraph: graph });
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
function resolveHitTest(
|
|
1777
|
-
frame: import("../render/index.ts").RenderFrame | null,
|
|
1778
|
-
point: import("../render/index.ts").RenderPoint,
|
|
1779
|
-
): import("../render/index.ts").RenderHitResult | null {
|
|
1780
|
-
if (!frame) return null;
|
|
1781
|
-
for (const page of frame.pages) {
|
|
1782
|
-
if (!containsPoint(page.frame, point)) continue;
|
|
1783
|
-
const regionHit = hitTestRegion(page, point, "body");
|
|
1784
|
-
if (regionHit) return regionHit;
|
|
1785
|
-
const header = hitTestRegion(page, point, "header");
|
|
1786
|
-
if (header) return header;
|
|
1787
|
-
const footer = hitTestRegion(page, point, "footer");
|
|
1788
|
-
if (footer) return footer;
|
|
1789
|
-
}
|
|
1790
|
-
return null;
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
function hitTestRegion(
|
|
1794
|
-
page: import("../render/index.ts").RenderPage,
|
|
1795
|
-
point: import("../render/index.ts").RenderPoint,
|
|
1796
|
-
kind: "body" | "header" | "footer",
|
|
1797
|
-
): import("../render/index.ts").RenderHitResult | null {
|
|
1798
|
-
const region =
|
|
1799
|
-
kind === "body"
|
|
1800
|
-
? page.regions.body
|
|
1801
|
-
: kind === "header"
|
|
1802
|
-
? page.regions.header
|
|
1803
|
-
: page.regions.footer;
|
|
1804
|
-
if (!region) return null;
|
|
1805
|
-
if (!containsPoint(region.frame, point)) return null;
|
|
1806
|
-
for (const block of region.blocks) {
|
|
1807
|
-
if (!containsPoint(block.frame, point)) continue;
|
|
1808
|
-
let bestLineIndex = -1;
|
|
1809
|
-
let bestLineDistance = Number.POSITIVE_INFINITY;
|
|
1810
|
-
for (let i = 0; i < block.lines.length; i++) {
|
|
1811
|
-
const line = block.lines[i]!;
|
|
1812
|
-
const midY = line.frame.topPx + line.frame.heightPx / 2;
|
|
1813
|
-
const distance = Math.abs(midY - point.yPx);
|
|
1814
|
-
if (distance < bestLineDistance) {
|
|
1815
|
-
bestLineDistance = distance;
|
|
1816
|
-
bestLineIndex = i;
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
const lineIndex = bestLineIndex >= 0 ? bestLineIndex : 0;
|
|
1820
|
-
const line = block.lines[lineIndex];
|
|
1821
|
-
const runtimeOffset = line?.anchors[0]?.runtimeOffset ?? block.fragment.from;
|
|
1822
|
-
return {
|
|
1823
|
-
pageIndex: page.page.pageIndex,
|
|
1824
|
-
regionKind: region.region.kind,
|
|
1825
|
-
blockId: block.fragment.blockId,
|
|
1826
|
-
fragmentId: block.fragment.fragmentId,
|
|
1827
|
-
lineIndex,
|
|
1828
|
-
runtimeOffset,
|
|
1829
|
-
};
|
|
1830
|
-
}
|
|
1831
|
-
// Point fell inside the region but between blocks — snap to the nearest block.
|
|
1832
|
-
let nearestBlock: import("../render/index.ts").RenderBlock | null = null;
|
|
1833
|
-
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
1834
|
-
for (const block of region.blocks) {
|
|
1835
|
-
const distance = Math.min(
|
|
1836
|
-
Math.abs(point.yPx - block.frame.topPx),
|
|
1837
|
-
Math.abs(point.yPx - (block.frame.topPx + block.frame.heightPx)),
|
|
1838
|
-
);
|
|
1839
|
-
if (distance < nearestDistance) {
|
|
1840
|
-
nearestBlock = block;
|
|
1841
|
-
nearestDistance = distance;
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
if (!nearestBlock) return null;
|
|
1845
|
-
return {
|
|
1846
|
-
pageIndex: page.page.pageIndex,
|
|
1847
|
-
regionKind: region.region.kind,
|
|
1848
|
-
blockId: nearestBlock.fragment.blockId,
|
|
1849
|
-
fragmentId: nearestBlock.fragment.fragmentId,
|
|
1850
|
-
lineIndex: 0,
|
|
1851
|
-
runtimeOffset: nearestBlock.fragment.from,
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
function containsPoint(
|
|
1856
|
-
rect: import("../render/index.ts").RenderFrameRect,
|
|
1857
|
-
point: import("../render/index.ts").RenderPoint,
|
|
1858
|
-
): boolean {
|
|
1859
|
-
return (
|
|
1860
|
-
point.xPx >= rect.leftPx &&
|
|
1861
|
-
point.xPx <= rect.leftPx + rect.widthPx &&
|
|
1862
|
-
point.yPx >= rect.topPx &&
|
|
1863
|
-
point.yPx <= rect.topPx + rect.heightPx
|
|
1864
|
-
);
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
function resolveAnchorRects(
|
|
1868
|
-
frame: import("../render/index.ts").RenderFrame | null,
|
|
1869
|
-
query: import("../render/index.ts").RenderAnchorQuery,
|
|
1870
|
-
): readonly import("../render/index.ts").RenderFrameRect[] {
|
|
1871
|
-
if (!frame) return [];
|
|
1872
|
-
switch (query.kind) {
|
|
1873
|
-
case "runtime-offset": {
|
|
1874
|
-
const offset =
|
|
1875
|
-
typeof query.value === "number" ? query.value : Number(query.value);
|
|
1876
|
-
if (!Number.isFinite(offset)) return [];
|
|
1877
|
-
const rect = frame.anchorIndex.byRuntimeOffset(offset, query.story);
|
|
1878
|
-
return rect ? [rect] : [];
|
|
1879
|
-
}
|
|
1880
|
-
case "block-id": {
|
|
1881
|
-
const rect = frame.anchorIndex.byBlockId(String(query.value));
|
|
1882
|
-
return rect ? [rect] : [];
|
|
1883
|
-
}
|
|
1884
|
-
case "fragment-id": {
|
|
1885
|
-
const rect = frame.anchorIndex.byFragmentId(String(query.value));
|
|
1886
|
-
return rect ? [rect] : [];
|
|
1887
|
-
}
|
|
1888
|
-
case "page-index": {
|
|
1889
|
-
const pageIndex =
|
|
1890
|
-
typeof query.value === "number" ? query.value : Number(query.value);
|
|
1891
|
-
if (!Number.isFinite(pageIndex)) return [];
|
|
1892
|
-
const rect = frame.anchorIndex.byPageIndex(pageIndex);
|
|
1893
|
-
return rect ? [rect] : [];
|
|
1894
|
-
}
|
|
1895
|
-
case "scope-id": {
|
|
1896
|
-
return frame.anchorIndex.byScopeId(String(query.value));
|
|
1897
|
-
}
|
|
1898
|
-
case "comment-id": {
|
|
1899
|
-
const rect = frame.anchorIndex.byCommentId(String(query.value));
|
|
1900
|
-
return rect ? [rect] : [];
|
|
1901
|
-
}
|
|
1902
|
-
case "revision-id": {
|
|
1903
|
-
const rect = frame.anchorIndex.byRevisionId(String(query.value));
|
|
1904
|
-
return rect ? [rect] : [];
|
|
1905
|
-
}
|
|
1906
|
-
default: {
|
|
1907
|
-
const exhaustive: never = query.kind;
|
|
1908
|
-
void exhaustive;
|
|
1909
|
-
return [];
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
1599
|
+
// Line-box collection (`collectLineBoxesForRegion`, `resolveRegionEntry`,
|
|
1600
|
+
// `EMPTY_LINE_BOXES`, `RuntimeLineBoxAlias`) and workflow-rail query
|
|
1601
|
+
// (`collectScopeRailSegmentsForQuery`) moved to
|
|
1602
|
+
// `src/runtime/geometry/project-fragments.ts` +
|
|
1603
|
+
// `src/runtime/geometry/project-anchors.ts` in refactor/05 Slice 2b. The
|
|
1604
|
+
// facet's `getLineBoxes` / `getScopeRailSegments` / `getAllScopeRailSegments`
|
|
1605
|
+
// / `getAllScopeCardModels` methods above now import from there. The D1
|
|
1606
|
+
// `emitLayoutGuardWarning` probes (including the
|
|
1607
|
+
// `collectScopeRailSegmentsForQuery` null-input probe) are ported alongside
|
|
1608
|
+
// via the exported `emitLayoutGuardWarning` symbol — they continue to
|
|
1609
|
+
// fire through `setActiveLayoutWarningEmitter`.
|
|
1610
|
+
//
|
|
1611
|
+
// Hit-test (`resolveHitTest`, `hitTestRegion`, `containsPoint`) and
|
|
1612
|
+
// anchor-rect resolution (`resolveAnchorRects`) were moved in Slice 2a.
|
|
1613
|
+
// Deletion of the remaining layout-facet wrappers lands in Slice 6 once
|
|
1614
|
+
// consumers have flipped to the geometry facet.
|
|
1913
1615
|
|
|
1914
1616
|
// ---------------------------------------------------------------------------
|
|
1915
1617
|
// Table render plan helpers (P4)
|
|
@@ -1968,17 +1670,20 @@ function findTableBlockByBlockId(
|
|
|
1968
1670
|
function resolveTableStyleResolutionForPlan(
|
|
1969
1671
|
surfaceTable: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
|
|
1970
1672
|
document: LayoutEngineQueryInput["document"],
|
|
1971
|
-
):
|
|
1673
|
+
): ResolvedTableStyleResolution | null {
|
|
1972
1674
|
const canonicalTable = findCanonicalTableByBlockId(
|
|
1973
1675
|
document.content.children,
|
|
1974
1676
|
surfaceTable.blockId,
|
|
1975
1677
|
{ counter: { value: 0 } },
|
|
1976
1678
|
);
|
|
1977
1679
|
if (!canonicalTable) return null;
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1680
|
+
// L03 boundary: delegate through a FormattingContext for this single
|
|
1681
|
+
// call. The context is cheap to construct for a one-shot read; when
|
|
1682
|
+
// `getTableRenderPlan` is called in a batch, the caller's own context
|
|
1683
|
+
// would be preferable, but the current facet signature doesn't thread
|
|
1684
|
+
// one through. Keeping this narrow keeps the production boundary
|
|
1685
|
+
// consistent (no direct sub-resolver imports outside Layer 03).
|
|
1686
|
+
return createFormattingContext(document).resolveTable(canonicalTable);
|
|
1982
1687
|
}
|
|
1983
1688
|
|
|
1984
1689
|
/**
|
|
@@ -2058,6 +1763,46 @@ function resolveBodyRegionBlocks(
|
|
|
2058
1763
|
return Object.freeze(blocks);
|
|
2059
1764
|
}
|
|
2060
1765
|
|
|
1766
|
+
function resolveColumnRegionBlocks(
|
|
1767
|
+
node: RuntimePageNode,
|
|
1768
|
+
graph: RuntimePageGraph,
|
|
1769
|
+
findBodyBlockById: (blockId: string) => SurfaceBlockSnapshot | undefined,
|
|
1770
|
+
columnIndex: number,
|
|
1771
|
+
): readonly PublicRegionBlock[] {
|
|
1772
|
+
// Refactor/04 Slice 4 — per-column block resolution. Reads the live
|
|
1773
|
+
// `regions.columns[columnIndex].fragmentIds` list that `buildRegions`
|
|
1774
|
+
// partitions when the section paginated under a multi-column layout.
|
|
1775
|
+
// Single-column pages leave `regions.columns` undefined; out-of-range
|
|
1776
|
+
// `columnIndex` is a caller contract error we treat gracefully.
|
|
1777
|
+
const columns = node.regions.columns;
|
|
1778
|
+
if (!columns) return Object.freeze([]);
|
|
1779
|
+
const column = columns[columnIndex];
|
|
1780
|
+
if (!column) return Object.freeze([]);
|
|
1781
|
+
|
|
1782
|
+
const fragmentsById = new Map<string, RuntimeBlockFragment>();
|
|
1783
|
+
for (const fragment of graph.fragments) {
|
|
1784
|
+
fragmentsById.set(fragment.fragmentId, fragment);
|
|
1785
|
+
}
|
|
1786
|
+
const blocks: PublicRegionBlock[] = [];
|
|
1787
|
+
for (const fragmentId of column.fragmentIds) {
|
|
1788
|
+
const fragment = fragmentsById.get(fragmentId);
|
|
1789
|
+
if (!fragment) continue;
|
|
1790
|
+
const blockSnapshot = findBodyBlockById(fragment.blockId);
|
|
1791
|
+
if (!blockSnapshot) continue;
|
|
1792
|
+
blocks.push({
|
|
1793
|
+
blockId: fragment.blockId,
|
|
1794
|
+
fragmentId,
|
|
1795
|
+
pageIndex: node.pageIndex,
|
|
1796
|
+
regionKind: "column",
|
|
1797
|
+
runtimeFromOffset: fragment.from,
|
|
1798
|
+
runtimeToOffset: fragment.to,
|
|
1799
|
+
heightTwips: fragment.heightTwips,
|
|
1800
|
+
blockSnapshot,
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
return Object.freeze(blocks);
|
|
1804
|
+
}
|
|
1805
|
+
|
|
2061
1806
|
function resolveHeaderFooterRegionBlocks(
|
|
2062
1807
|
pageIndex: number,
|
|
2063
1808
|
regionKind: "header" | "footer",
|