@beyondwork/docx-react-component 1.0.55 → 1.0.57
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/package.json +43 -32
- package/src/api/public-types.ts +157 -0
- package/src/compare/diff-engine.ts +3 -0
- package/src/core/commands/formatting-commands.ts +1 -0
- package/src/core/commands/index.ts +17 -11
- package/src/core/selection/mapping.ts +18 -1
- package/src/core/selection/review-anchors.ts +29 -18
- package/src/io/chart-preview-resolver.ts +175 -41
- package/src/io/docx-session.ts +57 -2
- package/src/io/export/serialize-main-document.ts +82 -0
- package/src/io/export/serialize-styles.ts +61 -3
- package/src/io/export/table-properties-xml.ts +19 -4
- package/src/io/normalize/normalize-text.ts +33 -0
- package/src/io/ooxml/parse-anchor.ts +182 -0
- package/src/io/ooxml/parse-drawing.ts +319 -0
- package/src/io/ooxml/parse-fields.ts +115 -2
- package/src/io/ooxml/parse-fill.ts +215 -0
- package/src/io/ooxml/parse-font-table.ts +190 -0
- package/src/io/ooxml/parse-footnotes.ts +52 -1
- package/src/io/ooxml/parse-main-document.ts +241 -1
- package/src/io/ooxml/parse-numbering.ts +96 -0
- package/src/io/ooxml/parse-picture.ts +107 -0
- package/src/io/ooxml/parse-settings.ts +34 -0
- package/src/io/ooxml/parse-shapes.ts +87 -0
- package/src/io/ooxml/parse-solid-fill.ts +11 -0
- package/src/io/ooxml/parse-styles.ts +74 -1
- package/src/io/ooxml/parse-theme.ts +60 -0
- package/src/io/paste/html-clipboard.ts +449 -0
- package/src/io/paste/word-clipboard.ts +5 -1
- package/src/legal/_document-root.ts +26 -0
- package/src/legal/bookmarks.ts +4 -3
- package/src/legal/cross-references.ts +3 -2
- package/src/legal/defined-terms.ts +2 -1
- package/src/legal/signature-blocks.ts +2 -1
- package/src/model/canonical-document.ts +415 -3
- package/src/runtime/chart/chart-model-store.ts +73 -10
- package/src/runtime/document-runtime.ts +693 -41
- package/src/runtime/edit-ops/index.ts +129 -0
- package/src/runtime/event-refresh-hints.ts +7 -0
- package/src/runtime/field-resolver.ts +341 -0
- package/src/runtime/footnote-resolver.ts +55 -0
- package/src/runtime/hyperlink-color-resolver.ts +13 -10
- package/src/runtime/object-grab/index.ts +51 -0
- package/src/runtime/paragraph-style-resolver.ts +105 -0
- package/src/runtime/resolved-numbering-geometry.ts +12 -0
- package/src/runtime/selection/cursor-ops.ts +186 -15
- package/src/runtime/selection/index.ts +17 -1
- package/src/runtime/structure-ops/index.ts +77 -0
- package/src/runtime/styles-cascade.ts +33 -0
- package/src/runtime/surface-projection.ts +186 -12
- package/src/runtime/theme-color-resolver.ts +189 -44
- package/src/runtime/units.ts +46 -0
- package/src/runtime/view-state.ts +13 -2
- package/src/ui/WordReviewEditor.tsx +168 -10
- package/src/ui/editor-runtime-boundary.ts +94 -1
- package/src/ui/editor-shell-view.tsx +1 -1
- package/src/ui/runtime-shortcut-dispatch.ts +17 -3
- package/src/ui-tailwind/chart/ChartSurface.tsx +36 -10
- package/src/ui-tailwind/chart/layout/plot-area.ts +120 -45
- package/src/ui-tailwind/chart/render/area.tsx +22 -4
- package/src/ui-tailwind/chart/render/bar-column.tsx +37 -11
- package/src/ui-tailwind/chart/render/bubble.tsx +6 -2
- package/src/ui-tailwind/chart/render/combo.tsx +37 -4
- package/src/ui-tailwind/chart/render/line.tsx +28 -5
- package/src/ui-tailwind/chart/render/pie.tsx +36 -16
- package/src/ui-tailwind/chart/render/progressive-render.ts +8 -1
- package/src/ui-tailwind/chart/render/scatter.tsx +9 -4
- package/src/ui-tailwind/chrome/avatar-initials.ts +15 -0
- package/src/ui-tailwind/chrome/tw-comment-preview.tsx +3 -1
- package/src/ui-tailwind/chrome/tw-context-menu.tsx +14 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +3 -2
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +30 -11
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +15 -2
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +1 -1
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +24 -7
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +31 -12
- package/src/ui-tailwind/chrome-overlay/page-border-resolver.ts +211 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +1 -0
- package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +74 -0
- package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +65 -0
- package/src/ui-tailwind/chrome-overlay/tw-page-border-overlay.tsx +233 -0
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +135 -13
- package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +51 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +12 -4
- package/src/ui-tailwind/chrome-overlay/tw-scope-card.tsx +32 -12
- package/src/ui-tailwind/chrome-overlay/tw-toc-outline-sidebar.tsx +133 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +49 -10
- package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +119 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +236 -9
- package/src/ui-tailwind/editor-surface/pm-schema.ts +192 -11
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +28 -3
- package/src/ui-tailwind/editor-surface/shape-renderer.ts +206 -0
- package/src/ui-tailwind/editor-surface/surface-layer.ts +66 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +29 -0
- package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +7 -1
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +22 -6
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +10 -16
- package/src/ui-tailwind/review/tw-health-panel.tsx +0 -25
- package/src/ui-tailwind/review/tw-rail-card.tsx +38 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +2 -2
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +5 -12
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +2 -2
- package/src/ui-tailwind/theme/editor-theme.css +1 -0
- package/src/ui-tailwind/theme/tokens.css +6 -0
- package/src/ui-tailwind/theme/tokens.ts +10 -0
- package/src/validation/compatibility-engine.ts +2 -0
- package/src/validation/docx-comment-proof.ts +12 -3
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beyondwork/docx-react-component",
|
|
3
3
|
"publisher": "beyondwork",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.57",
|
|
5
5
|
"description": "Embeddable React Word (docx) editor with review, comments, tracked changes, and round-trip OOXML fidelity.",
|
|
6
|
+
"packageManager": "pnpm@10.30.3",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"sideEffects": [
|
|
8
9
|
"**/*.css"
|
|
@@ -92,6 +93,37 @@
|
|
|
92
93
|
"./ui-tailwind/theme/editor-theme.css": "./src/ui-tailwind/theme/editor-theme.css"
|
|
93
94
|
},
|
|
94
95
|
"types": "./src/index.ts",
|
|
96
|
+
"scripts": {
|
|
97
|
+
"build": "tsup",
|
|
98
|
+
"test": "bash scripts/run-workspace-tests.sh",
|
|
99
|
+
"test:repo": "node scripts/ci-check-layout-engine-version.mjs && node scripts/run-repo-tests.mjs core",
|
|
100
|
+
"test:repo:all": "node scripts/run-repo-tests.mjs all",
|
|
101
|
+
"test:repo:optional": "node scripts/run-repo-tests.mjs optional",
|
|
102
|
+
"test:repo:browser-ui": "node scripts/run-repo-tests.mjs browser-ui",
|
|
103
|
+
"test:wcag-audit": "node scripts/run-repo-tests.mjs wcag-audit",
|
|
104
|
+
"test:harness": "pnpm --filter @docx-react-component/react-word-editor-harness test",
|
|
105
|
+
"test:visual": "VISUAL_SMOKE_PROFILE=bare pnpm exec playwright test --project=chromium",
|
|
106
|
+
"test:visual:chrome": "VISUAL_SMOKE_PROFILE=chrome-cycle pnpm exec playwright test --project=chromium",
|
|
107
|
+
"visual:list-runs": "node scripts/visual-smoke-list-runs.mjs",
|
|
108
|
+
"mcp:visual-smoke": "node scripts/visual-smoke-mcp.mjs",
|
|
109
|
+
"lint": "pnpm run lint:no-authored-js && pnpm run lint:docs-contracts && pnpm run lint:tsgo && pnpm run lint:tsgo:harness",
|
|
110
|
+
"lint:docs-contracts": "bash scripts/check-reference-load-contract.sh",
|
|
111
|
+
"lint:no-authored-js": "bash scripts/check-no-authored-js.sh",
|
|
112
|
+
"lint:tsgo": "tsgo --noEmit -p tsconfig.build.json",
|
|
113
|
+
"lint:tsgo:harness": "pnpm --filter @docx-react-component/react-word-editor-harness lint:tsgo",
|
|
114
|
+
"generate:token-reference": "node scripts/generate-token-reference.mjs",
|
|
115
|
+
"check:token-reference": "node scripts/generate-token-reference.mjs --check",
|
|
116
|
+
"context7:api-check": "bash scripts/context7-export-env.sh run bash scripts/context7-api-check.sh",
|
|
117
|
+
"wave:doctor": "bash scripts/context7-export-env.sh run pnpm exec wave doctor --json",
|
|
118
|
+
"wave:dry-run": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main --dry-run --no-dashboard",
|
|
119
|
+
"wave:launch": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main",
|
|
120
|
+
"wave:launch:managed": "bash scripts/wave-launch.sh",
|
|
121
|
+
"wave:status": "bash scripts/wave-status.sh",
|
|
122
|
+
"wave:watch": "bash scripts/wave-watch.sh --follow",
|
|
123
|
+
"wave:dashboard:current": "bash scripts/wave-dashboard-attach.sh current",
|
|
124
|
+
"wave:dashboard:global": "bash scripts/wave-dashboard-attach.sh global",
|
|
125
|
+
"harness:dev": "pnpm --filter @docx-react-component/react-word-editor-harness dev"
|
|
126
|
+
},
|
|
95
127
|
"keywords": [
|
|
96
128
|
"docx",
|
|
97
129
|
"word",
|
|
@@ -175,35 +207,14 @@
|
|
|
175
207
|
"y-protocols": "^1.0.7",
|
|
176
208
|
"yjs": "^13.6.30"
|
|
177
209
|
},
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
"
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
"test:visual": "VISUAL_SMOKE_PROFILE=bare pnpm exec playwright test --project=chromium",
|
|
188
|
-
"test:visual:chrome": "VISUAL_SMOKE_PROFILE=chrome-cycle pnpm exec playwright test --project=chromium",
|
|
189
|
-
"visual:list-runs": "node scripts/visual-smoke-list-runs.mjs",
|
|
190
|
-
"mcp:visual-smoke": "node scripts/visual-smoke-mcp.mjs",
|
|
191
|
-
"lint": "pnpm run lint:no-authored-js && pnpm run lint:docs-contracts && pnpm run lint:tsgo && pnpm run lint:tsgo:harness",
|
|
192
|
-
"lint:docs-contracts": "bash scripts/check-reference-load-contract.sh",
|
|
193
|
-
"lint:no-authored-js": "bash scripts/check-no-authored-js.sh",
|
|
194
|
-
"lint:tsgo": "tsgo --noEmit -p tsconfig.build.json",
|
|
195
|
-
"lint:tsgo:harness": "pnpm --filter @docx-react-component/react-word-editor-harness lint:tsgo",
|
|
196
|
-
"generate:token-reference": "node scripts/generate-token-reference.mjs",
|
|
197
|
-
"check:token-reference": "node scripts/generate-token-reference.mjs --check",
|
|
198
|
-
"context7:api-check": "bash scripts/context7-export-env.sh run bash scripts/context7-api-check.sh",
|
|
199
|
-
"wave:doctor": "bash scripts/context7-export-env.sh run pnpm exec wave doctor --json",
|
|
200
|
-
"wave:dry-run": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main --dry-run --no-dashboard",
|
|
201
|
-
"wave:launch": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main",
|
|
202
|
-
"wave:launch:managed": "bash scripts/wave-launch.sh",
|
|
203
|
-
"wave:status": "bash scripts/wave-status.sh",
|
|
204
|
-
"wave:watch": "bash scripts/wave-watch.sh --follow",
|
|
205
|
-
"wave:dashboard:current": "bash scripts/wave-dashboard-attach.sh current",
|
|
206
|
-
"wave:dashboard:global": "bash scripts/wave-dashboard-attach.sh global",
|
|
207
|
-
"harness:dev": "pnpm --filter @docx-react-component/react-word-editor-harness dev"
|
|
210
|
+
"pnpm": {
|
|
211
|
+
"onlyBuiltDependencies": [
|
|
212
|
+
"esbuild",
|
|
213
|
+
"sharp"
|
|
214
|
+
],
|
|
215
|
+
"overrides": {
|
|
216
|
+
"react": "19.2.4",
|
|
217
|
+
"react-dom": "19.2.4"
|
|
218
|
+
}
|
|
208
219
|
}
|
|
209
|
-
}
|
|
220
|
+
}
|
package/src/api/public-types.ts
CHANGED
|
@@ -717,11 +717,17 @@ export type SnapshotRefreshChangeKind =
|
|
|
717
717
|
| "structure"
|
|
718
718
|
| "checkpoint";
|
|
719
719
|
|
|
720
|
+
export interface TocRefreshTrigger {
|
|
721
|
+
headingContentChanged: boolean;
|
|
722
|
+
headingStructureChanged: boolean;
|
|
723
|
+
}
|
|
724
|
+
|
|
720
725
|
export interface SnapshotRefreshHints {
|
|
721
726
|
invalidate: SnapshotRefreshInvalidateTarget[];
|
|
722
727
|
staleTargets: SnapshotRefreshStaleTarget[];
|
|
723
728
|
changeKinds: SnapshotRefreshChangeKind[];
|
|
724
729
|
checkpointType?: "session" | "snapshot" | "export";
|
|
730
|
+
tocRefreshTrigger?: TocRefreshTrigger;
|
|
725
731
|
}
|
|
726
732
|
|
|
727
733
|
export interface StyleCatalogEntrySnapshot {
|
|
@@ -798,6 +804,45 @@ export type SurfaceTextMark =
|
|
|
798
804
|
| "smallCaps"
|
|
799
805
|
| "allCaps";
|
|
800
806
|
|
|
807
|
+
/**
|
|
808
|
+
* V2c.4 / V2c.5 — DrawingFrame anchor geometry projected onto image + shape
|
|
809
|
+
* segments. Mirrors the canonical `AnchorGeometry` shape (defined in
|
|
810
|
+
* `src/model/canonical-document.ts`) with the fields chrome consumers need
|
|
811
|
+
* for float-wrap (Lane 6d N9), object-selection chrome (N6), and frame
|
|
812
|
+
* positioning. EMU values are kept verbatim — converters that need px
|
|
813
|
+
* apply 9525 EMU = 1 px at 96 dpi.
|
|
814
|
+
*/
|
|
815
|
+
export interface SurfaceDrawingAnchor {
|
|
816
|
+
display: "inline" | "floating";
|
|
817
|
+
wrapMode: "none" | "square" | "tight" | "through" | "topAndBottom";
|
|
818
|
+
extent: { widthEmu: number; heightEmu: number };
|
|
819
|
+
positionH?: { relativeFrom: string; align?: string; offset?: number };
|
|
820
|
+
positionV?: { relativeFrom: string; align?: string; offset?: number };
|
|
821
|
+
distMargins?: { top?: number; bottom?: number; left?: number; right?: number };
|
|
822
|
+
relativeHeight?: number;
|
|
823
|
+
behindDoc?: boolean;
|
|
824
|
+
layoutInCell?: boolean;
|
|
825
|
+
allowOverlap?: boolean;
|
|
826
|
+
simplePos?: boolean;
|
|
827
|
+
/** docPr.id / .name / .descr — used for accessibility chrome and selection labels. */
|
|
828
|
+
docPr?: { id: string; name?: string; descr?: string };
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* V2c.4 — Picture-effect data (crop, rotation, flip, preset clip geometry).
|
|
833
|
+
* `srcRect` percentages match OOXML's `a:srcRect` semantics: 0 = no crop,
|
|
834
|
+
* 100 000 = fully cropped from that edge. `rotation` is in 60 000ths of a
|
|
835
|
+
* degree (OOXML `a:xfrm a:rot`).
|
|
836
|
+
*/
|
|
837
|
+
export interface SurfacePictureEffects {
|
|
838
|
+
srcRect?: { top: number; bottom: number; left: number; right: number };
|
|
839
|
+
rotation?: number;
|
|
840
|
+
flipH?: boolean;
|
|
841
|
+
flipV?: boolean;
|
|
842
|
+
presetGeom?: string;
|
|
843
|
+
stretch?: boolean;
|
|
844
|
+
}
|
|
845
|
+
|
|
801
846
|
export type SurfaceInlineSegment =
|
|
802
847
|
| {
|
|
803
848
|
segmentId: string;
|
|
@@ -836,6 +881,19 @@ export type SurfaceInlineSegment =
|
|
|
836
881
|
state: "editable" | "missing";
|
|
837
882
|
display?: "inline" | "floating";
|
|
838
883
|
detail?: string;
|
|
884
|
+
/**
|
|
885
|
+
* V2c.4 — DrawingFrame anchor geometry surfaced for Lane 6d float-wrap
|
|
886
|
+
* (P7) and chrome consumers. Present only when the canonical model
|
|
887
|
+
* carries non-trivial anchor metadata; inline pictures with default
|
|
888
|
+
* positioning omit it so the simple-image path stays cheap.
|
|
889
|
+
*/
|
|
890
|
+
anchor?: SurfaceDrawingAnchor;
|
|
891
|
+
/**
|
|
892
|
+
* V2c.4 — Picture-effect data (crop, rotation, flip, preset geometry).
|
|
893
|
+
* Absent when none of the underlying `PictureContent` effect fields
|
|
894
|
+
* are set, so consumers can fast-path image rendering when undefined.
|
|
895
|
+
*/
|
|
896
|
+
pictureEffects?: SurfacePictureEffects;
|
|
839
897
|
}
|
|
840
898
|
| {
|
|
841
899
|
segmentId: string;
|
|
@@ -886,6 +944,44 @@ export type SurfaceInlineSegment =
|
|
|
886
944
|
instruction: string;
|
|
887
945
|
refreshStatus: FieldRefreshStatus;
|
|
888
946
|
label: string;
|
|
947
|
+
}
|
|
948
|
+
| {
|
|
949
|
+
/**
|
|
950
|
+
* V2c.5 — DrawingFrame shape segment. Replaces the `complex_preview`
|
|
951
|
+
* fallback that used to swallow `wps:wsp` shapes. Carries the
|
|
952
|
+
* geometry preset, fill/line, optional textbox flag + first-paragraph
|
|
953
|
+
* preview, and (for floating shapes) anchor geometry. Lane 6d's N10
|
|
954
|
+
* shape rendering consumes this segment.
|
|
955
|
+
*/
|
|
956
|
+
segmentId: string;
|
|
957
|
+
kind: "shape";
|
|
958
|
+
from: number;
|
|
959
|
+
to: number;
|
|
960
|
+
label: string;
|
|
961
|
+
detail: string;
|
|
962
|
+
anchor?: SurfaceDrawingAnchor;
|
|
963
|
+
geometry?: string;
|
|
964
|
+
fill?:
|
|
965
|
+
| { kind: "solid"; color: string; colorType: "srgbClr" | "schemeClr" }
|
|
966
|
+
| { kind: "none" }
|
|
967
|
+
| {
|
|
968
|
+
kind: "gradient";
|
|
969
|
+
stops: Array<{ pos: number; color: string; colorType: "srgbClr" | "schemeClr" }>;
|
|
970
|
+
direction:
|
|
971
|
+
| { kind: "linear"; angle: number; scaled?: boolean }
|
|
972
|
+
| { kind: "path"; path: "circle" | "rect" | "shape" };
|
|
973
|
+
rotWithShape?: boolean;
|
|
974
|
+
}
|
|
975
|
+
| {
|
|
976
|
+
kind: "pattern";
|
|
977
|
+
preset: string;
|
|
978
|
+
fg?: { color: string; colorType: "srgbClr" | "schemeClr" };
|
|
979
|
+
bg?: { color: string; colorType: "srgbClr" | "schemeClr" };
|
|
980
|
+
};
|
|
981
|
+
line?: { color?: string; widthEmu?: number; noLine?: boolean };
|
|
982
|
+
isTextBox?: boolean;
|
|
983
|
+
/** First-paragraph plain-text preview when `isTextBox` is true. */
|
|
984
|
+
txbxText?: string;
|
|
889
985
|
};
|
|
890
986
|
|
|
891
987
|
export interface SurfaceTableCellSnapshot {
|
|
@@ -2563,6 +2659,12 @@ export type WordReviewEditorEvent =
|
|
|
2563
2659
|
documentId: string;
|
|
2564
2660
|
activeStory: EditorStoryTarget;
|
|
2565
2661
|
}
|
|
2662
|
+
| {
|
|
2663
|
+
type: "toc_auto_refreshed";
|
|
2664
|
+
documentId: string;
|
|
2665
|
+
entryCount: number;
|
|
2666
|
+
trigger: TocRefreshTrigger;
|
|
2667
|
+
}
|
|
2566
2668
|
| {
|
|
2567
2669
|
type: "warning_added";
|
|
2568
2670
|
documentId: string;
|
|
@@ -3060,6 +3162,61 @@ export interface WordReviewEditorRef {
|
|
|
3060
3162
|
* add merge-intent + richer caret placement as paste parsers come online.
|
|
3061
3163
|
*/
|
|
3062
3164
|
insertFragment(fragment: CanonicalDocumentFragment, target?: EditorAnchorProjection): void;
|
|
3165
|
+
/**
|
|
3166
|
+
* I2 Tier B Slice 4b — serialize `target` (or the current selection) to a
|
|
3167
|
+
* `CanonicalDocumentFragment` and store it in the editor's internal
|
|
3168
|
+
* clipboard buffer. No document mutation.
|
|
3169
|
+
*/
|
|
3170
|
+
copy(target?: EditorAnchorProjection): void;
|
|
3171
|
+
/**
|
|
3172
|
+
* I2 Tier B Slice 4b — `copy(target)` + delete the range.
|
|
3173
|
+
*/
|
|
3174
|
+
cut(target?: EditorAnchorProjection): void;
|
|
3175
|
+
/**
|
|
3176
|
+
* I2 Tier B Slice 4b — return the last fragment written by `cut` / `copy`,
|
|
3177
|
+
* or `null` if none has been captured yet. Hosts pair this with
|
|
3178
|
+
* `insertFragment` to implement paste while Slice 4b's async-Clipboard-API
|
|
3179
|
+
* write lands with Slice 5.
|
|
3180
|
+
*/
|
|
3181
|
+
getClipboardBuffer(): CanonicalDocumentFragment | null;
|
|
3182
|
+
/**
|
|
3183
|
+
* v5 close-out — return the current clipboard buffer serialized to the
|
|
3184
|
+
* wire formats browsers/Word accept, or `null` when no clipboard op has
|
|
3185
|
+
* been performed. Hosts use this inside their own DOM `copy`/`cut` event
|
|
3186
|
+
* handler to feed `navigator.clipboard.write` (the editor does not
|
|
3187
|
+
* install the DOM handler itself).
|
|
3188
|
+
*/
|
|
3189
|
+
getClipboardWireFormats(): { wordml: string; html: string; plainText: string } | null;
|
|
3190
|
+
/**
|
|
3191
|
+
* R.3 ObjectGrabLayer — grab an inline / floating object (image, shape)
|
|
3192
|
+
* by its stable id. Single-select; replaces any previously grabbed
|
|
3193
|
+
* object. Lane 6 P11 chrome reads the grab state to paint handles.
|
|
3194
|
+
*/
|
|
3195
|
+
selectObject(objectId: string): void;
|
|
3196
|
+
/**
|
|
3197
|
+
* R.3 — release the grabbed object, if any. Safe to call when nothing
|
|
3198
|
+
* is grabbed.
|
|
3199
|
+
*/
|
|
3200
|
+
deselectObject(): void;
|
|
3201
|
+
/**
|
|
3202
|
+
* R.3 — return the grabbed object's id, or `null` when nothing is
|
|
3203
|
+
* grabbed.
|
|
3204
|
+
*/
|
|
3205
|
+
getGrabbedObject(): string | null;
|
|
3206
|
+
/**
|
|
3207
|
+
* R.5.a — open an action bracket. Hosts wrap compound edits (paste,
|
|
3208
|
+
* cut+paste, agent suggestion-apply) so snapshot emission + collab
|
|
3209
|
+
* broadcast + undo grouping see them as a single action.
|
|
3210
|
+
*
|
|
3211
|
+
* Phase 1: opt-in. Existing commands do not auto-bracket. Hosts that
|
|
3212
|
+
* want single-undo paste call `startAction("paste")` →
|
|
3213
|
+
* `insertFragment(fragment)` → `endAction()`.
|
|
3214
|
+
*/
|
|
3215
|
+
startAction(name: string): void;
|
|
3216
|
+
/** R.5.a — close one level of action bracketing. Unbalanced calls are no-ops. */
|
|
3217
|
+
endAction(): void;
|
|
3218
|
+
/** R.5.a — `true` when the runtime is inside one or more action brackets. */
|
|
3219
|
+
isInAction(): boolean;
|
|
3063
3220
|
toggleBulletedList(): void;
|
|
3064
3221
|
toggleNumberedList(): void;
|
|
3065
3222
|
toggleBold(): void;
|
|
@@ -522,6 +522,7 @@ function getInlineLength(node: InlineNode): number {
|
|
|
522
522
|
case "shape":
|
|
523
523
|
case "wordart":
|
|
524
524
|
case "vml_shape":
|
|
525
|
+
case "drawing_frame":
|
|
525
526
|
return 1;
|
|
526
527
|
}
|
|
527
528
|
}
|
|
@@ -581,6 +582,8 @@ function getInlineDisplayText(node: InlineNode): string {
|
|
|
581
582
|
return node.text;
|
|
582
583
|
case "vml_shape":
|
|
583
584
|
return node.text ?? "[VML Shape]";
|
|
585
|
+
case "drawing_frame":
|
|
586
|
+
return node.content.type === "picture" ? "[Image]" : "[Drawing]";
|
|
584
587
|
}
|
|
585
588
|
}
|
|
586
589
|
|
|
@@ -89,7 +89,8 @@ import {
|
|
|
89
89
|
setHeaderFooterLinkAtSectionIndex,
|
|
90
90
|
} from "./section-layout-commands.ts";
|
|
91
91
|
import { insertPageBreak, insertTable } from "./text-commands.ts";
|
|
92
|
-
import {
|
|
92
|
+
import { editLayer } from "../../runtime/edit-ops/index.ts";
|
|
93
|
+
import { structureLayer } from "../../runtime/structure-ops/index.ts";
|
|
93
94
|
import type { TableSelectionDescriptor } from "../../runtime/table-commands.ts";
|
|
94
95
|
|
|
95
96
|
export type ContentChildrenPatch =
|
|
@@ -575,8 +576,10 @@ export function executeEditorCommand(
|
|
|
575
576
|
? applySuggestingInsert(state, command.text, context)
|
|
576
577
|
: undefined;
|
|
577
578
|
if (suggestingResult) return suggestingResult;
|
|
579
|
+
// R.2 — dispatch via the named EditLayer entry point so the seam is the
|
|
580
|
+
// single site where R.5.a/b hooks will attach.
|
|
578
581
|
return applyTextCommand(state, context.timestamp, (document, selection) =>
|
|
579
|
-
|
|
582
|
+
editLayer.applyTextInsert(document, selection, command.text, context, command.formatting),
|
|
580
583
|
);
|
|
581
584
|
}
|
|
582
585
|
case "text.delete-backward": {
|
|
@@ -585,7 +588,7 @@ export function executeEditorCommand(
|
|
|
585
588
|
: undefined;
|
|
586
589
|
if (suggestingResult) return suggestingResult;
|
|
587
590
|
return applyTextCommand(state, context.timestamp, (document, selection) =>
|
|
588
|
-
|
|
591
|
+
editLayer.applyDeleteBackward(document, selection, context),
|
|
589
592
|
);
|
|
590
593
|
}
|
|
591
594
|
case "text.delete-forward": {
|
|
@@ -594,7 +597,7 @@ export function executeEditorCommand(
|
|
|
594
597
|
: undefined;
|
|
595
598
|
if (suggestingResult) return suggestingResult;
|
|
596
599
|
return applyTextCommand(state, context.timestamp, (document, selection) =>
|
|
597
|
-
|
|
600
|
+
editLayer.applyDeleteForward(document, selection, context),
|
|
598
601
|
);
|
|
599
602
|
}
|
|
600
603
|
case "text.insert-tab": {
|
|
@@ -603,7 +606,7 @@ export function executeEditorCommand(
|
|
|
603
606
|
: undefined;
|
|
604
607
|
if (suggestingResult) return suggestingResult;
|
|
605
608
|
return applyTextCommand(state, context.timestamp, (document, selection) =>
|
|
606
|
-
|
|
609
|
+
editLayer.applyInsertTab(document, selection, context),
|
|
607
610
|
);
|
|
608
611
|
}
|
|
609
612
|
case "text.outdent-tab": {
|
|
@@ -632,7 +635,7 @@ export function executeEditorCommand(
|
|
|
632
635
|
: undefined;
|
|
633
636
|
if (suggestingResult) return suggestingResult;
|
|
634
637
|
return applyTextCommand(state, context.timestamp, (document, selection) =>
|
|
635
|
-
|
|
638
|
+
editLayer.applyInsertHardBreak(document, selection, context),
|
|
636
639
|
);
|
|
637
640
|
}
|
|
638
641
|
case "paragraph.split":
|
|
@@ -641,15 +644,18 @@ export function executeEditorCommand(
|
|
|
641
644
|
if (suggestingResult) return suggestingResult;
|
|
642
645
|
}
|
|
643
646
|
return applyTextCommand(state, context.timestamp, (document, selection) =>
|
|
644
|
-
|
|
647
|
+
editLayer.applySplitParagraph(document, selection, context),
|
|
645
648
|
);
|
|
646
649
|
case "fragment.insert": {
|
|
647
|
-
// I2 Tier B Slice 1 — route through the
|
|
650
|
+
// I2 Tier B Slice 1 + R.3 — route through the StructureLayer seam. No
|
|
648
651
|
// suggesting-mode branch yet; fragment insertion always lands as a direct
|
|
649
652
|
// edit. Future slices will gate behind track-changes when a fixture needs it.
|
|
650
|
-
const result = applyFragmentInsert(
|
|
651
|
-
|
|
652
|
-
|
|
653
|
+
const result = structureLayer.applyFragmentInsert(
|
|
654
|
+
state.document,
|
|
655
|
+
state.selection,
|
|
656
|
+
command.fragment,
|
|
657
|
+
{ timestamp: context.timestamp },
|
|
658
|
+
);
|
|
653
659
|
return buildDocumentReplaceTransaction(state, context, result);
|
|
654
660
|
}
|
|
655
661
|
case "runtime.set-read-only":
|
|
@@ -31,7 +31,24 @@ export interface DetachedAnchor {
|
|
|
31
31
|
reason: "deleted" | "invalidatedByStructureChange" | "importAmbiguity";
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Internal representation of an anchor projection — uses `DocRange` so
|
|
36
|
+
* mapping helpers compose ranges independently of assoc semantics. The
|
|
37
|
+
* public-facing shape lives at `src/api/public-types.ts` (same simple name
|
|
38
|
+
* `EditorAnchorProjection`) and is flat (`{ kind: "range", from, to, assoc }`).
|
|
39
|
+
* Conversion between the two goes through `src/core/selection/anchor-conversion.ts`.
|
|
40
|
+
*/
|
|
41
|
+
export type InternalEditorAnchorProjection = RangeAnchor | NodeAnchor | DetachedAnchor;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated X3 Phase 5 — prefer `InternalEditorAnchorProjection` to avoid
|
|
45
|
+
* name-collision with the public `EditorAnchorProjection` from
|
|
46
|
+
* `src/api/public-types.ts`. Internal call-sites have migrated (via
|
|
47
|
+
* `import type { EditorAnchorProjection as InternalEditorAnchorProjection }`
|
|
48
|
+
* aliasing in `document-runtime.ts`). This alias stays for one release cycle
|
|
49
|
+
* so third-party internal consumers don't break. Remove in v2.1+.
|
|
50
|
+
*/
|
|
51
|
+
export type EditorAnchorProjection = InternalEditorAnchorProjection;
|
|
35
52
|
|
|
36
53
|
export interface MappingStep {
|
|
37
54
|
from: Position;
|
|
@@ -104,17 +104,22 @@ export function rangeStaysWithinSingleParagraph(
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
107
|
+
* Width of the paragraph-to-table proximity window used by
|
|
108
|
+
* `snapCommentAnchorAwayFromTable` to decide when to nudge endpoints to
|
|
109
|
+
* paragraph boundaries. Originally the I8 rejection threshold before Lane 3b
|
|
110
|
+
* §O8 shipped; now used only by the (opt-in) snap helper for hosts that
|
|
111
|
+
* prefer clean anchors.
|
|
112
112
|
*/
|
|
113
113
|
export const TABLE_ADJACENT_WINDOW = 1;
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
/**
|
|
116
|
+
* I8 guard removal (post-O8) — the `comment_anchor_table_adjacent` rejection
|
|
117
|
+
* reason has been retired now that Lane 3b §O8 fixed the serializer's
|
|
118
|
+
* per-paragraph offset walker. The type alias remains as a deprecated union
|
|
119
|
+
* stub so existing host code that narrows on it keeps compiling; new code
|
|
120
|
+
* should simply check against `"invalid_comment_anchor"`.
|
|
121
|
+
*/
|
|
122
|
+
export type CommentAnchorRejectionReason = "invalid_comment_anchor";
|
|
118
123
|
|
|
119
124
|
export function canCreateDocxCommentAnchor(
|
|
120
125
|
content: unknown,
|
|
@@ -140,17 +145,18 @@ export function commentAnchorRejectionReason(
|
|
|
140
145
|
return "invalid_comment_anchor";
|
|
141
146
|
}
|
|
142
147
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
148
|
+
// I8 branch removed — mid-run-near-table anchors now serialize cleanly
|
|
149
|
+
// via Lane 3b §O8's `walkInlineNodeForBoundaries` fix.
|
|
147
150
|
return null;
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
+
* Snap a mid-run-near-table anchor to paragraph boundaries when a host opts
|
|
155
|
+
* into `snapToSafeBoundary`. Originally a defensive workaround for the pre-O8
|
|
156
|
+
* serializer bug; now a boundary-preference convenience for hosts that dislike
|
|
157
|
+
* mid-run comment anchors on principle. Returns `null` if the anchor cannot
|
|
158
|
+
* be rescued (e.g. crosses an opaque block); returns the input unchanged if
|
|
159
|
+
* it doesn't need snapping.
|
|
154
160
|
*/
|
|
155
161
|
export function snapCommentAnchorAwayFromTable(
|
|
156
162
|
content: unknown,
|
|
@@ -161,9 +167,14 @@ export function snapCommentAnchorAwayFromTable(
|
|
|
161
167
|
const normalized = normalizeRange(anchor.range);
|
|
162
168
|
if (normalized.from === normalized.to) return null;
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (
|
|
170
|
+
// If the anchor is already flagged invalid for other reasons (crosses an
|
|
171
|
+
// opaque block, etc.) we can't rescue it by snapping.
|
|
172
|
+
if (commentAnchorRejectionReason(content, anchor) !== null) return null;
|
|
173
|
+
|
|
174
|
+
// Detect mid-run-near-table via structural check directly (independent of
|
|
175
|
+
// rejection reason — the rejection branch is gone post-O8). If the anchor
|
|
176
|
+
// doesn't need snapping, pass it through unchanged.
|
|
177
|
+
if (!rangeLandsMidRunNearTableBoundary(content, normalized)) return anchor;
|
|
167
178
|
|
|
168
179
|
const surfaceBlocks = readSurfaceBlocks(content);
|
|
169
180
|
if (!surfaceBlocks) return null;
|