@beyondwork/docx-react-component 1.0.66 → 1.0.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -931
- package/package.json +26 -27
- package/src/api/anchor-conversion.ts +43 -0
- package/src/api/editor-state-types.ts +2 -1
- package/src/api/public-types.ts +504 -101
- package/src/api/session-state.ts +4 -0
- package/src/api/v3/README.md +91 -0
- package/src/api/v3/_create.ts +146 -0
- package/src/api/v3/_layer-metadata.ts +362 -0
- package/src/api/v3/_mocks.ts +84 -0
- package/src/api/v3/_runtime-handle.ts +162 -0
- package/src/api/v3/_ux-response.ts +73 -0
- package/src/api/v3/ai/_metadata-audit.ts +225 -0
- package/src/api/v3/ai/attach.ts +235 -0
- package/src/api/v3/ai/bundle.ts +132 -0
- package/src/api/v3/ai/explain.ts +144 -0
- package/src/api/v3/ai/export.ts +54 -0
- package/src/api/v3/ai/inspect.ts +118 -0
- package/src/api/v3/ai/policy.ts +77 -0
- package/src/api/v3/ai/replacement.ts +341 -0
- package/src/api/v3/ai/resolve.ts +133 -0
- package/src/api/v3/index.ts +79 -0
- package/src/api/v3/runtime/chart.ts +310 -0
- package/src/api/v3/runtime/clipboard.ts +81 -0
- package/src/api/v3/runtime/collab.ts +331 -0
- package/src/api/v3/runtime/content.ts +236 -0
- package/src/api/v3/runtime/document.ts +282 -0
- package/src/api/v3/runtime/formatting.ts +186 -0
- package/src/api/v3/runtime/geometry.ts +349 -0
- package/src/api/v3/runtime/layout.ts +108 -0
- package/src/api/v3/runtime/review.ts +129 -0
- package/src/api/v3/runtime/search.ts +74 -0
- package/src/api/v3/runtime/table.ts +63 -0
- package/src/api/v3/runtime/workflow.ts +434 -0
- package/src/api/v3/ui/_context.ts +86 -0
- package/src/api/v3/ui/_create.ts +65 -0
- package/src/api/v3/ui/_types.ts +520 -0
- package/src/api/v3/ui/chrome-composition.ts +342 -0
- package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
- package/src/api/v3/ui/chrome.ts +476 -0
- package/src/api/v3/ui/debug.ts +124 -0
- package/src/api/v3/ui/index.ts +64 -0
- package/src/api/v3/ui/overlays-visibility.ts +170 -0
- package/src/api/v3/ui/overlays.ts +427 -0
- package/src/api/v3/ui/scope.ts +71 -0
- package/src/api/v3/ui/session.ts +100 -0
- package/src/api/v3/ui/surface.ts +170 -0
- package/src/api/v3/ui/viewport.ts +303 -0
- package/src/core/commands/index.ts +28 -6
- package/src/core/commands/list-commands.ts +3 -2
- package/src/core/commands/section-layout-commands.ts +9 -8
- package/src/core/schema/text-schema.ts +16 -0
- package/src/core/selection/mapping.ts +33 -72
- package/src/core/state/editor-state.ts +96 -189
- package/src/index.ts +23 -4
- package/src/io/chart-preview-resolver.ts +1 -1
- package/src/io/docx-session.ts +36 -4795
- package/src/io/export/build-app-properties-xml.ts +1 -1
- package/src/io/export/serialize-comments.ts +1 -1
- package/src/io/export/serialize-headers-footers.ts +6 -1
- package/src/io/export/serialize-main-document.ts +45 -0
- package/src/io/export/serialize-run-formatting.ts +17 -2
- package/src/io/export/twip.ts +1 -1
- package/src/io/normalize/normalize-text.ts +27 -20
- package/src/io/ooxml/chart/parse-series.ts +1 -1
- package/src/io/ooxml/chart/resolve-color.ts +2 -2
- package/src/io/ooxml/chart/types.ts +1 -1
- package/src/io/ooxml/classify-embedding.ts +83 -33
- package/src/io/ooxml/parse-fill.ts +1 -1
- package/src/io/ooxml/parse-main-document.ts +71 -1
- package/src/io/ooxml/parse-object.ts +14 -10
- package/src/io/ooxml/parse-run-formatting.ts +47 -1
- package/src/io/ooxml/property-grab-bag.ts +2 -2
- package/src/io/ooxml/units.ts +11 -0
- package/src/io/ooxml/workflow-payload.ts +282 -7
- package/src/model/anchor.ts +85 -0
- package/src/model/canonical-document.ts +351 -15
- package/src/model/chart-types.ts +1 -1
- package/src/model/layout/index.ts +83 -0
- package/src/model/layout/page-graph-types.ts +181 -0
- package/src/model/layout/page-layout-snapshot.ts +105 -0
- package/src/model/layout/resolved-layout-types.ts +47 -0
- package/src/model/layout/runtime-page-graph-types.ts +102 -0
- package/src/model/paragraph-scope-ids.ts +72 -0
- package/src/model/review/comment-types.ts +112 -0
- package/src/model/review/index.ts +2 -0
- package/src/model/review/revision-types.ts +215 -0
- package/src/model/snapshot.ts +32 -0
- package/src/review/store/comment-store.ts +21 -47
- package/src/review/store/revision-types.ts +40 -198
- package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
- package/src/runtime/collab/runtime-collab-sync.ts +13 -3
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
- package/src/runtime/debug/event-ring-buffer.ts +64 -0
- package/src/runtime/debug/probability-sampler.ts +18 -0
- package/src/runtime/debug/runtime-debug-facet.ts +67 -0
- package/src/runtime/debug/stage-tokens.ts +31 -0
- package/src/runtime/debug/telemetry-bus.ts +271 -0
- package/src/runtime/debug/types.ts +275 -0
- package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
- package/src/runtime/document-layout.ts +8 -6
- package/src/runtime/document-runtime.ts +843 -1141
- package/src/runtime/document-search.ts +1 -1
- package/src/runtime/edit-ops/index.ts +1 -1
- package/src/runtime/external-send-runtime.ts +1 -1
- package/src/runtime/formatting/document-lookup.ts +235 -0
- package/src/runtime/formatting/field/registry.ts +41 -0
- package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
- package/src/runtime/formatting/font-resolution.ts +83 -0
- package/src/runtime/formatting/formatting-context.ts +903 -0
- package/src/runtime/formatting/formatting-types.ts +157 -0
- package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
- package/src/runtime/formatting/index.ts +125 -0
- package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
- package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
- package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
- package/src/runtime/formatting/projector.ts +75 -0
- package/src/runtime/formatting/resolve-effective.ts +407 -0
- package/src/runtime/formatting/revision-display.ts +105 -0
- package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
- package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
- package/src/runtime/formatting/telemetry-bridge.ts +106 -0
- package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
- package/src/runtime/geometry/caret-geometry.ts +164 -0
- package/src/runtime/geometry/geometry-facet.ts +364 -0
- package/src/runtime/geometry/geometry-types.ts +256 -0
- package/src/runtime/geometry/hit-test.ts +125 -0
- package/src/runtime/geometry/index.ts +71 -0
- package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
- package/src/runtime/geometry/invalidation.ts +35 -0
- package/src/runtime/geometry/object-handles.ts +77 -0
- package/src/runtime/geometry/overlay-rects.ts +85 -0
- package/src/runtime/geometry/project-anchors.ts +100 -0
- package/src/runtime/geometry/project-fragments.ts +216 -0
- package/src/runtime/geometry/projector.ts +129 -0
- package/src/runtime/geometry/replacement-envelope.ts +130 -0
- package/src/runtime/geometry/viewport.ts +218 -0
- package/src/runtime/layout/compat-input-ledger.ts +211 -0
- package/src/runtime/layout/index.ts +6 -1
- package/src/runtime/layout/inert-layout-facet.ts +12 -7
- package/src/runtime/layout/layout-engine-instance.ts +189 -11
- package/src/runtime/layout/layout-engine-version.ts +450 -1
- package/src/runtime/layout/layout-facet-types.ts +60 -0
- package/src/runtime/layout/layout-measurement-provider.ts +13 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
- package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
- package/src/runtime/layout/page-graph.ts +62 -209
- package/src/runtime/layout/page-story-resolver.ts +7 -12
- package/src/runtime/layout/paginated-layout-engine.ts +186 -11
- package/src/runtime/layout/project-block-fragments.ts +11 -0
- package/src/runtime/layout/projector.ts +90 -0
- package/src/runtime/layout/public-facet.ts +187 -442
- package/src/runtime/layout/resolved-formatting-state.ts +158 -26
- package/src/runtime/layout/table-render-plan.ts +1 -1
- package/src/runtime/prerender/cache-envelope.ts +6 -1
- package/src/runtime/prerender/prerender-document.ts +18 -23
- package/src/runtime/render/decoration-resolver.ts +1 -1
- package/src/runtime/render/render-frame-types.ts +20 -0
- package/src/runtime/render/render-kernel.ts +94 -25
- package/src/runtime/scopes/_formatting-seam.ts +262 -0
- package/src/runtime/scopes/_scope-dependencies.ts +49 -0
- package/src/runtime/scopes/action-validation.ts +356 -0
- package/src/runtime/scopes/attach-explanation.ts +102 -0
- package/src/runtime/scopes/audit-bundle.ts +71 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
- package/src/runtime/scopes/compile-scope.ts +262 -0
- package/src/runtime/scopes/compiler-service.ts +431 -0
- package/src/runtime/scopes/create-issue.ts +107 -0
- package/src/runtime/scopes/enumerate-scopes.ts +543 -0
- package/src/runtime/scopes/evidence.ts +233 -0
- package/src/runtime/scopes/index.ts +150 -0
- package/src/runtime/scopes/position-map.ts +214 -0
- package/src/runtime/scopes/preservation-boundary.ts +91 -0
- package/src/runtime/scopes/projector.ts +49 -0
- package/src/runtime/scopes/replaceability.ts +87 -0
- package/src/runtime/scopes/replacement/apply.ts +228 -0
- package/src/runtime/scopes/replacement/compile.ts +59 -0
- package/src/runtime/scopes/replacement/propose.ts +42 -0
- package/src/runtime/scopes/resolve-reference.ts +347 -0
- package/src/runtime/scopes/review-bundle.ts +141 -0
- package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
- package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
- package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
- package/src/runtime/scopes/scope-kinds/field.ts +65 -0
- package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
- package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
- package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
- package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
- package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
- package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
- package/src/runtime/scopes/scope-kinds/table.ts +55 -0
- package/src/runtime/scopes/scope-range.ts +208 -0
- package/src/runtime/scopes/semantic-scope-types.ts +454 -0
- package/src/runtime/scopes/workflow-overlap.ts +92 -0
- package/src/runtime/selection/index.ts +1 -1
- package/src/runtime/structure-ops/fragment-insert.ts +1 -1
- package/src/runtime/structure-ops/index.ts +1 -1
- package/src/runtime/surface-projection.ts +232 -262
- package/src/runtime/units.ts +4 -2
- package/src/runtime/workflow/coordinator.ts +1348 -0
- package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
- package/src/runtime/workflow/index.ts +25 -0
- package/src/runtime/workflow/markup-mode-policy.ts +98 -0
- package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
- package/src/runtime/workflow/metadata-persistence.ts +306 -0
- package/src/runtime/workflow/metadata-writer.ts +123 -0
- package/src/runtime/workflow/overlay-store.ts +690 -0
- package/src/runtime/workflow/projector.ts +127 -0
- package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
- package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
- package/src/runtime/workflow/rail/types.ts +198 -0
- package/src/runtime/workflow/scope-rail-composer.ts +39 -0
- package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
- package/src/runtime/workflow/scope-writer.ts +188 -0
- package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
- package/src/runtime/workflow/visibility-policy.ts +129 -0
- package/src/session/_sync-legacy.ts +66 -0
- package/src/session/export/embedded-reconstitute.ts +104 -0
- package/src/session/export/export-diagnostics.ts +85 -0
- package/src/session/export/export-validation.ts +110 -0
- package/src/session/export/index.ts +34 -0
- package/src/session/export/preservation-reattach.ts +30 -0
- package/src/session/export/serialize-dispatch.ts +165 -0
- package/src/session/export/stateful-export-pipeline.ts +432 -0
- package/src/session/export/stateful-export.ts +684 -0
- package/src/session/import/canonical-assembly.ts +227 -0
- package/src/session/import/diagnostics-session.ts +54 -0
- package/src/session/import/embedded-discovery.ts +225 -0
- package/src/session/import/embedded-offload.ts +337 -0
- package/src/session/import/import-diagnostics.ts +69 -0
- package/src/session/import/loader-types.ts +313 -0
- package/src/session/import/loader.ts +1834 -0
- package/src/session/import/normalize.ts +195 -0
- package/src/session/import/package-parts.ts +217 -0
- package/src/session/import/package-read.ts +195 -0
- package/src/session/import/parse-orchestration.ts +105 -0
- package/src/session/import/part-constants.ts +70 -0
- package/src/session/import/part-discovery.ts +94 -0
- package/src/session/import/preservation-index.ts +46 -0
- package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
- package/src/session/import/review-import.ts +508 -0
- package/src/session/import/styles-consolidation.ts +281 -0
- package/src/session/import/workflow-scope-import.ts +256 -0
- package/src/session/index.ts +37 -0
- package/src/session/session-state.ts +69 -0
- package/src/session/session.ts +532 -0
- package/src/session/shared/protection.ts +228 -0
- package/src/session/shared/session-utils.ts +82 -0
- package/src/session/types.ts +499 -0
- package/src/shell/chart-snapshots.ts +96 -0
- package/src/shell/media-previews.ts +85 -0
- package/src/shell/overlay-anchor-bridge.ts +53 -0
- package/src/shell/paste-adapter.ts +23 -0
- package/src/shell/ref-commands.ts +1697 -0
- package/src/shell/ref-utilities.ts +48 -0
- package/src/shell/search.ts +51 -0
- package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
- package/src/shell/ui-subscriber-channels.ts +81 -0
- package/src/shell/use-collab-sync.ts +116 -0
- package/src/ui/WordReviewEditor.tsx +496 -2051
- package/src/ui/editor-shell-view.tsx +30 -1
- package/src/ui/editor-surface-controller.tsx +49 -1
- package/src/ui/headless/revision-decoration-model.ts +83 -0
- package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
- package/src/ui/headless/scoped-chrome-policy.ts +2 -2
- package/src/ui/headless/selection-tool-context.ts +1 -1
- package/src/ui/headless/selection-tool-resolver.ts +1 -1
- package/src/ui/runtime-shortcut-dispatch.ts +46 -1
- package/src/ui/ui-controller-factory.ts +221 -0
- package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
- package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
- package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
- package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
- package/src/ui-tailwind/chart/render/area.tsx +3 -3
- package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
- package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
- package/src/ui-tailwind/chart/render/combo.tsx +2 -2
- package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
- package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
- package/src/ui-tailwind/chart/render/line.tsx +3 -3
- package/src/ui-tailwind/chart/render/pie.tsx +6 -6
- package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
- package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
- package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
- package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
- package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
- package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
- package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
- package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
- package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
- package/src/ui-tailwind/debug/README.md +57 -0
- package/src/ui-tailwind/debug/index.ts +3 -0
- package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
- package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
- package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
- package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
- package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
- package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
- package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
- package/src/ui-tailwind/index.ts +0 -5
- package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
- package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
- package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
- package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
- package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
- package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
- package/src/ui-tailwind/review-workspace/types.ts +408 -0
- package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
- package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
- package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
- package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
- package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
- package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
- package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
- package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
- package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
- package/src/ui-tailwind/theme/editor-theme.css +25 -0
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
- package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
- package/src/ui-tailwind/ui-api-context.tsx +43 -0
- package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
- package/src/validation/compatibility-engine.ts +6 -6
- package/src/runtime/styles-cascade.ts +0 -33
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
- /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
- /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
- /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
|
@@ -48,6 +48,14 @@
|
|
|
48
48
|
|
|
49
49
|
import * as React from "react";
|
|
50
50
|
import type { WordReviewEditorLayoutFacet } from "../../api/public-types";
|
|
51
|
+
import { incrementInvalidationCounter } from "../editor-surface/perf-probe";
|
|
52
|
+
import {
|
|
53
|
+
resolvePageOverlayRectsFromGeometry as resolvePageOverlayRectsFromGeometryImpl,
|
|
54
|
+
type GeometryFacet,
|
|
55
|
+
type OverlayVisiblePageIndexRange,
|
|
56
|
+
} from "../../runtime/geometry/index.ts";
|
|
57
|
+
import type { ApiV3Ui } from "../../api/v3/ui";
|
|
58
|
+
import { useUiApi } from "../ui-api-context";
|
|
51
59
|
|
|
52
60
|
// ---------------------------------------------------------------------------
|
|
53
61
|
// Measurement
|
|
@@ -394,6 +402,22 @@ function resolveOffsetHeight(widget: HTMLElement): number {
|
|
|
394
402
|
export interface TwPageStackOverlayLayerProps {
|
|
395
403
|
/** Layout facet — source of the page count. */
|
|
396
404
|
facet: WordReviewEditorLayoutFacet;
|
|
405
|
+
/**
|
|
406
|
+
* Geometry facet — source of per-page rects when the render kernel has
|
|
407
|
+
* produced a frame (refactor/05 Slice 3b). When provided and
|
|
408
|
+
* `geometryFacet.getPage(0)` resolves, the overlay reads page rects
|
|
409
|
+
* directly from the kernel frame (tagged `space: "frame"`, which
|
|
410
|
+
* coincides with the overlay root's coordinate space — the overlay is
|
|
411
|
+
* a direct child of `wre-page-surface` at z-0 per v22 N1). This
|
|
412
|
+
* eliminates the overlay's G2 violation entirely for the warm path.
|
|
413
|
+
*
|
|
414
|
+
* When omitted, or when `getPage(0)` returns null (cold-open, before
|
|
415
|
+
* first render frame), the overlay falls back to the DOM-measurement
|
|
416
|
+
* path via `measureWidgetsViaBoundingRect` /
|
|
417
|
+
* `measureWidgetsViaOffsetChain` — preserved as the cold-open seam per
|
|
418
|
+
* architecture 05 Slice 3 exit criteria.
|
|
419
|
+
*/
|
|
420
|
+
geometryFacet?: GeometryFacet;
|
|
397
421
|
/** Scroll root element whose page-boundary widgets drive measurement. */
|
|
398
422
|
scrollRoot: HTMLElement | null;
|
|
399
423
|
/**
|
|
@@ -407,6 +431,76 @@ export interface TwPageStackOverlayLayerProps {
|
|
|
407
431
|
"data-testid"?: string;
|
|
408
432
|
}
|
|
409
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Slice 3b · Re-export of the pure geometry-projection helper that now
|
|
436
|
+
* lives in `src/runtime/geometry/overlay-rects.ts`. The `L05` layer
|
|
437
|
+
* owns the projection math; the overlay component re-exports from this
|
|
438
|
+
* module for back-compat with existing imports.
|
|
439
|
+
*
|
|
440
|
+
* Known coordinate-space caveat documented in
|
|
441
|
+
* `src/runtime/geometry/overlay-rects.ts` — the kernel's page-stacking
|
|
442
|
+
* gap (16 px) diverges from the DOM chrome's inter-page gap (48 px).
|
|
443
|
+
* Until Slice 3c reconciles them, production consumers should not pass
|
|
444
|
+
* a `geometryFacet` to this overlay — the DOM-measurement path remains
|
|
445
|
+
* the default.
|
|
446
|
+
*/
|
|
447
|
+
export const resolvePageOverlayRectsFromGeometry =
|
|
448
|
+
resolvePageOverlayRectsFromGeometryImpl;
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* DS-C2 (designsystem.md §8.8.1 "Page / ruler / header-footer bands"
|
|
452
|
+
* row) — resolve per-page overlay rects via `ui.overlays.getAnchor` so
|
|
453
|
+
* the overlay's primary read seam is the public UI API, not the
|
|
454
|
+
* geometry facet directly. Returns `null` when `ui` cannot resolve the
|
|
455
|
+
* first page (cold-open or no controller bound); caller falls back to
|
|
456
|
+
* the geometry-facet / DOM paths below.
|
|
457
|
+
*
|
|
458
|
+
* `pageIds` is supplied by the caller when available (from the
|
|
459
|
+
* geometry facet's `getPage(i).pageId` metadata). When absent, the
|
|
460
|
+
* helper synthesizes `page-${index}` ids for the React `key=` slot —
|
|
461
|
+
* stable within a run, unstable across reloads. The L10 follow-up
|
|
462
|
+
* ticket on `ui.overlays` page-id enumeration (see
|
|
463
|
+
* `cross-layer-coord-10.md §1.7`) retires the synthesis path.
|
|
464
|
+
*/
|
|
465
|
+
export function resolvePageOverlayRectsFromUiApi(
|
|
466
|
+
ui: ApiV3Ui,
|
|
467
|
+
pageCount: number,
|
|
468
|
+
visiblePageIndexRange: VisiblePageIndexRange | null | undefined,
|
|
469
|
+
pageIds: readonly string[] | null,
|
|
470
|
+
): readonly PageOverlayRect[] | null {
|
|
471
|
+
if (pageCount <= 0) return [];
|
|
472
|
+
const firstAnchor = ui.overlays.getAnchor({ kind: "page", value: 0 });
|
|
473
|
+
if (!firstAnchor) return null;
|
|
474
|
+
const start = visiblePageIndexRange?.start ?? 0;
|
|
475
|
+
const end = Math.min(
|
|
476
|
+
visiblePageIndexRange?.end ?? pageCount,
|
|
477
|
+
pageCount,
|
|
478
|
+
);
|
|
479
|
+
// Flicker-remediation 2026-04-22 (all-or-nothing policy): a single
|
|
480
|
+
// missing visible-page anchor returns null so the caller falls
|
|
481
|
+
// through to the geometry/DOM path instead of rendering a partial
|
|
482
|
+
// rect set. Under the prior "skip missing rows" policy a transiently-
|
|
483
|
+
// unresolved anchor during relayout would drop the paper background
|
|
484
|
+
// for pages 2..N while page 1 stayed painted — visibly gray bands
|
|
485
|
+
// between white papers. Atomic resolution forces consistency.
|
|
486
|
+
const rects: PageOverlayRect[] = [];
|
|
487
|
+
for (let i = start; i < end; i += 1) {
|
|
488
|
+
const rect =
|
|
489
|
+
i === 0 ? firstAnchor : ui.overlays.getAnchor({ kind: "page", value: i });
|
|
490
|
+
if (!rect) {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
rects.push({
|
|
494
|
+
pageId: pageIds?.[i] ?? `page-${i}`,
|
|
495
|
+
pageIndex: i,
|
|
496
|
+
topPx: rect.topPx,
|
|
497
|
+
bottomPx: rect.topPx + rect.heightPx,
|
|
498
|
+
heightPx: rect.heightPx,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
return rects;
|
|
502
|
+
}
|
|
503
|
+
|
|
410
504
|
/**
|
|
411
505
|
* The layer itself. Renders one decorative `<div>` per page with the
|
|
412
506
|
* same card-shadow + rounded border treatment that `.wre-page-chrome`
|
|
@@ -417,12 +511,34 @@ export interface TwPageStackOverlayLayerProps {
|
|
|
417
511
|
*/
|
|
418
512
|
export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = ({
|
|
419
513
|
facet,
|
|
514
|
+
geometryFacet,
|
|
420
515
|
scrollRoot,
|
|
421
516
|
renderFrameRevision,
|
|
422
517
|
visiblePageIndexRange,
|
|
423
518
|
"data-testid": testId,
|
|
424
519
|
}) => {
|
|
425
|
-
|
|
520
|
+
// DS-C2 — prefer `ui.overlays.getAnchor({ kind: "page", ... })` as
|
|
521
|
+
// the page-rect read seam when a `UiApiProvider` is mounted. Returns
|
|
522
|
+
// null here when headless / off-provider; the overlay then falls
|
|
523
|
+
// through to the existing geometry-facet / DOM paths.
|
|
524
|
+
const ui = useUiApi();
|
|
525
|
+
// Flicker-remediation 2026-04-22: compute initial rects synchronously
|
|
526
|
+
// from the geometry facet when the kernel is already warm, so the
|
|
527
|
+
// first paint has correct paper cards instead of an empty overlay
|
|
528
|
+
// that only populates after `useEffect` ticks. Cold-open paths where
|
|
529
|
+
// `geometryFacet` isn't passed / returns null still fall back to
|
|
530
|
+
// the empty initial state + the fallback paper rendered below.
|
|
531
|
+
const [rects, setRects] = React.useState<readonly PageOverlayRect[]>(() => {
|
|
532
|
+
if (!geometryFacet) return [];
|
|
533
|
+
const pageCount = facet.getPageCount();
|
|
534
|
+
if (pageCount <= 0) return [];
|
|
535
|
+
const warm = resolvePageOverlayRectsFromGeometry(
|
|
536
|
+
geometryFacet,
|
|
537
|
+
pageCount,
|
|
538
|
+
visiblePageIndexRange,
|
|
539
|
+
);
|
|
540
|
+
return warm ?? [];
|
|
541
|
+
});
|
|
426
542
|
// P3.d fix: the overlay root acts as the **measurement origin** so
|
|
427
543
|
// widget `topPx` / `bottomPx` are expressed in the exact coordinate
|
|
428
544
|
// space the overlay paints in. Using `scrollRoot` as origin (P3.b
|
|
@@ -457,6 +573,61 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
|
|
|
457
573
|
}
|
|
458
574
|
const origin = overlayRootRef.current;
|
|
459
575
|
const pageCount = facet.getPageCount();
|
|
576
|
+
|
|
577
|
+
// DS-C2 — first try the UI API seam so presentation code does not
|
|
578
|
+
// reach into the geometry facet directly. Page-ids come from the
|
|
579
|
+
// geometry facet when the caller forwarded one; synthesized
|
|
580
|
+
// otherwise. When `ui.overlays.getAnchor` returns null for page 0
|
|
581
|
+
// the geometry-direct and DOM paths below still run.
|
|
582
|
+
//
|
|
583
|
+
// §4.10 telemetry (2026-04-23) — the all-or-nothing resolution
|
|
584
|
+
// policy above is correct but unprobed. `overlay.page.ui_api.hit`
|
|
585
|
+
// increments when the UI-API path resolves the full visible-range;
|
|
586
|
+
// `overlay.page.ui_api.fallthrough` increments when the path
|
|
587
|
+
// returns null and we continue to the geometry/DOM fallback. The
|
|
588
|
+
// ratio lets a future bench assert fall-through stays below a
|
|
589
|
+
// threshold during steady-state typing (follow-up work — bench
|
|
590
|
+
// setup for F01/F08 typing scenarios is a separate task).
|
|
591
|
+
if (ui) {
|
|
592
|
+
const pageIds: string[] | null = geometryFacet
|
|
593
|
+
? Array.from({ length: pageCount }, (_, i) => {
|
|
594
|
+
const page = geometryFacet.getPage(i);
|
|
595
|
+
return page?.pageId ?? `page-${i}`;
|
|
596
|
+
})
|
|
597
|
+
: null;
|
|
598
|
+
const uiRects = resolvePageOverlayRectsFromUiApi(
|
|
599
|
+
ui,
|
|
600
|
+
pageCount,
|
|
601
|
+
visiblePageIndexRange,
|
|
602
|
+
pageIds,
|
|
603
|
+
);
|
|
604
|
+
if (uiRects !== null) {
|
|
605
|
+
incrementInvalidationCounter("overlay.page.ui_api.hit");
|
|
606
|
+
setRects(uiRects);
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
incrementInvalidationCounter("overlay.page.ui_api.fallthrough");
|
|
610
|
+
} else {
|
|
611
|
+
incrementInvalidationCounter("overlay.page.ui_api.unavailable");
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Slice 3b: when the geometry facet resolves page 0 through the
|
|
615
|
+
// render kernel, read rects directly from the kernel frame — zero
|
|
616
|
+
// DOM measurement, zero forced layouts. The DOM path below remains
|
|
617
|
+
// for the cold-open window (first frame not yet emitted) and for
|
|
618
|
+
// wiring sites that haven't handed over a geometry facet.
|
|
619
|
+
if (geometryFacet) {
|
|
620
|
+
const geometryRects = resolvePageOverlayRectsFromGeometry(
|
|
621
|
+
geometryFacet,
|
|
622
|
+
pageCount,
|
|
623
|
+
visiblePageIndexRange,
|
|
624
|
+
);
|
|
625
|
+
if (geometryRects !== null) {
|
|
626
|
+
setRects(geometryRects);
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
460
631
|
if (origin) {
|
|
461
632
|
const widgets = measureWidgetsViaBoundingRect(scrollRoot, origin, {
|
|
462
633
|
pageCount,
|
|
@@ -486,7 +657,7 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
|
|
|
486
657
|
}),
|
|
487
658
|
);
|
|
488
659
|
}
|
|
489
|
-
}, [facet, scrollRoot, visiblePageIndexRange]);
|
|
660
|
+
}, [facet, geometryFacet, scrollRoot, ui, visiblePageIndexRange]);
|
|
490
661
|
|
|
491
662
|
const refreshRects = React.useCallback(() => {
|
|
492
663
|
if (!scrollRoot) {
|
|
@@ -597,6 +768,16 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
|
|
|
597
768
|
// frames until the next `renderFrameRevision` tick. Keeping the
|
|
598
769
|
// root element present + empty is cheap (one `<div>`) and makes the
|
|
599
770
|
// ref resolve during the first layout-effect pass.
|
|
771
|
+
//
|
|
772
|
+
// Flicker-remediation 2026-04-22: when rects are not yet available
|
|
773
|
+
// (cold-open; geometry facet has no kernel yet; DOM not measured),
|
|
774
|
+
// paint a full-area paper-color fallback card so the user sees a
|
|
775
|
+
// white page rather than the gray workspace canvas flashing through.
|
|
776
|
+
// The fallback uses the same paper chrome (bg / border / shadow /
|
|
777
|
+
// radius) as individual page cards, rendered as `inset-0` so it
|
|
778
|
+
// spans whatever region the scroll root currently occupies. When
|
|
779
|
+
// `rects` populates on the next refresh pass the fallback is
|
|
780
|
+
// replaced by N discrete cards.
|
|
600
781
|
if (rects.length === 0) {
|
|
601
782
|
return (
|
|
602
783
|
<div
|
|
@@ -605,7 +786,20 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
|
|
|
605
786
|
aria-hidden="true"
|
|
606
787
|
data-testid={testId ?? "page-stack-overlay"}
|
|
607
788
|
data-page-count="0"
|
|
608
|
-
|
|
789
|
+
data-fallback-paper="true"
|
|
790
|
+
>
|
|
791
|
+
<div
|
|
792
|
+
className="wre-page-stack-overlay-frame wre-page-stack-overlay-frame--fallback absolute inset-0"
|
|
793
|
+
aria-hidden="true"
|
|
794
|
+
style={{
|
|
795
|
+
backgroundColor: "var(--color-page-bg, white)",
|
|
796
|
+
border: "1px solid var(--color-page-border, rgba(148,163,184,0.2))",
|
|
797
|
+
borderRadius: "var(--radius-page, 4px)",
|
|
798
|
+
boxShadow:
|
|
799
|
+
"0 8px 24px -20px var(--color-page-shadow, rgba(15,23,42,0.38))",
|
|
800
|
+
}}
|
|
801
|
+
/>
|
|
802
|
+
</div>
|
|
609
803
|
);
|
|
610
804
|
}
|
|
611
805
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type { RenderBlockDecoration } from "../../
|
|
2
|
+
import type { RenderBlockDecoration } from "../../api/public-types.ts";
|
|
3
3
|
import { AUTHOR_PALETTE } from "../../ui/headless/revision-decoration-model";
|
|
4
4
|
|
|
5
5
|
const BAR_WIDTH_PX = 3;
|
|
@@ -24,21 +24,33 @@ import {
|
|
|
24
24
|
type OverlayCoordinateSpace,
|
|
25
25
|
} from "./chrome-overlay-projector";
|
|
26
26
|
import { TwScopeCard } from "./tw-scope-card";
|
|
27
|
+
import { useLocalSurfaceRequest } from "../chrome/local-surface-arbiter";
|
|
27
28
|
import type {
|
|
28
29
|
EditorRole,
|
|
29
30
|
ScopeCardModel,
|
|
30
31
|
ScopeIssueAction,
|
|
31
32
|
WorkflowScopeMode,
|
|
32
33
|
} from "../../api/public-types";
|
|
33
|
-
import type { RenderFrameRect } from "../../
|
|
34
|
-
import type { WordReviewEditorLayoutFacet } from "../../
|
|
34
|
+
import type { RenderFrameRect } from "../../api/public-types.ts";
|
|
35
|
+
import type { WordReviewEditorLayoutFacet } from "../../api/public-types.ts";
|
|
36
|
+
import type { WorkflowFacet } from "../../api/public-types.ts";
|
|
35
37
|
|
|
36
38
|
// ---------------------------------------------------------------------------
|
|
37
39
|
// Types
|
|
38
40
|
// ---------------------------------------------------------------------------
|
|
39
41
|
|
|
40
42
|
export interface TwScopeCardLayerProps {
|
|
43
|
+
/**
|
|
44
|
+
* Layout facet — still required for `getRenderFrame()` etc. Scope-
|
|
45
|
+
* card data now flows through `workflowFacet` per Layer-06 Slice 4.
|
|
46
|
+
*/
|
|
41
47
|
facet: WordReviewEditorLayoutFacet;
|
|
48
|
+
/**
|
|
49
|
+
* Workflow facet — canonical source of scope card models
|
|
50
|
+
* (`runtime.workflow.getAllScopeCardModels()`). `null` is treated as
|
|
51
|
+
* "no cards".
|
|
52
|
+
*/
|
|
53
|
+
workflowFacet: WorkflowFacet | null;
|
|
42
54
|
activeScopeId: string | null;
|
|
43
55
|
onClose: () => void;
|
|
44
56
|
onModeChange: (scopeId: string, mode: WorkflowScopeMode) => void;
|
|
@@ -77,6 +89,7 @@ const CARD_FALLBACK_TOP_PX = 16;
|
|
|
77
89
|
|
|
78
90
|
export const TwScopeCardLayer: React.FC<TwScopeCardLayerProps> = ({
|
|
79
91
|
facet,
|
|
92
|
+
workflowFacet,
|
|
80
93
|
activeScopeId,
|
|
81
94
|
onClose,
|
|
82
95
|
onModeChange,
|
|
@@ -106,10 +119,7 @@ export const TwScopeCardLayer: React.FC<TwScopeCardLayerProps> = ({
|
|
|
106
119
|
// The effective scope is the pinned one if it still resolves to a
|
|
107
120
|
// model, else the active one. When a pinned scope disappears
|
|
108
121
|
// (e.g. the host cleared the overlay), drop the pin.
|
|
109
|
-
const models =
|
|
110
|
-
typeof facet.getAllScopeCardModels === "function"
|
|
111
|
-
? facet.getAllScopeCardModels()
|
|
112
|
-
: [];
|
|
122
|
+
const models = workflowFacet?.getAllScopeCardModels() ?? [];
|
|
113
123
|
|
|
114
124
|
const pinnedModel = pinnedScopeId
|
|
115
125
|
? models.find((m) => m.scopeId === pinnedScopeId) ?? null
|
|
@@ -128,10 +138,29 @@ export const TwScopeCardLayer: React.FC<TwScopeCardLayerProps> = ({
|
|
|
128
138
|
}, [pinnedScopeId, models]);
|
|
129
139
|
|
|
130
140
|
const effectiveScopeId = pinnedModel ? pinnedScopeId : activeScopeId;
|
|
141
|
+
const isPinnedEffective = pinnedScopeId !== null && pinnedScopeId === effectiveScopeId;
|
|
142
|
+
|
|
143
|
+
// Phase F.3 — request the scope-card slot from the shared arbiter.
|
|
144
|
+
// Pinned scope cards go into the orthogonal pinned slot so the rail
|
|
145
|
+
// (or a peer surface) can coexist; non-pinned scope cards take the
|
|
146
|
+
// single active slot at priority 7 and displace every lower peer.
|
|
147
|
+
// The hook MUST be called unconditionally — pass `null` when no
|
|
148
|
+
// scope is effective, which is a safe no-op.
|
|
149
|
+
const isArbiterActive = useLocalSurfaceRequest(
|
|
150
|
+
effectiveScopeId
|
|
151
|
+
? {
|
|
152
|
+
kind: "scope-card",
|
|
153
|
+
id: effectiveScopeId,
|
|
154
|
+
pinned: isPinnedEffective,
|
|
155
|
+
}
|
|
156
|
+
: null,
|
|
157
|
+
);
|
|
158
|
+
|
|
131
159
|
if (!effectiveScopeId) return null;
|
|
132
160
|
const model: ScopeCardModel | undefined =
|
|
133
161
|
pinnedModel ?? models.find((m) => m.scopeId === effectiveScopeId);
|
|
134
162
|
if (!model) return null;
|
|
163
|
+
if (!isArbiterActive) return null;
|
|
135
164
|
|
|
136
165
|
const projectorSpace: OverlayCoordinateSpace =
|
|
137
166
|
space ?? { originLeftPx: 0, originTopPx: 0 };
|
|
@@ -17,17 +17,29 @@ import {
|
|
|
17
17
|
projectRectToOverlay,
|
|
18
18
|
type OverlayCoordinateSpace,
|
|
19
19
|
} from "./chrome-overlay-projector";
|
|
20
|
-
import type { RenderFrame, RenderFrameRect } from "../../
|
|
21
|
-
import type { ScopeRailSegment, ScopeRailPosture } from "../../
|
|
22
|
-
import type {
|
|
20
|
+
import type { RenderFrame, RenderFrameRect } from "../../api/public-types.ts";
|
|
21
|
+
import type { ScopeRailSegment, ScopeRailPosture } from "../../api/public-types.ts";
|
|
22
|
+
import type { WorkflowFacet } from "../../api/public-types.ts";
|
|
23
|
+
import type { GeometryFacet } from "../../api/public-types";
|
|
23
24
|
|
|
24
25
|
// ---------------------------------------------------------------------------
|
|
25
26
|
// Types
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
27
28
|
|
|
28
29
|
export interface TwScopeRailLayerProps {
|
|
29
|
-
/**
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Geometry facet — used for `getRenderFrame()`. Migrated from
|
|
32
|
+
* `facet: WordReviewEditorLayoutFacet` in refactor/05 cross-lane-coord
|
|
33
|
+
* §8.4 pass. Rail-segment + scope-card data flows through
|
|
34
|
+
* `workflowFacet` per Layer-06 Slice 4's seam inversion.
|
|
35
|
+
*/
|
|
36
|
+
geometryFacet: GeometryFacet;
|
|
37
|
+
/**
|
|
38
|
+
* Workflow facet — canonical source of scope rail segments + scope
|
|
39
|
+
* card models (`runtime.workflow.*`). Required for the layer to
|
|
40
|
+
* render anything; passing `null` makes the layer a no-op.
|
|
41
|
+
*/
|
|
42
|
+
workflowFacet: WorkflowFacet | null;
|
|
31
43
|
/** Overlay's coordinate space. Defaults to the overlay's own origin. */
|
|
32
44
|
space?: OverlayCoordinateSpace;
|
|
33
45
|
/** Horizontal pad (px) the rail gutter occupies to the left of body. */
|
|
@@ -80,7 +92,8 @@ const LABEL_WIDTH_PX = 40;
|
|
|
80
92
|
const STACK_OFFSET_PX = 6;
|
|
81
93
|
|
|
82
94
|
export const TwScopeRailLayer: React.FC<TwScopeRailLayerProps> = ({
|
|
83
|
-
|
|
95
|
+
geometryFacet,
|
|
96
|
+
workflowFacet,
|
|
84
97
|
space,
|
|
85
98
|
railLaneWidthPx = DEFAULT_RAIL_LANE_PX,
|
|
86
99
|
activeScopeId,
|
|
@@ -88,10 +101,8 @@ export const TwScopeRailLayer: React.FC<TwScopeRailLayerProps> = ({
|
|
|
88
101
|
onSegmentClick,
|
|
89
102
|
"data-testid": testId,
|
|
90
103
|
}) => {
|
|
91
|
-
const frame =
|
|
92
|
-
|
|
93
|
-
: null;
|
|
94
|
-
const segments = facet.getAllScopeRailSegments();
|
|
104
|
+
const frame = geometryFacet.getRenderFrame() ?? null;
|
|
105
|
+
const segments = workflowFacet?.getAllRailSegments() ?? [];
|
|
95
106
|
|
|
96
107
|
if (!frame || segments.length === 0) {
|
|
97
108
|
return null;
|
|
@@ -99,12 +110,9 @@ export const TwScopeRailLayer: React.FC<TwScopeRailLayerProps> = ({
|
|
|
99
110
|
|
|
100
111
|
// P2: which scopes currently have a `source: "ai"` candidate
|
|
101
112
|
// overlapping — drives the agent-pending shimmer class on their
|
|
102
|
-
// tints.
|
|
103
|
-
// shimmer logic lives in the runtime, not the overlay.
|
|
104
|
-
const cardModels =
|
|
105
|
-
typeof facet.getAllScopeCardModels === "function"
|
|
106
|
-
? facet.getAllScopeCardModels()
|
|
107
|
-
: [];
|
|
113
|
+
// tints. Reads from the workflow facet's card-model projection so the
|
|
114
|
+
// shimmer logic lives in the Layer-06 runtime, not the overlay.
|
|
115
|
+
const cardModels = workflowFacet?.getAllScopeCardModels() ?? [];
|
|
108
116
|
const agentPendingByScope = new Map<string, boolean>();
|
|
109
117
|
for (const model of cardModels) {
|
|
110
118
|
if (model.agentPending) {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import React from "react";
|
|
13
13
|
import type { SurfaceTableRowSnapshot } from "../../api/public-types.ts";
|
|
14
|
-
import type { WordReviewEditorLayoutFacet } from "../../
|
|
14
|
+
import type { WordReviewEditorLayoutFacet } from "../../api/public-types.ts";
|
|
15
15
|
|
|
16
16
|
export interface TwTableContinuationHeaderProps {
|
|
17
17
|
blockId: string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Phase Q — Debug UX (reserved)
|
|
2
|
+
|
|
3
|
+
Target for the runtime-embedded debug UX consumed through `ui.debug.attach()`
|
|
4
|
+
(layer 10, refactor/10 Slice 5). This directory is **reserved** — the Slice 5
|
|
5
|
+
ship includes the UI API substrate (`src/api/v3/ui/debug.ts` +
|
|
6
|
+
`UiController.attachDebug` hook), while the React presentation components +
|
|
7
|
+
the public `debugMode` prop + the visibility invariant test are a **Phase Q
|
|
8
|
+
follow-up** per `docs/plans/refactor/10-ui-api.md` Risk #3:
|
|
9
|
+
|
|
10
|
+
> **Phase Q UX surface area.** `src/ui-tailwind/debug/**` is a new substantial
|
|
11
|
+
> UI surface. *Mitigation:* ship substrate in M4 Slice 5; polish in follow-up.
|
|
12
|
+
|
|
13
|
+
## Planned files (follow-up)
|
|
14
|
+
|
|
15
|
+
| File | Purpose |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `tw-debug-top-bar.tsx` | Minimal top bar when `debugMode: "top-bar"` — document hash, scope count, invalidation counter |
|
|
18
|
+
| `tw-debug-overlay.tsx` | Full overlay when `debugMode: "full"` — renders `DebugInspectorSnapshot` sections |
|
|
19
|
+
| `tw-debug-repl.tsx` | REPL with `api`, `runtime`, `debug` in scope; localStorage-persisted history |
|
|
20
|
+
| `tw-debug-event-tail.tsx` | Tail of the last N events on active telemetry channels |
|
|
21
|
+
| `keybindings.ts` | Cmd/Ctrl+Shift+D toggles top-bar ↔ full |
|
|
22
|
+
|
|
23
|
+
## Planned prop (follow-up)
|
|
24
|
+
|
|
25
|
+
Add `debugMode?: "off" | "top-bar" | "full"` to `WordReviewEditorProps`.
|
|
26
|
+
**Default MUST be `"off"`** per CLAUDE.md Protected Invariants § "Phase Q
|
|
27
|
+
placeholder" — this default has regressed multiple times in predecessor
|
|
28
|
+
surfaces (`showUnsupportedObjectPreviews`, `unsupportedPreviewsPolicy`).
|
|
29
|
+
|
|
30
|
+
## Planned test (follow-up)
|
|
31
|
+
|
|
32
|
+
`test/ui/debug-mode-visibility-invariant.test.ts` — asserts:
|
|
33
|
+
- `debugMode: "off"` → no debug UI renders
|
|
34
|
+
- `debugMode: "top-bar"` → only the top bar renders
|
|
35
|
+
- `debugMode: "full"` → overlay renders
|
|
36
|
+
|
|
37
|
+
## How Slice 5 consumers wire today
|
|
38
|
+
|
|
39
|
+
Until the Phase Q React components land, Slice 5 ships only the contract:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { createUiApi } from "@beyondwork/docx-react-component/api/v3/ui";
|
|
43
|
+
|
|
44
|
+
const ui = createUiApi(handle);
|
|
45
|
+
ui.session.bind({
|
|
46
|
+
kind: "runtime-direct",
|
|
47
|
+
id: "my-mount",
|
|
48
|
+
attachDebug(session) {
|
|
49
|
+
// bind-side: wire runtime.debug.bus + getSnapshot to your debug surface
|
|
50
|
+
const off = runtime.debug.bus.on(/* ... */, (evt) => {/* render */});
|
|
51
|
+
return () => off();
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
const attachment = ui.debug.attach({ id: "s1", channels: ["api", "render"] });
|
|
55
|
+
// later:
|
|
56
|
+
attachment.detach();
|
|
57
|
+
```
|