@beyondwork/docx-react-component 1.0.47 → 1.0.48
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 +115 -1
- package/src/compare/diff-engine.ts +4 -0
- package/src/core/commands/add-scope.ts +257 -0
- package/src/core/commands/formatting-commands.ts +2 -0
- package/src/core/schema/text-schema.ts +95 -1
- package/src/core/state/text-transaction.ts +17 -5
- package/src/io/chart-preview-resolver.ts +27 -0
- package/src/io/docx-session.ts +226 -38
- package/src/io/export/serialize-main-document.ts +37 -0
- package/src/io/export/serialize-settings.ts +421 -0
- package/src/io/export/serialize-styles.ts +10 -0
- package/src/io/normalize/normalize-text.ts +1 -0
- package/src/io/ooxml/chart/parse-axis.ts +277 -0
- package/src/io/ooxml/chart/parse-chart-space.ts +813 -0
- package/src/io/ooxml/chart/parse-series.ts +570 -0
- package/src/io/ooxml/chart/resolve-color.ts +251 -0
- package/src/io/ooxml/chart/types.ts +420 -0
- package/src/io/ooxml/parse-block-structure.ts +99 -0
- package/src/io/ooxml/parse-complex-content.ts +87 -2
- package/src/io/ooxml/parse-main-document.ts +115 -1
- package/src/io/ooxml/parse-scope-markers.ts +184 -0
- package/src/io/ooxml/parse-settings-blueprint.ts +349 -0
- package/src/io/ooxml/parse-settings.ts +97 -1
- package/src/io/ooxml/parse-styles.ts +65 -0
- package/src/io/ooxml/parse-theme.ts +2 -127
- package/src/io/ooxml/xml-attr-helpers.ts +59 -1
- package/src/io/ooxml/xml-parser.ts +142 -0
- package/src/model/canonical-document.ts +94 -0
- package/src/model/scope-markers.ts +144 -0
- package/src/runtime/collab/base-doc-fingerprint.ts +99 -0
- package/src/runtime/collab/checkpoint-election.ts +75 -0
- package/src/runtime/collab/checkpoint-scheduler.ts +204 -0
- package/src/runtime/collab/checkpoint-store.ts +115 -0
- package/src/runtime/collab/event-types.ts +27 -0
- package/src/runtime/collab/index.ts +22 -0
- package/src/runtime/collab/remote-cursor-awareness.ts +167 -0
- package/src/runtime/collab/runtime-collab-sync.ts +279 -0
- package/src/runtime/document-runtime.ts +214 -16
- package/src/runtime/editor-surface/capabilities.ts +63 -50
- package/src/runtime/layout/layout-engine-version.ts +8 -1
- package/src/runtime/prerender/cache-envelope.ts +19 -7
- package/src/runtime/prerender/cache-key.ts +25 -14
- package/src/runtime/prerender/canonical-document-hash.ts +63 -0
- package/src/runtime/prerender/customxml-cache.ts +211 -0
- package/src/runtime/prerender/customxml-probe.ts +78 -0
- package/src/runtime/prerender/prerender-document.ts +74 -7
- package/src/runtime/scope-resolver.ts +148 -0
- package/src/runtime/scope-tag-registry.ts +10 -0
- package/src/runtime/surface-projection.ts +8 -1
- package/src/ui/WordReviewEditor.tsx +30 -0
- package/src/ui/editor-runtime-boundary.ts +6 -1
- package/src/ui/runtime-shortcut-dispatch.ts +12 -7
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse chart axis elements.
|
|
3
|
+
*
|
|
4
|
+
* OOXML defines four axis element names:
|
|
5
|
+
* c:catAx (category) c:valAx (value) c:dateAx (date) c:serAx (series)
|
|
6
|
+
*
|
|
7
|
+
* They share a common set of child elements (c:axId, c:delete, c:axPos,
|
|
8
|
+
* c:title, c:majorGridlines, c:minorGridlines, c:numFmt, c:crossAx, etc.)
|
|
9
|
+
* plus axis-specific extensions. This parser produces a discriminated
|
|
10
|
+
* `Axis` union that records which root element was seen.
|
|
11
|
+
*
|
|
12
|
+
* Note: c:delete has inverted semantics — `val="1"` means *invisible* and
|
|
13
|
+
* a missing element means *visible*. We store the normal-sense boolean
|
|
14
|
+
* on `AxisBase.visible`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
findChildOptional,
|
|
19
|
+
localName,
|
|
20
|
+
readFloatVal,
|
|
21
|
+
readIntVal,
|
|
22
|
+
readStringAttr,
|
|
23
|
+
textContent,
|
|
24
|
+
} from "../xml-attr-helpers.ts";
|
|
25
|
+
import type { XmlElementNode } from "../xml-element.ts";
|
|
26
|
+
import { parseXml } from "../xml-parser.ts";
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
Axis,
|
|
30
|
+
AxisBase,
|
|
31
|
+
CategoryAxis,
|
|
32
|
+
DateAxis,
|
|
33
|
+
SeriesAxis,
|
|
34
|
+
Title,
|
|
35
|
+
ValueAxis,
|
|
36
|
+
} from "./types.ts";
|
|
37
|
+
|
|
38
|
+
const AXIS_LOCAL_NAMES = new Set(["catAx", "valAx", "dateAx", "serAx"]);
|
|
39
|
+
|
|
40
|
+
/** Parse an axis element from raw XML. Throws if the root is not a known axis. */
|
|
41
|
+
export function parseAxis(xml: string): Axis {
|
|
42
|
+
const root = parseXml(xml);
|
|
43
|
+
let axisNode: XmlElementNode | undefined;
|
|
44
|
+
for (const child of root.children) {
|
|
45
|
+
if (child.type !== "element") continue;
|
|
46
|
+
if (AXIS_LOCAL_NAMES.has(localName(child.name))) {
|
|
47
|
+
axisNode = child;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!axisNode) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`parseAxis: expected one of catAx/valAx/dateAx/serAx at root`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return parseAxisNode(axisNode);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Dispatch to the axis-kind-specific parser based on the element name. */
|
|
60
|
+
export function parseAxisNode(node: XmlElementNode): Axis {
|
|
61
|
+
const base = parseAxisBase(node);
|
|
62
|
+
switch (localName(node.name)) {
|
|
63
|
+
case "catAx":
|
|
64
|
+
return parseCategoryAxisFields(node, base);
|
|
65
|
+
case "valAx":
|
|
66
|
+
return parseValueAxisFields(node, base);
|
|
67
|
+
case "dateAx":
|
|
68
|
+
return parseDateAxisFields(node, base);
|
|
69
|
+
case "serAx":
|
|
70
|
+
return { ...base, kind: "series" } satisfies SeriesAxis;
|
|
71
|
+
default:
|
|
72
|
+
throw new Error(`parseAxisNode: unsupported axis element ${node.name}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseAxisBase(node: XmlElementNode): AxisBase {
|
|
77
|
+
const axIdNode = findChildOptional(node, "axId");
|
|
78
|
+
const id = axIdNode ? (readStringAttr(axIdNode, "val") ?? "") : "";
|
|
79
|
+
const deleteNode = findChildOptional(node, "delete");
|
|
80
|
+
// c:delete has inverted semantics.
|
|
81
|
+
const deleteVal = deleteNode?.attributes["val"] ?? "0";
|
|
82
|
+
const visible = deleteVal !== "1" && deleteVal.toLowerCase() !== "true";
|
|
83
|
+
|
|
84
|
+
const positionRaw = findChildOptional(node, "axPos")?.attributes["val"] ?? "b";
|
|
85
|
+
const position: AxisBase["position"] =
|
|
86
|
+
positionRaw === "b" || positionRaw === "t" || positionRaw === "l" || positionRaw === "r"
|
|
87
|
+
? positionRaw
|
|
88
|
+
: "b";
|
|
89
|
+
|
|
90
|
+
const crossAxisId = findChildOptional(node, "crossAx")?.attributes["val"];
|
|
91
|
+
const crossesAt = parseCrossesAt(findChildOptional(node, "crosses"));
|
|
92
|
+
|
|
93
|
+
const base: AxisBase = {
|
|
94
|
+
id,
|
|
95
|
+
position,
|
|
96
|
+
visible,
|
|
97
|
+
};
|
|
98
|
+
if (crossAxisId !== undefined) base.crossAxisId = crossAxisId;
|
|
99
|
+
if (crossesAt !== undefined) base.crossesAt = crossesAt;
|
|
100
|
+
|
|
101
|
+
const title = parseAxisTitle(findChildOptional(node, "title"));
|
|
102
|
+
if (title) base.title = title;
|
|
103
|
+
|
|
104
|
+
if (findChildOptional(node, "majorGridlines")) base.majorGridlines = true;
|
|
105
|
+
if (findChildOptional(node, "minorGridlines")) base.minorGridlines = true;
|
|
106
|
+
|
|
107
|
+
const majorUnit = readFloatVal(findChildOptional(node, "majorUnit"));
|
|
108
|
+
if (majorUnit !== undefined) base.majorUnit = majorUnit;
|
|
109
|
+
const minorUnit = readFloatVal(findChildOptional(node, "minorUnit"));
|
|
110
|
+
if (minorUnit !== undefined) base.minorUnit = minorUnit;
|
|
111
|
+
|
|
112
|
+
const numFmtNode = findChildOptional(node, "numFmt");
|
|
113
|
+
if (numFmtNode) {
|
|
114
|
+
const formatCode = numFmtNode.attributes["formatCode"];
|
|
115
|
+
if (formatCode !== undefined) base.numberFormat = formatCode;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return base;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function parseCrossesAt(
|
|
122
|
+
crossesNode: XmlElementNode | undefined,
|
|
123
|
+
): number | "autoZero" | "max" | "min" | undefined {
|
|
124
|
+
if (!crossesNode) return undefined;
|
|
125
|
+
const val = crossesNode.attributes["val"];
|
|
126
|
+
if (val === undefined) return undefined;
|
|
127
|
+
if (val === "autoZero" || val === "max" || val === "min") return val;
|
|
128
|
+
const n = Number.parseFloat(val);
|
|
129
|
+
return Number.isFinite(n) ? n : undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function parseAxisTitle(titleNode: XmlElementNode | undefined): Title | undefined {
|
|
133
|
+
if (!titleNode) return undefined;
|
|
134
|
+
let text: string | undefined;
|
|
135
|
+
const tx = findChildOptional(titleNode, "tx");
|
|
136
|
+
if (tx) {
|
|
137
|
+
const rich = findChildOptional(tx, "rich");
|
|
138
|
+
if (rich) {
|
|
139
|
+
const texts: string[] = [];
|
|
140
|
+
const collectT = (children: XmlElementNode["children"]): void => {
|
|
141
|
+
for (const c of children) {
|
|
142
|
+
if (c.type !== "element") continue;
|
|
143
|
+
if (localName(c.name) === "t") {
|
|
144
|
+
texts.push(textContent(c));
|
|
145
|
+
} else {
|
|
146
|
+
collectT(c.children);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
collectT(rich.children);
|
|
151
|
+
text = texts.join("");
|
|
152
|
+
} else {
|
|
153
|
+
const v = findChildOptional(tx, "v");
|
|
154
|
+
if (v) text = textContent(v);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const overlay = findChildOptional(titleNode, "overlay")?.attributes["val"] === "1";
|
|
158
|
+
const title: Title = { overlay };
|
|
159
|
+
if (text) title.text = text;
|
|
160
|
+
return title;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Category axis
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
function parseCategoryAxisFields(
|
|
168
|
+
node: XmlElementNode,
|
|
169
|
+
base: AxisBase,
|
|
170
|
+
): CategoryAxis {
|
|
171
|
+
const auto = findChildOptional(node, "auto")?.attributes["val"] === "1";
|
|
172
|
+
const labelAlignRaw = findChildOptional(node, "lblAlgn")?.attributes["val"];
|
|
173
|
+
const labelAlign =
|
|
174
|
+
labelAlignRaw === "ctr" || labelAlignRaw === "l" || labelAlignRaw === "r"
|
|
175
|
+
? labelAlignRaw
|
|
176
|
+
: undefined;
|
|
177
|
+
const labelOffset = readIntVal(findChildOptional(node, "lblOffset"));
|
|
178
|
+
const tickMarkRaw = findChildOptional(node, "majorTickMark")?.attributes["val"];
|
|
179
|
+
const tickMark =
|
|
180
|
+
tickMarkRaw === "none" ||
|
|
181
|
+
tickMarkRaw === "in" ||
|
|
182
|
+
tickMarkRaw === "out" ||
|
|
183
|
+
tickMarkRaw === "cross"
|
|
184
|
+
? tickMarkRaw
|
|
185
|
+
: undefined;
|
|
186
|
+
const tickLabelSkip = readIntVal(findChildOptional(node, "tickLblSkip"));
|
|
187
|
+
const tickMarkSkip = readIntVal(findChildOptional(node, "tickMarkSkip"));
|
|
188
|
+
|
|
189
|
+
const axis: CategoryAxis = {
|
|
190
|
+
...base,
|
|
191
|
+
kind: "category",
|
|
192
|
+
auto,
|
|
193
|
+
categoryLabels: [],
|
|
194
|
+
};
|
|
195
|
+
if (labelAlign) axis.labelAlign = labelAlign;
|
|
196
|
+
if (labelOffset !== undefined) axis.labelOffset = labelOffset;
|
|
197
|
+
if (tickMark) axis.tickMark = tickMark;
|
|
198
|
+
if (tickLabelSkip !== undefined) axis.tickLabelSkip = tickLabelSkip;
|
|
199
|
+
if (tickMarkSkip !== undefined) axis.tickMarkSkip = tickMarkSkip;
|
|
200
|
+
return axis;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// Value axis
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
function parseValueAxisFields(
|
|
208
|
+
node: XmlElementNode,
|
|
209
|
+
base: AxisBase,
|
|
210
|
+
): ValueAxis {
|
|
211
|
+
const scaling = findChildOptional(node, "scaling");
|
|
212
|
+
const min = readFloatVal(scaling ? findChildOptional(scaling, "min") : undefined);
|
|
213
|
+
const max = readFloatVal(scaling ? findChildOptional(scaling, "max") : undefined);
|
|
214
|
+
const logBase = readFloatVal(
|
|
215
|
+
scaling ? findChildOptional(scaling, "logBase") : undefined,
|
|
216
|
+
);
|
|
217
|
+
const orientation = scaling
|
|
218
|
+
? findChildOptional(scaling, "orientation")?.attributes["val"]
|
|
219
|
+
: undefined;
|
|
220
|
+
const reverse = orientation === "maxMin";
|
|
221
|
+
|
|
222
|
+
const crossBetweenRaw = findChildOptional(node, "crossBetween")?.attributes["val"];
|
|
223
|
+
const crossBetween =
|
|
224
|
+
crossBetweenRaw === "between" || crossBetweenRaw === "midCat"
|
|
225
|
+
? crossBetweenRaw
|
|
226
|
+
: undefined;
|
|
227
|
+
|
|
228
|
+
const axis: ValueAxis = {
|
|
229
|
+
...base,
|
|
230
|
+
kind: "value",
|
|
231
|
+
reverse,
|
|
232
|
+
};
|
|
233
|
+
if (min !== undefined) axis.min = min;
|
|
234
|
+
if (max !== undefined) axis.max = max;
|
|
235
|
+
if (logBase !== undefined) axis.logBase = logBase;
|
|
236
|
+
if (crossBetween) axis.crossBetween = crossBetween;
|
|
237
|
+
return axis;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Date axis
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
function parseDateAxisFields(
|
|
245
|
+
node: XmlElementNode,
|
|
246
|
+
base: AxisBase,
|
|
247
|
+
): DateAxis {
|
|
248
|
+
const scaling = findChildOptional(node, "scaling");
|
|
249
|
+
const min = readFloatVal(scaling ? findChildOptional(scaling, "min") : undefined);
|
|
250
|
+
const max = readFloatVal(scaling ? findChildOptional(scaling, "max") : undefined);
|
|
251
|
+
const baseTimeUnit = asTimeUnit(
|
|
252
|
+
findChildOptional(node, "baseTimeUnit")?.attributes["val"],
|
|
253
|
+
);
|
|
254
|
+
const majorTimeUnit = asTimeUnit(
|
|
255
|
+
findChildOptional(node, "majorTimeUnit")?.attributes["val"],
|
|
256
|
+
);
|
|
257
|
+
const minorTimeUnit = asTimeUnit(
|
|
258
|
+
findChildOptional(node, "minorTimeUnit")?.attributes["val"],
|
|
259
|
+
);
|
|
260
|
+
const axis: DateAxis = {
|
|
261
|
+
...base,
|
|
262
|
+
kind: "date",
|
|
263
|
+
};
|
|
264
|
+
if (min !== undefined) axis.min = min;
|
|
265
|
+
if (max !== undefined) axis.max = max;
|
|
266
|
+
if (baseTimeUnit) axis.baseTimeUnit = baseTimeUnit;
|
|
267
|
+
if (majorTimeUnit) axis.majorTimeUnit = majorTimeUnit;
|
|
268
|
+
if (minorTimeUnit) axis.minorTimeUnit = minorTimeUnit;
|
|
269
|
+
return axis;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function asTimeUnit(
|
|
273
|
+
raw: string | undefined,
|
|
274
|
+
): "days" | "months" | "years" | undefined {
|
|
275
|
+
if (raw === "days" || raw === "months" || raw === "years") return raw;
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|