@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
|
@@ -1,62 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `basedOn` reference, with cycle detection.
|
|
2
|
+
* Layer 03 — four-tier style cascade core.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* stop the walk silently (the leaf is still returned).
|
|
4
|
+
* Owns the primitive merge helpers (`mergeRun`, `mergeParagraph`) and the
|
|
5
|
+
* drivers that walk the `basedOn` chains to produce effective formatting:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* - `resolveEffectiveParagraphFormatting` — docDefaults → basedOn chain
|
|
8
|
+
* (root-to-leaf) → direct
|
|
9
|
+
* - `resolveEffectiveRunFormatting` — docDefaults.run → paragraph-style
|
|
10
|
+
* chain rPr → character-style chain rPr → direct
|
|
11
|
+
* - `resolveNumberingMarkerRunFormatting` — docDefaults.run →
|
|
12
|
+
* paragraph-style chain → paragraph-mark rPr → level rPr
|
|
13
|
+
* - `resolveTableCellTextFormatting` — docDefaults → table-style chain
|
|
14
|
+
*
|
|
15
|
+
* The chain walkers (`resolveParagraphStyleChain`, `resolveCharacterStyleChain`)
|
|
16
|
+
* remain in `./paragraph-style-resolver.ts` and are imported from there —
|
|
17
|
+
* they are not cascade drivers, they are tree-walkers.
|
|
18
|
+
*
|
|
19
|
+
* Contract: all drivers are pure functions on (input, catalog). They do not
|
|
20
|
+
* consult the document content, the theme, the numbering catalog, or any
|
|
21
|
+
* layout state. Theme concretization + numbering + field + revision-display
|
|
22
|
+
* posture layer on top in `./resolve-effective.ts`.
|
|
11
23
|
*/
|
|
12
24
|
|
|
13
25
|
import type {
|
|
14
|
-
CanonicalFontTable,
|
|
15
26
|
CanonicalParagraphFormatting,
|
|
16
27
|
CanonicalRunFormatting,
|
|
17
|
-
CharacterStyleDefinition,
|
|
18
|
-
ParagraphStyleDefinition,
|
|
19
28
|
StylesCatalog,
|
|
29
|
+
TableStyleConditionalRegion,
|
|
20
30
|
TableStyleDefinition,
|
|
21
|
-
} from "
|
|
31
|
+
} from "../../model/canonical-document.ts";
|
|
32
|
+
import {
|
|
33
|
+
resolveCharacterStyleChain,
|
|
34
|
+
resolveParagraphStyleChain,
|
|
35
|
+
} from "./paragraph-style-resolver.ts";
|
|
22
36
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
): string[] {
|
|
27
|
-
const chain: string[] = [];
|
|
28
|
-
if (!catalog) return chain;
|
|
29
|
-
const visited = new Set<string>();
|
|
30
|
-
let current: string | undefined = styleId;
|
|
31
|
-
while (current && !visited.has(current)) {
|
|
32
|
-
visited.add(current);
|
|
33
|
-
const def: ParagraphStyleDefinition | undefined = catalog.paragraphs[current];
|
|
34
|
-
if (!def) break;
|
|
35
|
-
chain.push(current);
|
|
36
|
-
current = def.basedOn;
|
|
37
|
-
}
|
|
38
|
-
return chain;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function resolveCharacterStyleChain(
|
|
42
|
-
styleId: string,
|
|
43
|
-
catalog: StylesCatalog | undefined,
|
|
44
|
-
): string[] {
|
|
45
|
-
const chain: string[] = [];
|
|
46
|
-
if (!catalog) return chain;
|
|
47
|
-
const visited = new Set<string>();
|
|
48
|
-
let current: string | undefined = styleId;
|
|
49
|
-
while (current && !visited.has(current)) {
|
|
50
|
-
visited.add(current);
|
|
51
|
-
const def: CharacterStyleDefinition | undefined = catalog.characters[current];
|
|
52
|
-
if (!def) break;
|
|
53
|
-
chain.push(current);
|
|
54
|
-
current = def.basedOn;
|
|
55
|
-
}
|
|
56
|
-
return chain;
|
|
57
|
-
}
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Merge primitives
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
58
40
|
|
|
59
|
-
function mergeRun(
|
|
41
|
+
export function mergeRun(
|
|
60
42
|
base: CanonicalRunFormatting | undefined,
|
|
61
43
|
over: CanonicalRunFormatting | undefined,
|
|
62
44
|
): CanonicalRunFormatting | undefined {
|
|
@@ -64,7 +46,7 @@ function mergeRun(
|
|
|
64
46
|
return { ...(base ?? {}), ...(over ?? {}) };
|
|
65
47
|
}
|
|
66
48
|
|
|
67
|
-
function mergeParagraph(
|
|
49
|
+
export function mergeParagraph(
|
|
68
50
|
base: CanonicalParagraphFormatting | undefined,
|
|
69
51
|
over: CanonicalParagraphFormatting | undefined,
|
|
70
52
|
): CanonicalParagraphFormatting | undefined {
|
|
@@ -91,13 +73,32 @@ function mergeParagraph(
|
|
|
91
73
|
return merged;
|
|
92
74
|
}
|
|
93
75
|
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Driver inputs
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
|
|
94
80
|
export interface ParagraphResolveInput {
|
|
95
81
|
styleId: string | undefined;
|
|
96
82
|
direct: CanonicalParagraphFormatting | undefined;
|
|
97
83
|
}
|
|
98
84
|
|
|
85
|
+
export interface RunResolveInput {
|
|
86
|
+
paragraphStyleId: string | undefined;
|
|
87
|
+
characterStyleId: string | undefined;
|
|
88
|
+
direct: CanonicalRunFormatting | undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface MarkerResolveInput {
|
|
92
|
+
paragraphStyleId: string | undefined;
|
|
93
|
+
levelRunProperties: CanonicalRunFormatting | undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Drivers
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
99
100
|
/**
|
|
100
|
-
*
|
|
101
|
+
* Paragraph formatting cascade: docDefaults.paragraph → basedOn chain
|
|
101
102
|
* (root-to-leaf) → direct. Returns `{}` when nothing is present.
|
|
102
103
|
*/
|
|
103
104
|
export function resolveEffectiveParagraphFormatting(
|
|
@@ -107,7 +108,7 @@ export function resolveEffectiveParagraphFormatting(
|
|
|
107
108
|
let acc: CanonicalParagraphFormatting | undefined = catalog?.docDefaults?.paragraph;
|
|
108
109
|
if (catalog && input.styleId) {
|
|
109
110
|
const chain = resolveParagraphStyleChain(input.styleId, catalog);
|
|
110
|
-
// Walk root-to-leaf (most-general first) so the most-specific style wins
|
|
111
|
+
// Walk root-to-leaf (most-general first) so the most-specific style wins.
|
|
111
112
|
for (let i = chain.length - 1; i >= 0; i -= 1) {
|
|
112
113
|
const styleId = chain[i]!;
|
|
113
114
|
acc = mergeParagraph(acc, catalog.paragraphs[styleId]?.paragraphProperties);
|
|
@@ -117,14 +118,8 @@ export function resolveEffectiveParagraphFormatting(
|
|
|
117
118
|
return acc ?? {};
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
export interface RunResolveInput {
|
|
121
|
-
paragraphStyleId: string | undefined;
|
|
122
|
-
characterStyleId: string | undefined;
|
|
123
|
-
direct: CanonicalRunFormatting | undefined;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
121
|
/**
|
|
127
|
-
*
|
|
122
|
+
* Run formatting cascade: docDefaults.run → paragraph-style-chain rPr
|
|
128
123
|
* (root-to-leaf) → character-style-chain (root-to-leaf) → direct. Returns
|
|
129
124
|
* `{}` when nothing is present.
|
|
130
125
|
*/
|
|
@@ -151,102 +146,35 @@ export function resolveEffectiveRunFormatting(
|
|
|
151
146
|
return acc ?? {};
|
|
152
147
|
}
|
|
153
148
|
|
|
154
|
-
export interface MarkerResolveInput {
|
|
155
|
-
paragraphStyleId: string | undefined;
|
|
156
|
-
levelRunProperties: CanonicalRunFormatting | undefined;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
149
|
/**
|
|
160
|
-
*
|
|
161
|
-
* the number/bullet glyph itself (bold, color, font, size, etc.).
|
|
150
|
+
* Numbering marker rPr cascade (ECMA-376 §17.9).
|
|
162
151
|
*
|
|
163
|
-
*
|
|
164
|
-
* 1. `docDefaults.run`
|
|
165
|
-
* 2. Paragraph style chain
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* 4. `levelRunProperties` — `<w:lvl><w:rPr>` on the numbering level. Per
|
|
171
|
-
* ECMA-376, this is the most specific formatting for the marker and
|
|
172
|
-
* overrides the paragraph's run formatting entirely for the marker.
|
|
152
|
+
* Order (lowest → highest priority):
|
|
153
|
+
* 1. `docDefaults.run`
|
|
154
|
+
* 2. Paragraph style chain `runProperties` — root-to-leaf
|
|
155
|
+
* 3. Leaf paragraph style's `paragraphProperties.paragraphMarkRunProperties`
|
|
156
|
+
* (Word stores the mark rPr separately from body rPr; the marker
|
|
157
|
+
* inherits from the mark).
|
|
158
|
+
* 4. `levelRunProperties` (`<w:lvl><w:rPr>`) — final word.
|
|
173
159
|
*/
|
|
174
160
|
export function resolveNumberingMarkerRunFormatting(
|
|
175
161
|
input: MarkerResolveInput,
|
|
176
162
|
catalog: StylesCatalog | undefined,
|
|
177
163
|
): CanonicalRunFormatting {
|
|
178
|
-
// Start with docDefaults baseline
|
|
179
164
|
let acc: CanonicalRunFormatting | undefined = catalog?.docDefaults?.run;
|
|
180
|
-
|
|
181
|
-
// Walk the paragraph style chain's rPr (root-to-leaf, most-specific wins)
|
|
182
165
|
if (catalog && input.paragraphStyleId) {
|
|
183
166
|
const chain = resolveParagraphStyleChain(input.paragraphStyleId, catalog);
|
|
184
167
|
for (let i = chain.length - 1; i >= 0; i -= 1) {
|
|
185
168
|
const styleId = chain[i]!;
|
|
186
169
|
acc = mergeRun(acc, catalog.paragraphs[styleId]?.runProperties);
|
|
187
170
|
}
|
|
188
|
-
// Leaf paragraph style's paragraph-mark rPr layers on top of the chain
|
|
189
171
|
const leaf = catalog.paragraphs[input.paragraphStyleId];
|
|
190
172
|
acc = mergeRun(acc, leaf?.paragraphProperties?.paragraphMarkRunProperties);
|
|
191
173
|
}
|
|
192
|
-
|
|
193
|
-
// Level rPr has the final say (per ECMA-376 17.9)
|
|
194
174
|
acc = mergeRun(acc, input.levelRunProperties);
|
|
195
175
|
return acc ?? {};
|
|
196
176
|
}
|
|
197
177
|
|
|
198
|
-
/**
|
|
199
|
-
* Return the `w:next` style ID for `styleId` — the paragraph style Word
|
|
200
|
-
* applies after pressing Enter at the end of a paragraph of this style.
|
|
201
|
-
* Used by Lane 1's suggest-paragraph-split command.
|
|
202
|
-
*/
|
|
203
|
-
export function getNextStyleId(
|
|
204
|
-
styleId: string,
|
|
205
|
-
catalog: StylesCatalog | undefined,
|
|
206
|
-
): string | undefined {
|
|
207
|
-
return catalog?.paragraphs[styleId]?.nextStyle;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Resolve the effective font family name for a run.
|
|
212
|
-
*
|
|
213
|
-
* Walks the ECMA-376 §17.3.2.26 precedence for `<w:rFonts>`: `ascii` →
|
|
214
|
-
* `hAnsi` → `eastAsia` → `cs`. When none of those resolve on the direct
|
|
215
|
-
* run formatting, layers the paragraph/character style cascade for the
|
|
216
|
-
* same four fields, then falls back to the caller-supplied
|
|
217
|
-
* `themeMinorFont` (ECMA-376 default for body text).
|
|
218
|
-
*
|
|
219
|
-
* `fontTable`, when supplied, is consulted only for presence — an entry
|
|
220
|
-
* whose `w:name` does not appear in `fontTable.fonts` is still returned
|
|
221
|
-
* as-is (Word behavior: substitute at render time, not at model resolve).
|
|
222
|
-
* Lane 3a's measurement backend owns the substitution decision.
|
|
223
|
-
*
|
|
224
|
-
* Returns undefined only when no source in the cascade supplies a family
|
|
225
|
-
* name (rare — production docs always hit docDefaults or the theme).
|
|
226
|
-
*/
|
|
227
|
-
export function resolveRunFontFamily(
|
|
228
|
-
input: RunResolveInput,
|
|
229
|
-
catalog: StylesCatalog | undefined,
|
|
230
|
-
themeMinorFont: string | undefined,
|
|
231
|
-
fontTable?: CanonicalFontTable | undefined,
|
|
232
|
-
): string | undefined {
|
|
233
|
-
// `fontTable` is currently unused inside this resolver; the ECMA-376
|
|
234
|
-
// rFonts precedence does not require consulting the package's fontTable
|
|
235
|
-
// to pick a name. It is reserved so Lane 3a's measurement backend can
|
|
236
|
-
// layer substitution (e.g. pick a monospace fallback when the resolved
|
|
237
|
-
// name has `pitch === "fixed"`) by threading the same table through.
|
|
238
|
-
void fontTable;
|
|
239
|
-
const resolved = resolveEffectiveRunFormatting(input, catalog);
|
|
240
|
-
const name =
|
|
241
|
-
resolved.fontFamilyAscii ??
|
|
242
|
-
resolved.fontFamilyHAnsi ??
|
|
243
|
-
resolved.fontFamilyEastAsia ??
|
|
244
|
-
resolved.fontFamilyCs ??
|
|
245
|
-
resolved.fontFamily ??
|
|
246
|
-
themeMinorFont;
|
|
247
|
-
return name;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
178
|
function resolveTableStyleChain(
|
|
251
179
|
styleId: string,
|
|
252
180
|
catalog: StylesCatalog | undefined,
|
|
@@ -273,26 +201,41 @@ function resolveTableStyleChain(
|
|
|
273
201
|
* 1. `catalog.docDefaults.paragraph` / `.run`
|
|
274
202
|
* 2. Table style's `basedOn` chain, walked root-to-leaf, projecting each
|
|
275
203
|
* style's `formatting.paragraphProperties` / `.runProperties`.
|
|
204
|
+
* 3. When `activeRegions` is supplied — the `conditionalFormatting[region]`
|
|
205
|
+
* pPr / rPr for each active region, applied in the caller's region
|
|
206
|
+
* order (typically `getActiveCellRegions()` output: row bands →
|
|
207
|
+
* column bands → first/last row → first/last column → corner cells).
|
|
208
|
+
* Higher regions in the list win over lower — consistent with
|
|
209
|
+
* ECMA-376 §17.7.6 region-precedence semantics and matches how
|
|
210
|
+
* `mergeStyleFormattingCell` already layers cell-level properties.
|
|
276
211
|
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
* `resolveEffectiveRunFormatting`; this function only returns the floor.
|
|
212
|
+
* Callers that have no region information (e.g. a non-contextual lookup)
|
|
213
|
+
* omit `activeRegions` and receive the basedOn-chain floor only. Per-paragraph
|
|
214
|
+
* and per-run formatting from the cell's content is layered on top by the
|
|
215
|
+
* paragraph + run cascade drivers; this function returns the pre-direct
|
|
216
|
+
* table-style floor.
|
|
283
217
|
*/
|
|
284
218
|
export function resolveTableCellTextFormatting(
|
|
285
219
|
tableStyleId: string | undefined,
|
|
286
220
|
catalog: StylesCatalog | undefined,
|
|
221
|
+
activeRegions?: readonly TableStyleConditionalRegion[],
|
|
287
222
|
): { paragraph: CanonicalParagraphFormatting; run: CanonicalRunFormatting } {
|
|
288
223
|
let paragraph: CanonicalParagraphFormatting | undefined = catalog?.docDefaults?.paragraph;
|
|
289
224
|
let run: CanonicalRunFormatting | undefined = catalog?.docDefaults?.run;
|
|
290
225
|
if (catalog && tableStyleId) {
|
|
291
226
|
const chain = resolveTableStyleChain(tableStyleId, catalog);
|
|
292
227
|
for (let i = chain.length - 1; i >= 0; i -= 1) {
|
|
293
|
-
const
|
|
294
|
-
paragraph = mergeParagraph(paragraph, formatting?.paragraphProperties);
|
|
295
|
-
run = mergeRun(run, formatting?.runProperties);
|
|
228
|
+
const def = chain[i]!;
|
|
229
|
+
paragraph = mergeParagraph(paragraph, def.formatting?.paragraphProperties);
|
|
230
|
+
run = mergeRun(run, def.formatting?.runProperties);
|
|
231
|
+
if (activeRegions && activeRegions.length > 0 && def.conditionalFormatting) {
|
|
232
|
+
for (const region of activeRegions) {
|
|
233
|
+
const regionFormatting = def.conditionalFormatting[region];
|
|
234
|
+
if (!regionFormatting) continue;
|
|
235
|
+
paragraph = mergeParagraph(paragraph, regionFormatting.paragraphProperties);
|
|
236
|
+
run = mergeRun(run, regionFormatting.runProperties);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
296
239
|
}
|
|
297
240
|
}
|
|
298
241
|
return { paragraph: paragraph ?? {}, run: run ?? {} };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 03 — formatting-telemetry bridge.
|
|
3
|
+
*
|
|
4
|
+
* Consumers (surface-projection, document-runtime, field resolver) pass a
|
|
5
|
+
* `ResolveEffectiveFormattingOptions.emitFormattingTelemetry` callback
|
|
6
|
+
* that bridges entry events onto the runtime `TelemetryBus`. This helper
|
|
7
|
+
* builds that callback with:
|
|
8
|
+
*
|
|
9
|
+
* - Probability gating for `formatting.resolution_sampled` (default
|
|
10
|
+
* rate `0.01` — 1% of resolutions).
|
|
11
|
+
* - Unfiltered pass-through for `formatting.cache.invalidated` and
|
|
12
|
+
* `formatting.revision_display.mode_changed` (low-frequency signals).
|
|
13
|
+
* - Bus-level `isEnabled("formatting")` short-circuit so the callback
|
|
14
|
+
* returns immediately when the channel is off, preserving the
|
|
15
|
+
* "zero cost when off" contract.
|
|
16
|
+
*
|
|
17
|
+
* The bridge lives in the formatting layer so it can stay colocated with
|
|
18
|
+
* the telemetry event type. The telemetry bus `TelemetryBus` is imported
|
|
19
|
+
* by type only; there is no value dependency on layer 02's debug
|
|
20
|
+
* infrastructure at runtime.
|
|
21
|
+
*
|
|
22
|
+
* Performance: each call is a channel-enabled check (O(1)) + an optional
|
|
23
|
+
* Math.random for sampled events. `bus.emitLazy` is used for sampled
|
|
24
|
+
* events so the payload factory runs only on hit.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { TelemetryBus } from "../debug/telemetry-bus.ts";
|
|
28
|
+
import { shouldEmitSample } from "../debug/probability-sampler.ts";
|
|
29
|
+
import type { FormattingTelemetryEvent } from "./resolve-effective.ts";
|
|
30
|
+
|
|
31
|
+
export interface FormattingTelemetryBridgeOptions {
|
|
32
|
+
/** Probability gate for `formatting.resolution_sampled` events.
|
|
33
|
+
* Default `0.01` (1%). Set to 0 to disable sample emission entirely. */
|
|
34
|
+
readonly resolutionSampleRate?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const DEFAULT_RESOLUTION_SAMPLE_RATE = 0.01;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Build an `emitFormattingTelemetry` callback suitable for passing to
|
|
41
|
+
* `resolveEffectiveFormatting({ ..., emitFormattingTelemetry })`. Wraps
|
|
42
|
+
* the runtime telemetry bus with probability-gated sampling for the
|
|
43
|
+
* high-frequency event.
|
|
44
|
+
*/
|
|
45
|
+
export function buildFormattingTelemetryBridge(
|
|
46
|
+
bus: TelemetryBus,
|
|
47
|
+
options: FormattingTelemetryBridgeOptions = {},
|
|
48
|
+
): (event: FormattingTelemetryEvent) => void {
|
|
49
|
+
const sampleRate = options.resolutionSampleRate ?? DEFAULT_RESOLUTION_SAMPLE_RATE;
|
|
50
|
+
|
|
51
|
+
return function emit(event: FormattingTelemetryEvent): void {
|
|
52
|
+
if (!bus.isEnabled("formatting")) return;
|
|
53
|
+
|
|
54
|
+
switch (event.type) {
|
|
55
|
+
case "formatting.resolution_sampled": {
|
|
56
|
+
if (!shouldEmitSample(sampleRate)) return;
|
|
57
|
+
bus.emit({
|
|
58
|
+
channel: "formatting",
|
|
59
|
+
type: event.type,
|
|
60
|
+
t: 0,
|
|
61
|
+
payload: event.payload,
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
case "formatting.cache.invalidated": {
|
|
66
|
+
bus.emit({
|
|
67
|
+
channel: "formatting",
|
|
68
|
+
type: event.type,
|
|
69
|
+
t: 0,
|
|
70
|
+
payload: event.payload,
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
case "formatting.numbering_format_unsupported": {
|
|
75
|
+
// Low-frequency fidelity-gap signal (dedup happens at the emit
|
|
76
|
+
// site — see surface-projection). No sampling; every hit matters.
|
|
77
|
+
bus.emit({
|
|
78
|
+
channel: "formatting",
|
|
79
|
+
type: event.type,
|
|
80
|
+
t: 0,
|
|
81
|
+
payload: event.payload,
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Narrow helper for emitting the revision-display mode-change event.
|
|
91
|
+
* Consumers (render-kernel, surface-projection) call this directly when
|
|
92
|
+
* the active markup mode toggles — it's a state-change event, not per
|
|
93
|
+
* resolution.
|
|
94
|
+
*/
|
|
95
|
+
export function emitRevisionDisplayModeChanged(
|
|
96
|
+
bus: TelemetryBus,
|
|
97
|
+
mode: "clean" | "simple" | "all",
|
|
98
|
+
): void {
|
|
99
|
+
if (!bus.isEnabled("formatting")) return;
|
|
100
|
+
bus.emit({
|
|
101
|
+
channel: "formatting",
|
|
102
|
+
type: "formatting.revision_display.mode_changed",
|
|
103
|
+
t: 0,
|
|
104
|
+
payload: { mode },
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -24,9 +24,8 @@
|
|
|
24
24
|
* reference byte-for-byte.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import type { CanonicalRunFormatting, CanonicalTheme, ClrSchemeMappingSlot
|
|
28
|
-
import {
|
|
29
|
-
import { GRADIENT_STOP_UNITS } from "./units.ts";
|
|
27
|
+
import type { CanonicalRunFormatting, CanonicalTheme, ClrSchemeMappingSlot } from "../../model/canonical-document.ts";
|
|
28
|
+
import { GRADIENT_STOP_UNITS } from "../units.ts";
|
|
30
29
|
|
|
31
30
|
/**
|
|
32
31
|
* DrawingML color modifier (ECMA-376 §20.1.2.3.x).
|
|
@@ -98,33 +97,6 @@ export class ThemeColorResolver {
|
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
99
|
|
|
101
|
-
/**
|
|
102
|
-
* Collapse `<w:color>`-style theme-slot + tint + shade references into a
|
|
103
|
-
* single resolved hex colour. §17-only byte-form path; does NOT apply
|
|
104
|
-
* `w:clrSchemeMapping` remap.
|
|
105
|
-
*
|
|
106
|
-
* @deprecated Use `ThemeColorResolver.resolveWordThemeColor` instead —
|
|
107
|
-
* it honours clrSchemeMapping. This free function is retained only for
|
|
108
|
-
* its targeted unit tests (`test/io/theme-color-tint-shade.test.ts`) and
|
|
109
|
-
* will be removed once those migrate to the class.
|
|
110
|
-
*/
|
|
111
|
-
export function resolveThemeColorHex(
|
|
112
|
-
rPr: Pick<
|
|
113
|
-
CanonicalRunFormatting,
|
|
114
|
-
"colorHex" | "colorThemeSlot" | "colorThemeTint" | "colorThemeShade"
|
|
115
|
-
>,
|
|
116
|
-
theme: ResolvedTheme | undefined,
|
|
117
|
-
): string | undefined {
|
|
118
|
-
if (rPr.colorHex === "auto") return "auto";
|
|
119
|
-
if (rPr.colorHex) return rPr.colorHex;
|
|
120
|
-
if (!rPr.colorThemeSlot) return undefined;
|
|
121
|
-
|
|
122
|
-
const baseHex = resolveThemeColor(theme, rPr.colorThemeSlot);
|
|
123
|
-
if (!baseHex) return undefined;
|
|
124
|
-
|
|
125
|
-
return applyThemeTintShade(baseHex, rPr.colorThemeTint, rPr.colorThemeShade);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
100
|
/**
|
|
129
101
|
* Post-process a cascade of run formatting to concretize any
|
|
130
102
|
* theme-color-only reference into a paintable `colorHex`.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 05 — Caret + selection-rect geometry.
|
|
3
|
+
*
|
|
4
|
+
* Pure projections against a `RenderFrame`:
|
|
5
|
+
*
|
|
6
|
+
* - `resolveCaretGeometry(frame, offset, story?)` → `CaretGeometry | null`
|
|
7
|
+
* Returns the caret position + line height + baseline + writing
|
|
8
|
+
* direction at `offset`, projected to frame-local pixels.
|
|
9
|
+
* - `resolveSelectionRects(frame, { from, to, story? })`
|
|
10
|
+
* Returns one `GeometryRect` per line the selection covers when
|
|
11
|
+
* per-line data is available, or the kernel's union selection rect
|
|
12
|
+
* otherwise. Empty range collapses to a zero-width caret rect;
|
|
13
|
+
* off-document ranges return `[]`.
|
|
14
|
+
*
|
|
15
|
+
* Slice-4 substrate notes:
|
|
16
|
+
*
|
|
17
|
+
* - The primary source is `frame.anchorIndex` — the render kernel's
|
|
18
|
+
* anchor lookup is populated for every layout-produced offset even
|
|
19
|
+
* when per-line `RenderLine[]` arrays are empty (which they are for
|
|
20
|
+
* synthetic docs with no measurement provider). `byRuntimeOffset`
|
|
21
|
+
* returns a rect shaped like "the line at that offset", which gives
|
|
22
|
+
* the caret its correct top + height. When per-line anchors DO
|
|
23
|
+
* populate (Slice 5 with richer line projection), selection-rect
|
|
24
|
+
* enumeration upgrades to one-rect-per-line automatically.
|
|
25
|
+
* - **RTL + bidi** is reserved. `direction` is always `"ltr"` in this
|
|
26
|
+
* slice because the render kernel does not yet expose run-level
|
|
27
|
+
* writing-direction metadata. The `CaretGeometry.direction` field
|
|
28
|
+
* is stable so a future slice can fill in RTL without a consumer-
|
|
29
|
+
* visible API change.
|
|
30
|
+
* - **Empty blocks** snap to the block's left edge at the full line
|
|
31
|
+
* height — the Word-compatible behavior. `byRuntimeOffset` on an
|
|
32
|
+
* offset inside an empty paragraph returns the paragraph's rect;
|
|
33
|
+
* the caret lives at that rect's leftPx.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type { EditorStoryTarget } from "../../api/public-types";
|
|
37
|
+
import type {
|
|
38
|
+
RenderFrame,
|
|
39
|
+
RenderFrameRect,
|
|
40
|
+
} from "../render/index.ts";
|
|
41
|
+
import type {
|
|
42
|
+
CaretGeometry,
|
|
43
|
+
GeometryRect,
|
|
44
|
+
} from "./geometry-types.ts";
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the caret for `offset`, or `null` if the offset falls outside
|
|
48
|
+
* the frame's resolvable range. Slice 4 routes through
|
|
49
|
+
* `frame.anchorIndex.byRuntimeOffset`; Slice 5 tightens x-position
|
|
50
|
+
* within a line once per-run anchors land.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveCaretGeometry(
|
|
53
|
+
frame: RenderFrame | null,
|
|
54
|
+
offset: number,
|
|
55
|
+
story?: EditorStoryTarget,
|
|
56
|
+
): CaretGeometry | null {
|
|
57
|
+
if (!frame) return null;
|
|
58
|
+
if (!Number.isFinite(offset)) return null;
|
|
59
|
+
|
|
60
|
+
const anchorRect = frame.anchorIndex.byRuntimeOffset(offset, story);
|
|
61
|
+
if (!anchorRect) return null;
|
|
62
|
+
|
|
63
|
+
const rect: GeometryRect = {
|
|
64
|
+
leftPx: anchorRect.leftPx,
|
|
65
|
+
topPx: anchorRect.topPx,
|
|
66
|
+
widthPx: 0,
|
|
67
|
+
heightPx: anchorRect.heightPx,
|
|
68
|
+
space: "frame",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Slice 7b (2026-04-22): `direction` is hardcoded "ltr" and
|
|
72
|
+
// `baseline` uses a 0.8 * height heuristic. Both are substrate
|
|
73
|
+
// placeholders pending the render-kernel's per-run anchor work
|
|
74
|
+
// (refactor/05 Slice 7, Task 2). Tag the coarsest precision so
|
|
75
|
+
// consumers can gate bidi-sensitive work.
|
|
76
|
+
return {
|
|
77
|
+
rect,
|
|
78
|
+
baseline: resolveBaselinePx(anchorRect),
|
|
79
|
+
height: anchorRect.heightPx,
|
|
80
|
+
direction: "ltr", // reserved for a future bidi-aware slice.
|
|
81
|
+
precision: "heuristic",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolve `GeometryRect[]` for a selection range. Slice 4 produces:
|
|
87
|
+
* - an empty list when either endpoint can't be resolved
|
|
88
|
+
* - a single zero-width caret rect when `from === to`
|
|
89
|
+
* - a single union rect otherwise (via `frame.anchorIndex.bySelection`)
|
|
90
|
+
*
|
|
91
|
+
* When the kernel's per-line anchor projection matures (Slice 5+), this
|
|
92
|
+
* function flips to emitting one rect per line. The single-rect fallback
|
|
93
|
+
* keeps chrome surfaces that currently call `getAnchorRects({ kind:
|
|
94
|
+
* "runtime-offset", … })[0]` in sync with the new selection API.
|
|
95
|
+
*/
|
|
96
|
+
export function resolveSelectionRects(
|
|
97
|
+
frame: RenderFrame | null,
|
|
98
|
+
range: {
|
|
99
|
+
from: number;
|
|
100
|
+
to: number;
|
|
101
|
+
story?: EditorStoryTarget;
|
|
102
|
+
},
|
|
103
|
+
): readonly GeometryRect[] {
|
|
104
|
+
if (!frame) return [];
|
|
105
|
+
const { from, to } = range;
|
|
106
|
+
if (!Number.isFinite(from) || !Number.isFinite(to)) return [];
|
|
107
|
+
const lo = Math.min(from, to);
|
|
108
|
+
const hi = Math.max(from, to);
|
|
109
|
+
|
|
110
|
+
if (lo === hi) {
|
|
111
|
+
const caret = resolveCaretGeometry(frame, lo, range.story);
|
|
112
|
+
if (!caret) return [];
|
|
113
|
+
// Caret rect for a collapsed range is an exact anchor-index read —
|
|
114
|
+
// the placeholder-grade metadata on `CaretGeometry` (direction,
|
|
115
|
+
// baseline) applies to the caret as a whole, not to the rect's
|
|
116
|
+
// position. Return the rect untagged so callers that iterate
|
|
117
|
+
// `getSelectionRects(...)` and expect pixel-exact carets see the
|
|
118
|
+
// expected `"exact"` default.
|
|
119
|
+
return [caret.rect];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const union = frame.anchorIndex.bySelection(lo, hi, range.story);
|
|
123
|
+
if (!union) return [];
|
|
124
|
+
// Slice 7b (2026-04-22): the substrate returns ONE union rect for any
|
|
125
|
+
// non-collapsed range. That rect is geometrically correct at the
|
|
126
|
+
// block level but loses per-line detail — tag it `within-tolerance`
|
|
127
|
+
// so callers can gate per-line chrome work. When the render kernel
|
|
128
|
+
// ships per-run anchors (refactor/05 Slice 7 Task 2), this site
|
|
129
|
+
// upgrades to multiple `"exact"` rects automatically.
|
|
130
|
+
return [toGeometryRect(union, "within-tolerance")];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Internals
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
function toGeometryRect(
|
|
138
|
+
rect: RenderFrameRect,
|
|
139
|
+
precision?: GeometryRect["precision"],
|
|
140
|
+
): GeometryRect {
|
|
141
|
+
const out: GeometryRect = {
|
|
142
|
+
leftPx: rect.leftPx,
|
|
143
|
+
topPx: rect.topPx,
|
|
144
|
+
widthPx: rect.widthPx,
|
|
145
|
+
heightPx: rect.heightPx,
|
|
146
|
+
space: "frame",
|
|
147
|
+
};
|
|
148
|
+
if (precision !== undefined) {
|
|
149
|
+
out.precision = precision;
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Approximate the baseline offset within a line rect. The render frame
|
|
156
|
+
* does not yet carry per-anchor baseline metadata, so Slice 4 uses a
|
|
157
|
+
* fixed 0.8× ratio — the typical cap-height heuristic for Latin scripts.
|
|
158
|
+
* A later slice replaces this with the per-line `baselineTwips` once
|
|
159
|
+
* per-line anchors are populated.
|
|
160
|
+
*/
|
|
161
|
+
function resolveBaselinePx(rect: RenderFrameRect): number {
|
|
162
|
+
if (rect.heightPx <= 0) return 0;
|
|
163
|
+
return rect.heightPx * 0.8;
|
|
164
|
+
}
|