@beyondwork/docx-react-component 1.0.67 → 1.0.70
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 -932
- 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 -4797
- 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,499 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 01 public type surface for `src/session/**`.
|
|
3
|
+
*
|
|
4
|
+
* These types mirror the reserved shape in
|
|
5
|
+
* `docs/architecture/01-package-session.md` § "Public entry points".
|
|
6
|
+
* They are the contract consumers see; the implementation in
|
|
7
|
+
* `src/session/session.ts` may still delegate transitionally to the
|
|
8
|
+
* legacy `src/io/docx-session.ts` while the extraction completes.
|
|
9
|
+
*
|
|
10
|
+
* P6 clean: imports only from `src/api/**` (type-only), `src/model/**`,
|
|
11
|
+
* `src/io/**`, and `src/preservation/**`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
CanonicalDocument,
|
|
16
|
+
DocumentRootNode,
|
|
17
|
+
} from "../model/canonical-document.ts";
|
|
18
|
+
import type {
|
|
19
|
+
CompatibilityReport,
|
|
20
|
+
EditorError,
|
|
21
|
+
EditorHostAdapter,
|
|
22
|
+
EditorSurfaceSnapshot,
|
|
23
|
+
ExportDocxOptions,
|
|
24
|
+
ExportResult,
|
|
25
|
+
LoadStage,
|
|
26
|
+
PersistedEditorSnapshot,
|
|
27
|
+
ProtectionSnapshot,
|
|
28
|
+
} from "../api/public-types.ts";
|
|
29
|
+
import type { EmbeddingKind } from "../io/ooxml/classify-embedding.ts";
|
|
30
|
+
import type { LoadSchedulerBackend } from "../io/load-scheduler.ts";
|
|
31
|
+
import type { PreservationStore } from "../model/canonical-document.ts";
|
|
32
|
+
import type { EditorSessionState } from "./session-state.ts";
|
|
33
|
+
|
|
34
|
+
// Re-export legacy types so downstream consumers that still need them
|
|
35
|
+
// during the transition can reach them from the session barrel. These
|
|
36
|
+
// are explicitly transitional and scheduled for removal in Slice 5 once
|
|
37
|
+
// the legacy `src/io/docx-session.ts` is deleted.
|
|
38
|
+
export type {
|
|
39
|
+
EditorHostAdapter,
|
|
40
|
+
ExportDocxOptions,
|
|
41
|
+
ExportResult,
|
|
42
|
+
LoadStage,
|
|
43
|
+
PersistedEditorSnapshot,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Runtime-side projection ports
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Input passed by the session load path to a caller-supplied
|
|
52
|
+
* `ProgressiveSurfaceProjector`. The session carries the body-stage
|
|
53
|
+
* normalized root content plus the viewport accounting it has already
|
|
54
|
+
* computed; the projector assembles a provisional canonical envelope
|
|
55
|
+
* and calls the runtime-layer `createEditorSurfaceSnapshot` with a
|
|
56
|
+
* default selection + `MAIN_STORY_TARGET`.
|
|
57
|
+
*
|
|
58
|
+
* Kept deliberately minimal — extending the contract requires a
|
|
59
|
+
* coordinated change in the session load path + every consumer.
|
|
60
|
+
*/
|
|
61
|
+
export interface ProgressiveSurfaceProjectorInput {
|
|
62
|
+
/** Body-stage normalized root content. */
|
|
63
|
+
rootContent: DocumentRootNode;
|
|
64
|
+
/** Document id stamped on the provisional canonical envelope. */
|
|
65
|
+
documentId: string;
|
|
66
|
+
/** First-paint viewport size (blocks in the windowed view). */
|
|
67
|
+
blocksRealized: number;
|
|
68
|
+
/** Total block count in the normalized document. */
|
|
69
|
+
blocksTotal: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Runtime-side port invoked by the session to synthesize the
|
|
74
|
+
* progressive surface without pulling `src/runtime/**` into the session
|
|
75
|
+
* layer. The UI boundary implements it by binding in
|
|
76
|
+
* `createEditorSurfaceSnapshot` + a default selection + the main story
|
|
77
|
+
* target; tests bind the same runtime helper directly.
|
|
78
|
+
*/
|
|
79
|
+
export type ProgressiveSurfaceProjector = (
|
|
80
|
+
input: ProgressiveSurfaceProjectorInput,
|
|
81
|
+
) => EditorSurfaceSnapshot;
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Reserved Layer-01 options + results (architecture §Public entry points)
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Options for `DocxSession.open(bytes, opts)`.
|
|
89
|
+
*
|
|
90
|
+
* Field list mirrors the legacy `LoadDocxEditorSessionOptions` minus
|
|
91
|
+
* `bytes` (now a positional arg) and minus options that are specific to
|
|
92
|
+
* the internal async scheduler (the session class handles scheduler
|
|
93
|
+
* selection itself). Hosts pass their adapter and optional telemetry
|
|
94
|
+
* bus; everything else is wired from the session internals.
|
|
95
|
+
*/
|
|
96
|
+
export interface OpenOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Stable document identifier minted by the host. Flows through to
|
|
99
|
+
* `EditorSessionState.documentId` + `OpenResult.sessionState`.
|
|
100
|
+
*/
|
|
101
|
+
documentId?: string;
|
|
102
|
+
/** Human-readable label, surfaced in telemetry only. */
|
|
103
|
+
sourceLabel?: string;
|
|
104
|
+
/** Optional editor build identifier; default is the package version. */
|
|
105
|
+
editorBuild?: string;
|
|
106
|
+
/** Host adapter for chart previews, session storage, logging. */
|
|
107
|
+
hostAdapter?: EditorHostAdapter;
|
|
108
|
+
/**
|
|
109
|
+
* P8 Step 7 — explicit opt-in for embedded-document offload at
|
|
110
|
+
* load time. When `true` AND `hostAdapter.storeEmbeddedDocument`
|
|
111
|
+
* is defined, the session materialises every `offloadable`
|
|
112
|
+
* embedded document, computes sha-256, calls the adapter, and
|
|
113
|
+
* persists the `bw:embeddings` customXml reference + inline-bytes
|
|
114
|
+
* fallback.
|
|
115
|
+
*
|
|
116
|
+
* Default `false`. Offload is OFF unless the host opts in
|
|
117
|
+
* explicitly — supplying a `hostAdapter` for other purposes
|
|
118
|
+
* (chart-preview, save-session, log-event) never silently
|
|
119
|
+
* activates offload work.
|
|
120
|
+
*
|
|
121
|
+
* Rationale: per cross-layer-coord-04 §1.13, sha-256 +
|
|
122
|
+
* base64-encode of a large (2.5 MB) offloadable embedding adds
|
|
123
|
+
* ~300 ms to cold-open. Hosts that genuinely want offload opt in;
|
|
124
|
+
* hosts that only want the adapter for other purposes pay zero.
|
|
125
|
+
*/
|
|
126
|
+
offloadEmbeddedDocuments?: boolean;
|
|
127
|
+
/** Per-stage load instrumentation callback. */
|
|
128
|
+
onLoadStage?: (stage: LoadStage, durationMs: number) => void;
|
|
129
|
+
/**
|
|
130
|
+
* Optional telemetry bus. When supplied, the loader brackets every
|
|
131
|
+
* `parseMainDocumentXml` invocation with `setActiveParseTelemetryBus`
|
|
132
|
+
* so the parser emits on the `parse` channel. Typically the same
|
|
133
|
+
* bus is also passed to `createDocumentRuntime({ telemetryBus })`
|
|
134
|
+
* so one bus spans both load and runtime observers.
|
|
135
|
+
*
|
|
136
|
+
* Type signature uses `unknown` so the public session barrel does
|
|
137
|
+
* not drag in runtime-layer type dependencies; the loader narrows
|
|
138
|
+
* to the concrete `TelemetryBus` shape internally.
|
|
139
|
+
*/
|
|
140
|
+
telemetryBus?: unknown;
|
|
141
|
+
/**
|
|
142
|
+
* L7 Phase 2.5 Plan B B.6b — optional laycache envelope. When
|
|
143
|
+
* supplied, the loader skips the five expensive parse stages and
|
|
144
|
+
* uses the envelope's canonical document directly. Prefer
|
|
145
|
+
* `tryLaycacheEnvelope: true` over this — with that option the
|
|
146
|
+
* session runs the probe itself. Callers still wanting to supply
|
|
147
|
+
* a pre-probed envelope (e.g. a custom caching layer) can pass it
|
|
148
|
+
* here; when both are set, this wins.
|
|
149
|
+
*
|
|
150
|
+
* Type is `unknown` so the session barrel does not drag runtime
|
|
151
|
+
* layer types into its surface; the loader narrows to the concrete
|
|
152
|
+
* `CacheEnvelope` internally.
|
|
153
|
+
*/
|
|
154
|
+
laycacheEnvelope?: unknown;
|
|
155
|
+
/**
|
|
156
|
+
* Run `tryReadLaycacheEnvelope(bytes)` inside `DocxSession.open()`
|
|
157
|
+
* before dispatching to the legacy loader. When the probe returns a
|
|
158
|
+
* validated envelope, the loader short-circuits the five expensive
|
|
159
|
+
* parse stages and uses the cached `canonicalDocument` directly;
|
|
160
|
+
* when it returns null, the full parse runs. The probe itself is
|
|
161
|
+
* ~20–50 ms on extra-large documents.
|
|
162
|
+
*
|
|
163
|
+
* CLAUDE.md Performance Invariant 10: do not insert blocking work
|
|
164
|
+
* between the probe and the loader. Setting this to `true` keeps
|
|
165
|
+
* the two colocated inside the session; callers MUST NOT run a
|
|
166
|
+
* manual probe before `open()` and then also set this flag.
|
|
167
|
+
*
|
|
168
|
+
* Default: `false` (skip the probe; full parse). `laycacheEnvelope`
|
|
169
|
+
* takes precedence when both are set.
|
|
170
|
+
*/
|
|
171
|
+
tryLaycacheEnvelope?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Callback that runs the laycache-envelope probe on the source
|
|
174
|
+
* bytes. When `tryLaycacheEnvelope: true` is set AND this callback
|
|
175
|
+
* is supplied, the session invokes it (before the full parse) to
|
|
176
|
+
* check whether the package carries a pre-computed laycache
|
|
177
|
+
* envelope. On a hit, the returned `{ envelope }` is used as the
|
|
178
|
+
* short-circuit source; on a miss, full parse runs.
|
|
179
|
+
*
|
|
180
|
+
* Typed as a function returning `unknown` so this session-layer
|
|
181
|
+
* option does not transit `src/runtime/prerender/**` (the concrete
|
|
182
|
+
* `CacheEnvelope` type + `tryReadLaycacheEnvelope` implementation
|
|
183
|
+
* both live under runtime, which §P6 forbids session imports
|
|
184
|
+
* against). The shell / prerender entry-point wires the concrete
|
|
185
|
+
* probe; session narrows opaquely.
|
|
186
|
+
*
|
|
187
|
+
* Slice 5e-11 item-1 introduced this DI seam to retire the last
|
|
188
|
+
* `src/session/session.ts → src/runtime/prerender/customxml-probe.ts`
|
|
189
|
+
* debt exception (cross-layer-coord-01 §1).
|
|
190
|
+
*/
|
|
191
|
+
laycacheProbe?: (
|
|
192
|
+
bytes: Uint8Array | ArrayBuffer,
|
|
193
|
+
) => Promise<{ envelope: unknown } | null>;
|
|
194
|
+
/**
|
|
195
|
+
* Host-adapter Stage 0B.1: optional callback invoked when chart
|
|
196
|
+
* previews have finished resolving off the critical path. Fires
|
|
197
|
+
* with the canonical document that carries the resolved previews;
|
|
198
|
+
* the UI uses this to hydrate the runtime's chart-preview facet
|
|
199
|
+
* without blocking first paint.
|
|
200
|
+
*
|
|
201
|
+
* CLAUDE.md Performance Invariant 9 — do NOT `await` this, and do
|
|
202
|
+
* not rely on it for first-paint correctness. When omitted,
|
|
203
|
+
* chart-preview synthesis runs inline on the load path.
|
|
204
|
+
*/
|
|
205
|
+
onChartPreviewsReady?: (resolvedDoc: CanonicalDocument) => void;
|
|
206
|
+
/**
|
|
207
|
+
* C2c progressive-snapshot callback. When supplied AND no cached
|
|
208
|
+
* laycache envelope is in play, the loader fires this once after
|
|
209
|
+
* the body-normalize stage with a viewport-windowed surface snapshot
|
|
210
|
+
* so the UI can paint the first page before the full session
|
|
211
|
+
* resolves. CLAUDE.md Performance Invariant 8 pins the caller-side
|
|
212
|
+
* wiring: the callback MUST be fed through `React.startTransition`
|
|
213
|
+
* and the state slot MUST be cleared before committing the full
|
|
214
|
+
* runtime, or the progressive render turns into a blocking flicker.
|
|
215
|
+
*
|
|
216
|
+
* Only fires on the cold path — `laycacheEnvelope` set (either
|
|
217
|
+
* explicitly or via `tryLaycacheEnvelope`) skips the synthesis
|
|
218
|
+
* because the short-circuit is already fast enough that a
|
|
219
|
+
* pre-commit adds more overhead than it saves.
|
|
220
|
+
*/
|
|
221
|
+
onProgressiveSnapshot?: (partial: {
|
|
222
|
+
/**
|
|
223
|
+
* Projected surface. Only populated when `surfaceProjector` is also
|
|
224
|
+
* supplied — the session layer does not own surface projection
|
|
225
|
+
* (architecture §P6: session imports are forbidden from
|
|
226
|
+
* `src/runtime/**`). Consumers that need the projected surface
|
|
227
|
+
* either supply a `surfaceProjector` (recommended) or project the
|
|
228
|
+
* surface themselves from the normalized content available on the
|
|
229
|
+
* final `OpenResult`.
|
|
230
|
+
*/
|
|
231
|
+
surface?: EditorSurfaceSnapshot;
|
|
232
|
+
phase: "viewport";
|
|
233
|
+
blocksRealized: number;
|
|
234
|
+
blocksTotal: number;
|
|
235
|
+
}) => void;
|
|
236
|
+
/**
|
|
237
|
+
* Runtime-side port that projects a viewport-windowed
|
|
238
|
+
* `EditorSurfaceSnapshot` from the body-stage normalized content.
|
|
239
|
+
*
|
|
240
|
+
* When supplied with `onProgressiveSnapshot`, the session invokes
|
|
241
|
+
* this port to synthesize the surface before firing the callback.
|
|
242
|
+
* When absent, the session skips the projection and the callback
|
|
243
|
+
* fires with `surface: undefined`. This keeps the session layer
|
|
244
|
+
* P6-clean — surface projection lives in `src/runtime/**`; the
|
|
245
|
+
* session never reaches into it.
|
|
246
|
+
*
|
|
247
|
+
* The `editor-runtime-boundary.ts` load path binds the real
|
|
248
|
+
* projector (`createEditorSurfaceSnapshot` + default selection +
|
|
249
|
+
* `MAIN_STORY_TARGET`) and passes it through here.
|
|
250
|
+
*/
|
|
251
|
+
surfaceProjector?: ProgressiveSurfaceProjector;
|
|
252
|
+
/**
|
|
253
|
+
* Override the load scheduler backend. When supplied, the session
|
|
254
|
+
* constructs the internal scheduler with `backendOverride` set to
|
|
255
|
+
* this value; otherwise auto-detect picks the best backend for the
|
|
256
|
+
* current environment (scheduler.yield → MessageChannel →
|
|
257
|
+
* setTimeout → sync).
|
|
258
|
+
*
|
|
259
|
+
* The only caller today is `prerenderDocument` in
|
|
260
|
+
* `src/runtime/prerender/**`, which forces `"sync"` so the staged
|
|
261
|
+
* loader runs without yielding in Node / SSR contexts where
|
|
262
|
+
* determinism matters. Hosts that open interactively should omit
|
|
263
|
+
* this field and let auto-detect run.
|
|
264
|
+
*/
|
|
265
|
+
schedulerBackend?: LoadSchedulerBackend;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Options for `DocxSession.export(doc, opts)`.
|
|
270
|
+
*
|
|
271
|
+
* Reserved as an alias of `ExportDocxOptions` for now. Slice 4 wires
|
|
272
|
+
* export orchestration into `src/session/export/**` and promotes any
|
|
273
|
+
* new fields here; the alias keeps the public surface stable.
|
|
274
|
+
*/
|
|
275
|
+
export type ExportOptions = ExportDocxOptions;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Options for `DocxSession.validate(doc, opts)`.
|
|
279
|
+
*
|
|
280
|
+
* Reserved for Slice 4's export-validation work; the validate entry
|
|
281
|
+
* runs the compatibility engine against a provided canonical document
|
|
282
|
+
* without opening a package. Currently empty; fields expand as the
|
|
283
|
+
* validator wires in.
|
|
284
|
+
*/
|
|
285
|
+
export interface ValidateOptions {
|
|
286
|
+
/**
|
|
287
|
+
* Optional profile selector — future validator can emit different
|
|
288
|
+
* report shapes for different target consumers (UI diagnostics panel
|
|
289
|
+
* vs. CI gate vs. export-blocking check).
|
|
290
|
+
*/
|
|
291
|
+
profile?: "default" | "export-blocking";
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Reserved opaque snapshot of the preservation store as it stood at
|
|
296
|
+
* open time. Carries enough information to drive round-trip on export.
|
|
297
|
+
*
|
|
298
|
+
* The concrete shape is an alias of the existing `PreservationStore`
|
|
299
|
+
* model type; exposed here so Layer 01 owns the snapshot contract even
|
|
300
|
+
* while the store implementation lives in `src/preservation/**` /
|
|
301
|
+
* `src/model/**`.
|
|
302
|
+
*/
|
|
303
|
+
export type PreservationSnapshot = PreservationStore;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Result of `DocxSession.open(bytes, opts)`. Mirrors the architecture
|
|
307
|
+
* doc exactly: session state + canonical document + compatibility
|
|
308
|
+
* report + preservation snapshot + embedded-document manifest (P8).
|
|
309
|
+
*
|
|
310
|
+
* Every field here is part of the reserved Layer-01 public contract.
|
|
311
|
+
* The transitional legacy-session handle that in-tree services still
|
|
312
|
+
* need during the Slice-4 → Slice-5 migration is carried through a
|
|
313
|
+
* WeakMap-backed accessor (`getLegacyOpenView`) in the
|
|
314
|
+
* `src/session/_internal-legacy.ts` module — NOT as a public field on
|
|
315
|
+
* this shape. The architecture doc has no `_legacy` escape hatch,
|
|
316
|
+
* and public consumers must not see one.
|
|
317
|
+
*/
|
|
318
|
+
export interface OpenResult {
|
|
319
|
+
readonly sessionState: EditorSessionState;
|
|
320
|
+
readonly canonicalDocument: CanonicalDocument;
|
|
321
|
+
readonly compatibility: CompatibilityReport;
|
|
322
|
+
readonly preservation: PreservationSnapshot;
|
|
323
|
+
readonly embeddedDocuments: readonly EmbeddedDocumentManifest[];
|
|
324
|
+
/**
|
|
325
|
+
* `true` when the source package declared document protection that
|
|
326
|
+
* makes editing invalid on open (e.g. `readOnly` protection
|
|
327
|
+
* setting). Callers use this to surface a non-interactive view of
|
|
328
|
+
* the document without reaching into the transitional legacy view.
|
|
329
|
+
*
|
|
330
|
+
* Slice 5e-1 promoted this off `LegacyOpenView`.
|
|
331
|
+
*/
|
|
332
|
+
readonly readOnly: boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Populated when the parse pipeline produced an unrecoverable error
|
|
335
|
+
* that leaves the session unusable for editing (e.g. OPC structure
|
|
336
|
+
* rejected, main-document.xml not parseable). The session is still
|
|
337
|
+
* returned so callers can show a diagnostic snapshot; presence of
|
|
338
|
+
* this field signals "do not enter the normal runtime path".
|
|
339
|
+
*
|
|
340
|
+
* Slice 5e-1 promoted this off `LegacyOpenView`.
|
|
341
|
+
*/
|
|
342
|
+
readonly fatalError?: EditorError;
|
|
343
|
+
/**
|
|
344
|
+
* Snapshot of `/word/settings.xml` document-protection state at
|
|
345
|
+
* open time. Downstream code uses this to gate command availability
|
|
346
|
+
* without re-reading the package.
|
|
347
|
+
*
|
|
348
|
+
* Slice 5e-1 promoted this off `LegacyOpenView`.
|
|
349
|
+
*/
|
|
350
|
+
readonly protectionSnapshot: ProtectionSnapshot;
|
|
351
|
+
/**
|
|
352
|
+
* When an internal `tryLaycacheEnvelope` probe hit OR the caller
|
|
353
|
+
* supplied an explicit `laycacheEnvelope` option, the resolved
|
|
354
|
+
* envelope is surfaced here so callers can extract auxiliary data
|
|
355
|
+
* such as the cached layout graph (for `seedLayoutCache`) without
|
|
356
|
+
* re-running the probe.
|
|
357
|
+
*
|
|
358
|
+
* Typed `unknown` so the session barrel does not drag runtime-layer
|
|
359
|
+
* `CacheEnvelope` types into its public surface; callers cast to
|
|
360
|
+
* the concrete shape at the consumption site.
|
|
361
|
+
*/
|
|
362
|
+
readonly laycacheEnvelope?: unknown;
|
|
363
|
+
/**
|
|
364
|
+
* Persisted snapshot of the initial session state. Stable
|
|
365
|
+
* serialization envelope that hosts can hand to `load()` on a later
|
|
366
|
+
* mount to rehydrate the same document. Used by snapshot-based
|
|
367
|
+
* persistence flows (session-bootstrap, validator orchestrator,
|
|
368
|
+
* debug harness). Graduated from `LegacyOpenView.initialSnapshot`
|
|
369
|
+
* in Slice 5e-11 item-4.
|
|
370
|
+
*/
|
|
371
|
+
readonly initialSnapshot: PersistedEditorSnapshot;
|
|
372
|
+
/**
|
|
373
|
+
* Schema-1.2 editor-state payload parsed from the source package's
|
|
374
|
+
* `customXml/item1.xml` at open time, if present. Hosts use this
|
|
375
|
+
* to rehydrate per-document editor overlays (workflow metadata,
|
|
376
|
+
* scope definitions, host annotations). Present only when the
|
|
377
|
+
* source package carried the schema-1.2 envelope; absent for
|
|
378
|
+
* non-workflow-enabled documents.
|
|
379
|
+
*
|
|
380
|
+
* Graduated from `LegacyOpenView.initialEditorStatePayload` per the
|
|
381
|
+
* L06 `OpenResult` shape decision (2026-04-22, `docs/architecture/
|
|
382
|
+
* 06-workflow-review.md` §"Open-time surface").
|
|
383
|
+
*
|
|
384
|
+
* Typed `unknown` so the session barrel does not drag the
|
|
385
|
+
* `EditorStatePayload` type from `src/io/ooxml/workflow-payload.ts`
|
|
386
|
+
* into its public surface; callers cast at the consumption site.
|
|
387
|
+
*/
|
|
388
|
+
readonly initialEditorStatePayload?: unknown;
|
|
389
|
+
/**
|
|
390
|
+
* Export closure bound to this session's captured
|
|
391
|
+
* `ImportedDocxState`. Equivalent to
|
|
392
|
+
* `docxSession.export(sessionState, opts)` — the convenience
|
|
393
|
+
* method avoids requiring hosts to retain a reference to the
|
|
394
|
+
* `DocxSession` instance when they only hold the `OpenResult`.
|
|
395
|
+
* Same result, same byte-reuse fast path, same reconstitute
|
|
396
|
+
* pipeline.
|
|
397
|
+
*/
|
|
398
|
+
readonly exportDocx: (
|
|
399
|
+
sessionStateOrSnapshot: EditorSessionState | PersistedEditorSnapshot,
|
|
400
|
+
opts?: ExportOptions,
|
|
401
|
+
) => Promise<ExportResult>;
|
|
402
|
+
/**
|
|
403
|
+
* Releases any pending idle callbacks the load scheduler queued
|
|
404
|
+
* during parse. Callers SHOULD invoke on unmount to cancel
|
|
405
|
+
* in-flight off-critical-path work (chart-preview resolution,
|
|
406
|
+
* etc.) — CLAUDE.md Performance Invariant 9. Optional because the
|
|
407
|
+
* sync scheduler backend (used by `prerenderDocument`) has nothing
|
|
408
|
+
* to cancel.
|
|
409
|
+
*
|
|
410
|
+
* Equivalent to calling `docxSession.dispose()` on the owning
|
|
411
|
+
* `DocxSession` instance.
|
|
412
|
+
*/
|
|
413
|
+
readonly dispose?: () => void;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Sentinel returned by `DocxSession.reopenFromSnapshot()` when the
|
|
418
|
+
* rehydrate path cannot produce a usable `OpenResult`. Never thrown —
|
|
419
|
+
* always returned as a data value so callers can diff + display
|
|
420
|
+
* without a try/catch envelope.
|
|
421
|
+
*
|
|
422
|
+
* Discriminant: presence of `reason` — the `OpenResult` shape has no
|
|
423
|
+
* `reason` field. Consumers: `if ("reason" in result) { /* barrier *\/ }`.
|
|
424
|
+
*/
|
|
425
|
+
export interface ReopenBarrier {
|
|
426
|
+
/**
|
|
427
|
+
* Coarse-grained reason enum. Stable across minor versions;
|
|
428
|
+
* additive changes only. Hosts typically map this to a localized
|
|
429
|
+
* UI message and/or an audit event.
|
|
430
|
+
*/
|
|
431
|
+
readonly reason:
|
|
432
|
+
| "no-source-package"
|
|
433
|
+
| "invalid-digest"
|
|
434
|
+
| "corrupted-bytes"
|
|
435
|
+
| "unsupported-schema";
|
|
436
|
+
/**
|
|
437
|
+
* Human-readable explanation tied to `reason`. Stable enough for
|
|
438
|
+
* surfacing verbatim in diagnostic logs. Not localised.
|
|
439
|
+
*/
|
|
440
|
+
readonly message: string;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Type guard helper — narrows `OpenResult | ReopenBarrier` to the
|
|
445
|
+
* barrier arm. The discriminant is the presence of `reason`.
|
|
446
|
+
*/
|
|
447
|
+
export function isReopenBarrier(
|
|
448
|
+
result: OpenResult | ReopenBarrier,
|
|
449
|
+
): result is ReopenBarrier {
|
|
450
|
+
return (result as Partial<ReopenBarrier>).reason !== undefined;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Result of `DocxSession.validate(doc, opts)`.
|
|
455
|
+
*
|
|
456
|
+
* Reserved shape — Slice 4 implements the runner and decides whether
|
|
457
|
+
* findings carry line/column context or only stable codes. The field
|
|
458
|
+
* list here is the minimum the architecture needs: a severity-tagged
|
|
459
|
+
* record list plus a pass/fail verdict.
|
|
460
|
+
*/
|
|
461
|
+
export interface ValidationReport {
|
|
462
|
+
readonly ok: boolean;
|
|
463
|
+
readonly findings: readonly ValidationFinding[];
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
export interface ValidationFinding {
|
|
467
|
+
readonly code: string;
|
|
468
|
+
readonly severity: "info" | "warning" | "error";
|
|
469
|
+
readonly message: string;
|
|
470
|
+
readonly featureKey?: string;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// ---------------------------------------------------------------------------
|
|
474
|
+
// P8 · Embedded-document manifest (architecture §P8)
|
|
475
|
+
// ---------------------------------------------------------------------------
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Per-entry shape for every embedded OLE object or `w:altChunk` target
|
|
479
|
+
* discovered on open. Matches the reservation at
|
|
480
|
+
* `docs/architecture/01-package-session.md` § Public entry points:
|
|
481
|
+
* - `id` stable across open/export (derived from content fingerprint)
|
|
482
|
+
* - `kind` three-way classification from `classifyEmbedding()`
|
|
483
|
+
* - `progId`, `mimeType`, `filename` are signal-best-effort metadata
|
|
484
|
+
* - `size` is the byte length of the underlying package part
|
|
485
|
+
* - `relationshipId` points to the owning rId in the main-document
|
|
486
|
+
* relationships (or the containing story for altChunk targets)
|
|
487
|
+
* - `bytes()` is lazy — the part bytes are materialized on demand,
|
|
488
|
+
* never eagerly copied at open time (Performance Invariant 9)
|
|
489
|
+
*/
|
|
490
|
+
export interface EmbeddedDocumentManifest {
|
|
491
|
+
readonly id: string;
|
|
492
|
+
readonly kind: EmbeddingKind;
|
|
493
|
+
readonly progId?: string;
|
|
494
|
+
readonly mimeType?: string;
|
|
495
|
+
readonly filename?: string;
|
|
496
|
+
readonly size: number;
|
|
497
|
+
readonly relationshipId: string;
|
|
498
|
+
readonly bytes: () => Uint8Array;
|
|
499
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell helper — chart-snapshot projection.
|
|
3
|
+
*
|
|
4
|
+
* Walks a `CanonicalDocument` and projects the chart-preview inlines into
|
|
5
|
+
* public-API `ChartSnapshot` records. Consumers: the React editor ref
|
|
6
|
+
* (`getChartSnapshots` / `getChartSnapshot`) and any headless consumer
|
|
7
|
+
* that needs chart reads without mounting the editor.
|
|
8
|
+
*
|
|
9
|
+
* This lives in `src/shell/` rather than `src/ui/` because it's a pure
|
|
10
|
+
* projection between the canonical document (L02) and the public API
|
|
11
|
+
* (L07 reads) — no DOM, no React, no presentation. `src/ui/` is the
|
|
12
|
+
* presentation layer; keeping this helper outside it retires two
|
|
13
|
+
* substrate-reach-through imports (`runtime/chart/chart-model-store` +
|
|
14
|
+
* `runtime/chart/chart-snapshot`) from the Layer-11 boundary register.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { CanonicalDocument } from "../model/canonical-document.ts";
|
|
18
|
+
import type { ChartSnapshot } from "../api/public-types.ts";
|
|
19
|
+
import { stableChartId } from "../runtime/chart/chart-model-store.ts";
|
|
20
|
+
import { projectChartSnapshot } from "../runtime/chart/chart-snapshot.ts";
|
|
21
|
+
|
|
22
|
+
type BlockArray = CanonicalDocument["content"]["children"];
|
|
23
|
+
|
|
24
|
+
export function collectChartSnapshots(doc: CanonicalDocument): ChartSnapshot[] {
|
|
25
|
+
const results: ChartSnapshot[] = [];
|
|
26
|
+
collectChartSnapshotsFromBlocks(doc.content.children, results);
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Walk the canonical document, compute each chart_preview's stableChartId,
|
|
32
|
+
* and project a snapshot for the first matching id. Short-circuits on
|
|
33
|
+
* match so the happy path is O(k) in blocks-until-match rather than the
|
|
34
|
+
* O(N) the `collect().find()` fallback incurred for every ref call. For
|
|
35
|
+
* hosts that call `getChartSnapshot` in a tight loop over many chartIds,
|
|
36
|
+
* this reduces the cost from O(N²) to O(N·k).
|
|
37
|
+
*/
|
|
38
|
+
export function lookupChartSnapshot(
|
|
39
|
+
doc: CanonicalDocument,
|
|
40
|
+
chartId: string,
|
|
41
|
+
): ChartSnapshot | null {
|
|
42
|
+
return lookupChartSnapshotInBlocks(doc.content.children, chartId);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function lookupChartSnapshotInBlocks(
|
|
46
|
+
blocks: BlockArray,
|
|
47
|
+
chartId: string,
|
|
48
|
+
): ChartSnapshot | null {
|
|
49
|
+
for (const block of blocks) {
|
|
50
|
+
if (block.type === "paragraph") {
|
|
51
|
+
for (const inline of block.children) {
|
|
52
|
+
if (inline.type === "chart_preview" && inline.parsedData) {
|
|
53
|
+
const id = stableChartId(inline.rawXml);
|
|
54
|
+
if (id === chartId) {
|
|
55
|
+
return projectChartSnapshot(id, inline.parsedData);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else if (block.type === "table") {
|
|
60
|
+
for (const row of block.rows) {
|
|
61
|
+
for (const cell of row.cells) {
|
|
62
|
+
const found = lookupChartSnapshotInBlocks(cell.children, chartId);
|
|
63
|
+
if (found) return found;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} else if (block.type === "sdt" || block.type === "custom_xml") {
|
|
67
|
+
const found = lookupChartSnapshotInBlocks(block.children, chartId);
|
|
68
|
+
if (found) return found;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function collectChartSnapshotsFromBlocks(
|
|
75
|
+
blocks: BlockArray,
|
|
76
|
+
results: ChartSnapshot[],
|
|
77
|
+
): void {
|
|
78
|
+
for (const block of blocks) {
|
|
79
|
+
if (block.type === "paragraph") {
|
|
80
|
+
for (const inline of block.children) {
|
|
81
|
+
if (inline.type === "chart_preview" && inline.parsedData) {
|
|
82
|
+
const chartId = stableChartId(inline.rawXml);
|
|
83
|
+
results.push(projectChartSnapshot(chartId, inline.parsedData));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} else if (block.type === "table") {
|
|
87
|
+
for (const row of block.rows) {
|
|
88
|
+
for (const cell of row.cells) {
|
|
89
|
+
collectChartSnapshotsFromBlocks(cell.children, results);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else if (block.type === "sdt" || block.type === "custom_xml") {
|
|
93
|
+
collectChartSnapshotsFromBlocks(block.children, results);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell helper — media-preview catalog construction.
|
|
3
|
+
*
|
|
4
|
+
* Builds the inline `data:` URLs the mounted editor feeds to image
|
|
5
|
+
* render paths. Reads the persisted source-package bytes, verifies the
|
|
6
|
+
* digest, walks the OPC parts table, and projects each canonical media
|
|
7
|
+
* item into a `MediaPreviewDescriptor`.
|
|
8
|
+
*
|
|
9
|
+
* SVG is included in the browser-safe content-type allowlist — Chromium
|
|
10
|
+
* sandboxes SVGs loaded via `<img src="data:image/svg+xml;base64,…">`
|
|
11
|
+
* (no script execution, no external refs), so XSS surface matches PNG.
|
|
12
|
+
* Required for CCEP-synthesized chart previews (Stage 0B) and hosts
|
|
13
|
+
* that ship `.svg` inside `word/media/`.
|
|
14
|
+
*
|
|
15
|
+
* Lives in `src/shell/` so the three `io/**` substrate imports stay
|
|
16
|
+
* outside the L11 boundary register — package decoding is a shell
|
|
17
|
+
* concern, not a presentation one.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { CanonicalDocument } from "../model/canonical-document.ts";
|
|
21
|
+
import type { PersistedSourcePackage } from "../model/snapshot.ts";
|
|
22
|
+
import type { MediaPreviewDescriptor } from "../ui-tailwind/editor-surface/pm-state-from-snapshot";
|
|
23
|
+
import {
|
|
24
|
+
decodePersistedSourcePackageBytes,
|
|
25
|
+
hasValidPersistedSourcePackageDigest,
|
|
26
|
+
} from "../io/source-package-provenance.ts";
|
|
27
|
+
import { readOpcPackage } from "../io/opc/package-reader.ts";
|
|
28
|
+
|
|
29
|
+
const BROWSER_SAFE_PREVIEW_TYPES = new Set([
|
|
30
|
+
"image/png",
|
|
31
|
+
"image/jpeg",
|
|
32
|
+
"image/jpg",
|
|
33
|
+
"image/gif",
|
|
34
|
+
"image/webp",
|
|
35
|
+
"image/bmp",
|
|
36
|
+
"image/svg+xml",
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
export function buildMediaPreviews(
|
|
40
|
+
sourcePackage: PersistedSourcePackage | null | undefined,
|
|
41
|
+
canonicalDocument: CanonicalDocument,
|
|
42
|
+
): Record<string, MediaPreviewDescriptor> {
|
|
43
|
+
if (!sourcePackage) {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const bytes = decodePersistedSourcePackageBytes(sourcePackage);
|
|
48
|
+
if (!hasValidPersistedSourcePackageDigest(sourcePackage, bytes)) {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
const opc = readOpcPackage(bytes);
|
|
52
|
+
const previews: Record<string, MediaPreviewDescriptor> = {};
|
|
53
|
+
for (const item of Object.values(canonicalDocument.media.items)) {
|
|
54
|
+
const contentType = item.contentType?.toLowerCase();
|
|
55
|
+
const part = opc.parts.get(item.packagePartName);
|
|
56
|
+
if (
|
|
57
|
+
!part?.bytes ||
|
|
58
|
+
!contentType ||
|
|
59
|
+
!BROWSER_SAFE_PREVIEW_TYPES.has(contentType)
|
|
60
|
+
) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
previews[item.mediaId] = {
|
|
64
|
+
src: createImageDataUrl(contentType, part.bytes),
|
|
65
|
+
...(item.widthEmu !== undefined ? { widthEmu: item.widthEmu } : {}),
|
|
66
|
+
...(item.heightEmu !== undefined ? { heightEmu: item.heightEmu } : {}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return previews;
|
|
70
|
+
} catch {
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function createImageDataUrl(contentType: string, bytes: Uint8Array): string {
|
|
76
|
+
return `data:${contentType};base64,${bytesToBase64(bytes)}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function bytesToBase64(bytes: Uint8Array): string {
|
|
80
|
+
let binary = "";
|
|
81
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
82
|
+
binary += String.fromCharCode(bytes[index] ?? 0);
|
|
83
|
+
}
|
|
84
|
+
return btoa(binary);
|
|
85
|
+
}
|