@beyondwork/docx-react-component 1.0.66 → 1.0.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -931
- package/package.json +26 -27
- package/src/api/anchor-conversion.ts +43 -0
- package/src/api/editor-state-types.ts +2 -1
- package/src/api/public-types.ts +504 -101
- package/src/api/session-state.ts +4 -0
- package/src/api/v3/README.md +91 -0
- package/src/api/v3/_create.ts +146 -0
- package/src/api/v3/_layer-metadata.ts +362 -0
- package/src/api/v3/_mocks.ts +84 -0
- package/src/api/v3/_runtime-handle.ts +162 -0
- package/src/api/v3/_ux-response.ts +73 -0
- package/src/api/v3/ai/_metadata-audit.ts +225 -0
- package/src/api/v3/ai/attach.ts +235 -0
- package/src/api/v3/ai/bundle.ts +132 -0
- package/src/api/v3/ai/explain.ts +144 -0
- package/src/api/v3/ai/export.ts +54 -0
- package/src/api/v3/ai/inspect.ts +118 -0
- package/src/api/v3/ai/policy.ts +77 -0
- package/src/api/v3/ai/replacement.ts +341 -0
- package/src/api/v3/ai/resolve.ts +133 -0
- package/src/api/v3/index.ts +79 -0
- package/src/api/v3/runtime/chart.ts +310 -0
- package/src/api/v3/runtime/clipboard.ts +81 -0
- package/src/api/v3/runtime/collab.ts +331 -0
- package/src/api/v3/runtime/content.ts +236 -0
- package/src/api/v3/runtime/document.ts +282 -0
- package/src/api/v3/runtime/formatting.ts +186 -0
- package/src/api/v3/runtime/geometry.ts +349 -0
- package/src/api/v3/runtime/layout.ts +108 -0
- package/src/api/v3/runtime/review.ts +129 -0
- package/src/api/v3/runtime/search.ts +74 -0
- package/src/api/v3/runtime/table.ts +63 -0
- package/src/api/v3/runtime/workflow.ts +434 -0
- package/src/api/v3/ui/_context.ts +86 -0
- package/src/api/v3/ui/_create.ts +65 -0
- package/src/api/v3/ui/_types.ts +520 -0
- package/src/api/v3/ui/chrome-composition.ts +342 -0
- package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
- package/src/api/v3/ui/chrome.ts +476 -0
- package/src/api/v3/ui/debug.ts +124 -0
- package/src/api/v3/ui/index.ts +64 -0
- package/src/api/v3/ui/overlays-visibility.ts +170 -0
- package/src/api/v3/ui/overlays.ts +427 -0
- package/src/api/v3/ui/scope.ts +71 -0
- package/src/api/v3/ui/session.ts +100 -0
- package/src/api/v3/ui/surface.ts +170 -0
- package/src/api/v3/ui/viewport.ts +303 -0
- package/src/core/commands/index.ts +28 -6
- package/src/core/commands/list-commands.ts +3 -2
- package/src/core/commands/section-layout-commands.ts +9 -8
- package/src/core/schema/text-schema.ts +16 -0
- package/src/core/selection/mapping.ts +33 -72
- package/src/core/state/editor-state.ts +96 -189
- package/src/index.ts +23 -4
- package/src/io/chart-preview-resolver.ts +1 -1
- package/src/io/docx-session.ts +36 -4795
- package/src/io/export/build-app-properties-xml.ts +1 -1
- package/src/io/export/serialize-comments.ts +1 -1
- package/src/io/export/serialize-headers-footers.ts +6 -1
- package/src/io/export/serialize-main-document.ts +45 -0
- package/src/io/export/serialize-run-formatting.ts +17 -2
- package/src/io/export/twip.ts +1 -1
- package/src/io/normalize/normalize-text.ts +27 -20
- package/src/io/ooxml/chart/parse-series.ts +1 -1
- package/src/io/ooxml/chart/resolve-color.ts +2 -2
- package/src/io/ooxml/chart/types.ts +1 -1
- package/src/io/ooxml/classify-embedding.ts +83 -33
- package/src/io/ooxml/parse-fill.ts +1 -1
- package/src/io/ooxml/parse-main-document.ts +71 -1
- package/src/io/ooxml/parse-object.ts +14 -10
- package/src/io/ooxml/parse-run-formatting.ts +47 -1
- package/src/io/ooxml/property-grab-bag.ts +2 -2
- package/src/io/ooxml/units.ts +11 -0
- package/src/io/ooxml/workflow-payload.ts +282 -7
- package/src/model/anchor.ts +85 -0
- package/src/model/canonical-document.ts +351 -15
- package/src/model/chart-types.ts +1 -1
- package/src/model/layout/index.ts +83 -0
- package/src/model/layout/page-graph-types.ts +181 -0
- package/src/model/layout/page-layout-snapshot.ts +105 -0
- package/src/model/layout/resolved-layout-types.ts +47 -0
- package/src/model/layout/runtime-page-graph-types.ts +102 -0
- package/src/model/paragraph-scope-ids.ts +72 -0
- package/src/model/review/comment-types.ts +112 -0
- package/src/model/review/index.ts +2 -0
- package/src/model/review/revision-types.ts +215 -0
- package/src/model/snapshot.ts +32 -0
- package/src/review/store/comment-store.ts +21 -47
- package/src/review/store/revision-types.ts +40 -198
- package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
- package/src/runtime/collab/runtime-collab-sync.ts +13 -3
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
- package/src/runtime/debug/event-ring-buffer.ts +64 -0
- package/src/runtime/debug/probability-sampler.ts +18 -0
- package/src/runtime/debug/runtime-debug-facet.ts +67 -0
- package/src/runtime/debug/stage-tokens.ts +31 -0
- package/src/runtime/debug/telemetry-bus.ts +271 -0
- package/src/runtime/debug/types.ts +275 -0
- package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
- package/src/runtime/document-layout.ts +8 -6
- package/src/runtime/document-runtime.ts +843 -1141
- package/src/runtime/document-search.ts +1 -1
- package/src/runtime/edit-ops/index.ts +1 -1
- package/src/runtime/external-send-runtime.ts +1 -1
- package/src/runtime/formatting/document-lookup.ts +235 -0
- package/src/runtime/formatting/field/registry.ts +41 -0
- package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
- package/src/runtime/formatting/font-resolution.ts +83 -0
- package/src/runtime/formatting/formatting-context.ts +903 -0
- package/src/runtime/formatting/formatting-types.ts +157 -0
- package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
- package/src/runtime/formatting/index.ts +125 -0
- package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
- package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
- package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
- package/src/runtime/formatting/projector.ts +75 -0
- package/src/runtime/formatting/resolve-effective.ts +407 -0
- package/src/runtime/formatting/revision-display.ts +105 -0
- package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
- package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
- package/src/runtime/formatting/telemetry-bridge.ts +106 -0
- package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
- package/src/runtime/geometry/caret-geometry.ts +164 -0
- package/src/runtime/geometry/geometry-facet.ts +364 -0
- package/src/runtime/geometry/geometry-types.ts +256 -0
- package/src/runtime/geometry/hit-test.ts +125 -0
- package/src/runtime/geometry/index.ts +71 -0
- package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
- package/src/runtime/geometry/invalidation.ts +35 -0
- package/src/runtime/geometry/object-handles.ts +77 -0
- package/src/runtime/geometry/overlay-rects.ts +85 -0
- package/src/runtime/geometry/project-anchors.ts +100 -0
- package/src/runtime/geometry/project-fragments.ts +216 -0
- package/src/runtime/geometry/projector.ts +129 -0
- package/src/runtime/geometry/replacement-envelope.ts +130 -0
- package/src/runtime/geometry/viewport.ts +218 -0
- package/src/runtime/layout/compat-input-ledger.ts +211 -0
- package/src/runtime/layout/index.ts +6 -1
- package/src/runtime/layout/inert-layout-facet.ts +12 -7
- package/src/runtime/layout/layout-engine-instance.ts +189 -11
- package/src/runtime/layout/layout-engine-version.ts +450 -1
- package/src/runtime/layout/layout-facet-types.ts +60 -0
- package/src/runtime/layout/layout-measurement-provider.ts +13 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
- package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
- package/src/runtime/layout/page-graph.ts +62 -209
- package/src/runtime/layout/page-story-resolver.ts +7 -12
- package/src/runtime/layout/paginated-layout-engine.ts +186 -11
- package/src/runtime/layout/project-block-fragments.ts +11 -0
- package/src/runtime/layout/projector.ts +90 -0
- package/src/runtime/layout/public-facet.ts +187 -442
- package/src/runtime/layout/resolved-formatting-state.ts +158 -26
- package/src/runtime/layout/table-render-plan.ts +1 -1
- package/src/runtime/prerender/cache-envelope.ts +6 -1
- package/src/runtime/prerender/prerender-document.ts +18 -23
- package/src/runtime/render/decoration-resolver.ts +1 -1
- package/src/runtime/render/render-frame-types.ts +20 -0
- package/src/runtime/render/render-kernel.ts +94 -25
- package/src/runtime/scopes/_formatting-seam.ts +262 -0
- package/src/runtime/scopes/_scope-dependencies.ts +49 -0
- package/src/runtime/scopes/action-validation.ts +356 -0
- package/src/runtime/scopes/attach-explanation.ts +102 -0
- package/src/runtime/scopes/audit-bundle.ts +71 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
- package/src/runtime/scopes/compile-scope.ts +262 -0
- package/src/runtime/scopes/compiler-service.ts +431 -0
- package/src/runtime/scopes/create-issue.ts +107 -0
- package/src/runtime/scopes/enumerate-scopes.ts +543 -0
- package/src/runtime/scopes/evidence.ts +233 -0
- package/src/runtime/scopes/index.ts +150 -0
- package/src/runtime/scopes/position-map.ts +214 -0
- package/src/runtime/scopes/preservation-boundary.ts +91 -0
- package/src/runtime/scopes/projector.ts +49 -0
- package/src/runtime/scopes/replaceability.ts +87 -0
- package/src/runtime/scopes/replacement/apply.ts +228 -0
- package/src/runtime/scopes/replacement/compile.ts +59 -0
- package/src/runtime/scopes/replacement/propose.ts +42 -0
- package/src/runtime/scopes/resolve-reference.ts +347 -0
- package/src/runtime/scopes/review-bundle.ts +141 -0
- package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
- package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
- package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
- package/src/runtime/scopes/scope-kinds/field.ts +65 -0
- package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
- package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
- package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
- package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
- package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
- package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
- package/src/runtime/scopes/scope-kinds/table.ts +55 -0
- package/src/runtime/scopes/scope-range.ts +208 -0
- package/src/runtime/scopes/semantic-scope-types.ts +454 -0
- package/src/runtime/scopes/workflow-overlap.ts +92 -0
- package/src/runtime/selection/index.ts +1 -1
- package/src/runtime/structure-ops/fragment-insert.ts +1 -1
- package/src/runtime/structure-ops/index.ts +1 -1
- package/src/runtime/surface-projection.ts +232 -262
- package/src/runtime/units.ts +4 -2
- package/src/runtime/workflow/coordinator.ts +1348 -0
- package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
- package/src/runtime/workflow/index.ts +25 -0
- package/src/runtime/workflow/markup-mode-policy.ts +98 -0
- package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
- package/src/runtime/workflow/metadata-persistence.ts +306 -0
- package/src/runtime/workflow/metadata-writer.ts +123 -0
- package/src/runtime/workflow/overlay-store.ts +690 -0
- package/src/runtime/workflow/projector.ts +127 -0
- package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
- package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
- package/src/runtime/workflow/rail/types.ts +198 -0
- package/src/runtime/workflow/scope-rail-composer.ts +39 -0
- package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
- package/src/runtime/workflow/scope-writer.ts +188 -0
- package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
- package/src/runtime/workflow/visibility-policy.ts +129 -0
- package/src/session/_sync-legacy.ts +66 -0
- package/src/session/export/embedded-reconstitute.ts +104 -0
- package/src/session/export/export-diagnostics.ts +85 -0
- package/src/session/export/export-validation.ts +110 -0
- package/src/session/export/index.ts +34 -0
- package/src/session/export/preservation-reattach.ts +30 -0
- package/src/session/export/serialize-dispatch.ts +165 -0
- package/src/session/export/stateful-export-pipeline.ts +432 -0
- package/src/session/export/stateful-export.ts +684 -0
- package/src/session/import/canonical-assembly.ts +227 -0
- package/src/session/import/diagnostics-session.ts +54 -0
- package/src/session/import/embedded-discovery.ts +225 -0
- package/src/session/import/embedded-offload.ts +337 -0
- package/src/session/import/import-diagnostics.ts +69 -0
- package/src/session/import/loader-types.ts +313 -0
- package/src/session/import/loader.ts +1834 -0
- package/src/session/import/normalize.ts +195 -0
- package/src/session/import/package-parts.ts +217 -0
- package/src/session/import/package-read.ts +195 -0
- package/src/session/import/parse-orchestration.ts +105 -0
- package/src/session/import/part-constants.ts +70 -0
- package/src/session/import/part-discovery.ts +94 -0
- package/src/session/import/preservation-index.ts +46 -0
- package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
- package/src/session/import/review-import.ts +508 -0
- package/src/session/import/styles-consolidation.ts +281 -0
- package/src/session/import/workflow-scope-import.ts +256 -0
- package/src/session/index.ts +37 -0
- package/src/session/session-state.ts +69 -0
- package/src/session/session.ts +532 -0
- package/src/session/shared/protection.ts +228 -0
- package/src/session/shared/session-utils.ts +82 -0
- package/src/session/types.ts +499 -0
- package/src/shell/chart-snapshots.ts +96 -0
- package/src/shell/media-previews.ts +85 -0
- package/src/shell/overlay-anchor-bridge.ts +53 -0
- package/src/shell/paste-adapter.ts +23 -0
- package/src/shell/ref-commands.ts +1697 -0
- package/src/shell/ref-utilities.ts +48 -0
- package/src/shell/search.ts +51 -0
- package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
- package/src/shell/ui-subscriber-channels.ts +81 -0
- package/src/shell/use-collab-sync.ts +116 -0
- package/src/ui/WordReviewEditor.tsx +496 -2051
- package/src/ui/editor-shell-view.tsx +30 -1
- package/src/ui/editor-surface-controller.tsx +49 -1
- package/src/ui/headless/revision-decoration-model.ts +83 -0
- package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
- package/src/ui/headless/scoped-chrome-policy.ts +2 -2
- package/src/ui/headless/selection-tool-context.ts +1 -1
- package/src/ui/headless/selection-tool-resolver.ts +1 -1
- package/src/ui/runtime-shortcut-dispatch.ts +46 -1
- package/src/ui/ui-controller-factory.ts +221 -0
- package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
- package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
- package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
- package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
- package/src/ui-tailwind/chart/render/area.tsx +3 -3
- package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
- package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
- package/src/ui-tailwind/chart/render/combo.tsx +2 -2
- package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
- package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
- package/src/ui-tailwind/chart/render/line.tsx +3 -3
- package/src/ui-tailwind/chart/render/pie.tsx +6 -6
- package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
- package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
- package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
- package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
- package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
- package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
- package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
- package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
- package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
- package/src/ui-tailwind/debug/README.md +57 -0
- package/src/ui-tailwind/debug/index.ts +3 -0
- package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
- package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
- package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
- package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
- package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
- package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
- package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
- package/src/ui-tailwind/index.ts +0 -5
- package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
- package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
- package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
- package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
- package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
- package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
- package/src/ui-tailwind/review-workspace/types.ts +408 -0
- package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
- package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
- package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
- package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
- package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
- package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
- package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
- package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
- package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
- package/src/ui-tailwind/theme/editor-theme.css +25 -0
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
- package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
- package/src/ui-tailwind/ui-api-context.tsx +43 -0
- package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
- package/src/validation/compatibility-engine.ts +6 -6
- package/src/runtime/styles-cascade.ts +0 -33
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
- /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
- /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
- /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Geometry facet.
|
|
3
|
+
*
|
|
4
|
+
* The `GeometryFacet` is the runtime-internal surface for concrete visual
|
|
5
|
+
* geometry. Per `docs/architecture/05-geometry-projection.md`, this surface
|
|
6
|
+
* owns rects, hit-tests, carets, anchors, and replacement envelopes; it is
|
|
7
|
+
* consumed by layer 07 (Runtime API) and chrome overlays.
|
|
8
|
+
*
|
|
9
|
+
* Slice 1: scaffold as a thin proxy over the layout facet.
|
|
10
|
+
* Slice 2a: direct path — `hitTest` / `getAnchorRects` call the moved
|
|
11
|
+
* pure helpers (`resolveHitTest` / `resolveAnchorRects`) against the
|
|
12
|
+
* render kernel's current frame.
|
|
13
|
+
* Slice 3: viewport becomes DOM-backed; chrome overlays subscribe.
|
|
14
|
+
* Slice 4: caret geometry.
|
|
15
|
+
* Slice 5: replacement envelope + object handles.
|
|
16
|
+
* Slice 6 (2026-04-22 wrapper-deletion pass): the layout-facet
|
|
17
|
+
* `hitTest` + `getAnchorRects` wrappers were deleted, along with the
|
|
18
|
+
* geometry-facet's layout-facet fallback paths. `hitTest` /
|
|
19
|
+
* `getAnchorRects` now return null / [] when no kernel is wired
|
|
20
|
+
* (headless tests, pre-paint); production always wires the kernel
|
|
21
|
+
* via `document-runtime.ts`.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { EditorStoryTarget } from "../../api/public-types";
|
|
25
|
+
import type { CanonicalDocument } from "../../model/canonical-document.ts";
|
|
26
|
+
import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
|
|
27
|
+
import type {
|
|
28
|
+
PublicLineBox,
|
|
29
|
+
PublicPageRegion,
|
|
30
|
+
WordReviewEditorLayoutFacet,
|
|
31
|
+
} from "../layout/public-facet.ts";
|
|
32
|
+
import type { RenderKernel } from "../render/index.ts";
|
|
33
|
+
import { resolveScope } from "../workflow/scope-resolver.ts";
|
|
34
|
+
import type { ScopeRailSegment } from "../workflow/rail/compose.ts";
|
|
35
|
+
import type {
|
|
36
|
+
AnchorQuery,
|
|
37
|
+
BlockGeometry,
|
|
38
|
+
CaretGeometry,
|
|
39
|
+
EnvelopeBundle,
|
|
40
|
+
GeometryRect,
|
|
41
|
+
HitTestPoint,
|
|
42
|
+
HitTestResult,
|
|
43
|
+
PageGeometry,
|
|
44
|
+
Viewport,
|
|
45
|
+
ViewportListener,
|
|
46
|
+
} from "./geometry-types.ts";
|
|
47
|
+
import {
|
|
48
|
+
resolveCaretGeometry,
|
|
49
|
+
resolveSelectionRects,
|
|
50
|
+
} from "./caret-geometry.ts";
|
|
51
|
+
import { resolveHitTest } from "./hit-test.ts";
|
|
52
|
+
import { resolveObjectHandles } from "./object-handles.ts";
|
|
53
|
+
import { resolveAnchorRects } from "./project-anchors.ts";
|
|
54
|
+
import {
|
|
55
|
+
resolveReplacementEnvelope,
|
|
56
|
+
type ReplacementScope,
|
|
57
|
+
} from "./replacement-envelope.ts";
|
|
58
|
+
import {
|
|
59
|
+
getBlockGeometryFromFrame,
|
|
60
|
+
getBlockRectsFromFrame,
|
|
61
|
+
getPageFromFrame,
|
|
62
|
+
} from "./project-fragments.ts";
|
|
63
|
+
import { createViewport, type ViewportHandle } from "./viewport.ts";
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Public surface
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
export interface GeometryFacet {
|
|
70
|
+
// Hit-test -------------------------------------------------------------
|
|
71
|
+
/**
|
|
72
|
+
* Resolve a point in the shell's overlay coordinate space to a canonical
|
|
73
|
+
* position. Routes directly to the render-kernel frame via
|
|
74
|
+
* `resolveHitTest`. Returns null when no kernel is wired (headless
|
|
75
|
+
* tests, pre-paint). The layout-facet fallback was deleted in the
|
|
76
|
+
* refactor/05 Slice 6 wrapper-deletion pass (2026-04-22).
|
|
77
|
+
*/
|
|
78
|
+
hitTest(point: HitTestPoint): HitTestResult | null;
|
|
79
|
+
|
|
80
|
+
// Anchors --------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Rect bundle for an anchor query (selection range, block id, scope id,
|
|
83
|
+
* etc.). Resolves directly via `resolveAnchorRects` against the render
|
|
84
|
+
* frame. Returns [] when no kernel is wired.
|
|
85
|
+
*/
|
|
86
|
+
getAnchorRects(query: AnchorQuery): readonly GeometryRect[];
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Convenience single-rect read — returns the first rect, or the union on
|
|
90
|
+
* spanning selections where the layout facet has already reduced it.
|
|
91
|
+
*/
|
|
92
|
+
getAnchor(query: AnchorQuery): GeometryRect | null;
|
|
93
|
+
|
|
94
|
+
// Fragment projection (Slice 2b) ---------------------------------------
|
|
95
|
+
/**
|
|
96
|
+
* Rects (one per page-fragment) for a block, tagged `space: "frame"`.
|
|
97
|
+
* Resolves through the render kernel's frame — a multi-page block yields
|
|
98
|
+
* multiple rects in page order. Returns `[]` when no kernel is wired or
|
|
99
|
+
* the block has no fragments.
|
|
100
|
+
*
|
|
101
|
+
* New in Slice 2b. Slice 5 promotes `v3 runtime.geometry.getBlockRects`
|
|
102
|
+
* from `mock` to `live-with-adapter` against this method.
|
|
103
|
+
*/
|
|
104
|
+
getBlockRects(blockId: string): readonly GeometryRect[];
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Resolve a page by index or id. Returns the `PageGeometry` read from
|
|
108
|
+
* the kernel's current frame, or `null` when no kernel is wired or the
|
|
109
|
+
* target page is not in the frame. New in Slice 3a — the substrate
|
|
110
|
+
* chrome overlays consume in place of `getBoundingClientRect` on the
|
|
111
|
+
* overlay root.
|
|
112
|
+
*
|
|
113
|
+
* Dispatch: `typeof target === "number"` resolves as a 0-based page
|
|
114
|
+
* index; any other value is resolved as a `pageId` string match.
|
|
115
|
+
* Numeric-looking strings (e.g. `"0"`) are treated as pageIds, not
|
|
116
|
+
* indices — match the runtime's `RuntimePageNode.pageId` shape.
|
|
117
|
+
*/
|
|
118
|
+
getPage(target: number | string): PageGeometry | null;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a block to its `BlockGeometry` (rects per page the block
|
|
122
|
+
* spans). Returns `null` when no kernel is wired or the block has no
|
|
123
|
+
* fragments. New in Slice 3a — the substrate `scroll-anchor` consumes
|
|
124
|
+
* in place of the `offsetTop` / `offsetParent` chain.
|
|
125
|
+
*/
|
|
126
|
+
getBlock(blockId: string): BlockGeometry | null;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Per-region line boxes for a page — delegates to the layout facet's
|
|
130
|
+
* `getLineBoxes` since body line boxes are measured by the paginator and
|
|
131
|
+
* header/footer/column/footnote-area lines are synthesized from
|
|
132
|
+
* fragment heights (see
|
|
133
|
+
* `src/runtime/geometry/project-fragments.ts::collectLineBoxesForRegion`,
|
|
134
|
+
* moved from the layout facet in Slice 2b).
|
|
135
|
+
*/
|
|
136
|
+
getLineBoxes(
|
|
137
|
+
pageIndex: number,
|
|
138
|
+
options?: { region?: PublicPageRegion["kind"]; columnIndex?: number },
|
|
139
|
+
): readonly PublicLineBox[];
|
|
140
|
+
|
|
141
|
+
// Workflow-scope rail methods removed by Layer-06 Slice 4. Consume
|
|
142
|
+
// via `runtime.workflow.getRailSegments(pageIndex)` /
|
|
143
|
+
// `runtime.workflow.getAllRailSegments()`. Layer-05 geometry now
|
|
144
|
+
// only exposes page/anchor/caret primitives; workflow composition
|
|
145
|
+
// is Layer-06's responsibility.
|
|
146
|
+
|
|
147
|
+
// Caret + selection (Slice 4) -----------------------------------------
|
|
148
|
+
getCaret(offset: number, story?: EditorStoryTarget): CaretGeometry | null;
|
|
149
|
+
getSelectionRects(range: {
|
|
150
|
+
from: number;
|
|
151
|
+
to: number;
|
|
152
|
+
story?: EditorStoryTarget;
|
|
153
|
+
}): readonly GeometryRect[];
|
|
154
|
+
|
|
155
|
+
// Replacement envelope + object handles (Slice 5) ---------------------
|
|
156
|
+
getReplacementEnvelope(scopeId: string): EnvelopeBundle | null;
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the handle points for an object. Slice-5 substrate
|
|
159
|
+
* addresses objects by `blockId` via `frame.anchorIndex.byBlockId`
|
|
160
|
+
* — so an inline image embedded in a paragraph resolves to the
|
|
161
|
+
* enclosing paragraph's rect, not the image's own rect. Callers
|
|
162
|
+
* that need per-object (not per-block) bboxes should consult the
|
|
163
|
+
* deferred-items list in the refactor/05 closure note: an object-
|
|
164
|
+
* specific anchor index is part of a later slice.
|
|
165
|
+
*/
|
|
166
|
+
getObjectHandles(objectId: string): readonly GeometryRect[];
|
|
167
|
+
|
|
168
|
+
// Render-kernel passthroughs (migration target for Layer 04's
|
|
169
|
+
// deprecated `layoutFacet.getRenderFrame` / `.getRenderZoom`;
|
|
170
|
+
// tracked in `docs/plans/cross-layer-coord-05.md` §8).
|
|
171
|
+
//
|
|
172
|
+
// These return the kernel's primitive types (`RenderFrame`,
|
|
173
|
+
// `RenderZoom`) rather than geometry-projected types — callers that
|
|
174
|
+
// only need a projection should use `getPage` / `getAnchorRects` /
|
|
175
|
+
// `getCaret` instead. The passthroughs exist specifically so UI
|
|
176
|
+
// consumers (selection-anchor resolver, table-grip layer,
|
|
177
|
+
// scope-rail layer, object-selection overlay, PM surface) can flip
|
|
178
|
+
// their `layoutFacet.getRenderFrame?.()` reads onto the geometry
|
|
179
|
+
// facet before the layout-facet versions are deleted.
|
|
180
|
+
getRenderFrame(
|
|
181
|
+
options?: import("../render/index.ts").RenderFrameQueryOptions,
|
|
182
|
+
): import("../render/index.ts").RenderFrame | null;
|
|
183
|
+
getRenderZoom(): import("../render/index.ts").RenderZoom | null;
|
|
184
|
+
|
|
185
|
+
// Viewport (Slice 3 wires real DOM reads) ------------------------------
|
|
186
|
+
getViewport(): Viewport;
|
|
187
|
+
subscribeViewport(listener: ViewportListener): () => void;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface CreateGeometryFacetInput {
|
|
191
|
+
layoutFacet: WordReviewEditorLayoutFacet;
|
|
192
|
+
/**
|
|
193
|
+
* Render-kernel getter. Geometry resolves through `resolveHitTest` /
|
|
194
|
+
* `resolveAnchorRects` against the kernel's current frame. When omitted
|
|
195
|
+
* (headless tests, pre-paint), `hitTest` returns null and
|
|
196
|
+
* `getAnchorRects` returns []. The layout-facet fallback was deleted in
|
|
197
|
+
* the refactor/05 Slice 6 wrapper-deletion pass (2026-04-22).
|
|
198
|
+
*/
|
|
199
|
+
renderKernel?: () => RenderKernel | null;
|
|
200
|
+
/**
|
|
201
|
+
* Canonical document getter. Required for `getReplacementEnvelope` to
|
|
202
|
+
* resolve scope ids to runtime offset ranges (via `resolveScope`).
|
|
203
|
+
* When omitted, `getReplacementEnvelope` returns `null` — same
|
|
204
|
+
* fall-through used when no renderKernel is wired. Slice 5 added.
|
|
205
|
+
*/
|
|
206
|
+
getCanonicalDocument?: () =>
|
|
207
|
+
| CanonicalDocument
|
|
208
|
+
| CanonicalDocumentEnvelope
|
|
209
|
+
| null
|
|
210
|
+
| undefined;
|
|
211
|
+
/**
|
|
212
|
+
* Optional viewport handle. When omitted, Slice 1's in-memory stub is
|
|
213
|
+
* used. Slice 3 installs a DOM-backed handle from `editor-surface`.
|
|
214
|
+
*/
|
|
215
|
+
viewport?: ViewportHandle;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// Factory
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
export function createGeometryFacet(
|
|
223
|
+
input: CreateGeometryFacetInput,
|
|
224
|
+
): GeometryFacet {
|
|
225
|
+
const { layoutFacet } = input;
|
|
226
|
+
const viewport = input.viewport ?? createViewport();
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
hitTest(point) {
|
|
230
|
+
// Slice 6 wrapper-deletion (2026-04-22): the layout-facet fallback
|
|
231
|
+
// was deleted. `hitTest` now resolves only through the render-kernel
|
|
232
|
+
// frame; returns null when no kernel is wired (headless tests,
|
|
233
|
+
// pre-paint).
|
|
234
|
+
const kernel = input.renderKernel?.();
|
|
235
|
+
if (!kernel) return null;
|
|
236
|
+
const frame = kernel.getRenderFrame();
|
|
237
|
+
const raw = resolveHitTest(frame, { xPx: point.xPx, yPx: point.yPx });
|
|
238
|
+
if (!raw) return null;
|
|
239
|
+
return {
|
|
240
|
+
pageIndex: raw.pageIndex,
|
|
241
|
+
regionKind: raw.regionKind,
|
|
242
|
+
blockId: raw.blockId,
|
|
243
|
+
fragmentId: raw.fragmentId,
|
|
244
|
+
lineIndex: raw.lineIndex,
|
|
245
|
+
runtimeOffset: raw.runtimeOffset,
|
|
246
|
+
};
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
getAnchorRects(query) {
|
|
250
|
+
// Slice 6 wrapper-deletion: kernel-only resolution; [] when no kernel.
|
|
251
|
+
const kernel = input.renderKernel?.();
|
|
252
|
+
if (!kernel) return [];
|
|
253
|
+
const frame = kernel.getRenderFrame();
|
|
254
|
+
const raw = resolveAnchorRects(frame, {
|
|
255
|
+
kind: query.kind,
|
|
256
|
+
value: query.value,
|
|
257
|
+
story: query.story,
|
|
258
|
+
});
|
|
259
|
+
if (raw.length === 0) return [];
|
|
260
|
+
return raw.map(
|
|
261
|
+
(r): GeometryRect => ({
|
|
262
|
+
leftPx: r.leftPx,
|
|
263
|
+
topPx: r.topPx,
|
|
264
|
+
widthPx: r.widthPx,
|
|
265
|
+
heightPx: r.heightPx,
|
|
266
|
+
space: "frame",
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
getAnchor(query) {
|
|
272
|
+
const rects = this.getAnchorRects(query);
|
|
273
|
+
return rects[0] ?? null;
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
getBlockRects(blockId) {
|
|
277
|
+
const kernel = input.renderKernel?.();
|
|
278
|
+
if (!kernel) return [];
|
|
279
|
+
return getBlockRectsFromFrame(kernel.getRenderFrame(), blockId);
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
getPage(target) {
|
|
283
|
+
const kernel = input.renderKernel?.();
|
|
284
|
+
if (!kernel) return null;
|
|
285
|
+
return getPageFromFrame(kernel.getRenderFrame(), target);
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
getBlock(blockId) {
|
|
289
|
+
const kernel = input.renderKernel?.();
|
|
290
|
+
if (!kernel) return null;
|
|
291
|
+
return getBlockGeometryFromFrame(kernel.getRenderFrame(), blockId);
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
getLineBoxes(pageIndex, options) {
|
|
295
|
+
return layoutFacet.getLineBoxes(pageIndex, options);
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
getCaret(offset, story) {
|
|
299
|
+
const kernel = input.renderKernel?.();
|
|
300
|
+
if (!kernel) return null;
|
|
301
|
+
return resolveCaretGeometry(kernel.getRenderFrame(), offset, story);
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
getSelectionRects(range) {
|
|
305
|
+
const kernel = input.renderKernel?.();
|
|
306
|
+
if (!kernel) return [];
|
|
307
|
+
return resolveSelectionRects(kernel.getRenderFrame(), range);
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
getReplacementEnvelope(scopeId) {
|
|
311
|
+
const kernel = input.renderKernel?.();
|
|
312
|
+
if (!kernel) return null;
|
|
313
|
+
const document = input.getCanonicalDocument?.();
|
|
314
|
+
if (!document) return null;
|
|
315
|
+
const anchor = resolveScope(document, scopeId);
|
|
316
|
+
if (!anchor) return null;
|
|
317
|
+
let scope: ReplacementScope;
|
|
318
|
+
if (anchor.kind === "range") {
|
|
319
|
+
scope = { kind: "range", from: anchor.from, to: anchor.to };
|
|
320
|
+
} else if (anchor.kind === "detached") {
|
|
321
|
+
scope = {
|
|
322
|
+
kind: "detached",
|
|
323
|
+
lastKnownRange: {
|
|
324
|
+
from: anchor.lastKnownRange.from,
|
|
325
|
+
to: anchor.lastKnownRange.to,
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
} else {
|
|
329
|
+
// node-anchor kind — not a replaceable range; caller wanted a
|
|
330
|
+
// range resolution. Future slice may add node-based envelopes.
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
return resolveReplacementEnvelope(kernel.getRenderFrame(), scope);
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
getObjectHandles(objectId) {
|
|
337
|
+
const kernel = input.renderKernel?.();
|
|
338
|
+
if (!kernel) return [];
|
|
339
|
+
return resolveObjectHandles(kernel.getRenderFrame(), objectId);
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
// Render-kernel passthroughs (migration target for layout-facet
|
|
343
|
+
// deprecated `getRenderFrame` / `getRenderZoom`).
|
|
344
|
+
getRenderFrame(options) {
|
|
345
|
+
const kernel = input.renderKernel?.();
|
|
346
|
+
if (!kernel) return null;
|
|
347
|
+
return kernel.getRenderFrame(options);
|
|
348
|
+
},
|
|
349
|
+
|
|
350
|
+
getRenderZoom() {
|
|
351
|
+
const kernel = input.renderKernel?.();
|
|
352
|
+
if (!kernel) return null;
|
|
353
|
+
return kernel.getZoom();
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
getViewport() {
|
|
357
|
+
return viewport.getViewport();
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
subscribeViewport(listener) {
|
|
361
|
+
return viewport.subscribe(listener);
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Geometry Projection — type surface.
|
|
3
|
+
*
|
|
4
|
+
* Per `docs/architecture/05-geometry-projection.md`, layer 05 owns concrete
|
|
5
|
+
* visual geometry (rects, hit-tests, carets, envelopes, anchors). This module
|
|
6
|
+
* defines the public type surface consumed by the `GeometryFacet` and by
|
|
7
|
+
* consumers through layer 07.
|
|
8
|
+
*
|
|
9
|
+
* Slice 1 (this slice) reserves the directory and publishes these types while
|
|
10
|
+
* the `GeometryFacet` delegates to the existing `layout/public-facet.ts` +
|
|
11
|
+
* `render/render-kernel.ts` sites — so the Slice-1 shapes intentionally
|
|
12
|
+
* mirror `RenderFrameRect`, `RenderHitResult`, and `RenderAnchorQuery` from
|
|
13
|
+
* `../render/render-frame-types.ts`. Slices 2+ migrate the implementations
|
|
14
|
+
* here and may evolve the types independently of the render-kernel shapes.
|
|
15
|
+
*
|
|
16
|
+
* Contract references (architecture 05):
|
|
17
|
+
* G1 — geometry is a projection of truth, not truth
|
|
18
|
+
* G2 — no DOM reads as document-structure authority
|
|
19
|
+
* G3 — all layout reads in callbacks coalesce via rAF
|
|
20
|
+
* G4 — invalidation is bounded by layout invalidation
|
|
21
|
+
* G5 — geometry coordinates are explicit (space + unit)
|
|
22
|
+
* G6 — hit-test, caret, and envelope are first-class operations
|
|
23
|
+
* G7 — replacement envelopes are stable under edits at the same scope
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { EditorStoryTarget } from "../../api/public-types";
|
|
27
|
+
import type { PublicPageRegion } from "../layout/public-facet.ts";
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// G5 · Coordinate space tags
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Every `GeometryRect` carries an explicit coordinate space. Consumers choose;
|
|
35
|
+
* the geometry layer never silently converts.
|
|
36
|
+
*
|
|
37
|
+
* - `twips` — document-relative semantic units. Zoom-independent. The
|
|
38
|
+
* representation the oracle compares against.
|
|
39
|
+
* - `frame` — frame-local pixels, post-zoom, origin at the frame root.
|
|
40
|
+
* This is what the render kernel emits today.
|
|
41
|
+
* - `overlay`— overlay-local pixels, origin at the overlay root (for
|
|
42
|
+
* chrome surfaces that read rects projected through
|
|
43
|
+
* `chrome-overlay-projector`).
|
|
44
|
+
*/
|
|
45
|
+
export type GeometrySpace = "twips" | "frame" | "overlay";
|
|
46
|
+
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Precision discriminator (refactor/05 Slice 7b · 2026-04-22)
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Precision tag carried on geometry results so callers can tell exact
|
|
53
|
+
* projections from substrate placeholders.
|
|
54
|
+
*
|
|
55
|
+
* - `"exact"` — value comes from a real per-run / per-line
|
|
56
|
+
* projection and should be consumed as ground
|
|
57
|
+
* truth. Consumers may render with pixel-level
|
|
58
|
+
* confidence.
|
|
59
|
+
* - `"within-tolerance"` — value comes from a real projection but was
|
|
60
|
+
* widened to a conservative bound (e.g. union
|
|
61
|
+
* rect across a wrapped range). Safe for visual
|
|
62
|
+
* chrome; may overshoot by one line.
|
|
63
|
+
* - `"heuristic"` — value comes from a substrate placeholder:
|
|
64
|
+
* hardcoded direction, baseline derived from a
|
|
65
|
+
* height ratio, object handles derived from
|
|
66
|
+
* enclosing-block bbox, etc. Consumers that need
|
|
67
|
+
* correctness (not just visual) should fall back
|
|
68
|
+
* or gate.
|
|
69
|
+
*
|
|
70
|
+
* Fields are optional on existing result types for backward-compat; treat
|
|
71
|
+
* a missing `precision` as `"exact"` when derived from the render kernel's
|
|
72
|
+
* frame/anchor index, and as `"heuristic"` when the value is known to be a
|
|
73
|
+
* substrate placeholder (caller-side convention — the method JSDoc names
|
|
74
|
+
* which).
|
|
75
|
+
*/
|
|
76
|
+
export type GeometryPrecision = "exact" | "within-tolerance" | "heuristic";
|
|
77
|
+
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Core rect shape
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Rect carrying its coordinate space. Pixel-valued in `frame` / `overlay`;
|
|
84
|
+
* twip-valued in `twips`. Consumers read `space` before interpreting the
|
|
85
|
+
* numeric fields.
|
|
86
|
+
*
|
|
87
|
+
* `precision` is optional; rects emitted from exact frame/anchor projections
|
|
88
|
+
* omit it (implicitly exact), while rects derived from substrate placeholders
|
|
89
|
+
* (union-rect selection, block-bbox object handle, etc.) tag themselves so
|
|
90
|
+
* callers can discriminate.
|
|
91
|
+
*/
|
|
92
|
+
export interface GeometryRect {
|
|
93
|
+
leftPx: number;
|
|
94
|
+
topPx: number;
|
|
95
|
+
widthPx: number;
|
|
96
|
+
heightPx: number;
|
|
97
|
+
space: GeometrySpace;
|
|
98
|
+
precision?: GeometryPrecision;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Per-granularity geometry nodes (read models; Slice 2+ populates them)
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
export interface PageGeometry {
|
|
106
|
+
pageId: string;
|
|
107
|
+
pageIndex: number;
|
|
108
|
+
frame: GeometryRect;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface BlockGeometry {
|
|
112
|
+
blockId: string;
|
|
113
|
+
rects: readonly GeometryRect[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface LineGeometry {
|
|
117
|
+
fragmentId: string;
|
|
118
|
+
lineIndex: number;
|
|
119
|
+
rect: GeometryRect;
|
|
120
|
+
/** Baseline offset from the line rect's top, in the rect's unit. */
|
|
121
|
+
baseline: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface RunGeometry {
|
|
125
|
+
runId: string;
|
|
126
|
+
rect: GeometryRect;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Caret + selection (Slice 4)
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
export interface CaretGeometry {
|
|
134
|
+
rect: GeometryRect;
|
|
135
|
+
/** Baseline offset from `rect.topPx`, in the rect's unit. */
|
|
136
|
+
baseline: number;
|
|
137
|
+
/** Caret height in the rect's unit. */
|
|
138
|
+
height: number;
|
|
139
|
+
/** Writing direction at the caret position. */
|
|
140
|
+
direction: "ltr" | "rtl";
|
|
141
|
+
/**
|
|
142
|
+
* Precision tag. Substrate caret today hardcodes `direction: "ltr"`
|
|
143
|
+
* and derives `baseline` from a `0.8 * height` heuristic — both
|
|
144
|
+
* fields are flagged `"heuristic"` until the render-kernel's per-run
|
|
145
|
+
* anchors ship. Rect position itself comes from `byRuntimeOffset` on
|
|
146
|
+
* the anchor index and is `"exact"` for unwrapped paragraphs,
|
|
147
|
+
* `"within-tolerance"` inside wrapped paragraphs. The coarsest tag
|
|
148
|
+
* wins — so today `precision` is always `"heuristic"`.
|
|
149
|
+
*/
|
|
150
|
+
precision?: GeometryPrecision;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// Hit-test (Slice 2 owns the real implementation)
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
export interface HitTestPoint {
|
|
158
|
+
xPx: number;
|
|
159
|
+
yPx: number;
|
|
160
|
+
space: GeometrySpace;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface HitTestResult {
|
|
164
|
+
pageIndex: number;
|
|
165
|
+
regionKind: PublicPageRegion["kind"];
|
|
166
|
+
blockId: string;
|
|
167
|
+
fragmentId: string;
|
|
168
|
+
lineIndex: number;
|
|
169
|
+
runtimeOffset: number;
|
|
170
|
+
/**
|
|
171
|
+
* Caret association relative to the resolved offset — reserved for Slice 4
|
|
172
|
+
* when caret geometry lands. Slice 1 proxy sets this to "after" to mirror
|
|
173
|
+
* the render-kernel's implicit association.
|
|
174
|
+
*/
|
|
175
|
+
assoc?: "before" | "after";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Anchor queries (Slice 2 migrates real implementation)
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
export type AnchorQueryKind =
|
|
183
|
+
| "runtime-offset"
|
|
184
|
+
| "block-id"
|
|
185
|
+
| "fragment-id"
|
|
186
|
+
| "scope-id"
|
|
187
|
+
| "comment-id"
|
|
188
|
+
| "revision-id"
|
|
189
|
+
| "page-index";
|
|
190
|
+
|
|
191
|
+
export interface AnchorQuery {
|
|
192
|
+
kind: AnchorQueryKind;
|
|
193
|
+
value: string | number;
|
|
194
|
+
story?: EditorStoryTarget;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
// Replacement envelopes + object handles (Slice 5)
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
export type EnvelopeConfidence = "exact" | "medium" | "detached";
|
|
202
|
+
|
|
203
|
+
export interface EnvelopeBundle {
|
|
204
|
+
/**
|
|
205
|
+
* Rect coverage for the resolved scope. Slice-5 substrate produces
|
|
206
|
+
* **one** union rect for any non-collapsed range (mirrors the
|
|
207
|
+
* Slice-4 `resolveSelectionRects` contract); when the render kernel
|
|
208
|
+
* grows per-run anchors, this field upgrades to one-rect-per-line
|
|
209
|
+
* automatically. Consumers that need per-line enumeration TODAY
|
|
210
|
+
* should check `scopeRects.length` and fall back to their own line
|
|
211
|
+
* walk if the count is lower than expected.
|
|
212
|
+
*/
|
|
213
|
+
scopeRects: readonly GeometryRect[];
|
|
214
|
+
/** Anchor point consumers attach chrome to (top-left of first rect). */
|
|
215
|
+
attachPoint: { xPx: number; yPx: number; space: GeometrySpace };
|
|
216
|
+
/**
|
|
217
|
+
* How confident the envelope is. `"detached"` means the scope's markers
|
|
218
|
+
* were removed; `lastKnownRange` describes the last observed rects.
|
|
219
|
+
*/
|
|
220
|
+
confidence: EnvelopeConfidence;
|
|
221
|
+
/**
|
|
222
|
+
* Number of entries in `scopeRects` — NOT the number of line boxes
|
|
223
|
+
* the scope covers in the source document. Under the Slice-5
|
|
224
|
+
* substrate this is always `1` for non-collapsed ranges; the field
|
|
225
|
+
* becomes a true line-count once per-run anchors land. Renaming to
|
|
226
|
+
* `scopeRectCount` is tracked in the deferred-items list for the
|
|
227
|
+
* layer-05 closure.
|
|
228
|
+
*/
|
|
229
|
+
linesCrossed: number;
|
|
230
|
+
/**
|
|
231
|
+
* Precision tag. `"exact"` when the envelope collapsed to a caret rect
|
|
232
|
+
* (single anchor position); `"within-tolerance"` when the envelope is
|
|
233
|
+
* a single union rect over a wrapped range (substrate default — may
|
|
234
|
+
* overshoot by up to one line of trailing whitespace); `"heuristic"`
|
|
235
|
+
* when the markers were detached and the envelope uses a last-known
|
|
236
|
+
* fallback. Consumers should gate per-line chrome work on
|
|
237
|
+
* `precision === "exact"`.
|
|
238
|
+
*/
|
|
239
|
+
precision?: GeometryPrecision;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
// Viewport (Slice 3 wires the real DOM read path)
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
|
|
246
|
+
export interface Viewport {
|
|
247
|
+
/** Scroll position of the editor root, in CSS pixels. */
|
|
248
|
+
scrollLeftPx: number;
|
|
249
|
+
scrollTopPx: number;
|
|
250
|
+
/** Device-pixel-ratio snapshot at read time. */
|
|
251
|
+
dpr: number;
|
|
252
|
+
/** Current zoom pxPerTwip (mirrors `RenderZoom.pxPerTwip`). */
|
|
253
|
+
pxPerTwip: number;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export type ViewportListener = (viewport: Viewport) => void;
|