@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,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Hit-test.
|
|
3
|
+
*
|
|
4
|
+
* Pure projection of a `RenderFrame` + `RenderPoint` onto a canonical
|
|
5
|
+
* `RenderHitResult`. Walks pages → regions → blocks → lines, snapping to
|
|
6
|
+
* the nearest line's first anchor to resolve a runtime offset.
|
|
7
|
+
*
|
|
8
|
+
* Slice 2a moves this implementation here from
|
|
9
|
+
* `src/runtime/layout/public-facet.ts`. The layout facet's deprecated
|
|
10
|
+
* `hitTest` method now delegates to `resolveHitTest` through this module —
|
|
11
|
+
* behavior is byte-identical. Slice 6 deletes the layout-facet wrapper.
|
|
12
|
+
*
|
|
13
|
+
* Contract (architecture 05 G6): hit-test is a first-class operation owned
|
|
14
|
+
* by layer 05; consumers MUST route through the geometry facet rather than
|
|
15
|
+
* re-implementing the walk.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
RenderBlock,
|
|
20
|
+
RenderFrame,
|
|
21
|
+
RenderFrameRect,
|
|
22
|
+
RenderHitResult,
|
|
23
|
+
RenderPage,
|
|
24
|
+
RenderPoint,
|
|
25
|
+
RenderStoryRegion,
|
|
26
|
+
} from "../render/index.ts";
|
|
27
|
+
|
|
28
|
+
export function resolveHitTest(
|
|
29
|
+
frame: RenderFrame | null,
|
|
30
|
+
point: RenderPoint,
|
|
31
|
+
): RenderHitResult | null {
|
|
32
|
+
if (!frame) return null;
|
|
33
|
+
for (const page of frame.pages) {
|
|
34
|
+
if (!containsPoint(page.frame, point)) continue;
|
|
35
|
+
// Check body first — it owns the bulk of the page. Header /
|
|
36
|
+
// footer / footnotes are secondary stories and only matter when
|
|
37
|
+
// the point falls outside the body.
|
|
38
|
+
const bodyHit = hitTestStoryRegion(page, point, page.regions.body);
|
|
39
|
+
if (bodyHit) return bodyHit;
|
|
40
|
+
if (page.regions.header) {
|
|
41
|
+
const header = hitTestStoryRegion(page, point, page.regions.header);
|
|
42
|
+
if (header) return header;
|
|
43
|
+
}
|
|
44
|
+
if (page.regions.footer) {
|
|
45
|
+
const footer = hitTestStoryRegion(page, point, page.regions.footer);
|
|
46
|
+
if (footer) return footer;
|
|
47
|
+
}
|
|
48
|
+
// Refactor/05 Slice 7d: footnote regions now participate in
|
|
49
|
+
// hit-test routing so a click inside the footnote area resolves
|
|
50
|
+
// to the correct story offset rather than snapping to the
|
|
51
|
+
// enclosing body page. Each footnote area is a first-class
|
|
52
|
+
// RenderStoryRegion with its own story target + blocks.
|
|
53
|
+
if (page.regions.footnotes) {
|
|
54
|
+
for (const footnoteRegion of page.regions.footnotes) {
|
|
55
|
+
const hit = hitTestStoryRegion(page, point, footnoteRegion);
|
|
56
|
+
if (hit) return hit;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function hitTestStoryRegion(
|
|
64
|
+
page: RenderPage,
|
|
65
|
+
point: RenderPoint,
|
|
66
|
+
region: RenderStoryRegion,
|
|
67
|
+
): RenderHitResult | null {
|
|
68
|
+
if (!containsPoint(region.frame, point)) return null;
|
|
69
|
+
for (const block of region.blocks) {
|
|
70
|
+
if (!containsPoint(block.frame, point)) continue;
|
|
71
|
+
let bestLineIndex = -1;
|
|
72
|
+
let bestLineDistance = Number.POSITIVE_INFINITY;
|
|
73
|
+
for (let i = 0; i < block.lines.length; i++) {
|
|
74
|
+
const line = block.lines[i]!;
|
|
75
|
+
const midY = line.frame.topPx + line.frame.heightPx / 2;
|
|
76
|
+
const distance = Math.abs(midY - point.yPx);
|
|
77
|
+
if (distance < bestLineDistance) {
|
|
78
|
+
bestLineDistance = distance;
|
|
79
|
+
bestLineIndex = i;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const lineIndex = bestLineIndex >= 0 ? bestLineIndex : 0;
|
|
83
|
+
const line = block.lines[lineIndex];
|
|
84
|
+
const runtimeOffset = line?.anchors[0]?.runtimeOffset ?? block.fragment.from;
|
|
85
|
+
return {
|
|
86
|
+
pageIndex: page.page.pageIndex,
|
|
87
|
+
regionKind: region.region.kind,
|
|
88
|
+
blockId: block.fragment.blockId,
|
|
89
|
+
fragmentId: block.fragment.fragmentId,
|
|
90
|
+
lineIndex,
|
|
91
|
+
runtimeOffset,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Point fell inside the region but between blocks — snap to the nearest block.
|
|
95
|
+
let nearestBlock: RenderBlock | null = null;
|
|
96
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
97
|
+
for (const block of region.blocks) {
|
|
98
|
+
const distance = Math.min(
|
|
99
|
+
Math.abs(point.yPx - block.frame.topPx),
|
|
100
|
+
Math.abs(point.yPx - (block.frame.topPx + block.frame.heightPx)),
|
|
101
|
+
);
|
|
102
|
+
if (distance < nearestDistance) {
|
|
103
|
+
nearestBlock = block;
|
|
104
|
+
nearestDistance = distance;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!nearestBlock) return null;
|
|
108
|
+
return {
|
|
109
|
+
pageIndex: page.page.pageIndex,
|
|
110
|
+
regionKind: region.region.kind,
|
|
111
|
+
blockId: nearestBlock.fragment.blockId,
|
|
112
|
+
fragmentId: nearestBlock.fragment.fragmentId,
|
|
113
|
+
lineIndex: 0,
|
|
114
|
+
runtimeOffset: nearestBlock.fragment.from,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function containsPoint(rect: RenderFrameRect, point: RenderPoint): boolean {
|
|
119
|
+
return (
|
|
120
|
+
point.xPx >= rect.leftPx &&
|
|
121
|
+
point.xPx <= rect.leftPx + rect.widthPx &&
|
|
122
|
+
point.yPx >= rect.topPx &&
|
|
123
|
+
point.yPx <= rect.topPx + rect.heightPx
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Geometry Projection — barrel.
|
|
3
|
+
*
|
|
4
|
+
* Public surface for the runtime-internal geometry layer. Architecture target
|
|
5
|
+
* lives at `docs/architecture/05-geometry-projection.md`; slice-by-slice
|
|
6
|
+
* migration plan at `docs/plans/refactor/05-geometry-projection.md`.
|
|
7
|
+
*
|
|
8
|
+
* Slice 1 exports the type surface + facet factory (thin proxy). Later slices
|
|
9
|
+
* add `hit-test.ts`, `project-anchors.ts`, `project-fragments.ts`,
|
|
10
|
+
* `caret-geometry.ts`, `replacement-envelope.ts`, `object-handles.ts`, and
|
|
11
|
+
* `projector.ts`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type {
|
|
15
|
+
GeometrySpace,
|
|
16
|
+
GeometryRect,
|
|
17
|
+
PageGeometry,
|
|
18
|
+
BlockGeometry,
|
|
19
|
+
LineGeometry,
|
|
20
|
+
RunGeometry,
|
|
21
|
+
CaretGeometry,
|
|
22
|
+
HitTestPoint,
|
|
23
|
+
HitTestResult,
|
|
24
|
+
AnchorQueryKind,
|
|
25
|
+
AnchorQuery,
|
|
26
|
+
EnvelopeConfidence,
|
|
27
|
+
EnvelopeBundle,
|
|
28
|
+
Viewport,
|
|
29
|
+
ViewportListener,
|
|
30
|
+
} from "./geometry-types.ts";
|
|
31
|
+
|
|
32
|
+
export type {
|
|
33
|
+
GeometryFacet,
|
|
34
|
+
CreateGeometryFacetInput,
|
|
35
|
+
} from "./geometry-facet.ts";
|
|
36
|
+
export { createGeometryFacet } from "./geometry-facet.ts";
|
|
37
|
+
export { createInertGeometryFacet } from "./inert-geometry-facet.ts";
|
|
38
|
+
|
|
39
|
+
export type {
|
|
40
|
+
ViewportHandle,
|
|
41
|
+
RootViewportHandle,
|
|
42
|
+
CreateViewportFromRootInput,
|
|
43
|
+
} from "./viewport.ts";
|
|
44
|
+
export { createViewport, createViewportFromRoot } from "./viewport.ts";
|
|
45
|
+
|
|
46
|
+
export type { GeometryCacheKey } from "./invalidation.ts";
|
|
47
|
+
export { makeGeometryCacheKey } from "./invalidation.ts";
|
|
48
|
+
|
|
49
|
+
export type {
|
|
50
|
+
PageOverlayRect,
|
|
51
|
+
VisiblePageIndexRange as OverlayVisiblePageIndexRange,
|
|
52
|
+
} from "./overlay-rects.ts";
|
|
53
|
+
export { resolvePageOverlayRectsFromGeometry } from "./overlay-rects.ts";
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
resolveCaretGeometry,
|
|
57
|
+
resolveSelectionRects,
|
|
58
|
+
} from "./caret-geometry.ts";
|
|
59
|
+
|
|
60
|
+
export { resolveObjectHandles } from "./object-handles.ts";
|
|
61
|
+
|
|
62
|
+
export type { ReplacementScope } from "./replacement-envelope.ts";
|
|
63
|
+
export { resolveReplacementEnvelope } from "./replacement-envelope.ts";
|
|
64
|
+
|
|
65
|
+
export type {
|
|
66
|
+
GeometryDebugEntry,
|
|
67
|
+
GeometryDebugCatalog,
|
|
68
|
+
GeometryDebugSample,
|
|
69
|
+
BuildGeometryDebugEntryInputs,
|
|
70
|
+
} from "./projector.ts";
|
|
71
|
+
export { buildGeometryDebugEntry } from "./projector.ts";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inert geometry facet used during the runtime-loading phase.
|
|
3
|
+
*
|
|
4
|
+
* Returns empty or null values for every query; subscribeViewport is a no-op.
|
|
5
|
+
* Mirrors `createInertLayoutFacet` in `src/runtime/layout/inert-layout-facet.ts`.
|
|
6
|
+
* The React shell replaces this with the real facet from
|
|
7
|
+
* `createGeometryFacet(...)` once the runtime is ready, so consumers never
|
|
8
|
+
* see a "missing" facet — only an empty one.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { GeometryFacet } from "./geometry-facet.ts";
|
|
12
|
+
import type { Viewport } from "./geometry-types.ts";
|
|
13
|
+
|
|
14
|
+
const INERT_VIEWPORT: Viewport = Object.freeze({
|
|
15
|
+
scrollLeftPx: 0,
|
|
16
|
+
scrollTopPx: 0,
|
|
17
|
+
dpr: 1,
|
|
18
|
+
pxPerTwip: 0,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export function createInertGeometryFacet(): GeometryFacet {
|
|
22
|
+
return {
|
|
23
|
+
hitTest: () => null,
|
|
24
|
+
getAnchorRects: () => [],
|
|
25
|
+
getAnchor: () => null,
|
|
26
|
+
getBlockRects: () => [],
|
|
27
|
+
getPage: () => null,
|
|
28
|
+
getBlock: () => null,
|
|
29
|
+
getLineBoxes: () => [],
|
|
30
|
+
// Scope-rail proxies removed in refactor/06 Slice 4C rail-seam inversion.
|
|
31
|
+
// Rail composition lives on `runtime.workflow.*` — the loading boundary
|
|
32
|
+
// exposes an inert workflow facet with the matching stubs.
|
|
33
|
+
getCaret: () => null,
|
|
34
|
+
getSelectionRects: () => [],
|
|
35
|
+
getReplacementEnvelope: () => null,
|
|
36
|
+
getObjectHandles: () => [],
|
|
37
|
+
// Render-kernel passthroughs — inert boundary has no kernel.
|
|
38
|
+
getRenderFrame: () => null,
|
|
39
|
+
getRenderZoom: () => null,
|
|
40
|
+
getViewport: () => INERT_VIEWPORT,
|
|
41
|
+
subscribeViewport: () => () => undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Geometry invalidation + cache-key helpers.
|
|
3
|
+
*
|
|
4
|
+
* Per architecture 05 contract G4, geometry invalidation is derived, not
|
|
5
|
+
* independent: when layout invalidates a page range, geometry for that range
|
|
6
|
+
* re-projects on next read. Per performance invariant 3 (CLAUDE.md), cache
|
|
7
|
+
* keys must be structural or content-specific — never `revisionToken` alone.
|
|
8
|
+
*
|
|
9
|
+
* Slice 1 scope: publish the key shape + stub `makeGeometryCacheKey` so
|
|
10
|
+
* later slices can thread it through the facet. No cache exists yet;
|
|
11
|
+
* Slice 2+ wires one behind the migrated `hitTest` / `getAnchorRects`
|
|
12
|
+
* implementations.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { GeometrySpace } from "./geometry-types.ts";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Geometry cache key. Keys are structural: `{ layoutRevision, zoom, space }`.
|
|
19
|
+
* Never `revisionToken` alone — that bypasses invariant 3 and re-computes
|
|
20
|
+
* every keystroke.
|
|
21
|
+
*/
|
|
22
|
+
export interface GeometryCacheKey {
|
|
23
|
+
layoutRevision: number;
|
|
24
|
+
pxPerTwip: number;
|
|
25
|
+
space: GeometrySpace;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Produce a stable string key from a `GeometryCacheKey`. Numbers are
|
|
30
|
+
* stringified via `toString()` (no locale) so cross-environment lookup is
|
|
31
|
+
* deterministic.
|
|
32
|
+
*/
|
|
33
|
+
export function makeGeometryCacheKey(key: GeometryCacheKey): string {
|
|
34
|
+
return `${key.layoutRevision}|${key.pxPerTwip}|${key.space}`;
|
|
35
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Object handle projection.
|
|
3
|
+
*
|
|
4
|
+
* `resolveObjectHandles(frame, objectId)` returns the set of
|
|
5
|
+
* `GeometryRect` handle points a chrome surface paints on a selected
|
|
6
|
+
* drawing frame / table / image: 8 resize grips (4 corners + 4 edge
|
|
7
|
+
* midpoints) plus 1 rotate anchor (centered above the top edge).
|
|
8
|
+
*
|
|
9
|
+
* Slice-7c substrate: the helper now routes through
|
|
10
|
+
* `frame.anchorIndex.byObjectId(objectId)` instead of `byBlockId`. The
|
|
11
|
+
* kernel's Slice-7c substrate delegates `byObjectId` → `byBlockId`
|
|
12
|
+
* (since object-metadata emission from the layout facet has not
|
|
13
|
+
* shipped), so behavior is unchanged today — but the consumer now
|
|
14
|
+
* reads the right seam. When the kernel grows per-object metadata
|
|
15
|
+
* (Slice 7d follow-up on the layout side), handles upgrade to the
|
|
16
|
+
* object's own bbox automatically.
|
|
17
|
+
*
|
|
18
|
+
* Each handle is a small zero-by-zero point rect (`widthPx === heightPx
|
|
19
|
+
* === 0`), letting chrome decide the painted grip size via CSS. The
|
|
20
|
+
* order is stable:
|
|
21
|
+
*
|
|
22
|
+
* index 0 — top-left index 4 — right
|
|
23
|
+
* index 1 — top-center index 5 — bottom-left
|
|
24
|
+
* index 2 — top-right index 6 — bottom-center
|
|
25
|
+
* index 3 — left index 7 — bottom-right
|
|
26
|
+
* index 8 — rotate anchor (20 px above the top-center handle)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import type { RenderFrame, RenderFrameRect } from "../render/index.ts";
|
|
30
|
+
import type { GeometryRect } from "./geometry-types.ts";
|
|
31
|
+
|
|
32
|
+
const ROTATE_HANDLE_OFFSET_PX = 20;
|
|
33
|
+
|
|
34
|
+
export function resolveObjectHandles(
|
|
35
|
+
frame: RenderFrame | null,
|
|
36
|
+
objectId: string,
|
|
37
|
+
): readonly GeometryRect[] {
|
|
38
|
+
if (!frame) return [];
|
|
39
|
+
const bbox = frame.anchorIndex.byObjectId(objectId);
|
|
40
|
+
if (!bbox) return [];
|
|
41
|
+
return buildHandles(bbox);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function buildHandles(bbox: RenderFrameRect): readonly GeometryRect[] {
|
|
45
|
+
const { leftPx, topPx, widthPx, heightPx } = bbox;
|
|
46
|
+
const right = leftPx + widthPx;
|
|
47
|
+
const bottom = topPx + heightPx;
|
|
48
|
+
const midX = leftPx + widthPx / 2;
|
|
49
|
+
const midY = topPx + heightPx / 2;
|
|
50
|
+
// Slice 7b (2026-04-22): object handles derive from the enclosing
|
|
51
|
+
// block's bbox (via `byBlockId`), not from the object's own bbox.
|
|
52
|
+
// When the object is a block-level drawing the bbox matches the
|
|
53
|
+
// object exactly (`within-tolerance`); when it's an inline image
|
|
54
|
+
// embedded in a paragraph the bbox is the whole paragraph rect
|
|
55
|
+
// (`heuristic`). Without an object index we can't discriminate the
|
|
56
|
+
// two cases — tag the coarser `heuristic` so consumers treat all
|
|
57
|
+
// handles as substrate-grade pending refactor/05 Slice 7 Task 4.
|
|
58
|
+
const point = (xPx: number, yPx: number): GeometryRect => ({
|
|
59
|
+
leftPx: xPx,
|
|
60
|
+
topPx: yPx,
|
|
61
|
+
widthPx: 0,
|
|
62
|
+
heightPx: 0,
|
|
63
|
+
space: "frame",
|
|
64
|
+
precision: "heuristic",
|
|
65
|
+
});
|
|
66
|
+
return [
|
|
67
|
+
point(leftPx, topPx), // 0 top-left
|
|
68
|
+
point(midX, topPx), // 1 top-center
|
|
69
|
+
point(right, topPx), // 2 top-right
|
|
70
|
+
point(leftPx, midY), // 3 left
|
|
71
|
+
point(right, midY), // 4 right
|
|
72
|
+
point(leftPx, bottom), // 5 bottom-left
|
|
73
|
+
point(midX, bottom), // 6 bottom-center
|
|
74
|
+
point(right, bottom), // 7 bottom-right
|
|
75
|
+
point(midX, topPx - ROTATE_HANDLE_OFFSET_PX), // 8 rotate
|
|
76
|
+
];
|
|
77
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Overlay rect projection.
|
|
3
|
+
*
|
|
4
|
+
* Pure helper for projecting a `GeometryFacet` into the
|
|
5
|
+
* `PageOverlayRect[]` shape chrome overlays consume. Lives in
|
|
6
|
+
* `src/runtime/geometry/` (not alongside the `.tsx` overlay component)
|
|
7
|
+
* so layer-05 tests can consume it without crossing into
|
|
8
|
+
* `src/ui-tailwind/**`, and because the helper has no React concerns.
|
|
9
|
+
*
|
|
10
|
+
* The overlay component (`src/ui-tailwind/chrome-overlay/tw-page-stack-
|
|
11
|
+
* overlay-layer.tsx`) re-exports this via a direct import so its public
|
|
12
|
+
* API surface is unchanged.
|
|
13
|
+
*
|
|
14
|
+
* **Coordinate-space caveat (known divergence).** The kernel stacks
|
|
15
|
+
* pages with `PAGE_GAP_PX = 16` (see `src/runtime/render/render-kernel.ts`)
|
|
16
|
+
* while the DOM stacks them with `interGapPx = 48` (see
|
|
17
|
+
* `src/ui-tailwind/editor-surface/pm-page-break-decorations.ts`). Using
|
|
18
|
+
* `page.frame.topPx` directly as an overlay rect is correct only for
|
|
19
|
+
* page 0; for pages 2..N the overlay rect drifts by ~32 px per boundary.
|
|
20
|
+
* This helper is the clean substrate; a subsequent Slice-3c reconciles
|
|
21
|
+
* the two gap constants before any production consumer wires the warm
|
|
22
|
+
* path. Until then the overlay component keeps its DOM-measurement path
|
|
23
|
+
* as the default and treats the geometry path as experimental.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { GeometryFacet } from "./geometry-facet.ts";
|
|
27
|
+
|
|
28
|
+
export interface PageOverlayRect {
|
|
29
|
+
pageId: string;
|
|
30
|
+
pageIndex: number;
|
|
31
|
+
topPx: number;
|
|
32
|
+
bottomPx: number;
|
|
33
|
+
heightPx: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface VisiblePageIndexRange {
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeVisibleRange(
|
|
42
|
+
range: VisiblePageIndexRange | null | undefined,
|
|
43
|
+
pageCount: number,
|
|
44
|
+
): VisiblePageIndexRange | null {
|
|
45
|
+
if (!range || pageCount <= 0) return null;
|
|
46
|
+
const start = Math.max(0, Math.min(range.start, pageCount));
|
|
47
|
+
const end = Math.max(start, Math.min(range.end, pageCount));
|
|
48
|
+
if (start >= end) return null;
|
|
49
|
+
return { start, end };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build the `PageOverlayRect` list from a `GeometryFacet`. Returns
|
|
54
|
+
* `null` when the facet does not resolve page 0 (cold-open) so the
|
|
55
|
+
* caller can fall back to a DOM-measurement path.
|
|
56
|
+
*/
|
|
57
|
+
export function resolvePageOverlayRectsFromGeometry(
|
|
58
|
+
geometryFacet: GeometryFacet,
|
|
59
|
+
pageCount: number,
|
|
60
|
+
visiblePageIndexRange: VisiblePageIndexRange | null | undefined,
|
|
61
|
+
): readonly PageOverlayRect[] | null {
|
|
62
|
+
if (pageCount <= 0) return [];
|
|
63
|
+
const first = geometryFacet.getPage(0);
|
|
64
|
+
if (!first) return null;
|
|
65
|
+
const normalizedVisible = normalizeVisibleRange(
|
|
66
|
+
visiblePageIndexRange,
|
|
67
|
+
pageCount,
|
|
68
|
+
);
|
|
69
|
+
const rects: PageOverlayRect[] = [];
|
|
70
|
+
for (let i = 0; i < pageCount; i += 1) {
|
|
71
|
+
if (normalizedVisible) {
|
|
72
|
+
if (i < normalizedVisible.start || i >= normalizedVisible.end) continue;
|
|
73
|
+
}
|
|
74
|
+
const page = geometryFacet.getPage(i);
|
|
75
|
+
if (!page) continue;
|
|
76
|
+
rects.push({
|
|
77
|
+
pageId: page.pageId,
|
|
78
|
+
pageIndex: page.pageIndex,
|
|
79
|
+
topPx: page.frame.topPx,
|
|
80
|
+
bottomPx: page.frame.topPx + page.frame.heightPx,
|
|
81
|
+
heightPx: page.frame.heightPx,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return rects;
|
|
85
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Anchor rect projection.
|
|
3
|
+
*
|
|
4
|
+
* Pure projection of a `RenderAnchorQuery` against a frame's
|
|
5
|
+
* `anchorIndex` into a rect list. Dispatches on query kind: runtime-offset,
|
|
6
|
+
* block-id, fragment-id, scope-id, comment-id, revision-id, page-index.
|
|
7
|
+
*
|
|
8
|
+
* Slice 2a moves this implementation here from
|
|
9
|
+
* `src/runtime/layout/public-facet.ts`. Layout facet's deprecated
|
|
10
|
+
* `getAnchorRects` delegates through this module — behavior byte-identical.
|
|
11
|
+
* Slice 6 deletes the layout-facet wrapper.
|
|
12
|
+
*
|
|
13
|
+
* Contract (architecture 05 G5): rects returned here are in the kernel's
|
|
14
|
+
* frame-local pixel space. Consumers that need twip or overlay coordinates
|
|
15
|
+
* convert via `chrome-overlay-projector.ts` or the caret/envelope helpers
|
|
16
|
+
* added in Slices 4–5.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type {
|
|
20
|
+
RenderAnchorQuery,
|
|
21
|
+
RenderFrame,
|
|
22
|
+
RenderFrameRect,
|
|
23
|
+
} from "../render/index.ts";
|
|
24
|
+
import { emitLayoutGuardWarning } from "../layout/public-facet.ts";
|
|
25
|
+
|
|
26
|
+
export function resolveAnchorRects(
|
|
27
|
+
frame: RenderFrame | null,
|
|
28
|
+
query: RenderAnchorQuery,
|
|
29
|
+
): readonly RenderFrameRect[] {
|
|
30
|
+
if (!frame) {
|
|
31
|
+
emitLayoutGuardWarning("resolveAnchorRects", {
|
|
32
|
+
queryKind: query.kind,
|
|
33
|
+
reason: "no-frame",
|
|
34
|
+
});
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
switch (query.kind) {
|
|
38
|
+
case "runtime-offset": {
|
|
39
|
+
const offset =
|
|
40
|
+
typeof query.value === "number" ? query.value : Number(query.value);
|
|
41
|
+
if (!Number.isFinite(offset)) {
|
|
42
|
+
emitLayoutGuardWarning("resolveAnchorRects", {
|
|
43
|
+
queryKind: query.kind,
|
|
44
|
+
reason: "non-finite-offset",
|
|
45
|
+
value: query.value,
|
|
46
|
+
});
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const rect = frame.anchorIndex.byRuntimeOffset(offset, query.story);
|
|
50
|
+
return rect ? [rect] : [];
|
|
51
|
+
}
|
|
52
|
+
case "block-id": {
|
|
53
|
+
const rect = frame.anchorIndex.byBlockId(String(query.value));
|
|
54
|
+
return rect ? [rect] : [];
|
|
55
|
+
}
|
|
56
|
+
case "fragment-id": {
|
|
57
|
+
const rect = frame.anchorIndex.byFragmentId(String(query.value));
|
|
58
|
+
return rect ? [rect] : [];
|
|
59
|
+
}
|
|
60
|
+
case "page-index": {
|
|
61
|
+
const pageIndex =
|
|
62
|
+
typeof query.value === "number" ? query.value : Number(query.value);
|
|
63
|
+
if (!Number.isFinite(pageIndex)) {
|
|
64
|
+
emitLayoutGuardWarning("resolveAnchorRects", {
|
|
65
|
+
queryKind: query.kind,
|
|
66
|
+
reason: "non-finite-page-index",
|
|
67
|
+
value: query.value,
|
|
68
|
+
});
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
const rect = frame.anchorIndex.byPageIndex(pageIndex);
|
|
72
|
+
return rect ? [rect] : [];
|
|
73
|
+
}
|
|
74
|
+
case "scope-id": {
|
|
75
|
+
return frame.anchorIndex.byScopeId(String(query.value));
|
|
76
|
+
}
|
|
77
|
+
case "comment-id": {
|
|
78
|
+
const rect = frame.anchorIndex.byCommentId(String(query.value));
|
|
79
|
+
return rect ? [rect] : [];
|
|
80
|
+
}
|
|
81
|
+
case "revision-id": {
|
|
82
|
+
const rect = frame.anchorIndex.byRevisionId(String(query.value));
|
|
83
|
+
return rect ? [rect] : [];
|
|
84
|
+
}
|
|
85
|
+
default: {
|
|
86
|
+
const exhaustive: never = query.kind;
|
|
87
|
+
void exhaustive;
|
|
88
|
+
emitLayoutGuardWarning("resolveAnchorRects", {
|
|
89
|
+
queryKind: "unknown",
|
|
90
|
+
reason: "exhaustive-default",
|
|
91
|
+
});
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// collectScopeRailSegmentsForQuery moved to
|
|
98
|
+
// `src/runtime/workflow/scope-rail-composer.ts` (L06 canonical home).
|
|
99
|
+
// Parked here by refactor/05 Slice 2b as a transitional home; returned
|
|
100
|
+
// to L06 ownership as part of the post-closure coord-doc §4 follow-up.
|