@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
|
@@ -27,6 +27,7 @@ import type {
|
|
|
27
27
|
TableStructureContextSnapshot,
|
|
28
28
|
WordReviewEditorLayoutFacet,
|
|
29
29
|
} from "../../api/public-types";
|
|
30
|
+
import type { GeometryFacet } from "../../api/public-types";
|
|
30
31
|
import type { OverlayCoordinateSpace } from "../chrome-overlay/chrome-overlay-projector";
|
|
31
32
|
import { projectRectToOverlay } from "../chrome-overlay/chrome-overlay-projector";
|
|
32
33
|
import { DEFAULT_PX_PER_TWIP } from "../../runtime/render/render-frame-types";
|
|
@@ -39,7 +40,19 @@ const MIN_COLUMN_TWIPS = 720;
|
|
|
39
40
|
const MIN_ROW_TWIPS = 120;
|
|
40
41
|
|
|
41
42
|
export interface TwTableGripLayerProps {
|
|
43
|
+
/**
|
|
44
|
+
* Layout facet — still used for layout-semantic reads
|
|
45
|
+
* (`getFirstPageIndexForBlock`, `getTableRenderPlan`). These stay
|
|
46
|
+
* on the layout facet per architecture-04 (twip-valued,
|
|
47
|
+
* page-graph-derived data, not pixel geometry).
|
|
48
|
+
*/
|
|
42
49
|
facet: WordReviewEditorLayoutFacet;
|
|
50
|
+
/**
|
|
51
|
+
* Geometry facet — used for render-frame + zoom access. Migrated
|
|
52
|
+
* from `facet.getRenderFrame` / `facet.getRenderZoom` in the
|
|
53
|
+
* refactor/05 cross-lane-coord §8.4 pass.
|
|
54
|
+
*/
|
|
55
|
+
geometryFacet: GeometryFacet;
|
|
43
56
|
tableContext: TableStructureContextSnapshot | null;
|
|
44
57
|
space?: OverlayCoordinateSpace;
|
|
45
58
|
disabled?: boolean;
|
|
@@ -53,6 +66,7 @@ export interface TwTableGripLayerProps {
|
|
|
53
66
|
|
|
54
67
|
export function TwTableGripLayer({
|
|
55
68
|
facet,
|
|
69
|
+
geometryFacet,
|
|
56
70
|
tableContext,
|
|
57
71
|
space,
|
|
58
72
|
disabled,
|
|
@@ -61,10 +75,7 @@ export function TwTableGripLayer({
|
|
|
61
75
|
}: TwTableGripLayerProps) {
|
|
62
76
|
if (!tableContext) return null;
|
|
63
77
|
|
|
64
|
-
const frame =
|
|
65
|
-
typeof facet.getRenderFrame === "function"
|
|
66
|
-
? (facet.getRenderFrame() ?? null)
|
|
67
|
-
: null;
|
|
78
|
+
const frame = geometryFacet.getRenderFrame() ?? null;
|
|
68
79
|
if (!frame) return null;
|
|
69
80
|
|
|
70
81
|
const blockId = `table-${tableContext.tableBlockIndex}`;
|
|
@@ -72,10 +83,7 @@ export function TwTableGripLayer({
|
|
|
72
83
|
const plan = facet.getTableRenderPlan(blockId, pageIndex);
|
|
73
84
|
if (!plan) return null;
|
|
74
85
|
|
|
75
|
-
const pxPerTwip =
|
|
76
|
-
typeof facet.getRenderZoom === "function"
|
|
77
|
-
? (facet.getRenderZoom()?.pxPerTwip ?? DEFAULT_PX_PER_TWIP)
|
|
78
|
-
: DEFAULT_PX_PER_TWIP;
|
|
86
|
+
const pxPerTwip = geometryFacet.getRenderZoom()?.pxPerTwip ?? DEFAULT_PX_PER_TWIP;
|
|
79
87
|
|
|
80
88
|
return (
|
|
81
89
|
<>
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TwWorkspaceChromeHost — composition-level mount that wires together:
|
|
3
|
+
* - the right-click context menu (portal-based, viewport-clamped)
|
|
4
|
+
* - the global command palette (Ctrl/Cmd+K)
|
|
5
|
+
* - the shared editor-action registry
|
|
6
|
+
*
|
|
7
|
+
* Per DESIGN-EDITOR.md §6.4 the three access routes (right-click,
|
|
8
|
+
* inline "More…" buttons shipped in Phase D, and command palette)
|
|
9
|
+
* all read from the same registry so they cannot diverge. This
|
|
10
|
+
* component is the single mount point that routes all three.
|
|
11
|
+
*
|
|
12
|
+
* Progressive-disclosure discipline (designsystem.md §2.1 principle 4):
|
|
13
|
+
* - Context menu opens only on user right-click and closes on
|
|
14
|
+
* Escape, outside-click, or row selection.
|
|
15
|
+
* - Menu is suppressed when no wired callback would produce at
|
|
16
|
+
* least one entry — no empty menus.
|
|
17
|
+
* - Command palette opens only on Ctrl/Cmd+K and fuzzy-matches
|
|
18
|
+
* across the same registry.
|
|
19
|
+
* - All surfaces dismiss themselves (run → dismiss) so focus
|
|
20
|
+
* returns to the editor immediately after an action fires.
|
|
21
|
+
*
|
|
22
|
+
* Host-side contract (TwReviewWorkspaceProps will thread this in):
|
|
23
|
+
* - `editorActionHost`: callback bag wired from ref methods
|
|
24
|
+
* (WordReviewEditorRef) that the shared registry dispatches to.
|
|
25
|
+
* Actions without a wired callback are hidden from every access
|
|
26
|
+
* route.
|
|
27
|
+
* - `mode`: current ChromeComposition.mode — drives mode-filtered
|
|
28
|
+
* actions (e.g. scope-only actions hide in edit mode).
|
|
29
|
+
* - `onContextMenuRequest` is the handler hosts pass into
|
|
30
|
+
* `tw-prosemirror-surface`'s command-bridge callback.
|
|
31
|
+
*
|
|
32
|
+
* Perf invariants honored:
|
|
33
|
+
* - No DOM reads on the edit path (invariant 7).
|
|
34
|
+
* - No PM-transaction subscriptions.
|
|
35
|
+
* - Portal mounts only while open (invariant 4).
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import React, { useImperativeHandle, useMemo, useRef } from "react";
|
|
39
|
+
|
|
40
|
+
import type {
|
|
41
|
+
EditorChromeMode,
|
|
42
|
+
EditorRailTab,
|
|
43
|
+
} from "../../api/v3/ui/chrome-composition";
|
|
44
|
+
import type {
|
|
45
|
+
EditorActionHostCallbacks,
|
|
46
|
+
TargetKind,
|
|
47
|
+
} from "./editor-action-registry";
|
|
48
|
+
import { buildPaletteGroupsFromRegistry } from "./editor-actions-to-palette";
|
|
49
|
+
import { TwCommandPaletteMount } from "./tw-command-palette-mount";
|
|
50
|
+
import { TwContextMenuPortal } from "./tw-context-menu-portal";
|
|
51
|
+
import {
|
|
52
|
+
useContextMenuController,
|
|
53
|
+
type ContextMenuRequest,
|
|
54
|
+
} from "./use-context-menu-controller";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build a stable host-callbacks proxy that always reads from the
|
|
58
|
+
* supplied ref. Pattern mirrors `callbacksRef` in
|
|
59
|
+
* `src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx:370–408`:
|
|
60
|
+
* the owning component sync-writes `hostRef.current = freshProps` at
|
|
61
|
+
* the top of every render, and consumers read through this proxy so
|
|
62
|
+
* they see the latest callbacks without the proxy identity ever
|
|
63
|
+
* changing. That stability lets the palette + registry + controller
|
|
64
|
+
* memo their outputs on (mode, proxy) — (mode) in practice, since the
|
|
65
|
+
* proxy is static per component lifetime.
|
|
66
|
+
*/
|
|
67
|
+
function createStableHostProxy(
|
|
68
|
+
hostRef: { current: EditorActionHostCallbacks },
|
|
69
|
+
): EditorActionHostCallbacks {
|
|
70
|
+
// Proxy construction is ~free and happens exactly once per component
|
|
71
|
+
// lifetime (see the empty-dep useMemo call site below). The `get`
|
|
72
|
+
// trap forwards to whichever callback the host currently has.
|
|
73
|
+
return new Proxy({} as EditorActionHostCallbacks, {
|
|
74
|
+
get: (_target, prop) => {
|
|
75
|
+
// Only read declared keys — filter `Symbol.toPrimitive` etc. so
|
|
76
|
+
// `typeof host[key] === "function"` checks elsewhere behave
|
|
77
|
+
// predictably.
|
|
78
|
+
if (typeof prop !== "string") return undefined;
|
|
79
|
+
return (hostRef.current as Record<string, unknown>)[prop];
|
|
80
|
+
},
|
|
81
|
+
has: (_target, prop) => {
|
|
82
|
+
if (typeof prop !== "string") return false;
|
|
83
|
+
return prop in (hostRef.current as Record<string, unknown>);
|
|
84
|
+
},
|
|
85
|
+
// `ownKeys` + `getOwnPropertyDescriptor` left default — iteration
|
|
86
|
+
// over the proxy isn't part of the registry contract.
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface TwWorkspaceChromeHostProps {
|
|
91
|
+
/** Current composition mode; filters mode-scoped actions. */
|
|
92
|
+
mode: EditorChromeMode;
|
|
93
|
+
/**
|
|
94
|
+
* Callback bag for shared editor actions. Actions whose callback is
|
|
95
|
+
* absent are hidden from every surface (progressive disclosure).
|
|
96
|
+
*/
|
|
97
|
+
editorActionHost: EditorActionHostCallbacks;
|
|
98
|
+
/**
|
|
99
|
+
* Optional scope root for target-kind resolution. Traversal stops
|
|
100
|
+
* here so right-click on a scope card doesn't walk into the shell.
|
|
101
|
+
*/
|
|
102
|
+
surfaceRoot?: Element | null;
|
|
103
|
+
/**
|
|
104
|
+
* Suppress the global Ctrl+K listener (e.g. while a higher-priority
|
|
105
|
+
* modal captures keyboard focus).
|
|
106
|
+
*/
|
|
107
|
+
paletteDisabled?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* When defined, the host routes keyboard Shift+F10 + "More…" button
|
|
110
|
+
* invocations here. Typically just the workspace's `contextMenuRef`
|
|
111
|
+
* — wiring below.
|
|
112
|
+
*/
|
|
113
|
+
controllerRef?: React.Ref<TwWorkspaceChromeHostController>;
|
|
114
|
+
/**
|
|
115
|
+
* Element to return focus to when the menu/palette closes. Usually
|
|
116
|
+
* the PM editor surface so typing resumes where it left off.
|
|
117
|
+
*/
|
|
118
|
+
returnFocusTo?: HTMLElement | null;
|
|
119
|
+
/**
|
|
120
|
+
* Host-supplied callback invoked when another chrome surface asks the
|
|
121
|
+
* rail to pivot to a specific tab — Phase E uses this for the signal-
|
|
122
|
+
* only diagnostics button (opens `"health"`) and the alert-banner's
|
|
123
|
+
* "Show detail" handoff. Hosts typically implement it by opening the
|
|
124
|
+
* rail drawer and forwarding `tab` to the rail's active-tab change
|
|
125
|
+
* handler. Omitting the prop turns `controller.openRailTab` into a
|
|
126
|
+
* no-op so hosts that haven't opted in see no behavior change.
|
|
127
|
+
*/
|
|
128
|
+
onOpenRailTab?: (tab: EditorRailTab, itemId?: string) => void;
|
|
129
|
+
/**
|
|
130
|
+
* Optional live table-structure context (Chrome Closure Pass · Task 3).
|
|
131
|
+
* When supplied and the right-click target lands inside a table cell,
|
|
132
|
+
* the menu controller adds tier-specific kinds (`"table-row"` /
|
|
133
|
+
* `"table-column"` / `"table-whole"`) so the menu entries match the
|
|
134
|
+
* §6.9 tier ladder. Pass null when no table is active or the snapshot
|
|
135
|
+
* is unavailable.
|
|
136
|
+
*/
|
|
137
|
+
tableContext?: import("../../api/public-types").TableStructureContextSnapshot | null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Imperative surface exposed via `controllerRef` so the workspace can:
|
|
142
|
+
* - forward contextmenu events from the pm-command-bridge into the
|
|
143
|
+
* menu controller
|
|
144
|
+
* - open the menu at the current caret (Shift+F10 from the shortcut
|
|
145
|
+
* dispatcher)
|
|
146
|
+
* - open the menu with pre-resolved target kinds ("More…" buttons
|
|
147
|
+
* on demoted floating toolbars — Phase D)
|
|
148
|
+
*/
|
|
149
|
+
export interface TwWorkspaceChromeHostController {
|
|
150
|
+
handleContextMenuRequest: (request: ContextMenuRequest) => void;
|
|
151
|
+
openWithKinds: (args: {
|
|
152
|
+
clientX: number;
|
|
153
|
+
clientY: number;
|
|
154
|
+
kinds: readonly TargetKind[];
|
|
155
|
+
}) => void;
|
|
156
|
+
dismissContextMenu: () => void;
|
|
157
|
+
/**
|
|
158
|
+
* Ask the host to pivot the management rail to `tab`. The host
|
|
159
|
+
* implementation (typically `TwReviewWorkspace`) opens the rail drawer
|
|
160
|
+
* and calls `onActiveRailTabChange(tab)`. No-op when the host didn't
|
|
161
|
+
* supply `onOpenRailTab`.
|
|
162
|
+
*/
|
|
163
|
+
openRailTab: (tab: EditorRailTab, itemId?: string) => void;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function TwWorkspaceChromeHost(
|
|
167
|
+
props: TwWorkspaceChromeHostProps,
|
|
168
|
+
): React.JSX.Element {
|
|
169
|
+
const {
|
|
170
|
+
mode,
|
|
171
|
+
editorActionHost,
|
|
172
|
+
surfaceRoot,
|
|
173
|
+
paletteDisabled,
|
|
174
|
+
controllerRef,
|
|
175
|
+
returnFocusTo,
|
|
176
|
+
onOpenRailTab,
|
|
177
|
+
} = props;
|
|
178
|
+
|
|
179
|
+
// B1 fix — mirror the `callbacksRef` pattern in tw-prosemirror-surface
|
|
180
|
+
// so the host-callbacks proxy passed into the controller and the
|
|
181
|
+
// palette adapter stays referentially stable across renders, even
|
|
182
|
+
// when the integrator rebuilds `editorActionHost` inline on every
|
|
183
|
+
// parent render. Perf invariant 4: palette memo deps collapse to
|
|
184
|
+
// `[mode]` so wholesale-snapshot re-renders don't rebuild groups.
|
|
185
|
+
const hostRef = useRef<EditorActionHostCallbacks>(editorActionHost);
|
|
186
|
+
hostRef.current = editorActionHost;
|
|
187
|
+
const stableHost = useMemo(() => createStableHostProxy(hostRef), []);
|
|
188
|
+
|
|
189
|
+
const controller = useContextMenuController({
|
|
190
|
+
mode,
|
|
191
|
+
host: stableHost,
|
|
192
|
+
root: surfaceRoot ?? null,
|
|
193
|
+
...(props.tableContext !== undefined ? { tableContext: props.tableContext } : {}),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// N2 fix — imperative handle identity must be stable across the
|
|
197
|
+
// component lifetime so downstream effects that read controllerRef
|
|
198
|
+
// don't self-trigger on every menu state change. Ref-wrap each
|
|
199
|
+
// method, then bind to empty deps.
|
|
200
|
+
const requestRef = useRef(controller.request);
|
|
201
|
+
requestRef.current = controller.request;
|
|
202
|
+
const requestWithKindsRef = useRef(controller.requestWithKinds);
|
|
203
|
+
requestWithKindsRef.current = controller.requestWithKinds;
|
|
204
|
+
const dismissRef = useRef(controller.dismiss);
|
|
205
|
+
dismissRef.current = controller.dismiss;
|
|
206
|
+
// Phase E.0 — ref-sync the rail-tab callback so the imperative handle
|
|
207
|
+
// identity stays stable while still dispatching to the freshest host
|
|
208
|
+
// closure on every call. `undefined` is kept in the ref when the host
|
|
209
|
+
// omits the prop so `openRailTab` becomes a safe no-op.
|
|
210
|
+
const openRailTabRef = useRef<
|
|
211
|
+
((tab: EditorRailTab, itemId?: string) => void) | undefined
|
|
212
|
+
>(onOpenRailTab);
|
|
213
|
+
openRailTabRef.current = onOpenRailTab;
|
|
214
|
+
|
|
215
|
+
useImperativeHandle(
|
|
216
|
+
controllerRef,
|
|
217
|
+
() => ({
|
|
218
|
+
handleContextMenuRequest: (req) => requestRef.current(req),
|
|
219
|
+
openWithKinds: (args) => requestWithKindsRef.current(args),
|
|
220
|
+
dismissContextMenu: () => dismissRef.current(),
|
|
221
|
+
openRailTab: (tab, itemId) => {
|
|
222
|
+
openRailTabRef.current?.(tab, itemId);
|
|
223
|
+
},
|
|
224
|
+
}),
|
|
225
|
+
[],
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// Palette groups rebuild only on mode change — host-callback identity
|
|
229
|
+
// is pinned via `stableHost`. `dismiss` passed into the registry is
|
|
230
|
+
// a no-op here: TwCommandPalette closes itself via `onOpenChange`.
|
|
231
|
+
const paletteGroups = useMemo(
|
|
232
|
+
() =>
|
|
233
|
+
buildPaletteGroupsFromRegistry({
|
|
234
|
+
mode,
|
|
235
|
+
host: stableHost,
|
|
236
|
+
dismiss: noopDismiss,
|
|
237
|
+
}),
|
|
238
|
+
[mode, stableHost],
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// When the palette would be empty (no wired callbacks), we still
|
|
242
|
+
// mount the adapter so the Ctrl+K listener is consistent, but pass
|
|
243
|
+
// an empty-state message so users see "nothing here" rather than a
|
|
244
|
+
// naked input.
|
|
245
|
+
const emptyMessage =
|
|
246
|
+
paletteGroups.length === 0
|
|
247
|
+
? "No commands are available in this posture."
|
|
248
|
+
: undefined;
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<>
|
|
252
|
+
<TwContextMenuPortal
|
|
253
|
+
open={controller.state.open}
|
|
254
|
+
clientX={controller.state.clientX}
|
|
255
|
+
clientY={controller.state.clientY}
|
|
256
|
+
entries={controller.state.entries}
|
|
257
|
+
onDismiss={controller.dismiss}
|
|
258
|
+
{...(returnFocusTo !== undefined ? { returnFocusTo } : {})}
|
|
259
|
+
/>
|
|
260
|
+
<TwCommandPaletteMount
|
|
261
|
+
groups={paletteGroups}
|
|
262
|
+
{...(paletteDisabled !== undefined ? { disabled: paletteDisabled } : {})}
|
|
263
|
+
{...(emptyMessage !== undefined ? { emptyMessage } : {})}
|
|
264
|
+
/>
|
|
265
|
+
</>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Module-scope constant so the dismiss reference fed into the palette
|
|
270
|
+
// adapter is stable across the component's lifetime — contributes to
|
|
271
|
+
// the useMemo([mode, stableHost]) cache stability. The palette's
|
|
272
|
+
// TwCommandPaletteMount owns its open state, so command invocations
|
|
273
|
+
// dismiss via the palette's own onOpenChange; this is just a hook.
|
|
274
|
+
function noopDismiss(): void {
|
|
275
|
+
// intentionally empty
|
|
276
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useContextMenuController — React hook that owns workspace-level
|
|
3
|
+
* context-menu state. Consumers (TwReviewWorkspace, Phase C.γ.3) wire
|
|
4
|
+
* the returned `request(event)` into their `onContextMenuRequested`
|
|
5
|
+
* callback, then render `<TwContextMenuPortal {...state} />`.
|
|
6
|
+
*
|
|
7
|
+
* Progressive-disclosure discipline (designsystem.md §2.1 principle 4):
|
|
8
|
+
* - No work happens until the user right-clicks. Target resolution,
|
|
9
|
+
* entry building, and portal mount all run ONLY inside `request()`.
|
|
10
|
+
* - The edit path is untouched (invariant 7).
|
|
11
|
+
*
|
|
12
|
+
* State shape is intentionally minimal — the hook doesn't own
|
|
13
|
+
* composition, host callbacks, or target-kind classification; those
|
|
14
|
+
* are passed in per request so the same hook works for right-click,
|
|
15
|
+
* "More…" buttons (Phase D), and keyboard Shift+F10 (Phase C.γ.5).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { useCallback, useState } from "react";
|
|
19
|
+
|
|
20
|
+
import type { TableStructureContextSnapshot } from "../../api/public-types";
|
|
21
|
+
import type { EditorChromeMode } from "../../api/v3/ui/chrome-composition";
|
|
22
|
+
import {
|
|
23
|
+
buildContextMenuEntries,
|
|
24
|
+
type BuildContextMenuInput,
|
|
25
|
+
} from "./build-context-menu-entries";
|
|
26
|
+
import type {
|
|
27
|
+
EditorActionHostCallbacks,
|
|
28
|
+
TargetKind,
|
|
29
|
+
} from "./editor-action-registry";
|
|
30
|
+
import { resolveTargetKind } from "./resolve-target-kind";
|
|
31
|
+
import type { ContextMenuEntry } from "./tw-context-menu";
|
|
32
|
+
import { resolveTableTier } from "./tw-table-context-toolbar";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Project a `TableTier` to additional `TargetKind`s the menu should
|
|
36
|
+
* include. Mirrors the §6.9 tier ladder: a row-selected context (T3)
|
|
37
|
+
* surfaces both `"table-row"` and `"table-cell"` actions; a whole-
|
|
38
|
+
* table context (T5) surfaces every tier. Used by the menu controller
|
|
39
|
+
* when the host supplies a live table structure context — Chrome
|
|
40
|
+
* Closure Pass · Task 3.
|
|
41
|
+
*/
|
|
42
|
+
function tableContextToKinds(
|
|
43
|
+
ctx: TableStructureContextSnapshot | null,
|
|
44
|
+
): readonly TargetKind[] {
|
|
45
|
+
if (!ctx) return [];
|
|
46
|
+
const tier = resolveTableTier(ctx);
|
|
47
|
+
switch (tier) {
|
|
48
|
+
case "caret-in-cell":
|
|
49
|
+
return ["table-cell"];
|
|
50
|
+
case "multi-cell":
|
|
51
|
+
return ["table-cell"];
|
|
52
|
+
case "row-selected":
|
|
53
|
+
return ["table-cell", "table-row"];
|
|
54
|
+
case "column-selected":
|
|
55
|
+
return ["table-cell", "table-column"];
|
|
56
|
+
case "whole-table":
|
|
57
|
+
return ["table-cell", "table-row", "table-column", "table-whole"];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ContextMenuRequest {
|
|
62
|
+
readonly clientX: number;
|
|
63
|
+
readonly clientY: number;
|
|
64
|
+
readonly target: EventTarget | null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ContextMenuState {
|
|
68
|
+
readonly open: boolean;
|
|
69
|
+
readonly clientX: number;
|
|
70
|
+
readonly clientY: number;
|
|
71
|
+
readonly entries: ContextMenuEntry[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface UseContextMenuControllerOptions {
|
|
75
|
+
readonly mode: EditorChromeMode;
|
|
76
|
+
readonly host: EditorActionHostCallbacks;
|
|
77
|
+
/**
|
|
78
|
+
* Optional root passed through to `resolveTargetKind` so traversal
|
|
79
|
+
* stops at the editor surface instead of walking into the shell
|
|
80
|
+
* header or rail.
|
|
81
|
+
*/
|
|
82
|
+
readonly root?: Element | null;
|
|
83
|
+
/**
|
|
84
|
+
* Advanced: override the builder (for "More…" buttons that know
|
|
85
|
+
* their target kind a priori and don't need DOM resolution).
|
|
86
|
+
*/
|
|
87
|
+
readonly resolveKinds?: (target: EventTarget | null) => readonly TargetKind[];
|
|
88
|
+
/**
|
|
89
|
+
* Optional live table structure context — when present and the
|
|
90
|
+
* right-click target resolves to `"table-cell"`, the controller
|
|
91
|
+
* adds tier-specific kinds (`"table-row"` / `"table-column"` /
|
|
92
|
+
* `"table-whole"`) so the menu entries match the §6.9 tier ladder
|
|
93
|
+
* (Chrome Closure Pass · Task 3). Pass null when no table is
|
|
94
|
+
* active or you do not have access to the snapshot.
|
|
95
|
+
*/
|
|
96
|
+
readonly tableContext?: TableStructureContextSnapshot | null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface ContextMenuController {
|
|
100
|
+
readonly state: ContextMenuState;
|
|
101
|
+
/** Call from the `onContextMenuRequested` bridge callback. */
|
|
102
|
+
request: (request: ContextMenuRequest) => void;
|
|
103
|
+
/** Open with pre-resolved kinds (Phase D "More…" buttons). */
|
|
104
|
+
requestWithKinds: (args: {
|
|
105
|
+
clientX: number;
|
|
106
|
+
clientY: number;
|
|
107
|
+
kinds: readonly TargetKind[];
|
|
108
|
+
}) => void;
|
|
109
|
+
dismiss: () => void;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const EMPTY_STATE: ContextMenuState = {
|
|
113
|
+
open: false,
|
|
114
|
+
clientX: 0,
|
|
115
|
+
clientY: 0,
|
|
116
|
+
entries: [],
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export function useContextMenuController(
|
|
120
|
+
options: UseContextMenuControllerOptions,
|
|
121
|
+
): ContextMenuController {
|
|
122
|
+
const { mode, host, root, resolveKinds, tableContext } = options;
|
|
123
|
+
const [state, setState] = useState<ContextMenuState>(EMPTY_STATE);
|
|
124
|
+
|
|
125
|
+
const dismiss = useCallback(() => {
|
|
126
|
+
setState(EMPTY_STATE);
|
|
127
|
+
}, []);
|
|
128
|
+
|
|
129
|
+
const buildEntries = useCallback(
|
|
130
|
+
(kinds: readonly TargetKind[]): ContextMenuEntry[] => {
|
|
131
|
+
const input: BuildContextMenuInput = {
|
|
132
|
+
targetKinds: kinds,
|
|
133
|
+
mode,
|
|
134
|
+
host,
|
|
135
|
+
dismiss,
|
|
136
|
+
};
|
|
137
|
+
return buildContextMenuEntries(input);
|
|
138
|
+
},
|
|
139
|
+
[mode, host, dismiss],
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const request = useCallback(
|
|
143
|
+
(req: ContextMenuRequest) => {
|
|
144
|
+
const baseKinds = resolveKinds
|
|
145
|
+
? resolveKinds(req.target)
|
|
146
|
+
: resolveTargetKind(req.target, { root: root ?? undefined });
|
|
147
|
+
// Chrome Closure Pass · Task 3 — augment with tier-specific
|
|
148
|
+
// kinds when a live table context is supplied and the target
|
|
149
|
+
// is in a table cell. Cell-level ops carry every table-* kind
|
|
150
|
+
// (so they are still visible) and tier-only ops (delete row /
|
|
151
|
+
// delete column) gate on the matching kind.
|
|
152
|
+
const tierKinds =
|
|
153
|
+
baseKinds.includes("table-cell") && tableContext
|
|
154
|
+
? tableContextToKinds(tableContext)
|
|
155
|
+
: [];
|
|
156
|
+
const merged = [...baseKinds];
|
|
157
|
+
for (const k of tierKinds) {
|
|
158
|
+
if (!merged.includes(k)) merged.push(k);
|
|
159
|
+
}
|
|
160
|
+
const entries = buildEntries(merged);
|
|
161
|
+
// Progressive disclosure: if no actions resolve (every host callback
|
|
162
|
+
// absent + no scope-anchor + etc), don't open an empty menu. Let
|
|
163
|
+
// the browser fall through instead.
|
|
164
|
+
if (entries.length === 0) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
setState({
|
|
168
|
+
open: true,
|
|
169
|
+
clientX: req.clientX,
|
|
170
|
+
clientY: req.clientY,
|
|
171
|
+
entries,
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
[buildEntries, resolveKinds, root, tableContext],
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const requestWithKinds = useCallback(
|
|
178
|
+
(args: {
|
|
179
|
+
clientX: number;
|
|
180
|
+
clientY: number;
|
|
181
|
+
kinds: readonly TargetKind[];
|
|
182
|
+
}) => {
|
|
183
|
+
const entries = buildEntries(args.kinds);
|
|
184
|
+
if (entries.length === 0) return;
|
|
185
|
+
setState({
|
|
186
|
+
open: true,
|
|
187
|
+
clientX: args.clientX,
|
|
188
|
+
clientY: args.clientY,
|
|
189
|
+
entries,
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
[buildEntries],
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// D.5.Nit1 — the return value is consumed directly by the caller
|
|
196
|
+
// (the component that called this hook). It isn't handed to any
|
|
197
|
+
// downstream memoizer, so `useMemo` here just pre-allocates an
|
|
198
|
+
// object that React's reconciler would allocate anyway. Plain
|
|
199
|
+
// object literal is clearer + one less hook slot to track.
|
|
200
|
+
return { state, request, requestWithKinds, dismiss };
|
|
201
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* rect math can be unit-tested and reused.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { RenderFrameRect } from "../../
|
|
11
|
+
import type { RenderFrameRect } from "../../api/public-types.ts";
|
|
12
12
|
import { recordPerfSample } from "../editor-surface/perf-probe.ts";
|
|
13
13
|
|
|
14
14
|
export interface OverlayCoordinateSpace {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import * as React from "react";
|
|
16
16
|
import type { OverlayCoordinateSpace } from "./chrome-overlay-projector";
|
|
17
|
-
import type { ScopeRailSegment } from "../../
|
|
17
|
+
import type { ScopeRailSegment } from "../../api/public-types.ts";
|
|
18
18
|
import type {
|
|
19
19
|
EditorRole,
|
|
20
20
|
EditorStoryTarget,
|
|
@@ -30,8 +30,21 @@ import { TwTableGripLayer } from "../chrome/tw-table-grip-layer";
|
|
|
30
30
|
import { TwObjectSelectionOverlay } from "./tw-object-selection-overlay";
|
|
31
31
|
|
|
32
32
|
export interface TwChromeOverlayProps {
|
|
33
|
-
/** Layout facet the overlay layers read from. */
|
|
33
|
+
/** Layout facet the overlay layers read from (layout-semantic data). */
|
|
34
34
|
facet: WordReviewEditorLayoutFacet;
|
|
35
|
+
/**
|
|
36
|
+
* Geometry facet for render-frame + zoom access. Migrated from
|
|
37
|
+
* `facet.getRenderFrame` / `.getRenderZoom` in refactor/05
|
|
38
|
+
* cross-lane-coord §8.4.
|
|
39
|
+
*/
|
|
40
|
+
geometryFacet: import("../../runtime/geometry/index.ts").GeometryFacet;
|
|
41
|
+
/**
|
|
42
|
+
* Workflow facet — Layer-06 canonical source of scope rail segments
|
|
43
|
+
* + scope card models (`runtime.workflow`). Required for scope-rail
|
|
44
|
+
* / scope-card rendering; pass `null` when no runtime is attached
|
|
45
|
+
* (e.g., during initial mount).
|
|
46
|
+
*/
|
|
47
|
+
workflowFacet: import("../../runtime/workflow/rail/types.ts").WorkflowFacet | null;
|
|
35
48
|
/** Optional coordinate space override. Defaults to the overlay origin. */
|
|
36
49
|
space?: OverlayCoordinateSpace;
|
|
37
50
|
/** Active scope id (for emphasis + rail tab sync). */
|
|
@@ -182,7 +195,9 @@ export interface TwChromeOverlayProps {
|
|
|
182
195
|
* pointer events on their interactive elements (buttons, handles).
|
|
183
196
|
*/
|
|
184
197
|
export const TwChromeOverlay: React.FC<TwChromeOverlayProps> = ({
|
|
198
|
+
workflowFacet,
|
|
185
199
|
facet,
|
|
200
|
+
geometryFacet,
|
|
186
201
|
space,
|
|
187
202
|
activeScopeId,
|
|
188
203
|
onScopeStripeClick,
|
|
@@ -231,7 +246,8 @@ export const TwChromeOverlay: React.FC<TwChromeOverlayProps> = ({
|
|
|
231
246
|
/>
|
|
232
247
|
) : null}
|
|
233
248
|
<TwScopeRailLayer
|
|
234
|
-
|
|
249
|
+
geometryFacet={geometryFacet}
|
|
250
|
+
workflowFacet={workflowFacet}
|
|
235
251
|
space={space}
|
|
236
252
|
activeScopeId={activeScopeId}
|
|
237
253
|
onStripeClick={onScopeStripeClick}
|
|
@@ -239,6 +255,7 @@ export const TwChromeOverlay: React.FC<TwChromeOverlayProps> = ({
|
|
|
239
255
|
/>
|
|
240
256
|
<TwScopeCardLayer
|
|
241
257
|
facet={facet}
|
|
258
|
+
workflowFacet={workflowFacet}
|
|
242
259
|
activeScopeId={activeScopeId ?? null}
|
|
243
260
|
onClose={onScopeCardClose ?? noop}
|
|
244
261
|
onModeChange={onScopeCardModeChange ?? noopModeChange}
|
|
@@ -252,6 +269,7 @@ export const TwChromeOverlay: React.FC<TwChromeOverlayProps> = ({
|
|
|
252
269
|
/>
|
|
253
270
|
<TwTableGripLayer
|
|
254
271
|
facet={facet}
|
|
272
|
+
geometryFacet={geometryFacet}
|
|
255
273
|
tableContext={tableContext ?? null}
|
|
256
274
|
space={space}
|
|
257
275
|
onSetColumnWidth={onSetColumnWidth}
|
|
@@ -261,7 +279,7 @@ export const TwChromeOverlay: React.FC<TwChromeOverlayProps> = ({
|
|
|
261
279
|
grabbedObjectId={grabbedObjectId ?? null}
|
|
262
280
|
grabbedObjectFromOffset={grabbedObjectFromOffset ?? null}
|
|
263
281
|
grabbedObjectToOffset={grabbedObjectToOffset ?? null}
|
|
264
|
-
|
|
282
|
+
geometryFacet={geometryFacet}
|
|
265
283
|
space={space}
|
|
266
284
|
onDeselect={onDeselectObject}
|
|
267
285
|
/>
|
|
@@ -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 { TwCommentPreview } from "../chrome/tw-comment-preview";
|
|
4
4
|
|
|
5
5
|
const WIDE_BREAKPOINT_PX = 1024;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Lock } from "lucide-react";
|
|
3
|
-
import type { RenderBlockDecoration } from "../../
|
|
3
|
+
import type { RenderBlockDecoration } from "../../api/public-types.ts";
|
|
4
4
|
|
|
5
5
|
const OUTLINE_INSET_PX = 2;
|
|
6
6
|
const BADGE_SIZE_PX = 20;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import * as React from "react";
|
|
22
22
|
import { useEffect, useRef } from "react";
|
|
23
|
-
import type {
|
|
23
|
+
import type { GeometryFacet } from "../../api/public-types";
|
|
24
24
|
import type { OverlayCoordinateSpace } from "./chrome-overlay-projector";
|
|
25
25
|
import { projectRectToOverlay } from "./chrome-overlay-projector";
|
|
26
26
|
|
|
@@ -45,8 +45,14 @@ export interface TwObjectSelectionOverlayProps {
|
|
|
45
45
|
grabbedObjectFromOffset: number | null;
|
|
46
46
|
/** Document offset (`to`) of the grabbed object's inline segment. Null when no object grabbed. */
|
|
47
47
|
grabbedObjectToOffset: number | null;
|
|
48
|
-
/**
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Geometry facet for render-frame + anchor-index access. Migrated
|
|
50
|
+
* from `facet: WordReviewEditorLayoutFacet` in the refactor/05
|
|
51
|
+
* cross-lane-coord §8.4 pass — layout-facet's `getRenderFrame` /
|
|
52
|
+
* `getRenderZoom` are being deleted; consumers read through
|
|
53
|
+
* `runtime.geometry` now.
|
|
54
|
+
*/
|
|
55
|
+
geometryFacet: GeometryFacet;
|
|
50
56
|
/** Optional overlay coordinate-space override. */
|
|
51
57
|
space?: OverlayCoordinateSpace;
|
|
52
58
|
/** Called when the user clicks outside the selection box. */
|
|
@@ -57,7 +63,7 @@ export function TwObjectSelectionOverlay({
|
|
|
57
63
|
grabbedObjectId,
|
|
58
64
|
grabbedObjectFromOffset,
|
|
59
65
|
grabbedObjectToOffset,
|
|
60
|
-
|
|
66
|
+
geometryFacet,
|
|
61
67
|
space,
|
|
62
68
|
onDeselect,
|
|
63
69
|
}: TwObjectSelectionOverlayProps) {
|
|
@@ -77,7 +83,7 @@ export function TwObjectSelectionOverlay({
|
|
|
77
83
|
|
|
78
84
|
if (!grabbedObjectId || grabbedObjectFromOffset == null) return null;
|
|
79
85
|
|
|
80
|
-
const frame =
|
|
86
|
+
const frame = geometryFacet.getRenderFrame();
|
|
81
87
|
if (!frame) return null;
|
|
82
88
|
|
|
83
89
|
const rawRect = grabbedObjectToOffset != null
|