@beyondwork/docx-react-component 1.0.106 → 1.0.109
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 +19 -5
- package/src/api/geometry-overlay-rects.ts +5 -0
- package/src/api/package-version.ts +1 -1
- package/src/api/page-anchor-id.ts +5 -0
- package/src/api/public-types.ts +16 -9
- package/src/api/table-node-specs.ts +6 -0
- package/src/api/v3/_create.ts +2 -1
- package/src/api/v3/_page-anchor-id.ts +52 -0
- package/src/api/v3/_runtime-handle.ts +92 -1
- package/src/api/v3/ai/_audit-time.ts +5 -0
- package/src/api/v3/ai/_pe2-evidence.ts +38 -0
- package/src/api/v3/ai/attach.ts +7 -2
- package/src/api/v3/ai/replacement.ts +101 -18
- package/src/api/v3/ai/resolve.ts +2 -2
- package/src/api/v3/ai/review.ts +177 -3
- package/src/api/v3/index.ts +1 -0
- package/src/api/v3/runtime/collab.ts +462 -0
- package/src/api/v3/runtime/document.ts +503 -20
- package/src/api/v3/runtime/geometry.ts +97 -0
- package/src/api/v3/runtime/layout.ts +744 -0
- package/src/api/v3/runtime/perf-probe.ts +14 -0
- package/src/api/v3/runtime/viewport.ts +9 -8
- package/src/api/v3/ui/_types.ts +149 -55
- package/src/api/v3/ui/chrome-preset-model.ts +5 -5
- package/src/api/v3/ui/debug.ts +115 -2
- package/src/api/v3/ui/index.ts +13 -0
- package/src/api/v3/ui/overlays.ts +0 -8
- package/src/api/v3/ui/surface.ts +56 -0
- package/src/api/v3/ui/viewport.ts +22 -9
- package/src/core/commands/image-commands.ts +1 -0
- package/src/core/commands/index.ts +6 -0
- package/src/core/schema/text-schema.ts +43 -5
- package/src/core/selection/mapping.ts +8 -1
- package/src/core/selection/review-anchors.ts +5 -1
- package/src/core/state/text-transaction.ts +8 -2
- package/src/io/export/serialize-revisions.ts +149 -1
- package/src/io/normalize/normalize-text.ts +6 -0
- package/src/io/ooxml/parse-bookmark-references.ts +55 -0
- package/src/io/ooxml/parse-fields.ts +24 -2
- package/src/io/ooxml/parse-headers-footers.ts +38 -5
- package/src/io/ooxml/parse-main-document.ts +153 -9
- package/src/io/ooxml/parse-numbering.ts +20 -0
- package/src/io/ooxml/parse-revisions.ts +19 -8
- package/src/io/opc/package-reader.ts +98 -8
- package/src/model/anchor.ts +4 -3
- package/src/model/canonical-document.ts +220 -2
- package/src/model/canonical-hash.ts +221 -0
- package/src/model/canonical-layout-inputs.ts +245 -6
- package/src/model/layout/index.ts +1 -0
- package/src/model/layout/page-graph-types.ts +118 -1
- package/src/model/review/revision-types.ts +14 -3
- package/src/preservation/store.ts +20 -4
- package/src/review/README.md +1 -1
- package/src/review/store/revision-actions.ts +14 -2
- package/src/runtime/collab/event-types.ts +67 -1
- package/src/runtime/collab/runtime-collab-sync.ts +177 -5
- package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
- package/src/runtime/document-heading-outline.ts +147 -0
- package/src/runtime/document-navigation.ts +8 -243
- package/src/runtime/document-runtime.ts +240 -97
- package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
- package/src/runtime/formatting/layout-inputs.ts +38 -5
- package/src/runtime/formatting/numbering/geometry.ts +28 -2
- package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
- package/src/runtime/geometry/caret-geometry.ts +5 -6
- package/src/runtime/geometry/geometry-facet.ts +60 -10
- package/src/runtime/geometry/geometry-index.ts +591 -20
- package/src/runtime/geometry/geometry-types.ts +59 -0
- package/src/runtime/geometry/hit-test.ts +11 -1
- package/src/runtime/geometry/overlay-rects.ts +5 -3
- package/src/runtime/geometry/project-anchors.ts +1 -1
- package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
- package/src/runtime/layout/index.ts +6 -0
- package/src/runtime/layout/layout-engine-instance.ts +6 -1
- package/src/runtime/layout/layout-engine-version.ts +181 -16
- package/src/runtime/layout/layout-facet-types.ts +6 -0
- package/src/runtime/layout/page-graph.ts +21 -4
- package/src/runtime/layout/paginated-layout-engine.ts +139 -15
- package/src/runtime/layout/project-block-fragments.ts +265 -7
- package/src/runtime/layout/public-facet.ts +78 -24
- package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
- package/src/runtime/layout/table-row-split.ts +92 -35
- package/src/runtime/prerender/cache-envelope.ts +2 -2
- package/src/runtime/prerender/cache-key.ts +5 -4
- package/src/runtime/prerender/customxml-cache.ts +0 -1
- package/src/runtime/render/render-kernel.ts +1 -1
- package/src/runtime/revision-runtime.ts +112 -10
- package/src/runtime/scopes/_scope-dependencies.ts +1 -0
- package/src/runtime/scopes/action-validation.ts +22 -2
- package/src/runtime/scopes/capabilities.ts +316 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
- package/src/runtime/scopes/compiler-service.ts +108 -4
- package/src/runtime/scopes/content-control-evidence.ts +79 -0
- package/src/runtime/scopes/create-issue.ts +5 -5
- package/src/runtime/scopes/evidence.ts +91 -0
- package/src/runtime/scopes/formatting/apply.ts +2 -0
- package/src/runtime/scopes/geometry-evidence.ts +130 -0
- package/src/runtime/scopes/index.ts +54 -0
- package/src/runtime/scopes/issue-lifecycle.ts +224 -0
- package/src/runtime/scopes/layout-evidence.ts +374 -0
- package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
- package/src/runtime/scopes/preservation-boundary.ts +7 -1
- package/src/runtime/scopes/replacement/apply.ts +97 -34
- package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
- package/src/runtime/scopes/semantic-scope-types.ts +242 -3
- package/src/runtime/scopes/visualization.ts +28 -0
- package/src/runtime/surface-projection.ts +44 -5
- package/src/runtime/telemetry/perf-probe.ts +216 -0
- package/src/runtime/virtualized-rendering.ts +36 -1
- package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
- package/src/runtime/workflow/coordinator.ts +39 -11
- package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
- package/src/runtime/workflow/index.ts +3 -0
- package/src/runtime/workflow/overlay-lane-types.ts +58 -0
- package/src/runtime/workflow/overlay-lanes.ts +168 -10
- package/src/runtime/workflow/overlay-store.ts +2 -2
- package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
- package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
- package/src/session/_sync-legacy.ts +17 -27
- package/src/session/import/loader.ts +6 -4
- package/src/session/import/source-package-evidence.ts +186 -2
- package/src/session/index.ts +5 -6
- package/src/session/session.ts +30 -56
- package/src/session/types.ts +8 -13
- package/src/shell/session-bootstrap.ts +155 -81
- package/src/ui/WordReviewEditor.tsx +520 -12
- package/src/ui/editor-shell-view.tsx +14 -4
- package/src/ui/editor-surface-controller.tsx +5 -3
- package/src/ui/headless/selection-tool-resolver.ts +1 -2
- package/src/ui/presence-overlay-lane.ts +0 -1
- package/src/ui/ui-controller-factory.ts +7 -0
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
- package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
- package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
- package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
- package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
- package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
- package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
- package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
- package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
- package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
- package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
- package/src/ui-tailwind/debug/README.md +4 -1
- package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
- package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
- package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
- package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
- package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
- package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
- package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
- package/src/ui-tailwind/review-workspace/types.ts +26 -12
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
- package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
- package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
export interface TableRowRangeContract {
|
|
2
|
+
readonly pageIndex?: number;
|
|
3
|
+
readonly pageNumber?: number;
|
|
4
|
+
readonly rowRange: {
|
|
5
|
+
readonly from: number;
|
|
6
|
+
readonly to: number;
|
|
7
|
+
readonly totalRows: number;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TableSplitRowContinuation {
|
|
12
|
+
readonly rowIndex: number;
|
|
13
|
+
readonly fromPageIndex?: number;
|
|
14
|
+
readonly toPageIndex?: number;
|
|
15
|
+
readonly fromPageNumber?: number;
|
|
16
|
+
readonly toPageNumber?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TableSplitRowCarry {
|
|
20
|
+
readonly rowIndex: number;
|
|
21
|
+
readonly continuesFromPreviousPage: boolean;
|
|
22
|
+
readonly continuesToNextPage: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Detect Word-style row continuations from adjacent page-local row ranges.
|
|
27
|
+
*
|
|
28
|
+
* Runtime table slices were initially row-boundary-only, so adjacent ranges
|
|
29
|
+
* looked like [0, 8), [8, 10). Word can split a row across the page boundary,
|
|
30
|
+
* which appears as an intentional overlap such as [0, 8), [7, 10). This helper
|
|
31
|
+
* keeps that contract explicit for D-8 table-pagination evidence and future
|
|
32
|
+
* split-row rendering work.
|
|
33
|
+
*/
|
|
34
|
+
export function collectSplitRowContinuations(
|
|
35
|
+
ranges: readonly TableRowRangeContract[],
|
|
36
|
+
): TableSplitRowContinuation[] {
|
|
37
|
+
const continuations: TableSplitRowContinuation[] = [];
|
|
38
|
+
const seen = new Set<string>();
|
|
39
|
+
|
|
40
|
+
for (let index = 1; index < ranges.length; index += 1) {
|
|
41
|
+
const previous = ranges[index - 1]!;
|
|
42
|
+
const current = ranges[index]!;
|
|
43
|
+
const overlapFrom = Math.max(previous.rowRange.from, current.rowRange.from);
|
|
44
|
+
const overlapTo = Math.min(previous.rowRange.to, current.rowRange.to);
|
|
45
|
+
for (let rowIndex = overlapFrom; rowIndex < overlapTo; rowIndex += 1) {
|
|
46
|
+
const key = `${rowIndex}:${previous.pageIndex ?? ""}:${current.pageIndex ?? ""}`;
|
|
47
|
+
if (seen.has(key)) continue;
|
|
48
|
+
seen.add(key);
|
|
49
|
+
continuations.push({
|
|
50
|
+
rowIndex,
|
|
51
|
+
...(previous.pageIndex !== undefined ? { fromPageIndex: previous.pageIndex } : {}),
|
|
52
|
+
...(current.pageIndex !== undefined ? { toPageIndex: current.pageIndex } : {}),
|
|
53
|
+
...(previous.pageNumber !== undefined ? { fromPageNumber: previous.pageNumber } : {}),
|
|
54
|
+
...(current.pageNumber !== undefined ? { toPageNumber: current.pageNumber } : {}),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return continuations;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function collectSplitRowCarryForPage(
|
|
63
|
+
ranges: readonly TableRowRangeContract[],
|
|
64
|
+
pageRangeIndex: number,
|
|
65
|
+
): TableSplitRowCarry[] {
|
|
66
|
+
const current = ranges[pageRangeIndex];
|
|
67
|
+
if (!current) return [];
|
|
68
|
+
|
|
69
|
+
const rows = new Map<number, TableSplitRowCarry>();
|
|
70
|
+
const addRows = (
|
|
71
|
+
from: number,
|
|
72
|
+
to: number,
|
|
73
|
+
direction: "fromPrevious" | "toNext",
|
|
74
|
+
): void => {
|
|
75
|
+
for (let rowIndex = from; rowIndex < to; rowIndex += 1) {
|
|
76
|
+
const prior = rows.get(rowIndex);
|
|
77
|
+
rows.set(rowIndex, {
|
|
78
|
+
rowIndex,
|
|
79
|
+
continuesFromPreviousPage:
|
|
80
|
+
direction === "fromPrevious" || prior?.continuesFromPreviousPage === true,
|
|
81
|
+
continuesToNextPage:
|
|
82
|
+
direction === "toNext" || prior?.continuesToNextPage === true,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const previous = ranges[pageRangeIndex - 1];
|
|
88
|
+
if (previous) {
|
|
89
|
+
addRows(
|
|
90
|
+
Math.max(previous.rowRange.from, current.rowRange.from),
|
|
91
|
+
Math.min(previous.rowRange.to, current.rowRange.to),
|
|
92
|
+
"fromPrevious",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const next = ranges[pageRangeIndex + 1];
|
|
97
|
+
if (next) {
|
|
98
|
+
addRows(
|
|
99
|
+
Math.max(current.rowRange.from, next.rowRange.from),
|
|
100
|
+
Math.min(current.rowRange.to, next.rowRange.to),
|
|
101
|
+
"toNext",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return [...rows.values()].sort((a, b) => a.rowIndex - b.rowIndex);
|
|
106
|
+
}
|
|
107
|
+
|
|
@@ -51,6 +51,9 @@ import { __resolveCellWidth } from "./paginated-layout-engine.ts";
|
|
|
51
51
|
|
|
52
52
|
const MIN_ROW_HEIGHT_TWIPS = 240;
|
|
53
53
|
const TABLE_ROW_PADDING_TWIPS = 120;
|
|
54
|
+
const AUTO_ROW_CALIBRATION_MIN_RESOLVED_TWIPS = 1440;
|
|
55
|
+
const AUTO_ROW_CALIBRATION_MIN_DELTA_TWIPS = 720;
|
|
56
|
+
const AUTO_ROW_CALIBRATION_MIN_RATIO = 1.75;
|
|
54
57
|
|
|
55
58
|
export interface MeasureTableRowHeightsInput {
|
|
56
59
|
block: Extract<SurfaceBlockSnapshot, { kind: "table" }>;
|
|
@@ -58,7 +61,12 @@ export interface MeasureTableRowHeightsInput {
|
|
|
58
61
|
measurementProvider?: LayoutMeasurementProvider;
|
|
59
62
|
defaultTabInterval?: number;
|
|
60
63
|
themeFonts?: LayoutThemeFonts;
|
|
61
|
-
contentMode?: "legacy-min" | "resolved";
|
|
64
|
+
contentMode?: "legacy-min" | "resolved" | "auto-height-calibrated";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface TableRowHeightProfile {
|
|
68
|
+
readonly heights: readonly number[];
|
|
69
|
+
readonly calibratedAutoRowIndexes: readonly number[];
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
/**
|
|
@@ -74,6 +82,12 @@ export interface MeasureTableRowHeightsInput {
|
|
|
74
82
|
export function measureTableRowHeights(
|
|
75
83
|
input: MeasureTableRowHeightsInput,
|
|
76
84
|
): number[] {
|
|
85
|
+
return [...measureTableRowHeightProfile(input).heights];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function measureTableRowHeightProfile(
|
|
89
|
+
input: MeasureTableRowHeightsInput,
|
|
90
|
+
): TableRowHeightProfile {
|
|
77
91
|
const {
|
|
78
92
|
block,
|
|
79
93
|
columnWidth,
|
|
@@ -83,66 +97,109 @@ export function measureTableRowHeights(
|
|
|
83
97
|
contentMode = "legacy-min",
|
|
84
98
|
} = input;
|
|
85
99
|
const heights: number[] = [];
|
|
100
|
+
const calibratedAutoRowIndexes: number[] = [];
|
|
86
101
|
|
|
87
102
|
const totalGridTwips = block.gridColumns.reduce((sum, w) => sum + w, 0);
|
|
88
103
|
const gridScale =
|
|
89
104
|
totalGridTwips > 0 && columnWidth > 0 ? columnWidth / totalGridTwips : 1;
|
|
90
105
|
|
|
91
|
-
for (
|
|
106
|
+
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
|
|
107
|
+
const row = block.rows[rowIndex]!;
|
|
92
108
|
const explicitHeight = row.height ?? 0;
|
|
93
109
|
const heightRule = row.heightRule ?? "auto";
|
|
94
110
|
const gridBefore = row.gridBefore ?? 0;
|
|
95
111
|
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
const measureContentHeight = (mode: "legacy-min" | "resolved"): number => {
|
|
113
|
+
let contentHeight = MIN_ROW_HEIGHT_TWIPS;
|
|
114
|
+
let columnCursor = gridBefore;
|
|
98
115
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
for (const cell of row.cells) {
|
|
117
|
+
const span = Math.max(1, cell.colspan ?? 1);
|
|
118
|
+
const cellWidth = __resolveCellWidth(
|
|
119
|
+
block.gridColumns,
|
|
120
|
+
columnCursor,
|
|
121
|
+
span,
|
|
122
|
+
columnWidth,
|
|
123
|
+
gridScale,
|
|
124
|
+
);
|
|
125
|
+
columnCursor += span;
|
|
109
126
|
|
|
110
|
-
|
|
127
|
+
if (cell.verticalMerge === "continue") continue;
|
|
111
128
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
let cellContentHeight = 0;
|
|
130
|
+
for (const child of cell.content) {
|
|
131
|
+
if (child.kind === "paragraph") {
|
|
132
|
+
cellContentHeight += mode === "resolved"
|
|
133
|
+
? measureParagraphStandaloneHeight(
|
|
134
|
+
child,
|
|
135
|
+
cellWidth,
|
|
136
|
+
measurementProvider,
|
|
137
|
+
defaultTabInterval,
|
|
138
|
+
themeFonts,
|
|
139
|
+
)
|
|
140
|
+
: MIN_ROW_HEIGHT_TWIPS;
|
|
141
|
+
} else {
|
|
142
|
+
cellContentHeight += MIN_ROW_HEIGHT_TWIPS;
|
|
143
|
+
}
|
|
126
144
|
}
|
|
145
|
+
contentHeight = Math.max(contentHeight, cellContentHeight + TABLE_ROW_PADDING_TWIPS);
|
|
127
146
|
}
|
|
128
|
-
|
|
129
|
-
|
|
147
|
+
|
|
148
|
+
return contentHeight;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const legacyContentHeight = measureContentHeight("legacy-min");
|
|
152
|
+
const resolvedContentHeight = contentMode === "legacy-min"
|
|
153
|
+
? legacyContentHeight
|
|
154
|
+
: measureContentHeight("resolved");
|
|
130
155
|
|
|
131
156
|
let rowHeight: number;
|
|
132
157
|
if (heightRule === "exact" && explicitHeight > 0) {
|
|
133
158
|
rowHeight = explicitHeight;
|
|
134
159
|
} else if (heightRule === "atLeast" && explicitHeight > 0) {
|
|
135
|
-
rowHeight = Math.max(explicitHeight,
|
|
160
|
+
rowHeight = Math.max(explicitHeight, resolvedContentHeight);
|
|
136
161
|
} else if (explicitHeight > 0) {
|
|
137
|
-
|
|
162
|
+
const legacyRowHeight = Math.max(explicitHeight, legacyContentHeight);
|
|
163
|
+
const resolvedRowHeight = Math.max(explicitHeight, resolvedContentHeight);
|
|
164
|
+
const shouldCalibrate =
|
|
165
|
+
contentMode === "auto-height-calibrated" &&
|
|
166
|
+
shouldUseResolvedAutoRowHeight(row, legacyRowHeight, resolvedRowHeight);
|
|
167
|
+
if (shouldCalibrate) calibratedAutoRowIndexes.push(rowIndex);
|
|
168
|
+
rowHeight = contentMode === "resolved" || shouldCalibrate
|
|
169
|
+
? resolvedRowHeight
|
|
170
|
+
: legacyRowHeight;
|
|
138
171
|
} else {
|
|
139
|
-
|
|
172
|
+
const shouldCalibrate =
|
|
173
|
+
contentMode === "auto-height-calibrated" &&
|
|
174
|
+
shouldUseResolvedAutoRowHeight(row, legacyContentHeight, resolvedContentHeight);
|
|
175
|
+
if (shouldCalibrate) calibratedAutoRowIndexes.push(rowIndex);
|
|
176
|
+
rowHeight = contentMode === "resolved" || shouldCalibrate
|
|
177
|
+
? resolvedContentHeight
|
|
178
|
+
: legacyContentHeight;
|
|
140
179
|
}
|
|
141
180
|
|
|
142
181
|
heights.push(Math.max(MIN_ROW_HEIGHT_TWIPS, rowHeight));
|
|
143
182
|
}
|
|
144
183
|
|
|
145
|
-
return
|
|
184
|
+
return {
|
|
185
|
+
heights: Object.freeze(heights),
|
|
186
|
+
calibratedAutoRowIndexes: Object.freeze(calibratedAutoRowIndexes),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function shouldUseResolvedAutoRowHeight(
|
|
191
|
+
row: Extract<SurfaceBlockSnapshot, { kind: "table" }>["rows"][number],
|
|
192
|
+
legacyHeight: number,
|
|
193
|
+
resolvedHeight: number,
|
|
194
|
+
): boolean {
|
|
195
|
+
if ((row.heightRule ?? "auto") === "exact") return false;
|
|
196
|
+
if (row.cantSplit === true) return false;
|
|
197
|
+
const delta = resolvedHeight - legacyHeight;
|
|
198
|
+
return (
|
|
199
|
+
resolvedHeight >= AUTO_ROW_CALIBRATION_MIN_RESOLVED_TWIPS &&
|
|
200
|
+
delta >= AUTO_ROW_CALIBRATION_MIN_DELTA_TWIPS &&
|
|
201
|
+
resolvedHeight / Math.max(1, legacyHeight) >= AUTO_ROW_CALIBRATION_MIN_RATIO
|
|
202
|
+
);
|
|
146
203
|
}
|
|
147
204
|
|
|
148
205
|
/**
|
|
@@ -17,8 +17,8 @@ import type { RuntimePageGraph } from "../../model/layout/runtime-page-graph-typ
|
|
|
17
17
|
* it, and the warm-path loader that rehydrates it.
|
|
18
18
|
*
|
|
19
19
|
* Load-time invariants checked by consumers before trusting the envelope:
|
|
20
|
-
* - `schemaVersion === LAYCACHE_SCHEMA_VERSION`
|
|
21
|
-
* - `engineVersion === LAYOUT_ENGINE_VERSION`
|
|
20
|
+
* - `schemaVersion === LAYCACHE_SCHEMA_VERSION` — cache shape matches
|
|
21
|
+
* - `engineVersion === LAYOUT_ENGINE_VERSION` — layout output matches
|
|
22
22
|
* - `graph.revision === 0` — canonical marker
|
|
23
23
|
*
|
|
24
24
|
* The envelope MUST be structured-clone-safe because IndexedDB and Plan B's
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
* metric source. "empirical-backend" in
|
|
15
15
|
* Plan A; a real font-derived string after
|
|
16
16
|
* Phase 8.
|
|
17
|
-
* 3. engineVersion — LAYOUT_ENGINE_VERSION from
|
|
18
|
-
* layout/layout-engine-version.ts.
|
|
19
|
-
*
|
|
17
|
+
* 3. engineVersion — LAYOUT_ENGINE_VERSION from
|
|
18
|
+
* src/runtime/layout/layout-engine-version.ts.
|
|
19
|
+
* Bumped when layout output or cache-key
|
|
20
|
+
* semantics change for the same input.
|
|
20
21
|
* 4. schemaVersion — LAYCACHE_SCHEMA_VERSION for envelope
|
|
21
|
-
* format.
|
|
22
|
+
* format and cached payload shape.
|
|
22
23
|
* 5. canonicalDocumentHash — (Plan B, schema v2) sha256 of sorted-keys
|
|
23
24
|
* JSON of the CanonicalDocument. Catches
|
|
24
25
|
* non-structural mutations (styles,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { MAIN_STORY_TARGET } from "../../core/selection/mapping.ts";
|
|
17
|
-
import { recordPerfSample } from "
|
|
17
|
+
import { recordPerfSample } from "../telemetry/perf-probe.ts";
|
|
18
18
|
import { storyTargetKey } from "../story-targeting.ts";
|
|
19
19
|
import type { EditorStoryTarget } from "../../api/public-types";
|
|
20
20
|
import type {
|
|
@@ -1,15 +1,25 @@
|
|
|
1
|
+
import type { EditorStoryTarget } from "../api/public-types.ts";
|
|
1
2
|
import type { CanonicalDocumentEnvelope } from "../core/state/editor-state.ts";
|
|
2
3
|
import {
|
|
3
4
|
getReviewCommandIntent,
|
|
4
5
|
isSingleRevisionReviewCommand,
|
|
5
6
|
type ReviewCommand,
|
|
6
7
|
} from "../core/commands/review-commands.ts";
|
|
7
|
-
import
|
|
8
|
+
import {
|
|
9
|
+
MAIN_STORY_TARGET,
|
|
10
|
+
storyTargetsEqual,
|
|
11
|
+
type TransactionMapping,
|
|
12
|
+
} from "../core/selection/mapping.ts";
|
|
8
13
|
import {
|
|
9
14
|
applyRevisionAction,
|
|
15
|
+
type ApplyRevisionActionResult,
|
|
10
16
|
type RevisionActionOutcome,
|
|
11
17
|
} from "../review/store/revision-actions.ts";
|
|
12
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
createRevisionStore,
|
|
20
|
+
type RevisionStore,
|
|
21
|
+
} from "../review/store/revision-store.ts";
|
|
22
|
+
import { getStoryBlocks, replaceStoryBlocks } from "./story-targeting.ts";
|
|
13
23
|
|
|
14
24
|
export interface RevisionRuntimeState {
|
|
15
25
|
document: CanonicalDocumentEnvelope;
|
|
@@ -30,7 +40,12 @@ export interface RevisionRuntimeCommandEffects {
|
|
|
30
40
|
|
|
31
41
|
export interface RevisionRuntimeCommandResult extends RevisionRuntimeState {
|
|
32
42
|
outcomes: RevisionActionOutcome[];
|
|
33
|
-
mappings: Array<{
|
|
43
|
+
mappings: Array<{
|
|
44
|
+
revisionId: string;
|
|
45
|
+
mapping: TransactionMapping;
|
|
46
|
+
steps: number;
|
|
47
|
+
storyTarget: EditorStoryTarget;
|
|
48
|
+
}>;
|
|
34
49
|
effects: RevisionRuntimeCommandEffects;
|
|
35
50
|
}
|
|
36
51
|
|
|
@@ -44,30 +59,31 @@ export function applyRevisionRuntimeCommand(
|
|
|
44
59
|
const revisionIds = expandLinkedMovePartners(rawRevisionIds, options.state.store);
|
|
45
60
|
|
|
46
61
|
const outcomes: RevisionActionOutcome[] = [];
|
|
47
|
-
const mappings:
|
|
62
|
+
const mappings: RevisionRuntimeCommandResult["mappings"] = [];
|
|
48
63
|
const appliedRevisionIds: string[] = [];
|
|
49
64
|
const detachedRevisionIds = new Set<string>();
|
|
50
65
|
|
|
51
66
|
let state = options.state;
|
|
52
67
|
|
|
53
68
|
for (const revisionId of revisionIds) {
|
|
69
|
+
const revision = state.store.revisions[revisionId];
|
|
70
|
+
const storyTarget = getRevisionStoryTarget(revision);
|
|
71
|
+
const scopedState = createStoryScopedRevisionState(state, storyTarget);
|
|
54
72
|
const result = applyRevisionAction({
|
|
55
|
-
document:
|
|
56
|
-
store:
|
|
73
|
+
document: scopedState.document,
|
|
74
|
+
store: scopedState.store,
|
|
57
75
|
revisionId,
|
|
58
76
|
intent: getReviewCommandIntent(options.command),
|
|
59
77
|
timestamp: options.timestamp,
|
|
60
78
|
});
|
|
61
79
|
|
|
62
|
-
state =
|
|
63
|
-
document: result.document,
|
|
64
|
-
store: result.store,
|
|
65
|
-
};
|
|
80
|
+
state = mergeStoryScopedRevisionResult(state, storyTarget, scopedState, result);
|
|
66
81
|
outcomes.push(result.outcome);
|
|
67
82
|
mappings.push({
|
|
68
83
|
revisionId,
|
|
69
84
|
mapping: result.mapping,
|
|
70
85
|
steps: result.mapping.steps.length,
|
|
86
|
+
storyTarget,
|
|
71
87
|
});
|
|
72
88
|
|
|
73
89
|
if (result.outcome.kind === "applied") {
|
|
@@ -94,6 +110,92 @@ export function applyRevisionRuntimeCommand(
|
|
|
94
110
|
};
|
|
95
111
|
}
|
|
96
112
|
|
|
113
|
+
interface StoryScopedRevisionState extends RevisionRuntimeState {
|
|
114
|
+
storyRevisionIds: readonly string[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function createStoryScopedRevisionState(
|
|
118
|
+
state: RevisionRuntimeState,
|
|
119
|
+
storyTarget: EditorStoryTarget,
|
|
120
|
+
): StoryScopedRevisionState {
|
|
121
|
+
if (storyTargetsEqual(storyTarget, MAIN_STORY_TARGET)) {
|
|
122
|
+
return {
|
|
123
|
+
...state,
|
|
124
|
+
storyRevisionIds: Object.keys(state.store.revisions),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const storyRevisionIds = Object.entries(state.store.revisions)
|
|
129
|
+
.filter(([, revision]) =>
|
|
130
|
+
storyTargetsEqual(getRevisionStoryTarget(revision), storyTarget)
|
|
131
|
+
)
|
|
132
|
+
.map(([revisionId]) => revisionId);
|
|
133
|
+
const storyRevisions = Object.fromEntries(
|
|
134
|
+
storyRevisionIds.map((revisionId) => [
|
|
135
|
+
revisionId,
|
|
136
|
+
state.store.revisions[revisionId]!,
|
|
137
|
+
]),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
document: {
|
|
142
|
+
...state.document,
|
|
143
|
+
content: {
|
|
144
|
+
...state.document.content,
|
|
145
|
+
children: [...getStoryBlocks(state.document, storyTarget)],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
store: createRevisionStore(storyRevisions),
|
|
149
|
+
storyRevisionIds,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function mergeStoryScopedRevisionResult(
|
|
154
|
+
previousState: RevisionRuntimeState,
|
|
155
|
+
storyTarget: EditorStoryTarget,
|
|
156
|
+
scopedState: StoryScopedRevisionState,
|
|
157
|
+
result: ApplyRevisionActionResult,
|
|
158
|
+
): RevisionRuntimeState {
|
|
159
|
+
if (storyTargetsEqual(storyTarget, MAIN_STORY_TARGET)) {
|
|
160
|
+
return {
|
|
161
|
+
document: result.document,
|
|
162
|
+
store: result.store,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const nextStore = createRevisionStore({
|
|
167
|
+
...previousState.store.revisions,
|
|
168
|
+
...Object.fromEntries(
|
|
169
|
+
scopedState.storyRevisionIds
|
|
170
|
+
.filter((revisionId) => result.store.revisions[revisionId])
|
|
171
|
+
.map((revisionId) => [
|
|
172
|
+
revisionId,
|
|
173
|
+
result.store.revisions[revisionId]!,
|
|
174
|
+
]),
|
|
175
|
+
),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
document: replaceStoryBlocks(
|
|
180
|
+
{
|
|
181
|
+
...previousState.document,
|
|
182
|
+
updatedAt: result.document.updatedAt,
|
|
183
|
+
},
|
|
184
|
+
storyTarget,
|
|
185
|
+
result.document.content.children,
|
|
186
|
+
),
|
|
187
|
+
store: nextStore,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function getRevisionStoryTarget(
|
|
192
|
+
revision: RevisionStore["revisions"][string] | undefined,
|
|
193
|
+
): EditorStoryTarget {
|
|
194
|
+
return revision?.metadata.storyTarget
|
|
195
|
+
? { ...revision.metadata.storyTarget }
|
|
196
|
+
: MAIN_STORY_TARGET;
|
|
197
|
+
}
|
|
198
|
+
|
|
97
199
|
function expandLinkedMovePartners(
|
|
98
200
|
revisionIds: readonly string[],
|
|
99
201
|
store: RevisionStore,
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
import { resolveScopeRange } from "./scope-range.ts";
|
|
64
64
|
import type {
|
|
65
65
|
ReplacementScope,
|
|
66
|
+
ScopeActionPosture,
|
|
66
67
|
ScopeActionOperationKind,
|
|
67
68
|
SemanticScope,
|
|
68
69
|
ValidationApproval,
|
|
@@ -144,8 +145,6 @@ function inferActionId(
|
|
|
144
145
|
case "insert-before":
|
|
145
146
|
case "insert-after":
|
|
146
147
|
return "generate_text";
|
|
147
|
-
case "split":
|
|
148
|
-
return "rewrite_paragraph";
|
|
149
148
|
case "annotate":
|
|
150
149
|
return "suggest_comment_response";
|
|
151
150
|
}
|
|
@@ -296,6 +295,17 @@ function collectPreservationVerdict(
|
|
|
296
295
|
): void {
|
|
297
296
|
const { document, scope, positionMap } = inputs;
|
|
298
297
|
if (inputs.skipPreservation === true) return;
|
|
298
|
+
// Insert-before / insert-after lower to collapsed insertions at the
|
|
299
|
+
// effective scope edge. They do not replace or delete the scope's
|
|
300
|
+
// current contents, so preserve-only payloads and nested markers
|
|
301
|
+
// inside the scope are not at risk in the same way they are for
|
|
302
|
+
// `replace`.
|
|
303
|
+
if (
|
|
304
|
+
inputs.operation === "insert-before" ||
|
|
305
|
+
inputs.operation === "insert-after"
|
|
306
|
+
) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
299
309
|
if (!document) return;
|
|
300
310
|
const pm = positionMap ?? buildScopePositionMap(document);
|
|
301
311
|
const range = inputs.enumeratedScope
|
|
@@ -397,6 +407,15 @@ function collectPolicyVerdict(
|
|
|
397
407
|
return undefined;
|
|
398
408
|
}
|
|
399
409
|
|
|
410
|
+
function validationPosture(
|
|
411
|
+
blockedReasons: readonly string[],
|
|
412
|
+
warnings: readonly ValidationIssue[],
|
|
413
|
+
): ScopeActionPosture {
|
|
414
|
+
if (blockedReasons.length > 0) return "hard-refusal";
|
|
415
|
+
if (warnings.length > 0) return "warn-and-proceed";
|
|
416
|
+
return "supported";
|
|
417
|
+
}
|
|
418
|
+
|
|
400
419
|
/**
|
|
401
420
|
* Compose a single validation verdict for a proposed scope replacement.
|
|
402
421
|
* Synchronous, deterministic, free of side effects. Safe to call in hot
|
|
@@ -420,6 +439,7 @@ export function composeScopeValidation(
|
|
|
420
439
|
const safe = blockedReasons.length === 0;
|
|
421
440
|
return {
|
|
422
441
|
safe,
|
|
442
|
+
posture: validationPosture(blockedReasons, warnings),
|
|
423
443
|
blockedReasons: Object.freeze([...blockedReasons]),
|
|
424
444
|
warnings: Object.freeze([...warnings]),
|
|
425
445
|
...(approval ? { approval } : {}),
|