@beyondwork/docx-react-component 1.0.37 → 1.0.38
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 +1 -1
- package/src/api/public-types.ts +319 -1
- package/src/core/commands/section-layout-commands.ts +58 -0
- package/src/core/commands/table-grid.ts +431 -0
- package/src/core/commands/table-structure-commands.ts +815 -55
- package/src/io/export/serialize-main-document.ts +2 -11
- package/src/io/export/serialize-numbering.ts +1 -2
- package/src/io/export/serialize-tables.ts +74 -0
- package/src/io/export/table-properties-xml.ts +139 -4
- package/src/io/normalize/normalize-text.ts +15 -0
- package/src/io/ooxml/parse-footnotes.ts +60 -0
- package/src/io/ooxml/parse-headers-footers.ts +60 -0
- package/src/io/ooxml/parse-main-document.ts +137 -0
- package/src/io/ooxml/parse-tables.ts +249 -0
- package/src/model/canonical-document.ts +34 -0
- package/src/runtime/document-layout.ts +4 -2
- package/src/runtime/document-navigation.ts +1 -1
- package/src/runtime/document-runtime.ts +114 -0
- package/src/runtime/layout/default-page-format.ts +96 -0
- package/src/runtime/layout/index.ts +45 -0
- package/src/runtime/layout/inert-layout-facet.ts +14 -0
- package/src/runtime/layout/layout-engine-instance.ts +33 -23
- package/src/runtime/layout/margin-preset-catalog.ts +178 -0
- package/src/runtime/layout/page-format-catalog.ts +233 -0
- package/src/runtime/layout/page-graph.ts +19 -0
- package/src/runtime/layout/paginated-layout-engine.ts +142 -9
- package/src/runtime/layout/project-block-fragments.ts +91 -0
- package/src/runtime/layout/public-facet.ts +709 -16
- package/src/runtime/layout/table-render-plan.ts +229 -0
- package/src/runtime/render/block-fragment-projection.ts +35 -0
- package/src/runtime/render/decoration-resolver.ts +189 -0
- package/src/runtime/render/index.ts +57 -0
- package/src/runtime/render/pending-op-delta-reader.ts +129 -0
- package/src/runtime/render/render-frame-types.ts +317 -0
- package/src/runtime/render/render-kernel.ts +755 -0
- package/src/runtime/view-state.ts +67 -0
- package/src/runtime/workflow-markup.ts +1 -5
- package/src/runtime/workflow-rail-segments.ts +280 -0
- package/src/ui/WordReviewEditor.tsx +84 -15
- package/src/ui/editor-shell-view.tsx +6 -0
- package/src/ui/headless/chrome-registry.ts +280 -14
- package/src/ui/headless/scoped-chrome-policy.ts +20 -1
- package/src/ui/headless/selection-tool-types.ts +10 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +23 -2
- package/src/ui-tailwind/chrome/role-action-sets.ts +74 -0
- package/src/ui-tailwind/chrome/tw-detach-handle.tsx +147 -0
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +163 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +57 -92
- package/src/ui-tailwind/chrome/tw-selection-tool-placement.ts +149 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +15 -4
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +274 -138
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +90 -0
- package/src/ui-tailwind/chrome-overlay/index.ts +22 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +86 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +178 -0
- package/src/ui-tailwind/chrome-overlay/tw-workspace-view-switcher.tsx +95 -0
- package/src/ui-tailwind/editor-surface/fast-text-edit-lane.ts +4 -0
- package/src/ui-tailwind/editor-surface/local-edit-session-state.ts +11 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +7 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +12 -1
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +22 -12
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +3 -0
- package/src/ui-tailwind/index.ts +33 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +2 -2
- package/src/ui-tailwind/review/tw-rail-card.tsx +150 -0
- package/src/ui-tailwind/review/tw-review-rail-footer.tsx +52 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +166 -11
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +108 -0
- package/src/ui-tailwind/theme/editor-theme.css +498 -163
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +559 -0
- package/src/ui-tailwind/toolbar/tw-scope-posture-menu.tsx +182 -0
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +162 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +69 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +136 -1
|
@@ -10,6 +10,8 @@ import type {
|
|
|
10
10
|
TableBorders,
|
|
11
11
|
TableCellBorders,
|
|
12
12
|
TableCellMargins,
|
|
13
|
+
TableFloatingProperties,
|
|
14
|
+
TableIndent,
|
|
13
15
|
TableLook,
|
|
14
16
|
TableWidth,
|
|
15
17
|
SectionProperties,
|
|
@@ -35,16 +37,31 @@ import { classifyFieldInstruction } from "./parse-fields.ts";
|
|
|
35
37
|
import { resolveHighlightColor } from "./highlight-colors.ts";
|
|
36
38
|
import {
|
|
37
39
|
readCellBorders as readSharedCellBorders,
|
|
40
|
+
readCellCnfStyle as readSharedCellCnfStyle,
|
|
41
|
+
readCellFitText as readSharedCellFitText,
|
|
42
|
+
readCellMargins as readSharedCellMargins,
|
|
43
|
+
readCellNoWrap as readSharedCellNoWrap,
|
|
38
44
|
readCellShading as readSharedCellShading,
|
|
45
|
+
readCellTextDirection as readSharedCellTextDirection,
|
|
39
46
|
readCellVerticalAlign as readSharedCellVerticalAlign,
|
|
40
47
|
readCellWidth as readSharedCellWidth,
|
|
41
48
|
readGridColumns as readSharedGridColumns,
|
|
49
|
+
readRowCantSplit as readSharedRowCantSplit,
|
|
50
|
+
readRowCnfStyle as readSharedRowCnfStyle,
|
|
42
51
|
readRowHeight as readSharedRowHeight,
|
|
43
52
|
readRowHeightRule as readSharedRowHeightRule,
|
|
53
|
+
readRowHorizontalAlignment as readSharedRowHorizontalAlignment,
|
|
44
54
|
readRowIsHeader as readSharedRowIsHeader,
|
|
45
55
|
readTableAlignment as readSharedTableAlignment,
|
|
56
|
+
readTableBidiVisual as readSharedTableBidiVisual,
|
|
46
57
|
readTableBorders as readSharedTableBorders,
|
|
58
|
+
readTableCaption as readSharedTableCaption,
|
|
47
59
|
readTableCellMargins as readSharedTableCellMargins,
|
|
60
|
+
readTableCellSpacing as readSharedTableCellSpacing,
|
|
61
|
+
readTableDescription as readSharedTableDescription,
|
|
62
|
+
readTableFloating as readSharedTableFloating,
|
|
63
|
+
readTableIndent as readSharedTableIndent,
|
|
64
|
+
readTableLayoutMode as readSharedTableLayoutMode,
|
|
48
65
|
readTableLook as readSharedTableLook,
|
|
49
66
|
readTableStyleId as readSharedTableStyleId,
|
|
50
67
|
readTableWidth as readSharedTableWidth,
|
|
@@ -332,6 +349,13 @@ export interface ParsedTableBlockNode {
|
|
|
332
349
|
alignment?: "left" | "center" | "right";
|
|
333
350
|
borders?: TableBorders;
|
|
334
351
|
cellMargins?: TableCellMargins;
|
|
352
|
+
indent?: TableIndent;
|
|
353
|
+
layoutMode?: "fixed" | "autofit";
|
|
354
|
+
cellSpacing?: TableWidth;
|
|
355
|
+
caption?: string;
|
|
356
|
+
description?: string;
|
|
357
|
+
bidiVisual?: boolean;
|
|
358
|
+
floating?: TableFloatingProperties;
|
|
335
359
|
rawXml: string;
|
|
336
360
|
}
|
|
337
361
|
|
|
@@ -346,6 +370,9 @@ export interface ParsedTableRowNode {
|
|
|
346
370
|
height?: number;
|
|
347
371
|
heightRule?: "auto" | "atLeast" | "exact";
|
|
348
372
|
isHeader?: boolean;
|
|
373
|
+
cantSplit?: boolean;
|
|
374
|
+
horizontalAlignment?: "left" | "center" | "right";
|
|
375
|
+
cnfStyle?: string;
|
|
349
376
|
rawXml: string;
|
|
350
377
|
}
|
|
351
378
|
|
|
@@ -359,6 +386,11 @@ export interface ParsedTableCellNode {
|
|
|
359
386
|
borders?: TableCellBorders;
|
|
360
387
|
shading?: CellShading;
|
|
361
388
|
verticalAlign?: "top" | "center" | "bottom";
|
|
389
|
+
textDirection?: "lrTb" | "tbRl" | "btLr";
|
|
390
|
+
noWrap?: boolean;
|
|
391
|
+
fitText?: boolean;
|
|
392
|
+
margins?: TableCellMargins;
|
|
393
|
+
cnfStyle?: string;
|
|
362
394
|
rawXml: string;
|
|
363
395
|
}
|
|
364
396
|
|
|
@@ -857,6 +889,13 @@ function parseTableElement(
|
|
|
857
889
|
let alignment: ParsedTableBlockNode["alignment"];
|
|
858
890
|
let borders: TableBorders | undefined;
|
|
859
891
|
let cellMargins: TableCellMargins | undefined;
|
|
892
|
+
let indent: TableIndent | undefined;
|
|
893
|
+
let layoutMode: ParsedTableBlockNode["layoutMode"];
|
|
894
|
+
let cellSpacing: TableWidth | undefined;
|
|
895
|
+
let caption: string | undefined;
|
|
896
|
+
let description: string | undefined;
|
|
897
|
+
let bidiVisual: boolean | undefined;
|
|
898
|
+
let floating: TableFloatingProperties | undefined;
|
|
860
899
|
const rows: ParsedTableRowNode[] = [];
|
|
861
900
|
|
|
862
901
|
for (const child of node.children) {
|
|
@@ -871,6 +910,13 @@ function parseTableElement(
|
|
|
871
910
|
alignment = readTableAlignment(child);
|
|
872
911
|
borders = readTableBorders(child);
|
|
873
912
|
cellMargins = readTableCellMargins(child);
|
|
913
|
+
indent = readTableIndent(child);
|
|
914
|
+
layoutMode = readTableLayoutMode(child);
|
|
915
|
+
cellSpacing = readTableCellSpacing(child);
|
|
916
|
+
caption = readTableCaption(child);
|
|
917
|
+
description = readTableDescription(child);
|
|
918
|
+
bidiVisual = readTableBidiVisual(child);
|
|
919
|
+
floating = readTableFloating(child);
|
|
874
920
|
break;
|
|
875
921
|
}
|
|
876
922
|
case "tblGrid": {
|
|
@@ -895,6 +941,13 @@ function parseTableElement(
|
|
|
895
941
|
...(alignment ? { alignment } : {}),
|
|
896
942
|
...(borders ? { borders } : {}),
|
|
897
943
|
...(cellMargins ? { cellMargins } : {}),
|
|
944
|
+
...(indent ? { indent } : {}),
|
|
945
|
+
...(layoutMode ? { layoutMode } : {}),
|
|
946
|
+
...(cellSpacing ? { cellSpacing } : {}),
|
|
947
|
+
...(caption !== undefined ? { caption } : {}),
|
|
948
|
+
...(description !== undefined ? { description } : {}),
|
|
949
|
+
...(bidiVisual !== undefined ? { bidiVisual } : {}),
|
|
950
|
+
...(floating ? { floating } : {}),
|
|
898
951
|
rawXml: sourceXml.slice(node.start, node.end),
|
|
899
952
|
};
|
|
900
953
|
}
|
|
@@ -915,6 +968,9 @@ function parseTableRowElement(
|
|
|
915
968
|
let height: number | undefined;
|
|
916
969
|
let heightRule: ParsedTableRowNode["heightRule"];
|
|
917
970
|
let isHeader: boolean | undefined;
|
|
971
|
+
let cantSplit: boolean | undefined;
|
|
972
|
+
let horizontalAlignment: ParsedTableRowNode["horizontalAlignment"];
|
|
973
|
+
let cnfStyle: string | undefined;
|
|
918
974
|
const cells: ParsedTableCellNode[] = [];
|
|
919
975
|
|
|
920
976
|
for (const child of node.children) {
|
|
@@ -930,6 +986,9 @@ function parseTableRowElement(
|
|
|
930
986
|
height = readRowHeight(child);
|
|
931
987
|
heightRule = readRowHeightRule(child);
|
|
932
988
|
isHeader = readRowIsHeader(child);
|
|
989
|
+
cantSplit = readRowCantSplit(child);
|
|
990
|
+
horizontalAlignment = readRowHorizontalAlignment(child);
|
|
991
|
+
cnfStyle = readRowCnfStyle(child);
|
|
933
992
|
break;
|
|
934
993
|
case "tc":
|
|
935
994
|
cells.push(parseTableCellElement(child, sourceXml, relationshipMap, relationships, mediaParts, sourcePartPath));
|
|
@@ -947,6 +1006,9 @@ function parseTableRowElement(
|
|
|
947
1006
|
...(height !== undefined ? { height } : {}),
|
|
948
1007
|
...(heightRule ? { heightRule } : {}),
|
|
949
1008
|
...(isHeader !== undefined ? { isHeader } : {}),
|
|
1009
|
+
...(cantSplit !== undefined ? { cantSplit } : {}),
|
|
1010
|
+
...(horizontalAlignment ? { horizontalAlignment } : {}),
|
|
1011
|
+
...(cnfStyle ? { cnfStyle } : {}),
|
|
950
1012
|
cells,
|
|
951
1013
|
rawXml: sourceXml.slice(node.start, node.end),
|
|
952
1014
|
};
|
|
@@ -967,6 +1029,11 @@ function parseTableCellElement(
|
|
|
967
1029
|
let borders: TableCellBorders | undefined;
|
|
968
1030
|
let shading: CellShading | undefined;
|
|
969
1031
|
let verticalAlign: ParsedTableCellNode["verticalAlign"];
|
|
1032
|
+
let textDirection: ParsedTableCellNode["textDirection"];
|
|
1033
|
+
let noWrap: boolean | undefined;
|
|
1034
|
+
let fitText: boolean | undefined;
|
|
1035
|
+
let margins: TableCellMargins | undefined;
|
|
1036
|
+
let cnfStyle: string | undefined;
|
|
970
1037
|
const children: ParsedBlockNode[] = [];
|
|
971
1038
|
|
|
972
1039
|
for (const child of node.children) {
|
|
@@ -981,6 +1048,11 @@ function parseTableCellElement(
|
|
|
981
1048
|
borders = readCellBorders(child);
|
|
982
1049
|
shading = readCellShading(child);
|
|
983
1050
|
verticalAlign = readCellVerticalAlign(child);
|
|
1051
|
+
textDirection = readCellTextDirection(child);
|
|
1052
|
+
noWrap = readCellNoWrap(child);
|
|
1053
|
+
fitText = readCellFitText(child);
|
|
1054
|
+
margins = readCellMargins(child);
|
|
1055
|
+
cnfStyle = readCellCnfStyle(child);
|
|
984
1056
|
break;
|
|
985
1057
|
}
|
|
986
1058
|
default: {
|
|
@@ -1001,6 +1073,11 @@ function parseTableCellElement(
|
|
|
1001
1073
|
...(borders ? { borders } : {}),
|
|
1002
1074
|
...(shading ? { shading } : {}),
|
|
1003
1075
|
...(verticalAlign ? { verticalAlign } : {}),
|
|
1076
|
+
...(textDirection ? { textDirection } : {}),
|
|
1077
|
+
...(noWrap !== undefined ? { noWrap } : {}),
|
|
1078
|
+
...(fitText !== undefined ? { fitText } : {}),
|
|
1079
|
+
...(margins ? { margins } : {}),
|
|
1080
|
+
...(cnfStyle ? { cnfStyle } : {}),
|
|
1004
1081
|
rawXml: sourceXml.slice(node.start, node.end),
|
|
1005
1082
|
};
|
|
1006
1083
|
}
|
|
@@ -1274,6 +1351,66 @@ function readCellVerticalAlign(node: XmlElementNode): ParsedTableCellNode["verti
|
|
|
1274
1351
|
return readSharedCellVerticalAlign(node);
|
|
1275
1352
|
}
|
|
1276
1353
|
|
|
1354
|
+
function readTableIndent(node: XmlElementNode): TableIndent | undefined {
|
|
1355
|
+
return readSharedTableIndent(node);
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
function readTableLayoutMode(node: XmlElementNode): ParsedTableBlockNode["layoutMode"] {
|
|
1359
|
+
return readSharedTableLayoutMode(node);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
function readTableCellSpacing(node: XmlElementNode): TableWidth | undefined {
|
|
1363
|
+
return readSharedTableCellSpacing(node);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
function readTableCaption(node: XmlElementNode): string | undefined {
|
|
1367
|
+
return readSharedTableCaption(node);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
function readTableDescription(node: XmlElementNode): string | undefined {
|
|
1371
|
+
return readSharedTableDescription(node);
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
function readTableBidiVisual(node: XmlElementNode): boolean | undefined {
|
|
1375
|
+
return readSharedTableBidiVisual(node);
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
function readTableFloating(node: XmlElementNode): TableFloatingProperties | undefined {
|
|
1379
|
+
return readSharedTableFloating(node);
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
function readRowCantSplit(node: XmlElementNode): boolean | undefined {
|
|
1383
|
+
return readSharedRowCantSplit(node);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
function readRowHorizontalAlignment(node: XmlElementNode): ParsedTableRowNode["horizontalAlignment"] {
|
|
1387
|
+
return readSharedRowHorizontalAlignment(node);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
function readRowCnfStyle(node: XmlElementNode): string | undefined {
|
|
1391
|
+
return readSharedRowCnfStyle(node);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
function readCellTextDirection(node: XmlElementNode): ParsedTableCellNode["textDirection"] {
|
|
1395
|
+
return readSharedCellTextDirection(node);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
function readCellNoWrap(node: XmlElementNode): boolean | undefined {
|
|
1399
|
+
return readSharedCellNoWrap(node);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
function readCellFitText(node: XmlElementNode): boolean | undefined {
|
|
1403
|
+
return readSharedCellFitText(node);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
function readCellMargins(node: XmlElementNode): TableCellMargins | undefined {
|
|
1407
|
+
return readSharedCellMargins(node);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
function readCellCnfStyle(node: XmlElementNode): string | undefined {
|
|
1411
|
+
return readSharedCellCnfStyle(node);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1277
1414
|
/**
|
|
1278
1415
|
* Check if a table's raw XML contains content that cannot safely round-trip
|
|
1279
1416
|
* through the parsed table path yet. This includes:
|
|
@@ -69,6 +69,25 @@ export interface ParsedTableLook {
|
|
|
69
69
|
noVBand?: boolean;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
export interface ParsedTableIndent {
|
|
73
|
+
value: number;
|
|
74
|
+
type: "dxa" | "auto" | "pct" | "nil";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ParsedTableFloating {
|
|
78
|
+
horizontalAnchor?: "margin" | "page" | "text";
|
|
79
|
+
verticalAnchor?: "margin" | "page" | "text";
|
|
80
|
+
horizontalAlign?: "left" | "center" | "right" | "inside" | "outside";
|
|
81
|
+
horizontalOffset?: number;
|
|
82
|
+
verticalAlign?: "top" | "center" | "bottom" | "inside" | "outside";
|
|
83
|
+
verticalOffset?: number;
|
|
84
|
+
leftFromText?: number;
|
|
85
|
+
rightFromText?: number;
|
|
86
|
+
topFromText?: number;
|
|
87
|
+
bottomFromText?: number;
|
|
88
|
+
overlap?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
72
91
|
export interface ParsedTableDocument {
|
|
73
92
|
tables: ParsedTable[];
|
|
74
93
|
}
|
|
@@ -85,6 +104,13 @@ export interface ParsedTable {
|
|
|
85
104
|
borders?: ParsedTableBorders;
|
|
86
105
|
cellMargins?: ParsedCellMargins;
|
|
87
106
|
tblLook?: ParsedTableLook;
|
|
107
|
+
indent?: ParsedTableIndent;
|
|
108
|
+
layoutMode?: "fixed" | "autofit";
|
|
109
|
+
cellSpacing?: ParsedTableWidth;
|
|
110
|
+
caption?: string;
|
|
111
|
+
description?: string;
|
|
112
|
+
bidiVisual?: boolean;
|
|
113
|
+
floating?: ParsedTableFloating;
|
|
88
114
|
}
|
|
89
115
|
|
|
90
116
|
export interface ParsedTableRow {
|
|
@@ -94,6 +120,9 @@ export interface ParsedTableRow {
|
|
|
94
120
|
height?: number;
|
|
95
121
|
heightRule?: "auto" | "atLeast" | "exact";
|
|
96
122
|
isHeader?: boolean;
|
|
123
|
+
cantSplit?: boolean;
|
|
124
|
+
horizontalAlignment?: "left" | "center" | "right";
|
|
125
|
+
cnfStyle?: string;
|
|
97
126
|
}
|
|
98
127
|
|
|
99
128
|
export interface ParsedTableCell {
|
|
@@ -106,6 +135,11 @@ export interface ParsedTableCell {
|
|
|
106
135
|
borders?: ParsedTableCellBorders;
|
|
107
136
|
shading?: ParsedCellShading;
|
|
108
137
|
verticalAlign?: "top" | "center" | "bottom";
|
|
138
|
+
textDirection?: "lrTb" | "tbRl" | "btLr";
|
|
139
|
+
noWrap?: boolean;
|
|
140
|
+
fitText?: boolean;
|
|
141
|
+
margins?: ParsedCellMargins;
|
|
142
|
+
cnfStyle?: string;
|
|
109
143
|
}
|
|
110
144
|
|
|
111
145
|
export function parseTablesFromDocumentXml(xml: string): ParsedTableDocument {
|
|
@@ -133,6 +167,13 @@ function parseTable(node: XmlElementNode, sourceXml: string): ParsedTable {
|
|
|
133
167
|
const borders = propertiesNode ? readTableBorders(propertiesNode) : undefined;
|
|
134
168
|
const cellMargins = propertiesNode ? readTableCellMargins(propertiesNode) : undefined;
|
|
135
169
|
const tblLook = propertiesNode ? readTableLook(propertiesNode) : undefined;
|
|
170
|
+
const indent = propertiesNode ? readTableIndent(propertiesNode) : undefined;
|
|
171
|
+
const layoutMode = propertiesNode ? readTableLayoutMode(propertiesNode) : undefined;
|
|
172
|
+
const cellSpacing = propertiesNode ? readTableCellSpacing(propertiesNode) : undefined;
|
|
173
|
+
const caption = propertiesNode ? readTableCaption(propertiesNode) : undefined;
|
|
174
|
+
const description = propertiesNode ? readTableDescription(propertiesNode) : undefined;
|
|
175
|
+
const bidiVisual = propertiesNode ? readTableBidiVisual(propertiesNode) : undefined;
|
|
176
|
+
const floating = propertiesNode ? readTableFloating(propertiesNode) : undefined;
|
|
136
177
|
|
|
137
178
|
return {
|
|
138
179
|
type: "table",
|
|
@@ -146,6 +187,13 @@ function parseTable(node: XmlElementNode, sourceXml: string): ParsedTable {
|
|
|
146
187
|
...(borders ? { borders } : {}),
|
|
147
188
|
...(cellMargins ? { cellMargins } : {}),
|
|
148
189
|
...(tblLook ? { tblLook } : {}),
|
|
190
|
+
...(indent ? { indent } : {}),
|
|
191
|
+
...(layoutMode ? { layoutMode } : {}),
|
|
192
|
+
...(cellSpacing ? { cellSpacing } : {}),
|
|
193
|
+
...(caption !== undefined ? { caption } : {}),
|
|
194
|
+
...(description !== undefined ? { description } : {}),
|
|
195
|
+
...(bidiVisual !== undefined ? { bidiVisual } : {}),
|
|
196
|
+
...(floating ? { floating } : {}),
|
|
149
197
|
};
|
|
150
198
|
}
|
|
151
199
|
|
|
@@ -154,6 +202,9 @@ function parseRow(node: XmlElementNode, sourceXml: string): ParsedTableRow {
|
|
|
154
202
|
const height = propertiesNode ? readRowHeight(propertiesNode) : undefined;
|
|
155
203
|
const heightRule = propertiesNode ? readRowHeightRule(propertiesNode) : undefined;
|
|
156
204
|
const isHeader = propertiesNode ? readRowIsHeader(propertiesNode) : undefined;
|
|
205
|
+
const cantSplit = propertiesNode ? readRowCantSplit(propertiesNode) : undefined;
|
|
206
|
+
const horizontalAlignment = propertiesNode ? readRowHorizontalAlignment(propertiesNode) : undefined;
|
|
207
|
+
const cnfStyle = propertiesNode ? readRowCnfStyle(propertiesNode) : undefined;
|
|
157
208
|
|
|
158
209
|
return {
|
|
159
210
|
...(propertiesNode ? { propertiesXml: sourceXml.slice(propertiesNode.start, propertiesNode.end) } : {}),
|
|
@@ -164,6 +215,9 @@ function parseRow(node: XmlElementNode, sourceXml: string): ParsedTableRow {
|
|
|
164
215
|
...(height !== undefined ? { height } : {}),
|
|
165
216
|
...(heightRule ? { heightRule } : {}),
|
|
166
217
|
...(isHeader !== undefined ? { isHeader } : {}),
|
|
218
|
+
...(cantSplit !== undefined ? { cantSplit } : {}),
|
|
219
|
+
...(horizontalAlignment ? { horizontalAlignment } : {}),
|
|
220
|
+
...(cnfStyle ? { cnfStyle } : {}),
|
|
167
221
|
};
|
|
168
222
|
}
|
|
169
223
|
|
|
@@ -179,6 +233,11 @@ function parseCell(node: XmlElementNode, sourceXml: string): ParsedTableCell {
|
|
|
179
233
|
const borders = propertiesNode ? readCellBorders(propertiesNode) : undefined;
|
|
180
234
|
const shading = propertiesNode ? readCellShading(propertiesNode) : undefined;
|
|
181
235
|
const verticalAlign = propertiesNode ? readCellVerticalAlign(propertiesNode) : undefined;
|
|
236
|
+
const textDirection = propertiesNode ? readCellTextDirection(propertiesNode) : undefined;
|
|
237
|
+
const noWrap = propertiesNode ? readCellNoWrap(propertiesNode) : undefined;
|
|
238
|
+
const fitText = propertiesNode ? readCellFitText(propertiesNode) : undefined;
|
|
239
|
+
const margins = propertiesNode ? readCellMargins(propertiesNode) : undefined;
|
|
240
|
+
const cnfStyle = propertiesNode ? readCellCnfStyle(propertiesNode) : undefined;
|
|
182
241
|
|
|
183
242
|
return {
|
|
184
243
|
...(propertiesNode ? { propertiesXml: sourceXml.slice(propertiesNode.start, propertiesNode.end) } : {}),
|
|
@@ -190,6 +249,11 @@ function parseCell(node: XmlElementNode, sourceXml: string): ParsedTableCell {
|
|
|
190
249
|
...(borders ? { borders } : {}),
|
|
191
250
|
...(shading ? { shading } : {}),
|
|
192
251
|
...(verticalAlign ? { verticalAlign } : {}),
|
|
252
|
+
...(textDirection ? { textDirection } : {}),
|
|
253
|
+
...(noWrap !== undefined ? { noWrap } : {}),
|
|
254
|
+
...(fitText !== undefined ? { fitText } : {}),
|
|
255
|
+
...(margins ? { margins } : {}),
|
|
256
|
+
...(cnfStyle ? { cnfStyle } : {}),
|
|
193
257
|
};
|
|
194
258
|
}
|
|
195
259
|
|
|
@@ -606,6 +670,191 @@ export function readRowIsHeader(propertiesNode: XmlElementNode): boolean | undef
|
|
|
606
670
|
return val !== "false" && val !== "0";
|
|
607
671
|
}
|
|
608
672
|
|
|
673
|
+
export function readTableIndent(propertiesNode: XmlElementNode): ParsedTableIndent | undefined {
|
|
674
|
+
const indentNode = findFirstChild(propertiesNode, "tblInd");
|
|
675
|
+
if (!indentNode) return undefined;
|
|
676
|
+
const valueRaw = indentNode.attributes["w:w"] ?? indentNode.attributes.w;
|
|
677
|
+
const value = valueRaw !== undefined ? Number.parseInt(valueRaw, 10) : 0;
|
|
678
|
+
if (!Number.isFinite(value)) return undefined;
|
|
679
|
+
const rawType = (indentNode.attributes["w:type"] ?? indentNode.attributes.type ?? "dxa").toLowerCase();
|
|
680
|
+
const type: ParsedTableIndent["type"] =
|
|
681
|
+
rawType === "auto" ? "auto" : rawType === "pct" ? "pct" : rawType === "nil" ? "nil" : "dxa";
|
|
682
|
+
return { value, type };
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export function readTableLayoutMode(propertiesNode: XmlElementNode): "fixed" | "autofit" | undefined {
|
|
686
|
+
const layoutNode = findFirstChild(propertiesNode, "tblLayout");
|
|
687
|
+
if (!layoutNode) return undefined;
|
|
688
|
+
const raw = (layoutNode.attributes["w:type"] ?? layoutNode.attributes.type ?? "").toLowerCase();
|
|
689
|
+
if (raw === "fixed") return "fixed";
|
|
690
|
+
if (raw === "autofit") return "autofit";
|
|
691
|
+
return undefined;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export function readTableCellSpacing(propertiesNode: XmlElementNode): ParsedTableWidth | undefined {
|
|
695
|
+
const spacingNode = findFirstChild(propertiesNode, "tblCellSpacing");
|
|
696
|
+
if (!spacingNode) return undefined;
|
|
697
|
+
const valueRaw = spacingNode.attributes["w:w"] ?? spacingNode.attributes.w;
|
|
698
|
+
const value = valueRaw !== undefined ? Number.parseInt(valueRaw, 10) : 0;
|
|
699
|
+
if (!Number.isFinite(value)) return undefined;
|
|
700
|
+
const rawType = (spacingNode.attributes["w:type"] ?? spacingNode.attributes.type ?? "dxa").toLowerCase();
|
|
701
|
+
const type: ParsedTableWidth["type"] =
|
|
702
|
+
rawType === "auto" ? "auto" : rawType === "pct" ? "pct" : rawType === "nil" ? "nil" : "dxa";
|
|
703
|
+
return { value, type };
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
export function readTableCaption(propertiesNode: XmlElementNode): string | undefined {
|
|
707
|
+
const captionNode = findFirstChild(propertiesNode, "tblCaption");
|
|
708
|
+
if (!captionNode) return undefined;
|
|
709
|
+
return captionNode.attributes["w:val"] ?? captionNode.attributes.val;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export function readTableDescription(propertiesNode: XmlElementNode): string | undefined {
|
|
713
|
+
const descriptionNode = findFirstChild(propertiesNode, "tblDescription");
|
|
714
|
+
if (!descriptionNode) return undefined;
|
|
715
|
+
return descriptionNode.attributes["w:val"] ?? descriptionNode.attributes.val;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
export function readTableBidiVisual(propertiesNode: XmlElementNode): boolean | undefined {
|
|
719
|
+
const bidiNode = findFirstChild(propertiesNode, "bidiVisual");
|
|
720
|
+
if (!bidiNode) return undefined;
|
|
721
|
+
const val = bidiNode.attributes["w:val"] ?? bidiNode.attributes.val;
|
|
722
|
+
return val !== "false" && val !== "0" && val !== "off";
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
export function readTableFloating(propertiesNode: XmlElementNode): ParsedTableFloating | undefined {
|
|
726
|
+
const tblpPrNode = findFirstChild(propertiesNode, "tblpPr");
|
|
727
|
+
const overlapNode = findFirstChild(propertiesNode, "tblOverlap");
|
|
728
|
+
if (!tblpPrNode && !overlapNode) return undefined;
|
|
729
|
+
|
|
730
|
+
const floating: ParsedTableFloating = {};
|
|
731
|
+
|
|
732
|
+
if (tblpPrNode) {
|
|
733
|
+
const attr = (name: string): string | undefined =>
|
|
734
|
+
tblpPrNode.attributes[`w:${name}`] ?? tblpPrNode.attributes[name];
|
|
735
|
+
const num = (raw: string | undefined): number | undefined => {
|
|
736
|
+
if (raw === undefined) return undefined;
|
|
737
|
+
const parsed = Number.parseInt(raw, 10);
|
|
738
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
739
|
+
};
|
|
740
|
+
const anchor = (raw: string | undefined): ParsedTableFloating["horizontalAnchor"] | undefined => {
|
|
741
|
+
if (raw === "margin" || raw === "page" || raw === "text") return raw;
|
|
742
|
+
return undefined;
|
|
743
|
+
};
|
|
744
|
+
const hAlign = (raw: string | undefined): ParsedTableFloating["horizontalAlign"] | undefined => {
|
|
745
|
+
if (raw === "left" || raw === "center" || raw === "right" || raw === "inside" || raw === "outside") return raw;
|
|
746
|
+
return undefined;
|
|
747
|
+
};
|
|
748
|
+
const vAlign = (raw: string | undefined): ParsedTableFloating["verticalAlign"] | undefined => {
|
|
749
|
+
if (raw === "top" || raw === "center" || raw === "bottom" || raw === "inside" || raw === "outside") return raw;
|
|
750
|
+
return undefined;
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
const hAnc = anchor(attr("horzAnchor"));
|
|
754
|
+
if (hAnc) floating.horizontalAnchor = hAnc;
|
|
755
|
+
const vAnc = anchor(attr("vertAnchor"));
|
|
756
|
+
if (vAnc) floating.verticalAnchor = vAnc;
|
|
757
|
+
const hA = hAlign(attr("tblpXSpec"));
|
|
758
|
+
if (hA) floating.horizontalAlign = hA;
|
|
759
|
+
const hOff = num(attr("tblpX"));
|
|
760
|
+
if (hOff !== undefined) floating.horizontalOffset = hOff;
|
|
761
|
+
const vA = vAlign(attr("tblpYSpec"));
|
|
762
|
+
if (vA) floating.verticalAlign = vA;
|
|
763
|
+
const vOff = num(attr("tblpY"));
|
|
764
|
+
if (vOff !== undefined) floating.verticalOffset = vOff;
|
|
765
|
+
const left = num(attr("leftFromText"));
|
|
766
|
+
if (left !== undefined) floating.leftFromText = left;
|
|
767
|
+
const right = num(attr("rightFromText"));
|
|
768
|
+
if (right !== undefined) floating.rightFromText = right;
|
|
769
|
+
const top = num(attr("topFromText"));
|
|
770
|
+
if (top !== undefined) floating.topFromText = top;
|
|
771
|
+
const bottom = num(attr("bottomFromText"));
|
|
772
|
+
if (bottom !== undefined) floating.bottomFromText = bottom;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (overlapNode) {
|
|
776
|
+
const val = (overlapNode.attributes["w:val"] ?? overlapNode.attributes.val ?? "overlap").toLowerCase();
|
|
777
|
+
floating.overlap = val === "overlap";
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return Object.keys(floating).length > 0 ? floating : undefined;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export function readRowCantSplit(propertiesNode: XmlElementNode): boolean | undefined {
|
|
784
|
+
const cantSplitNode = findFirstChild(propertiesNode, "cantSplit");
|
|
785
|
+
if (!cantSplitNode) return undefined;
|
|
786
|
+
const val = cantSplitNode.attributes["w:val"] ?? cantSplitNode.attributes.val;
|
|
787
|
+
return val !== "false" && val !== "0" && val !== "off";
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
export function readRowHorizontalAlignment(propertiesNode: XmlElementNode): "left" | "center" | "right" | undefined {
|
|
791
|
+
const jcNode = findFirstChild(propertiesNode, "jc");
|
|
792
|
+
if (!jcNode) return undefined;
|
|
793
|
+
const val = jcNode.attributes["w:val"] ?? jcNode.attributes.val;
|
|
794
|
+
if (val === "left" || val === "center" || val === "right") return val;
|
|
795
|
+
return undefined;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
export function readRowCnfStyle(propertiesNode: XmlElementNode): string | undefined {
|
|
799
|
+
const cnfNode = findFirstChild(propertiesNode, "cnfStyle");
|
|
800
|
+
if (!cnfNode) return undefined;
|
|
801
|
+
return cnfNode.attributes["w:val"] ?? cnfNode.attributes.val;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
export function readCellTextDirection(propertiesNode: XmlElementNode): "lrTb" | "tbRl" | "btLr" | undefined {
|
|
805
|
+
const dirNode = findFirstChild(propertiesNode, "textDirection");
|
|
806
|
+
if (!dirNode) return undefined;
|
|
807
|
+
const val = dirNode.attributes["w:val"] ?? dirNode.attributes.val;
|
|
808
|
+
if (val === "lrTb" || val === "tbRl" || val === "btLr") return val;
|
|
809
|
+
return undefined;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
export function readCellNoWrap(propertiesNode: XmlElementNode): boolean | undefined {
|
|
813
|
+
const noWrapNode = findFirstChild(propertiesNode, "noWrap");
|
|
814
|
+
if (!noWrapNode) return undefined;
|
|
815
|
+
const val = noWrapNode.attributes["w:val"] ?? noWrapNode.attributes.val;
|
|
816
|
+
return val !== "false" && val !== "0" && val !== "off";
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export function readCellFitText(propertiesNode: XmlElementNode): boolean | undefined {
|
|
820
|
+
const fitNode = findFirstChild(propertiesNode, "tcFitText");
|
|
821
|
+
if (!fitNode) return undefined;
|
|
822
|
+
const val = fitNode.attributes["w:val"] ?? fitNode.attributes.val;
|
|
823
|
+
return val !== "false" && val !== "0" && val !== "off";
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export function readCellMargins(propertiesNode: XmlElementNode): ParsedCellMargins | undefined {
|
|
827
|
+
const marginsNode = findFirstChild(propertiesNode, "tcMar");
|
|
828
|
+
if (!marginsNode) return undefined;
|
|
829
|
+
const readSide = (name: string): number | undefined => {
|
|
830
|
+
const sideNode = findFirstChild(marginsNode, name);
|
|
831
|
+
if (!sideNode) return undefined;
|
|
832
|
+
const raw = sideNode.attributes["w:w"] ?? sideNode.attributes.w;
|
|
833
|
+
if (raw === undefined) return undefined;
|
|
834
|
+
const parsed = Number.parseInt(raw, 10);
|
|
835
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
836
|
+
};
|
|
837
|
+
const top = readSide("top");
|
|
838
|
+
const bottom = readSide("bottom");
|
|
839
|
+
const left = readSide("start") ?? readSide("left");
|
|
840
|
+
const right = readSide("end") ?? readSide("right");
|
|
841
|
+
if (top === undefined && bottom === undefined && left === undefined && right === undefined) {
|
|
842
|
+
return undefined;
|
|
843
|
+
}
|
|
844
|
+
return {
|
|
845
|
+
...(top !== undefined ? { top } : {}),
|
|
846
|
+
...(bottom !== undefined ? { bottom } : {}),
|
|
847
|
+
...(left !== undefined ? { left } : {}),
|
|
848
|
+
...(right !== undefined ? { right } : {}),
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export function readCellCnfStyle(propertiesNode: XmlElementNode): string | undefined {
|
|
853
|
+
const cnfNode = findFirstChild(propertiesNode, "cnfStyle");
|
|
854
|
+
if (!cnfNode) return undefined;
|
|
855
|
+
return cnfNode.attributes["w:val"] ?? cnfNode.attributes.val;
|
|
856
|
+
}
|
|
857
|
+
|
|
609
858
|
function parseBorderSpec(child: XmlElementNode): ParsedBorderSpec | undefined {
|
|
610
859
|
const value = child.attributes["w:val"] ?? child.attributes.val;
|
|
611
860
|
const sizeRaw = child.attributes["w:sz"] ?? child.attributes.sz;
|
|
@@ -416,6 +416,25 @@ export interface TableWidth {
|
|
|
416
416
|
type: "dxa" | "auto" | "pct" | "nil";
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
+
export interface TableIndent {
|
|
420
|
+
value: number;
|
|
421
|
+
type: "dxa" | "auto" | "pct" | "nil";
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export interface TableFloatingProperties {
|
|
425
|
+
horizontalAnchor?: "margin" | "page" | "text";
|
|
426
|
+
verticalAnchor?: "margin" | "page" | "text";
|
|
427
|
+
horizontalAlign?: "left" | "center" | "right" | "inside" | "outside";
|
|
428
|
+
horizontalOffset?: number;
|
|
429
|
+
verticalAlign?: "top" | "center" | "bottom" | "inside" | "outside";
|
|
430
|
+
verticalOffset?: number;
|
|
431
|
+
leftFromText?: number;
|
|
432
|
+
rightFromText?: number;
|
|
433
|
+
topFromText?: number;
|
|
434
|
+
bottomFromText?: number;
|
|
435
|
+
overlap?: boolean;
|
|
436
|
+
}
|
|
437
|
+
|
|
419
438
|
export interface CellShading {
|
|
420
439
|
fill?: string;
|
|
421
440
|
color?: string;
|
|
@@ -481,6 +500,13 @@ export interface TableNode {
|
|
|
481
500
|
borders?: TableBorders;
|
|
482
501
|
cellMargins?: TableCellMargins;
|
|
483
502
|
tblLook?: TableLook;
|
|
503
|
+
indent?: TableIndent;
|
|
504
|
+
layoutMode?: "fixed" | "autofit";
|
|
505
|
+
cellSpacing?: TableWidth;
|
|
506
|
+
caption?: string;
|
|
507
|
+
description?: string;
|
|
508
|
+
bidiVisual?: boolean;
|
|
509
|
+
floating?: TableFloatingProperties;
|
|
484
510
|
}
|
|
485
511
|
|
|
486
512
|
export interface TableRowNode {
|
|
@@ -494,6 +520,9 @@ export interface TableRowNode {
|
|
|
494
520
|
height?: number;
|
|
495
521
|
heightRule?: "auto" | "atLeast" | "exact";
|
|
496
522
|
isHeader?: boolean;
|
|
523
|
+
cantSplit?: boolean;
|
|
524
|
+
horizontalAlignment?: "left" | "center" | "right";
|
|
525
|
+
cnfStyle?: string;
|
|
497
526
|
}
|
|
498
527
|
|
|
499
528
|
export interface TableCellNode {
|
|
@@ -506,6 +535,11 @@ export interface TableCellNode {
|
|
|
506
535
|
borders?: TableCellBorders;
|
|
507
536
|
shading?: CellShading;
|
|
508
537
|
verticalAlign?: "top" | "center" | "bottom";
|
|
538
|
+
textDirection?: "lrTb" | "tbRl" | "btLr";
|
|
539
|
+
noWrap?: boolean;
|
|
540
|
+
fitText?: boolean;
|
|
541
|
+
margins?: TableCellMargins;
|
|
542
|
+
cnfStyle?: string;
|
|
509
543
|
}
|
|
510
544
|
|
|
511
545
|
export interface SdtCheckboxState {
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
SubPartsCatalog,
|
|
16
16
|
} from "../model/canonical-document.ts";
|
|
17
17
|
import { createEditorSurfaceSnapshot } from "./surface-projection.ts";
|
|
18
|
+
import { resolveDefaultPageSizeTwips } from "./layout/default-page-format.ts";
|
|
18
19
|
import {
|
|
19
20
|
resolveSectionVariants,
|
|
20
21
|
sectionSupportsStoryTarget,
|
|
@@ -88,9 +89,10 @@ export function buildPageLayoutSnapshot(
|
|
|
88
89
|
properties: SectionProperties | undefined,
|
|
89
90
|
subParts: SubPartsCatalog | undefined,
|
|
90
91
|
): PageLayoutSnapshot {
|
|
92
|
+
const defaultSize = resolveDefaultPageSizeTwips();
|
|
91
93
|
const pageSize = properties?.pageSize ?? {
|
|
92
|
-
width:
|
|
93
|
-
height:
|
|
94
|
+
width: defaultSize.widthTwips,
|
|
95
|
+
height: defaultSize.heightTwips,
|
|
94
96
|
orientation: "portrait" as const,
|
|
95
97
|
};
|
|
96
98
|
const margins = properties?.pageMargins ?? {
|
|
@@ -206,7 +206,7 @@ function headingLevelFromStyleId(styleId?: string): number | null {
|
|
|
206
206
|
return null;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
function buildHeadingOutline(
|
|
209
|
+
export function buildHeadingOutline(
|
|
210
210
|
document: CanonicalDocumentEnvelope,
|
|
211
211
|
mainSurface: EditorSurfaceSnapshot,
|
|
212
212
|
sections: ResolvedDocumentSection[],
|