@a3s-lab/office 0.28.0 → 0.30.0

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.
Files changed (69) hide show
  1. package/README.md +126 -3
  2. package/dist/0~1403.js +1 -1
  3. package/dist/0~4980.js +1 -1
  4. package/dist/0~7048.js +1 -1
  5. package/dist/{0~7043.js → 0~7231.js} +400 -242
  6. package/dist/{0~5093.js → 0~7360.js} +293 -53
  7. package/dist/0~7614.js +1 -1
  8. package/dist/0~document-editor.js +1535 -102
  9. package/dist/0~presentation-editor.js +1 -1
  10. package/dist/0~spreadsheet-editor.js +184 -36
  11. package/dist/0~work-docx-export.js +437 -11
  12. package/dist/0~work-docx-import.js +32 -7
  13. package/dist/0~work-office-diagnostics.js +170 -7
  14. package/dist/0~work-pptx-export.js +1 -1
  15. package/dist/0~work-pptx-import.js +1 -1
  16. package/dist/0~work-presentation-charts.js +1 -1
  17. package/dist/1544.js +14 -2
  18. package/dist/4104.js +31 -8
  19. package/dist/4121.js +3448 -0
  20. package/dist/6282.js +558 -1688
  21. package/dist/8715.js +1 -1
  22. package/dist/core.js +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/internal/features/work/editors/document-command-catalog.d.ts +27 -0
  25. package/dist/internal/features/work/editors/document-font-dialog-model.d.ts +8 -2
  26. package/dist/internal/features/work/editors/document-font-dialog-run-border-model.d.ts +24 -0
  27. package/dist/internal/features/work/editors/document-font-dialog-run-border-section.d.ts +10 -0
  28. package/dist/internal/features/work/editors/document-font-dialog-run-shading-model.d.ts +23 -0
  29. package/dist/internal/features/work/editors/document-font-dialog-run-shading-section.d.ts +8 -0
  30. package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +2 -1
  31. package/dist/internal/features/work/editors/document-proofing-dialog-model.d.ts +22 -0
  32. package/dist/internal/features/work/editors/document-proofing-dialog.d.ts +7 -0
  33. package/dist/internal/features/work/editors/document-table-of-contents-dialog.d.ts +10 -0
  34. package/dist/internal/features/work/editors/document-toolbar.d.ts +3 -1
  35. package/dist/internal/features/work/editors/spreadsheet-data-validation.d.ts +7 -1
  36. package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +2 -0
  37. package/dist/internal/features/work/work-document-character-formatting.d.ts +12 -0
  38. package/dist/internal/features/work/work-document-format-changes.d.ts +7 -0
  39. package/dist/internal/features/work/work-document-highlight.d.ts +9 -0
  40. package/dist/internal/features/work/work-document-outline.d.ts +1 -0
  41. package/dist/internal/features/work/work-document-paragraph-shading.d.ts +6 -0
  42. package/dist/internal/features/work/work-document-proofing.d.ts +19 -0
  43. package/dist/internal/features/work/work-document-run-border.d.ts +11 -0
  44. package/dist/internal/features/work/work-document-run-shading.d.ts +12 -0
  45. package/dist/internal/features/work/work-document-table-of-contents-node.d.ts +18 -0
  46. package/dist/internal/features/work/work-document-table-of-contents.d.ts +51 -0
  47. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +4 -0
  48. package/dist/internal/features/work/work-docx-field-instructions.d.ts +1 -1
  49. package/dist/internal/features/work/work-docx-import.d.ts +3 -1
  50. package/dist/internal/features/work/work-docx-proofing-diagnostics.d.ts +3 -0
  51. package/dist/internal/features/work/work-docx-proofing.d.ts +38 -0
  52. package/dist/internal/features/work/work-docx-run-border-diagnostics.d.ts +3 -0
  53. package/dist/internal/features/work/work-docx-run-border-export.d.ts +17 -0
  54. package/dist/internal/features/work/work-docx-run-border.d.ts +20 -0
  55. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +9 -0
  56. package/dist/internal/features/work/work-docx-run-shading-diagnostics.d.ts +3 -0
  57. package/dist/internal/features/work/work-docx-run-shading-export.d.ts +17 -0
  58. package/dist/internal/features/work/work-docx-run-shading.d.ts +20 -0
  59. package/dist/internal/features/work/work-docx-table-of-contents-export.d.ts +11 -0
  60. package/dist/internal/features/work/work-docx-table-of-contents-import.d.ts +15 -0
  61. package/dist/internal/features/work/work-spreadsheet-data-validation.d.ts +7 -0
  62. package/dist/internal/features/work/work-types.d.ts +9 -0
  63. package/dist/internal/kernel/office-kernel-protocol.d.ts +1 -0
  64. package/dist/office-kernel.wasm +0 -0
  65. package/dist/styles.css +339 -1
  66. package/docs/latest/en/browser-editor-architecture.md +72 -1
  67. package/package.json +15 -2
  68. package/dist/5184.js +0 -662
  69. package/dist/9424.js +0 -16
package/dist/4121.js ADDED
@@ -0,0 +1,3448 @@
1
+ import jszip from "jszip";
2
+ import { Extension } from "@tiptap/core";
3
+ import { isHistoryTransaction } from "@tiptap/pm/history";
4
+ import { Plugin } from "@tiptap/pm/state";
5
+ import { Mapping } from "@tiptap/pm/transform";
6
+ const DOCUMENT_INTEGRITY_BOOKMARK = 1;
7
+ const DOCUMENT_INTEGRITY_FIELD = 2;
8
+ const DOCUMENT_INTEGRITY_IMAGE = 4;
9
+ const DOCUMENT_INTEGRITY_NOTE = 8;
10
+ const DOCUMENT_INTEGRITY_PARAGRAPH_IDENTITY = 16;
11
+ const DOCUMENT_INTEGRITY_TABLE_ROW_IDENTITY = 32;
12
+ const featureCache = new WeakMap();
13
+ function documentHasIntegrityFeature(document, feature) {
14
+ return (documentIntegrityFeatures(document, true) & feature) !== 0;
15
+ }
16
+ function primeDocumentIntegrityFeatures(document) {
17
+ document.forEach(primeDocumentIntegrityNode);
18
+ }
19
+ function primeDocumentIntegrityNode(node) {
20
+ if ('documentChunk' === node.type.name) {
21
+ const features = nonNegativeInteger(node.attrs.integrityFeatures);
22
+ if (null !== features) featureCache.set(node, features);
23
+ if (true !== node.attrs.windowContainer) return;
24
+ }
25
+ node.forEach(primeDocumentIntegrityNode);
26
+ }
27
+ function documentIntegrityFeatures(node, cacheNode) {
28
+ if (cacheNode) {
29
+ const cached = featureCache.get(node);
30
+ if (void 0 !== cached) return cached;
31
+ }
32
+ let features = nodeIntegrityFeatures(node);
33
+ node.forEach((child)=>{
34
+ features |= documentIntegrityFeatures(child, 'documentChunk' === child.type.name);
35
+ });
36
+ if (cacheNode) featureCache.set(node, features);
37
+ return features;
38
+ }
39
+ function nodeIntegrityFeatures(node) {
40
+ let features = 0;
41
+ switch(node.type.name){
42
+ case 'documentBookmarkBoundary':
43
+ features |= DOCUMENT_INTEGRITY_BOOKMARK;
44
+ break;
45
+ case 'documentCrossReference':
46
+ if ('bookmark' === node.attrs.targetType) features |= DOCUMENT_INTEGRITY_BOOKMARK;
47
+ break;
48
+ case 'documentField':
49
+ features |= DOCUMENT_INTEGRITY_FIELD;
50
+ break;
51
+ case 'image':
52
+ features |= DOCUMENT_INTEGRITY_IMAGE;
53
+ break;
54
+ case 'documentNote':
55
+ case 'documentNoteReference':
56
+ features |= DOCUMENT_INTEGRITY_NOTE;
57
+ break;
58
+ }
59
+ if (node.isText && node.marks.some((mark)=>'link' === mark.type.name && 'string' == typeof mark.attrs.href && mark.attrs.href.startsWith('#'))) features |= DOCUMENT_INTEGRITY_BOOKMARK;
60
+ if (identityComponent(node.attrs.paragraphId) || identityComponent(node.attrs.textId)) features |= DOCUMENT_INTEGRITY_PARAGRAPH_IDENTITY;
61
+ if (identityComponent(node.attrs.rowId) || identityComponent(node.attrs.rowTextId)) features |= DOCUMENT_INTEGRITY_TABLE_ROW_IDENTITY;
62
+ return features;
63
+ }
64
+ function identityComponent(value) {
65
+ return 'string' == typeof value && value.trim().length > 0;
66
+ }
67
+ function nonNegativeInteger(value) {
68
+ const number = Number(value);
69
+ return Number.isSafeInteger(number) && number >= 0 ? number : null;
70
+ }
71
+ function normalizeCssColor(source) {
72
+ const value = source?.trim().toLowerCase();
73
+ if (!value) return null;
74
+ if ('transparent' === value) return 'transparent';
75
+ const shortHex = /^#([0-9a-f]{3})$/i.exec(value);
76
+ if (shortHex?.[1]) return `#${Array.from(shortHex[1]).map((channel)=>`${channel}${channel}`).join('')}`;
77
+ if (/^#[0-9a-f]{6}$/i.test(value)) return value;
78
+ const rgb = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*([\d.]+))?\s*\)$/i.exec(value);
79
+ if (!rgb) return null;
80
+ const channels = rgb.slice(1, 4).map(Number);
81
+ if (channels.some((channel)=>channel < 0 || channel > 255)) return null;
82
+ if (void 0 !== rgb[4] && 0 === Number(rgb[4])) return 'transparent';
83
+ if (void 0 !== rgb[4] && 1 !== Number(rgb[4])) return null;
84
+ return `#${channels.map((channel)=>channel.toString(16).padStart(2, '0')).join('')}`;
85
+ }
86
+ function decodeXmlBytes(bytes, label) {
87
+ let encoding = 'utf-8';
88
+ let offset = 0;
89
+ if (0xef === bytes[0] && 0xbb === bytes[1] && 0xbf === bytes[2]) offset = 3;
90
+ else if (0xff === bytes[0] && 0xfe === bytes[1]) {
91
+ encoding = 'utf-16le';
92
+ offset = 2;
93
+ } else if (0xfe === bytes[0] && 0xff === bytes[1]) {
94
+ encoding = 'utf-16be';
95
+ offset = 2;
96
+ } else if (0x3c === bytes[0] && 0 === bytes[1] && 0x3f === bytes[2] && 0 === bytes[3]) encoding = 'utf-16le';
97
+ else if (0 === bytes[0] && 0x3c === bytes[1] && 0 === bytes[2] && 0x3f === bytes[3]) encoding = 'utf-16be';
98
+ try {
99
+ return new TextDecoder(encoding, {
100
+ fatal: true
101
+ }).decode(bytes.subarray(offset));
102
+ } catch {
103
+ throw new Error(`${label} uses an invalid ${encoding} XML encoding.`);
104
+ }
105
+ }
106
+ function serializeUtf8Xml(document) {
107
+ const serialized = new XMLSerializer().serializeToString(document);
108
+ const body = serialized.replace(/^\s*<\?xml[^?]*\?>\s*/i, '');
109
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>${body}`;
110
+ }
111
+ class OoxmlPackage {
112
+ zip;
113
+ textCache = new Map();
114
+ constructor(zip){
115
+ this.zip = zip;
116
+ }
117
+ static async load(buffer) {
118
+ return new OoxmlPackage(await jszip.loadAsync(buffer));
119
+ }
120
+ has(partPath) {
121
+ return Boolean(this.zip.file(partPath));
122
+ }
123
+ paths(prefix) {
124
+ return Object.keys(this.zip.files).filter((path)=>path.startsWith(prefix) && !this.zip.files[path]?.dir);
125
+ }
126
+ async text(partPath) {
127
+ const cached = this.textCache.get(partPath);
128
+ if (cached) return cached;
129
+ const entry = this.zip.file(partPath);
130
+ if (!entry) throw new Error(`Office package part is missing: ${partPath}`);
131
+ const pending = entry.async('uint8array').then((bytes)=>decodeXmlBytes(bytes, partPath));
132
+ this.textCache.set(partPath, pending);
133
+ try {
134
+ return await pending;
135
+ } catch (error) {
136
+ this.textCache.delete(partPath);
137
+ throw error;
138
+ }
139
+ }
140
+ async xml(partPath) {
141
+ return parseXml(await this.text(partPath), partPath);
142
+ }
143
+ async bytes(partPath) {
144
+ const entry = this.zip.file(partPath);
145
+ if (!entry) throw new Error(`Office package part is missing: ${partPath}`);
146
+ return entry.async('uint8array');
147
+ }
148
+ async relationships(sourcePart) {
149
+ const partPath = relationshipsPartPath(sourcePart);
150
+ if (!this.has(partPath)) return new Map();
151
+ const document = await this.xml(partPath);
152
+ return new Map(descendants(document, 'Relationship').map((element)=>{
153
+ const relationship = {
154
+ id: attribute(element, 'Id') ?? '',
155
+ target: resolvePartTarget(sourcePart, attribute(element, 'Target') ?? ''),
156
+ type: attribute(element, 'Type') ?? '',
157
+ targetMode: attribute(element, 'TargetMode') ?? void 0
158
+ };
159
+ return [
160
+ relationship.id,
161
+ relationship
162
+ ];
163
+ }));
164
+ }
165
+ }
166
+ function parseXml(source, label = 'Office XML') {
167
+ const document = new DOMParser().parseFromString(source, 'application/xml');
168
+ const error = descendants(document, 'parsererror')[0];
169
+ if (error) throw new Error(`${label} is not valid XML: ${error.textContent?.trim() || 'parse error'}`);
170
+ return document;
171
+ }
172
+ const xmlElementPatterns = new Map();
173
+ function xmlContainsAnyElement(source, localNames) {
174
+ if (!source || !localNames.length) return false;
175
+ const key = localNames.join('\u0000');
176
+ let pattern = xmlElementPatterns.get(key);
177
+ if (!pattern) {
178
+ const alternatives = localNames.map((name)=>name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
179
+ pattern = new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?(?:${alternatives})(?=[\\s/>])`);
180
+ xmlElementPatterns.set(key, pattern);
181
+ }
182
+ return pattern.test(source);
183
+ }
184
+ function attribute(element, name) {
185
+ const direct = element.getAttribute(name);
186
+ if (null !== direct) return direct;
187
+ const localName = name.includes(':') ? name.slice(name.indexOf(':') + 1) : name;
188
+ return Array.from(element.attributes).find((item)=>{
189
+ const itemLocalName = item.localName.includes(':') ? item.localName.slice(item.localName.indexOf(':') + 1) : item.localName;
190
+ return itemLocalName === localName && (!name.includes(':') || item.name === name);
191
+ })?.value ?? null;
192
+ }
193
+ function xmlNamespacePrefix(element, namespace) {
194
+ if (!namespace) return element.prefix;
195
+ if ('function' == typeof element.lookupPrefix) {
196
+ const prefix = element.lookupPrefix(namespace);
197
+ if (prefix) return prefix;
198
+ }
199
+ let current = element;
200
+ while(current){
201
+ if (current.namespaceURI === namespace && current.prefix) return current.prefix;
202
+ const declaration = Array.from(current.attributes).find((item)=>item.value === namespace && ('xmlns' === item.name || item.name.startsWith('xmlns:')));
203
+ if (declaration?.name.startsWith('xmlns:')) return declaration.name.slice(6);
204
+ current = current.parentElement;
205
+ }
206
+ return null;
207
+ }
208
+ function directChildren(parent, localName) {
209
+ return Array.from(parent.children).filter((element)=>!localName || element.localName === localName);
210
+ }
211
+ function directChild(parent, localName) {
212
+ return directChildren(parent, localName)[0];
213
+ }
214
+ function descendants(parent, localName) {
215
+ return Array.from(parent.querySelectorAll('*')).filter((element)=>element.localName === localName);
216
+ }
217
+ function firstDescendant(parent, localName) {
218
+ if (!parent) return;
219
+ return descendants(parent, localName)[0];
220
+ }
221
+ function childPath(parent, ...localNames) {
222
+ let current = parent;
223
+ for (const name of localNames){
224
+ if (!current) return;
225
+ current = directChild(current, name);
226
+ }
227
+ return current instanceof Element ? current : void 0;
228
+ }
229
+ function resolvePartTarget(sourcePart, target) {
230
+ if (/^[a-z][a-z0-9+.-]*:/i.test(target)) return target;
231
+ const segments = target.startsWith('/') ? [] : sourcePart.split('/').slice(0, -1);
232
+ for (const segment of target.replace(/^\/+/, '').split('/'))if (segment && '.' !== segment) if ('..' === segment) segments.pop();
233
+ else segments.push(segment);
234
+ return segments.join('/');
235
+ }
236
+ function contentTypeForPart(partPath) {
237
+ const extension = partPath.split('.').pop()?.toLowerCase();
238
+ const types = {
239
+ apng: 'image/apng',
240
+ bmp: 'image/bmp',
241
+ emf: 'image/emf',
242
+ gif: 'image/gif',
243
+ jpeg: 'image/jpeg',
244
+ jpg: 'image/jpeg',
245
+ png: 'image/png',
246
+ svg: 'image/svg+xml',
247
+ tif: 'image/tiff',
248
+ tiff: 'image/tiff',
249
+ webp: 'image/webp',
250
+ wmf: 'image/wmf'
251
+ };
252
+ return types[extension ?? ''] ?? 'application/octet-stream';
253
+ }
254
+ function bytesToDataUrl(bytes, contentType) {
255
+ let binary = '';
256
+ const chunkSize = 32768;
257
+ for(let offset = 0; offset < bytes.length; offset += chunkSize)binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
258
+ return `data:${contentType};base64,${btoa(binary)}`;
259
+ }
260
+ function relationshipsPartPath(sourcePart) {
261
+ const separator = sourcePart.lastIndexOf('/');
262
+ const directory = separator >= 0 ? sourcePart.slice(0, separator + 1) : '';
263
+ const fileName = separator >= 0 ? sourcePart.slice(separator + 1) : sourcePart;
264
+ return `${directory}_rels/${fileName}.rels`;
265
+ }
266
+ const WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
267
+ class DocxThemePatchCollector {
268
+ patches = [];
269
+ nextMarker = 1;
270
+ usedColors;
271
+ constructor(sourceHtml){
272
+ this.usedColors = sourceColors(sourceHtml);
273
+ }
274
+ marker(kind, reference, currentColor) {
275
+ if (!reference || normalizeColor(currentColor) !== reference.resolved) return null;
276
+ let marker = '';
277
+ do {
278
+ marker = (0xf00000 + this.nextMarker).toString(16).padStart(6, '0').toUpperCase();
279
+ this.nextMarker += 1;
280
+ }while (this.usedColors.has(marker))
281
+ this.usedColors.add(marker);
282
+ this.patches.push({
283
+ kind,
284
+ marker,
285
+ reference
286
+ });
287
+ return marker;
288
+ }
289
+ }
290
+ function serializeDocxThemeReference(reference) {
291
+ return reference ? JSON.stringify(reference) : void 0;
292
+ }
293
+ function parseDocxThemeReference(value) {
294
+ if (!value) return null;
295
+ try {
296
+ const parsed = JSON.parse(value);
297
+ const theme = 'string' == typeof parsed.theme ? parsed.theme.trim() : '';
298
+ const resolved = normalizeColor('string' == typeof parsed.resolved ? parsed.resolved : null);
299
+ const tint = byteHex(parsed.tint);
300
+ const shade = byteHex(parsed.shade);
301
+ if (!theme || !resolved) return null;
302
+ return {
303
+ theme,
304
+ resolved,
305
+ ...tint ? {
306
+ tint
307
+ } : {},
308
+ ...shade ? {
309
+ shade
310
+ } : {}
311
+ };
312
+ } catch {
313
+ return null;
314
+ }
315
+ }
316
+ async function patchDocxThemeReferences(buffer, patches) {
317
+ if (!patches.length) return buffer;
318
+ const archive = await jszip.loadAsync(buffer);
319
+ const byMarker = new Map(patches.map((patch)=>[
320
+ patch.marker,
321
+ patch
322
+ ]));
323
+ const entries = Object.values(archive.files).filter((entry)=>!entry.dir && /^word\/(?:document|header\d+|footer\d+|footnotes|endnotes|comments)\.xml$/.test(entry.name));
324
+ for (const entry of entries){
325
+ const document = parseXml(await entry.async('text'), entry.name);
326
+ let changed = false;
327
+ for (const element of Array.from(document.getElementsByTagName('*')))for (const target of themePatchTargets(element.localName)){
328
+ const marker = wordAttribute(element, target.directAttribute)?.toUpperCase();
329
+ const patch = marker ? byMarker.get(marker) : void 0;
330
+ if (patch && patch.kind === target.kind) {
331
+ setWordAttribute(document, element, target.directAttribute, patch.reference.resolved.slice(1).toUpperCase());
332
+ setWordAttribute(document, element, target.themeAttribute, patch.reference.theme);
333
+ setOptionalWordAttribute(document, element, target.tintAttribute, patch.reference.tint);
334
+ setOptionalWordAttribute(document, element, target.shadeAttribute, patch.reference.shade);
335
+ changed = true;
336
+ }
337
+ }
338
+ if (changed) archive.file(entry.name, new XMLSerializer().serializeToString(document));
339
+ }
340
+ return archive.generateAsync({
341
+ type: 'arraybuffer'
342
+ });
343
+ }
344
+ function themePatchTargets(localName) {
345
+ if ('color' === localName) return [
346
+ {
347
+ kind: 'color',
348
+ directAttribute: 'val',
349
+ themeAttribute: 'themeColor',
350
+ tintAttribute: 'themeTint',
351
+ shadeAttribute: 'themeShade'
352
+ }
353
+ ];
354
+ if ('u' === localName) return [
355
+ {
356
+ kind: 'underline',
357
+ directAttribute: 'color',
358
+ themeAttribute: 'themeColor',
359
+ tintAttribute: 'themeTint',
360
+ shadeAttribute: 'themeShade'
361
+ }
362
+ ];
363
+ if ('shd' === localName) return [
364
+ {
365
+ kind: 'fill',
366
+ directAttribute: 'fill',
367
+ themeAttribute: 'themeFill',
368
+ tintAttribute: 'themeFillTint',
369
+ shadeAttribute: 'themeFillShade'
370
+ },
371
+ {
372
+ kind: 'shadingColor',
373
+ directAttribute: 'color',
374
+ themeAttribute: 'themeColor',
375
+ tintAttribute: 'themeTint',
376
+ shadeAttribute: 'themeShade'
377
+ }
378
+ ];
379
+ return [
380
+ 'top',
381
+ 'right',
382
+ 'bottom',
383
+ 'left',
384
+ 'start',
385
+ 'end'
386
+ ].includes(localName) ? [
387
+ {
388
+ kind: 'border',
389
+ directAttribute: 'color',
390
+ themeAttribute: 'themeColor',
391
+ tintAttribute: 'themeTint',
392
+ shadeAttribute: 'themeShade'
393
+ }
394
+ ] : [];
395
+ }
396
+ function normalizeColor(value) {
397
+ const normalized = value?.trim().toLowerCase();
398
+ if (!normalized || !/^#[0-9a-f]{6}$/.test(normalized)) return null;
399
+ return normalized;
400
+ }
401
+ function sourceColors(source) {
402
+ const colors = new Set();
403
+ for (const match of source.matchAll(/#([0-9a-f]{6})\b/gi))if (match[1]) colors.add(match[1].toUpperCase());
404
+ for (const match of source.matchAll(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/gi)){
405
+ const channels = match.slice(1, 4).map(Number);
406
+ if (!channels.some((channel)=>channel < 0 || channel > 255)) colors.add(channels.map((channel)=>channel.toString(16).padStart(2, '0')).join('').toUpperCase());
407
+ }
408
+ return colors;
409
+ }
410
+ function byteHex(value) {
411
+ if ('string' != typeof value) return;
412
+ const normalized = value.trim().toUpperCase();
413
+ return /^[0-9A-F]{2}$/.test(normalized) ? normalized : void 0;
414
+ }
415
+ function wordAttribute(element, name) {
416
+ return element.getAttributeNS(WORD_NAMESPACE, name) ?? element.getAttribute(`w:${name}`);
417
+ }
418
+ function setWordAttribute(document, element, name, value) {
419
+ const prefix = xmlNamespacePrefix(document.documentElement, WORD_NAMESPACE) ?? 'w';
420
+ element.setAttributeNS(WORD_NAMESPACE, `${prefix}:${name}`, value);
421
+ }
422
+ function setOptionalWordAttribute(document, element, name, value) {
423
+ if (value) setWordAttribute(document, element, name, value);
424
+ else element.removeAttributeNS(WORD_NAMESPACE, name);
425
+ }
426
+ const DOCUMENT_PARAGRAPH_BORDERS_ATTRIBUTE = 'data-office-paragraph-borders';
427
+ const DOCUMENT_PARAGRAPH_BORDER_EDGES = [
428
+ 'top',
429
+ 'left',
430
+ 'bottom',
431
+ 'right',
432
+ 'between',
433
+ 'bar'
434
+ ];
435
+ const DOCUMENT_PARAGRAPH_BORDER_STYLES = [
436
+ 'nil',
437
+ 'none',
438
+ 'single',
439
+ 'thick',
440
+ 'double',
441
+ 'dotted',
442
+ 'dashed',
443
+ 'dotDash',
444
+ 'dotDotDash',
445
+ 'triple',
446
+ 'thinThickSmallGap',
447
+ 'thickThinSmallGap',
448
+ 'thinThickThinSmallGap',
449
+ 'thinThickMediumGap',
450
+ 'thickThinMediumGap',
451
+ 'thinThickThinMediumGap',
452
+ 'thinThickLargeGap',
453
+ 'thickThinLargeGap',
454
+ 'thinThickThinLargeGap',
455
+ 'wave',
456
+ 'doubleWave',
457
+ 'dashSmallGap',
458
+ 'dashDotStroked',
459
+ 'threeDEmboss',
460
+ 'threeDEngrave',
461
+ 'outset',
462
+ 'inset',
463
+ 'apples',
464
+ 'archedScallops',
465
+ 'babyPacifier',
466
+ 'babyRattle',
467
+ 'balloons3Colors',
468
+ 'balloonsHotAir',
469
+ 'basicBlackDashes',
470
+ 'basicBlackDots',
471
+ 'basicBlackSquares',
472
+ 'basicThinLines',
473
+ 'basicWhiteDashes',
474
+ 'basicWhiteDots',
475
+ 'basicWhiteSquares',
476
+ 'basicWideInline',
477
+ 'basicWideMidline',
478
+ 'basicWideOutline',
479
+ 'bats',
480
+ 'birds',
481
+ 'birdsFlight',
482
+ 'cabins',
483
+ 'cakeSlice',
484
+ 'candyCorn',
485
+ 'celticKnotwork',
486
+ 'certificateBanner',
487
+ 'chainLink',
488
+ 'champagneBottle',
489
+ 'checkedBarBlack',
490
+ 'checkedBarColor',
491
+ 'checkered',
492
+ 'christmasTree',
493
+ 'circlesLines',
494
+ 'circlesRectangles',
495
+ 'classicalWave',
496
+ 'clocks',
497
+ 'compass',
498
+ 'confetti',
499
+ 'confettiGrays',
500
+ 'confettiOutline',
501
+ 'confettiStreamers',
502
+ 'confettiWhite',
503
+ 'cornerTriangles',
504
+ 'couponCutoutDashes',
505
+ 'couponCutoutDots',
506
+ 'crazyMaze',
507
+ 'creaturesButterfly',
508
+ 'creaturesFish',
509
+ 'creaturesInsects',
510
+ 'creaturesLadyBug',
511
+ 'crossStitch',
512
+ 'cup',
513
+ 'decoArch',
514
+ 'decoArchColor',
515
+ 'decoBlocks',
516
+ 'diamondsGray',
517
+ 'doubleD',
518
+ 'doubleDiamonds',
519
+ 'earth1',
520
+ 'earth2',
521
+ 'eclipsingSquares1',
522
+ 'eclipsingSquares2',
523
+ 'eggsBlack',
524
+ 'fans',
525
+ 'film',
526
+ 'firecrackers',
527
+ 'flowersBlockPrint',
528
+ 'flowersDaisies',
529
+ 'flowersModern1',
530
+ 'flowersModern2',
531
+ 'flowersPansy',
532
+ 'flowersRedRose',
533
+ 'flowersRoses',
534
+ 'flowersTeacup',
535
+ 'flowersTiny',
536
+ 'gems',
537
+ 'gingerbreadMan',
538
+ 'gradient',
539
+ 'handmade1',
540
+ 'handmade2',
541
+ 'heartBalloon',
542
+ 'heartGray',
543
+ 'hearts',
544
+ 'heebieJeebies',
545
+ 'holly',
546
+ 'houseFunky',
547
+ 'hypnotic',
548
+ 'iceCreamCones',
549
+ 'lightBulb',
550
+ 'lightning1',
551
+ 'lightning2',
552
+ 'mapPins',
553
+ 'mapleLeaf',
554
+ 'mapleMuffins',
555
+ 'marquee',
556
+ 'marqueeToothed',
557
+ 'moons',
558
+ 'mosaic',
559
+ 'musicNotes',
560
+ 'northwest',
561
+ 'ovals',
562
+ 'packages',
563
+ 'palmsBlack',
564
+ 'palmsColor',
565
+ 'paperClips',
566
+ 'papyrus',
567
+ 'partyFavor',
568
+ 'partyGlass',
569
+ 'pencils',
570
+ 'people',
571
+ 'peopleWaving',
572
+ 'peopleHats',
573
+ 'poinsettias',
574
+ 'postageStamp',
575
+ 'pumpkin1',
576
+ 'pushPinNote2',
577
+ 'pushPinNote1',
578
+ 'pyramids',
579
+ 'pyramidsAbove',
580
+ 'quadrants',
581
+ 'rings',
582
+ 'safari',
583
+ 'sawtooth',
584
+ 'sawtoothGray',
585
+ 'scaredCat',
586
+ 'seattle',
587
+ 'shadowedSquares',
588
+ 'sharksTeeth',
589
+ 'shorebirdTracks',
590
+ 'skyrocket',
591
+ 'snowflakeFancy',
592
+ 'snowflakes',
593
+ 'sombrero',
594
+ 'southwest',
595
+ 'stars',
596
+ 'starsTop',
597
+ 'stars3d',
598
+ 'starsBlack',
599
+ 'starsShadowed',
600
+ 'sun',
601
+ 'swirligig',
602
+ 'tornPaper',
603
+ 'tornPaperBlack',
604
+ 'trees',
605
+ 'triangleParty',
606
+ 'triangles',
607
+ 'tribal1',
608
+ 'tribal2',
609
+ 'tribal3',
610
+ 'tribal4',
611
+ 'tribal5',
612
+ 'tribal6',
613
+ 'triangle1',
614
+ 'triangle2',
615
+ 'triangleCircle1',
616
+ 'triangleCircle2',
617
+ 'shapes1',
618
+ 'shapes2',
619
+ 'twistedLines1',
620
+ 'twistedLines2',
621
+ 'vine',
622
+ 'waveline',
623
+ 'weavingAngles',
624
+ 'weavingBraid',
625
+ 'weavingRibbon',
626
+ 'weavingStrips',
627
+ 'whiteFlowers',
628
+ 'woodwork',
629
+ 'xIllusions',
630
+ 'zanyTriangles',
631
+ 'zigZag',
632
+ 'zigZagStitch'
633
+ ];
634
+ const BORDER_STYLE_SET = new Set(DOCUMENT_PARAGRAPH_BORDER_STYLES);
635
+ const BORDER_EDGE_SET = new Set(DOCUMENT_PARAGRAPH_BORDER_EDGES);
636
+ const BORDER_PROPERTY_SET = new Set([
637
+ 'style',
638
+ 'color',
639
+ 'size',
640
+ 'space',
641
+ 'shadow',
642
+ 'frame'
643
+ ]);
644
+ const LINE_BORDER_STYLES = new Set(DOCUMENT_PARAGRAPH_BORDER_STYLES.slice(0, 27));
645
+ const DASHED_BORDER_STYLES = new Set([
646
+ 'dashed',
647
+ 'dashSmallGap',
648
+ 'dashDotStroked',
649
+ 'dotDash',
650
+ 'dotDotDash'
651
+ ]);
652
+ const DOUBLE_BORDER_STYLES = new Set([
653
+ 'double',
654
+ 'triple',
655
+ 'thinThickSmallGap',
656
+ 'thickThinSmallGap',
657
+ 'thinThickThinSmallGap',
658
+ 'thinThickMediumGap',
659
+ 'thickThinMediumGap',
660
+ 'thinThickThinMediumGap',
661
+ 'thinThickLargeGap',
662
+ 'thickThinLargeGap',
663
+ 'thinThickThinLargeGap',
664
+ 'doubleWave'
665
+ ]);
666
+ const MAX_SERIALIZED_PARAGRAPH_BORDERS = 32768;
667
+ const POINTS_TO_PIXELS = 96 / 72;
668
+ function normalizeDocumentParagraphBorders(source) {
669
+ if (!source || 'object' != typeof source || Array.isArray(source)) return null;
670
+ const record = source;
671
+ if (Object.keys(record).some((key)=>!BORDER_EDGE_SET.has(key))) return null;
672
+ const borders = {};
673
+ for (const edge of DOCUMENT_PARAGRAPH_BORDER_EDGES){
674
+ if (void 0 === record[edge]) continue;
675
+ const border = normalizeDocumentParagraphBorder(record[edge]);
676
+ if (!border) return null;
677
+ borders[edge] = border;
678
+ }
679
+ return Object.keys(borders).length ? borders : null;
680
+ }
681
+ function normalizeDocumentParagraphBorder(source) {
682
+ if (!source || 'object' != typeof source || Array.isArray(source)) return null;
683
+ const record = source;
684
+ if (Object.keys(record).some((key)=>!BORDER_PROPERTY_SET.has(key))) return null;
685
+ const style = record.style;
686
+ if ('string' != typeof style || !BORDER_STYLE_SET.has(style)) return null;
687
+ const normalizedStyle = style;
688
+ const color = normalizeBorderColor(record.color);
689
+ if (void 0 !== record.color && !color) return null;
690
+ const size = optionalInteger(record.size);
691
+ if (null === size || void 0 !== size && !validBorderSize(normalizedStyle, size)) return null;
692
+ const space = optionalInteger(record.space);
693
+ if (null === space || void 0 !== space && (space < 0 || space > 31)) return null;
694
+ const shadow = optionalBoolean(record.shadow);
695
+ const frame = optionalBoolean(record.frame);
696
+ if (null === shadow || null === frame) return null;
697
+ return {
698
+ style: normalizedStyle,
699
+ ...color ? {
700
+ color
701
+ } : {},
702
+ ...void 0 !== size ? {
703
+ size
704
+ } : {},
705
+ ...void 0 !== space ? {
706
+ space
707
+ } : {},
708
+ ...void 0 !== shadow ? {
709
+ shadow
710
+ } : {},
711
+ ...void 0 !== frame ? {
712
+ frame
713
+ } : {}
714
+ };
715
+ }
716
+ function parseDocumentParagraphBorders(source) {
717
+ if ('string' != typeof source) return normalizeDocumentParagraphBorders(source);
718
+ if (!source.trim() || source.length > MAX_SERIALIZED_PARAGRAPH_BORDERS) return null;
719
+ try {
720
+ return normalizeDocumentParagraphBorders(JSON.parse(source));
721
+ } catch {
722
+ return null;
723
+ }
724
+ }
725
+ function serializeDocumentParagraphBorders(source) {
726
+ const borders = normalizeDocumentParagraphBorders(source);
727
+ if (!borders) return;
728
+ return JSON.stringify(Object.fromEntries(DOCUMENT_PARAGRAPH_BORDER_EDGES.flatMap((edge)=>{
729
+ const border = borders[edge];
730
+ return border ? [
731
+ [
732
+ edge,
733
+ serializedBorder(border)
734
+ ]
735
+ ] : [];
736
+ })));
737
+ }
738
+ function parseDocumentParagraphBordersElement(element) {
739
+ const semantic = parseDocumentParagraphBorders(element.getAttribute(DOCUMENT_PARAGRAPH_BORDERS_ATTRIBUTE));
740
+ if (!semantic) return paragraphBordersFromCss(element);
741
+ const edited = {
742
+ ...semantic
743
+ };
744
+ for (const edge of [
745
+ 'top',
746
+ 'left',
747
+ 'bottom',
748
+ 'right'
749
+ ]){
750
+ const border = semantic[edge];
751
+ const css = cssBorder(element, edge);
752
+ if (!(!css || border && sameBorderPresentation(border, css))) {
753
+ if ('none' === css.style) {
754
+ edited[edge] = {
755
+ style: 'nil'
756
+ };
757
+ continue;
758
+ }
759
+ edited[edge] = {
760
+ ...border ?? {
761
+ style: 'single'
762
+ },
763
+ style: cssStyleToBorderStyle(css.style),
764
+ color: {
765
+ value: css.color
766
+ },
767
+ size: cssWidthToEighthPoints(css.width)
768
+ };
769
+ }
770
+ }
771
+ return normalizeDocumentParagraphBorders(edited);
772
+ }
773
+ function documentParagraphBordersDomAttributes(source) {
774
+ const borders = normalizeDocumentParagraphBorders(source);
775
+ const serialized = serializeDocumentParagraphBorders(borders);
776
+ if (!borders || !serialized) return {};
777
+ const styles = [];
778
+ const shadows = [];
779
+ for (const edge of [
780
+ 'top',
781
+ 'left',
782
+ 'bottom',
783
+ 'right'
784
+ ]){
785
+ const border = borders[edge];
786
+ if (!border) continue;
787
+ const presentation = documentBorderPresentation(border);
788
+ styles.push(`border-${edge}: ${formatPixels(presentation.width)}px ${presentation.style} ${presentation.color}`);
789
+ if (border.space) styles.push(`padding-${edge}: ${formatPixels(border.space * POINTS_TO_PIXELS)}px`);
790
+ if (border.shadow && presentation.width > 0) shadows.push(`2px 2px 0 ${presentation.color}`);
791
+ }
792
+ const between = borders.between ? documentBorderPresentation(borders.between) : null;
793
+ if (between && between.width > 0) shadows.push(`inset 0 -${formatPixels(between.width)}px 0 ${between.color}`);
794
+ const bar = borders.bar ? documentBorderPresentation(borders.bar) : null;
795
+ if (bar && bar.width > 0) shadows.push(`inset ${formatPixels(bar.width)}px 0 0 ${bar.color}`);
796
+ if (shadows.length) styles.push(`box-shadow: ${shadows.join(', ')}`);
797
+ return {
798
+ [DOCUMENT_PARAGRAPH_BORDERS_ATTRIBUTE]: serialized,
799
+ ...styles.length ? {
800
+ style: styles.join('; ')
801
+ } : {}
802
+ };
803
+ }
804
+ function isDocumentParagraphArtBorderStyle(style) {
805
+ return !LINE_BORDER_STYLES.has(style);
806
+ }
807
+ function normalizeBorderColor(source) {
808
+ if (!source || 'object' != typeof source || Array.isArray(source)) return null;
809
+ const record = source;
810
+ if (Object.keys(record).some((key)=>'value' !== key && 'theme' !== key)) return null;
811
+ const theme = parseDocxThemeReference('string' == typeof record.theme ? record.theme : record.theme ? JSON.stringify(record.theme) : void 0);
812
+ const direct = 'auto' === record.value ? 'auto' : 'string' == typeof record.value ? normalizeCssColor(record.value) : null;
813
+ const resolved = direct ?? theme?.resolved ?? null;
814
+ if (!resolved || 'transparent' === resolved) return null;
815
+ if (theme && resolved !== theme.resolved && !('auto' === resolved && 'none' === theme.theme && '#000000' === theme.resolved)) return null;
816
+ return {
817
+ value: resolved,
818
+ ...theme ? {
819
+ theme
820
+ } : {}
821
+ };
822
+ }
823
+ function serializedBorder(border) {
824
+ const color = border.color ? serializedBorderColor(border.color) : void 0;
825
+ return {
826
+ style: border.style,
827
+ ...color ? {
828
+ color
829
+ } : {},
830
+ ...void 0 !== border.size ? {
831
+ size: border.size
832
+ } : {},
833
+ ...void 0 !== border.space ? {
834
+ space: border.space
835
+ } : {},
836
+ ...void 0 !== border.shadow ? {
837
+ shadow: border.shadow
838
+ } : {},
839
+ ...void 0 !== border.frame ? {
840
+ frame: border.frame
841
+ } : {}
842
+ };
843
+ }
844
+ function serializedBorderColor(color) {
845
+ const theme = serializeDocxThemeReference(color.theme ?? null);
846
+ return {
847
+ value: color.value,
848
+ ...theme ? {
849
+ theme: JSON.parse(theme)
850
+ } : {}
851
+ };
852
+ }
853
+ function optionalInteger(value) {
854
+ if (void 0 === value) return;
855
+ return 'number' == typeof value && Number.isSafeInteger(value) ? value : null;
856
+ }
857
+ function optionalBoolean(value) {
858
+ if (void 0 === value) return;
859
+ return 'boolean' == typeof value ? value : null;
860
+ }
861
+ function validBorderSize(style, size) {
862
+ if ('nil' === style || 'none' === style) return size >= 0 && size <= 96;
863
+ return isDocumentParagraphArtBorderStyle(style) ? size >= 1 && size <= 31 : size >= 2 && size <= 96;
864
+ }
865
+ function documentBorderPresentation(border) {
866
+ if ('nil' === border.style || 'none' === border.style || !border.size) return {
867
+ color: 'transparent',
868
+ style: 'none',
869
+ width: 0
870
+ };
871
+ const width = Math.min(16, isDocumentParagraphArtBorderStyle(border.style) ? border.size * POINTS_TO_PIXELS : border.size / 6);
872
+ return {
873
+ color: border.color && 'auto' !== border.color.value ? border.color.value : '#000000',
874
+ style: borderStyleToCssStyle(border.style),
875
+ width
876
+ };
877
+ }
878
+ function borderStyleToCssStyle(style) {
879
+ if ('nil' === style || 'none' === style) return 'none';
880
+ if ('dotted' === style) return 'dotted';
881
+ if (DASHED_BORDER_STYLES.has(style)) return 'dashed';
882
+ if (DOUBLE_BORDER_STYLES.has(style)) return 'double';
883
+ if ('inset' === style || 'threeDEngrave' === style) return 'inset';
884
+ if ('outset' === style || 'threeDEmboss' === style) return 'outset';
885
+ return 'solid';
886
+ }
887
+ function paragraphBordersFromCss(element) {
888
+ const borders = {};
889
+ for (const edge of [
890
+ 'top',
891
+ 'left',
892
+ 'bottom',
893
+ 'right'
894
+ ]){
895
+ const css = cssBorder(element, edge);
896
+ if (css && 'none' !== css.style) borders[edge] = {
897
+ style: cssStyleToBorderStyle(css.style),
898
+ color: {
899
+ value: css.color
900
+ },
901
+ size: cssWidthToEighthPoints(css.width)
902
+ };
903
+ }
904
+ return normalizeDocumentParagraphBorders(borders);
905
+ }
906
+ function cssBorder(element, edge) {
907
+ const style = element.style.getPropertyValue(`border-${edge}-style`).trim();
908
+ const width = Number.parseFloat(element.style.getPropertyValue(`border-${edge}-width`));
909
+ const color = normalizeCssColor(element.style.getPropertyValue(`border-${edge}-color`));
910
+ if (!style) return null;
911
+ if ('none' === style || 'hidden' === style) return {
912
+ color: '#000000',
913
+ style: 'none',
914
+ width: 0
915
+ };
916
+ return color && 'transparent' !== color && Number.isFinite(width) && width > 0 ? {
917
+ color,
918
+ style,
919
+ width
920
+ } : null;
921
+ }
922
+ function sameBorderPresentation(border, css) {
923
+ const expected = documentBorderPresentation(border);
924
+ if ('none' === expected.style) return 'none' === css.style && 0 === css.width;
925
+ return expected.color === css.color && expected.style === css.style && Math.abs(expected.width - css.width) < 0.01;
926
+ }
927
+ function cssStyleToBorderStyle(style) {
928
+ if ('double' === style) return 'double';
929
+ if ('dashed' === style) return 'dashed';
930
+ if ('dotted' === style) return 'dotted';
931
+ if ('inset' === style || 'groove' === style) return 'inset';
932
+ if ('outset' === style || 'ridge' === style) return 'outset';
933
+ return 'single';
934
+ }
935
+ function cssWidthToEighthPoints(width) {
936
+ return Math.max(2, Math.min(96, Math.round(6 * width)));
937
+ }
938
+ function formatPixels(value) {
939
+ return Number(value.toFixed(3)).toString();
940
+ }
941
+ const DOCUMENT_RUN_BORDER_ATTRIBUTE = 'data-office-run-border';
942
+ const DOCUMENT_RUN_BORDER_STYLES = DOCUMENT_PARAGRAPH_BORDER_STYLES.slice(0, 27);
943
+ const MAX_SERIALIZED_RUN_BORDER_BYTES = 4096;
944
+ const work_document_run_border_POINTS_TO_PIXELS = 96 / 72;
945
+ function normalizeDocumentRunBorder(source) {
946
+ const border = normalizeDocumentParagraphBorder(source);
947
+ return border && !isDocumentParagraphArtBorderStyle(border.style) ? border : null;
948
+ }
949
+ function parseDocumentRunBorder(source) {
950
+ if ('string' != typeof source) return normalizeDocumentRunBorder(source);
951
+ if (!source.trim() || source.length > MAX_SERIALIZED_RUN_BORDER_BYTES) return null;
952
+ try {
953
+ return normalizeDocumentRunBorder(JSON.parse(source));
954
+ } catch {
955
+ return null;
956
+ }
957
+ }
958
+ function serializeDocumentRunBorder(source) {
959
+ const border = normalizeDocumentRunBorder(source);
960
+ if (!border) return;
961
+ const theme = serializeDocxThemeReference(border.color?.theme ?? null);
962
+ return JSON.stringify({
963
+ style: border.style,
964
+ ...border.color ? {
965
+ color: {
966
+ value: border.color.value,
967
+ ...theme ? {
968
+ theme: JSON.parse(theme)
969
+ } : {}
970
+ }
971
+ } : {},
972
+ ...void 0 !== border.size ? {
973
+ size: border.size
974
+ } : {},
975
+ ...void 0 !== border.space ? {
976
+ space: border.space
977
+ } : {},
978
+ ...void 0 !== border.shadow ? {
979
+ shadow: border.shadow
980
+ } : {},
981
+ ...void 0 !== border.frame ? {
982
+ frame: border.frame
983
+ } : {}
984
+ });
985
+ }
986
+ function parseDocumentRunBorderElement(element) {
987
+ const semantic = parseDocumentRunBorder(element.getAttribute(DOCUMENT_RUN_BORDER_ATTRIBUTE));
988
+ return semantic ?? documentRunBorderFromCss(element);
989
+ }
990
+ function documentRunBorderDomAttributes(source) {
991
+ const border = normalizeDocumentRunBorder(source);
992
+ const serialized = serializeDocumentRunBorder(border);
993
+ if (!border || !serialized) return {};
994
+ const presentation = documentBorderPresentation(border);
995
+ const declarations = [
996
+ `border: ${work_document_run_border_formatPixels(presentation.width)}px ${presentation.style} ${presentation.color}`,
997
+ `padding: ${work_document_run_border_formatPixels((border.space ?? 0) * work_document_run_border_POINTS_TO_PIXELS)}px`,
998
+ 'box-decoration-break: clone',
999
+ '-webkit-box-decoration-break: clone'
1000
+ ];
1001
+ if (border.shadow && presentation.width > 0) declarations.push(`box-shadow: 2px 2px 0 ${presentation.color}`);
1002
+ return {
1003
+ [DOCUMENT_RUN_BORDER_ATTRIBUTE]: serialized,
1004
+ style: declarations.join('; ')
1005
+ };
1006
+ }
1007
+ function documentRunBorderIsVisible(source) {
1008
+ const border = normalizeDocumentRunBorder(source);
1009
+ return Boolean(border && documentBorderPresentation(border).width > 0);
1010
+ }
1011
+ function documentRunBorderFromCss(element) {
1012
+ const style = element.style.borderStyle.trim();
1013
+ if (!style) return null;
1014
+ if ('none' === style || 'hidden' === style) return {
1015
+ style: 'none'
1016
+ };
1017
+ const width = Number.parseFloat(element.style.borderWidth);
1018
+ const color = normalizeCssColor(element.style.borderColor);
1019
+ if (!Number.isFinite(width) || width <= 0 || !color || 'transparent' === color) return null;
1020
+ const padding = Number.parseFloat(element.style.padding);
1021
+ return normalizeDocumentRunBorder({
1022
+ style: cssBorderStyle(style),
1023
+ color: {
1024
+ value: color
1025
+ },
1026
+ size: Math.max(2, Math.min(96, Math.round(6 * width))),
1027
+ ...Number.isFinite(padding) && padding >= 0 ? {
1028
+ space: Math.max(0, Math.min(31, Math.round(padding / work_document_run_border_POINTS_TO_PIXELS)))
1029
+ } : {}
1030
+ });
1031
+ }
1032
+ function cssBorderStyle(style) {
1033
+ if ('double' === style) return 'double';
1034
+ if ('dashed' === style) return 'dashed';
1035
+ if ('dotted' === style) return 'dotted';
1036
+ if ('inset' === style || 'groove' === style) return 'inset';
1037
+ if ('outset' === style || 'ridge' === style) return 'outset';
1038
+ return 'single';
1039
+ }
1040
+ function work_document_run_border_formatPixels(value) {
1041
+ return Number(value.toFixed(3)).toString();
1042
+ }
1043
+ const work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS = new Set([
1044
+ 'nil',
1045
+ 'clear',
1046
+ 'solid',
1047
+ 'horzStripe',
1048
+ 'vertStripe',
1049
+ 'reverseDiagStripe',
1050
+ 'diagStripe',
1051
+ 'horzCross',
1052
+ 'diagCross',
1053
+ 'thinHorzStripe',
1054
+ 'thinVertStripe',
1055
+ 'thinReverseDiagStripe',
1056
+ 'thinDiagStripe',
1057
+ 'thinHorzCross',
1058
+ 'thinDiagCross',
1059
+ 'pct5',
1060
+ 'pct10',
1061
+ 'pct12',
1062
+ 'pct15',
1063
+ 'pct20',
1064
+ 'pct25',
1065
+ 'pct30',
1066
+ 'pct35',
1067
+ 'pct37',
1068
+ 'pct40',
1069
+ 'pct45',
1070
+ 'pct50',
1071
+ 'pct55',
1072
+ 'pct60',
1073
+ 'pct62',
1074
+ 'pct65',
1075
+ 'pct70',
1076
+ 'pct75',
1077
+ 'pct80',
1078
+ 'pct85',
1079
+ 'pct87',
1080
+ 'pct90',
1081
+ 'pct95'
1082
+ ]);
1083
+ function normalizeDocumentParagraphShading(source) {
1084
+ if (!source || 'object' != typeof source) return null;
1085
+ const value = source;
1086
+ const pattern = value.pattern;
1087
+ if ('string' != typeof pattern || !work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS.has(pattern)) return null;
1088
+ const color = normalizeShadingColor(value.color);
1089
+ const fill = normalizeShadingColor(value.fill);
1090
+ if (void 0 !== value.color && !color || void 0 !== value.fill && !fill) return null;
1091
+ return {
1092
+ pattern: pattern,
1093
+ ...color ? {
1094
+ color
1095
+ } : {},
1096
+ ...fill ? {
1097
+ fill
1098
+ } : {}
1099
+ };
1100
+ }
1101
+ function parseDocumentParagraphShading(source) {
1102
+ if ('string' != typeof source) return normalizeDocumentParagraphShading(source);
1103
+ if (!source.trim()) return null;
1104
+ try {
1105
+ return normalizeDocumentParagraphShading(JSON.parse(source));
1106
+ } catch {
1107
+ return null;
1108
+ }
1109
+ }
1110
+ function serializeDocumentParagraphShading(source) {
1111
+ const shading = normalizeDocumentParagraphShading(source);
1112
+ if (!shading) return;
1113
+ return JSON.stringify({
1114
+ pattern: shading.pattern,
1115
+ ...shading.color ? {
1116
+ color: serializedShadingColor(shading.color)
1117
+ } : {},
1118
+ ...shading.fill ? {
1119
+ fill: serializedShadingColor(shading.fill)
1120
+ } : {}
1121
+ });
1122
+ }
1123
+ function parseDocumentParagraphShadingElement(element) {
1124
+ const semantic = parseDocumentParagraphShading(element.dataset.officeParagraphShading);
1125
+ const background = normalizeCssColor(element.style.backgroundColor);
1126
+ if (semantic) {
1127
+ const presentation = documentParagraphShadingPresentation(semantic);
1128
+ const expected = normalizeCssColor(presentation.backgroundColor);
1129
+ if (background && expected && background !== expected) {
1130
+ if ('transparent' === background) return {
1131
+ pattern: 'nil'
1132
+ };
1133
+ if (paragraphShadingBackgroundUsesForeground(semantic)) return {
1134
+ ...semantic,
1135
+ color: {
1136
+ value: background
1137
+ }
1138
+ };
1139
+ return {
1140
+ ...semantic,
1141
+ fill: {
1142
+ value: background
1143
+ }
1144
+ };
1145
+ }
1146
+ return semantic;
1147
+ }
1148
+ return background && 'transparent' !== background ? {
1149
+ pattern: 'clear',
1150
+ fill: {
1151
+ value: background
1152
+ }
1153
+ } : null;
1154
+ }
1155
+ function documentParagraphShadingDomAttributes(source) {
1156
+ const shading = normalizeDocumentParagraphShading(source);
1157
+ const serialized = serializeDocumentParagraphShading(shading);
1158
+ if (!shading || !serialized) return {};
1159
+ const presentation = documentParagraphShadingPresentation(shading);
1160
+ const styles = [
1161
+ `background-color: ${presentation.backgroundColor}`,
1162
+ presentation.backgroundImage ? `background-image: ${presentation.backgroundImage}` : '',
1163
+ presentation.backgroundSize ? `background-size: ${presentation.backgroundSize}` : ''
1164
+ ].filter(Boolean);
1165
+ return {
1166
+ 'data-office-paragraph-shading': serialized,
1167
+ style: styles.join('; ')
1168
+ };
1169
+ }
1170
+ function normalizeShadingColor(source) {
1171
+ if (!source || 'object' != typeof source) return null;
1172
+ const value = source;
1173
+ const theme = parseDocxThemeReference('string' == typeof value.theme ? value.theme : value.theme ? JSON.stringify(value.theme) : void 0);
1174
+ const direct = 'auto' === value.value ? 'auto' : 'string' == typeof value.value ? normalizeCssColor(value.value) : null;
1175
+ const resolved = direct ?? theme?.resolved ?? null;
1176
+ if (!resolved || 'transparent' === resolved) return null;
1177
+ if (theme && resolved !== theme.resolved) return null;
1178
+ return {
1179
+ value: resolved,
1180
+ ...theme ? {
1181
+ theme
1182
+ } : {}
1183
+ };
1184
+ }
1185
+ function serializedShadingColor(color) {
1186
+ const theme = serializeDocxThemeReference(color.theme ?? null);
1187
+ return {
1188
+ value: color.value,
1189
+ ...theme ? {
1190
+ theme: JSON.parse(theme)
1191
+ } : {}
1192
+ };
1193
+ }
1194
+ function documentParagraphShadingPresentation(shading) {
1195
+ if ('nil' === shading.pattern) return {
1196
+ backgroundColor: 'transparent'
1197
+ };
1198
+ const foreground = shadingColor(shading.color, '#000000');
1199
+ const background = shadingColor(shading.fill, 'transparent');
1200
+ if ('clear' === shading.pattern) return {
1201
+ backgroundColor: background
1202
+ };
1203
+ if ('solid' === shading.pattern) return {
1204
+ backgroundColor: foreground
1205
+ };
1206
+ const percentage = shadingPercentage(shading.pattern);
1207
+ if (null !== percentage) {
1208
+ const inverted = percentage > 50;
1209
+ const dotColor = inverted ? background : foreground;
1210
+ const baseColor = inverted ? foreground : background;
1211
+ const density = Math.min(50, inverted ? 100 - percentage : percentage);
1212
+ const spacing = Math.max(2, Math.round(9 - density / 7));
1213
+ return {
1214
+ backgroundColor: baseColor,
1215
+ backgroundImage: `radial-gradient(circle, ${dotColor} 0 1px, transparent 1.2px)`,
1216
+ backgroundSize: `${spacing}px ${spacing}px`
1217
+ };
1218
+ }
1219
+ const thin = shading.pattern.startsWith('thin');
1220
+ const width = thin ? 1 : 2;
1221
+ const period = thin ? 7 : 6;
1222
+ const stripe = (angle)=>`repeating-linear-gradient(${angle}deg, ${foreground} 0 ${width}px, transparent ${width}px ${period}px)`;
1223
+ const angles = shadingPatternAngles(shading.pattern);
1224
+ return {
1225
+ backgroundColor: background,
1226
+ backgroundImage: angles.map(stripe).join(', ')
1227
+ };
1228
+ }
1229
+ function shadingColor(color, fallback) {
1230
+ return color && 'auto' !== color.value ? color.value : fallback;
1231
+ }
1232
+ function shadingPercentage(pattern) {
1233
+ const match = /^pct(\d+)$/.exec(pattern);
1234
+ return match?.[1] ? Number(match[1]) : null;
1235
+ }
1236
+ function paragraphShadingBackgroundUsesForeground(shading) {
1237
+ if ('solid' === shading.pattern) return true;
1238
+ const percentage = shadingPercentage(shading.pattern);
1239
+ return null !== percentage && percentage > 50;
1240
+ }
1241
+ function shadingPatternAngles(pattern) {
1242
+ if (pattern.includes('HorzCross')) return [
1243
+ 0,
1244
+ 90
1245
+ ];
1246
+ if (pattern.includes('DiagCross')) return [
1247
+ 45,
1248
+ -45
1249
+ ];
1250
+ if (pattern.includes('VertStripe')) return [
1251
+ 90
1252
+ ];
1253
+ if (pattern.includes('ReverseDiagStripe')) return [
1254
+ -45
1255
+ ];
1256
+ if (pattern.includes('DiagStripe')) return [
1257
+ 45
1258
+ ];
1259
+ return [
1260
+ 0
1261
+ ];
1262
+ }
1263
+ const DOCUMENT_HIGHLIGHT_ATTRIBUTE = 'data-office-highlight';
1264
+ const DOCUMENT_HIGHLIGHT_VALUES = new Set([
1265
+ 'black',
1266
+ 'blue',
1267
+ 'cyan',
1268
+ 'darkBlue',
1269
+ 'darkCyan',
1270
+ 'darkGray',
1271
+ 'darkGreen',
1272
+ 'darkMagenta',
1273
+ 'darkRed',
1274
+ 'darkYellow',
1275
+ 'green',
1276
+ 'lightGray',
1277
+ 'magenta',
1278
+ 'none',
1279
+ 'red',
1280
+ 'white',
1281
+ 'yellow'
1282
+ ]);
1283
+ const HIGHLIGHT_COLORS = {
1284
+ black: '#000000',
1285
+ blue: '#0000ff',
1286
+ cyan: '#00ffff',
1287
+ darkBlue: '#000080',
1288
+ darkCyan: '#008080',
1289
+ darkGray: '#808080',
1290
+ darkGreen: '#008000',
1291
+ darkMagenta: '#800080',
1292
+ darkRed: '#800000',
1293
+ darkYellow: '#808000',
1294
+ green: '#00ff00',
1295
+ lightGray: '#c0c0c0',
1296
+ magenta: '#ff00ff',
1297
+ none: 'transparent',
1298
+ red: '#ff0000',
1299
+ white: '#ffffff',
1300
+ yellow: '#ffff00'
1301
+ };
1302
+ function normalizeDocumentHighlight(source) {
1303
+ return 'string' == typeof source && DOCUMENT_HIGHLIGHT_VALUES.has(source) ? source : null;
1304
+ }
1305
+ function documentHighlightFromDocxValue(source) {
1306
+ if ('string' != typeof source) return null;
1307
+ const normalized = source.trim().toLowerCase();
1308
+ for (const value of DOCUMENT_HIGHLIGHT_VALUES)if (value.toLowerCase() === normalized) return value;
1309
+ return null;
1310
+ }
1311
+ function documentHighlightCssColor(source) {
1312
+ const value = normalizeDocumentHighlight(source);
1313
+ return value ? HIGHLIGHT_COLORS[value] : null;
1314
+ }
1315
+ function documentHighlightForCssColor(source) {
1316
+ const color = normalizeCssColor('string' == typeof source ? source : null);
1317
+ if (!color) return null;
1318
+ for (const [value, candidate] of Object.entries(HIGHLIGHT_COLORS))if (candidate === color) return value;
1319
+ return null;
1320
+ }
1321
+ function documentHighlightFromElement(element) {
1322
+ return normalizeDocumentHighlight(element.getAttribute(DOCUMENT_HIGHLIGHT_ATTRIBUTE)) ?? documentHighlightForCssColor(element.style.backgroundColor);
1323
+ }
1324
+ function documentHighlightDomAttributes(source) {
1325
+ const value = normalizeDocumentHighlight(source);
1326
+ const color = documentHighlightCssColor(value);
1327
+ return value && color ? {
1328
+ [DOCUMENT_HIGHLIGHT_ATTRIBUTE]: value,
1329
+ style: `background-color: ${color}`
1330
+ } : {};
1331
+ }
1332
+ const DOCUMENT_RUN_SHADING_ATTRIBUTE = 'data-office-run-shading';
1333
+ const MAX_SERIALIZED_RUN_SHADING_BYTES = 4096;
1334
+ const RUN_SHADING_KEYS = new Set([
1335
+ 'pattern',
1336
+ 'color',
1337
+ 'fill'
1338
+ ]);
1339
+ const RUN_SHADING_COLOR_KEYS = new Set([
1340
+ 'value',
1341
+ 'theme'
1342
+ ]);
1343
+ const THEME_REFERENCE_KEYS = new Set([
1344
+ 'theme',
1345
+ 'resolved',
1346
+ 'tint',
1347
+ 'shade'
1348
+ ]);
1349
+ function normalizeDocumentRunShading(source) {
1350
+ if (!isRecordWithKeys(source, RUN_SHADING_KEYS)) return null;
1351
+ for (const name of [
1352
+ 'color',
1353
+ 'fill'
1354
+ ]){
1355
+ const color = source[name];
1356
+ if (void 0 !== color) {
1357
+ if (!isRecordWithKeys(color, RUN_SHADING_COLOR_KEYS)) return null;
1358
+ if (void 0 !== color.theme && !isRecordWithKeys(color.theme, THEME_REFERENCE_KEYS)) return null;
1359
+ }
1360
+ }
1361
+ return normalizeDocumentParagraphShading(source);
1362
+ }
1363
+ function parseDocumentRunShading(source) {
1364
+ if ('string' != typeof source) return normalizeDocumentRunShading(source);
1365
+ if (!source.trim() || source.length > MAX_SERIALIZED_RUN_SHADING_BYTES) return null;
1366
+ try {
1367
+ return normalizeDocumentRunShading(JSON.parse(source));
1368
+ } catch {
1369
+ return null;
1370
+ }
1371
+ }
1372
+ function serializeDocumentRunShading(source) {
1373
+ const shading = normalizeDocumentRunShading(source);
1374
+ const serialized = shading ? serializeDocumentParagraphShading(shading) : void 0;
1375
+ return serialized && serialized.length <= MAX_SERIALIZED_RUN_SHADING_BYTES ? serialized : void 0;
1376
+ }
1377
+ function parseDocumentRunShadingElement(element) {
1378
+ const semantic = parseDocumentRunShading(element.getAttribute(DOCUMENT_RUN_SHADING_ATTRIBUTE));
1379
+ if (!semantic) return null;
1380
+ if (element.hasAttribute(DOCUMENT_HIGHLIGHT_ATTRIBUTE)) return semantic;
1381
+ const background = normalizeCssColor(element.style.backgroundColor);
1382
+ const expected = normalizeCssColor(documentParagraphShadingPresentation(semantic).backgroundColor);
1383
+ if (!background || !expected || background === expected) return semantic;
1384
+ if ('transparent' === background) return {
1385
+ pattern: 'nil'
1386
+ };
1387
+ return paragraphShadingBackgroundUsesForeground(semantic) ? {
1388
+ ...semantic,
1389
+ color: {
1390
+ value: background
1391
+ }
1392
+ } : {
1393
+ ...semantic,
1394
+ fill: {
1395
+ value: background
1396
+ }
1397
+ };
1398
+ }
1399
+ function documentRunShadingDomAttributes(source) {
1400
+ const shading = normalizeDocumentRunShading(source);
1401
+ const serialized = serializeDocumentRunShading(shading);
1402
+ if (!shading || !serialized) return {};
1403
+ const paragraphAttributes = documentParagraphShadingDomAttributes(shading);
1404
+ const style = [
1405
+ paragraphAttributes.style,
1406
+ 'box-decoration-break: clone',
1407
+ '-webkit-box-decoration-break: clone'
1408
+ ].filter(Boolean).join('; ');
1409
+ return {
1410
+ [DOCUMENT_RUN_SHADING_ATTRIBUTE]: serialized,
1411
+ style
1412
+ };
1413
+ }
1414
+ function isRecordWithKeys(source, allowed) {
1415
+ return 'object' == typeof source && null !== source && !Array.isArray(source) && Object.keys(source).every((key)=>allowed.has(key));
1416
+ }
1417
+ const DOCUMENT_SCRIPT_FONTS_ATTRIBUTE = "data-office-script-fonts";
1418
+ const DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE = "data-office-script-font-slot";
1419
+ const MAX_FONT_NAME_LENGTH = 127;
1420
+ const MAX_SERIALIZED_SCRIPT_FONTS_LENGTH = 4096;
1421
+ const SCRIPT_FONT_KEYS = new Set([
1422
+ 'ascii',
1423
+ 'highAnsi',
1424
+ 'eastAsia',
1425
+ 'complexScript',
1426
+ 'hint'
1427
+ ]);
1428
+ const SCRIPT_FONT_FACE_KEYS = new Set([
1429
+ 'name',
1430
+ 'theme',
1431
+ 'resolved'
1432
+ ]);
1433
+ const SCRIPT_FONT_HINTS = new Set([
1434
+ 'default',
1435
+ 'eastAsia',
1436
+ 'cs'
1437
+ ]);
1438
+ const THEME_FONTS = new Set([
1439
+ 'majorEastAsia',
1440
+ 'majorBidi',
1441
+ 'majorAscii',
1442
+ 'majorHAnsi',
1443
+ 'minorEastAsia',
1444
+ 'minorBidi',
1445
+ 'minorAscii',
1446
+ 'minorHAnsi'
1447
+ ]);
1448
+ const SLOT_FALLBACK_ORDER = {
1449
+ ascii: [
1450
+ 'ascii',
1451
+ 'highAnsi',
1452
+ 'eastAsia',
1453
+ 'complexScript'
1454
+ ],
1455
+ highAnsi: [
1456
+ 'highAnsi',
1457
+ 'ascii',
1458
+ 'eastAsia',
1459
+ 'complexScript'
1460
+ ],
1461
+ eastAsia: [
1462
+ 'eastAsia',
1463
+ 'highAnsi',
1464
+ 'ascii',
1465
+ 'complexScript'
1466
+ ],
1467
+ complexScript: [
1468
+ 'complexScript',
1469
+ 'highAnsi',
1470
+ 'ascii',
1471
+ 'eastAsia'
1472
+ ]
1473
+ };
1474
+ const NEUTRAL_SCRIPT_CHARACTER = /^[\p{Cc}\p{Cf}\p{M}\p{N}\p{P}\p{S}\p{Z}]$/u;
1475
+ function normalizeDocumentScriptFonts(source) {
1476
+ if (!work_document_script_fonts_isRecordWithKeys(source, SCRIPT_FONT_KEYS)) return null;
1477
+ const normalized = {};
1478
+ for (const slot of scriptFontSlots){
1479
+ if (void 0 === source[slot]) continue;
1480
+ const face = normalizeDocumentScriptFontFace(source[slot]);
1481
+ if (!face) return null;
1482
+ normalized[slot] = face;
1483
+ }
1484
+ if (void 0 !== source.hint) {
1485
+ const hint = normalizeDocumentScriptFontHint(source.hint);
1486
+ if (!hint) return null;
1487
+ normalized.hint = hint;
1488
+ }
1489
+ return Object.keys(normalized).length ? normalized : null;
1490
+ }
1491
+ function serializeDocumentScriptFonts(source) {
1492
+ const fonts = normalizeDocumentScriptFonts(source);
1493
+ return fonts ? JSON.stringify(fonts) : null;
1494
+ }
1495
+ function parseDocumentScriptFonts(source) {
1496
+ if (!source || source.length > MAX_SERIALIZED_SCRIPT_FONTS_LENGTH) return null;
1497
+ try {
1498
+ return normalizeDocumentScriptFonts(JSON.parse(source));
1499
+ } catch {
1500
+ return null;
1501
+ }
1502
+ }
1503
+ function documentScriptFontsFromElement(element) {
1504
+ return parseDocumentScriptFonts(element.getAttribute(DOCUMENT_SCRIPT_FONTS_ATTRIBUTE));
1505
+ }
1506
+ function documentScriptFontSlotFromElement(element) {
1507
+ return normalizeDocumentScriptFontSlot(element.getAttribute(DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE));
1508
+ }
1509
+ function documentScriptFontsDomAttributes(source, slot) {
1510
+ const fonts = normalizeDocumentScriptFonts(source);
1511
+ const normalizedSlot = normalizeDocumentScriptFontSlot(slot);
1512
+ if (!fonts) return {};
1513
+ const serialized = serializeDocumentScriptFonts(fonts);
1514
+ if (!serialized) return {};
1515
+ const family = documentScriptFontFamily(fonts, normalizedSlot ?? documentScriptFontSlotFromHint(fonts.hint));
1516
+ return {
1517
+ [DOCUMENT_SCRIPT_FONTS_ATTRIBUTE]: serialized,
1518
+ ...normalizedSlot ? {
1519
+ [DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE]: normalizedSlot
1520
+ } : {},
1521
+ ...family ? {
1522
+ style: `font-family: ${family}`
1523
+ } : {}
1524
+ };
1525
+ }
1526
+ function documentScriptFontFamily(source, slot) {
1527
+ const fonts = normalizeDocumentScriptFonts(source);
1528
+ if (!fonts) return;
1529
+ const families = [];
1530
+ const seen = new Set();
1531
+ for (const candidate of documentScriptFontFallbackSlots(slot)){
1532
+ const family = documentScriptFontFaceFamily(fonts[candidate]);
1533
+ const key = family?.toLocaleLowerCase();
1534
+ if (!(!family || !key || seen.has(key))) {
1535
+ seen.add(key);
1536
+ families.push(cssFontFamily(family));
1537
+ }
1538
+ }
1539
+ return families.length ? families.join(', ') : void 0;
1540
+ }
1541
+ function documentScriptFontFallbackSlots(slot) {
1542
+ return SLOT_FALLBACK_ORDER[slot];
1543
+ }
1544
+ function documentScriptFontFamilyForRendering(source, slot, currentFontFamily) {
1545
+ const projected = documentScriptFontFamily(source, slot);
1546
+ const safeCurrent = safeCssFontFamilyList(currentFontFamily);
1547
+ if (!safeCurrent || !projected) return projected;
1548
+ const currentPrimary = documentFontNameFromCssFamily(safeCurrent);
1549
+ const projectedPrimary = documentFontNameFromCssFamily(projected);
1550
+ return currentPrimary && projectedPrimary && currentPrimary.toLocaleLowerCase() === projectedPrimary.toLocaleLowerCase() ? safeCurrent : projected;
1551
+ }
1552
+ function documentScriptFontDirectFamily(source, slot) {
1553
+ const fonts = normalizeDocumentScriptFonts(source);
1554
+ return fonts ? documentScriptFontFaceFamily(fonts[slot]) ?? null : null;
1555
+ }
1556
+ function documentScriptFontsForAllText(fontFamily) {
1557
+ const name = documentFontNameFromCssFamily(fontFamily);
1558
+ if (!name) return null;
1559
+ const face = {
1560
+ name,
1561
+ resolved: name
1562
+ };
1563
+ return {
1564
+ ascii: face,
1565
+ highAnsi: face,
1566
+ eastAsia: face,
1567
+ complexScript: face,
1568
+ hint: 'default'
1569
+ };
1570
+ }
1571
+ function patchDocumentScriptFonts(source, patch, fallbackFontFamily) {
1572
+ const current = normalizeDocumentScriptFonts(source) ?? documentScriptFontsForAllText(fallbackFontFamily) ?? {};
1573
+ const next = {
1574
+ ...current
1575
+ };
1576
+ if (void 0 !== patch.latin) {
1577
+ const face = directFontFace(patch.latin);
1578
+ if (face) {
1579
+ next.ascii = face;
1580
+ next.highAnsi = face;
1581
+ } else {
1582
+ delete next.ascii;
1583
+ delete next.highAnsi;
1584
+ }
1585
+ }
1586
+ if (void 0 !== patch.eastAsia) {
1587
+ const face = directFontFace(patch.eastAsia);
1588
+ if (face) next.eastAsia = face;
1589
+ else delete next.eastAsia;
1590
+ }
1591
+ if (void 0 !== patch.complexScript) {
1592
+ const face = directFontFace(patch.complexScript);
1593
+ if (face) next.complexScript = face;
1594
+ else delete next.complexScript;
1595
+ }
1596
+ return normalizeDocumentScriptFonts(next);
1597
+ }
1598
+ function documentScriptFontSegments(text, hint = 'default', forceComplexScript = false) {
1599
+ if (!text) return [];
1600
+ if (forceComplexScript) return [
1601
+ {
1602
+ from: 0,
1603
+ to: text.length,
1604
+ slot: 'complexScript'
1605
+ }
1606
+ ];
1607
+ const characters = [];
1608
+ let offset = 0;
1609
+ for (const character of text){
1610
+ const from = offset;
1611
+ offset += character.length;
1612
+ characters.push({
1613
+ from,
1614
+ to: offset,
1615
+ slot: strongDocumentScriptFontSlot(character)
1616
+ });
1617
+ }
1618
+ const fallback = documentScriptFontSlotFromHint(hint);
1619
+ let previous = null;
1620
+ for(let index = 0; index < characters.length; index += 1){
1621
+ const entry = characters[index];
1622
+ if (!entry) continue;
1623
+ if (entry.slot) {
1624
+ previous = entry.slot;
1625
+ continue;
1626
+ }
1627
+ let next = previous;
1628
+ if (!next) for(let cursor = index + 1; cursor < characters.length; cursor += 1){
1629
+ const candidate = characters[cursor]?.slot;
1630
+ if (candidate) {
1631
+ next = candidate;
1632
+ break;
1633
+ }
1634
+ }
1635
+ entry.slot = next ?? fallback;
1636
+ }
1637
+ const segments = [];
1638
+ for (const entry of characters){
1639
+ const slot = entry.slot ?? fallback;
1640
+ const prior = segments[segments.length - 1];
1641
+ if (prior?.slot === slot && prior.to === entry.from) prior.to = entry.to;
1642
+ else segments.push({
1643
+ from: entry.from,
1644
+ to: entry.to,
1645
+ slot
1646
+ });
1647
+ }
1648
+ return segments;
1649
+ }
1650
+ function normalizeDocumentScriptFontSlot(value) {
1651
+ return scriptFontSlots.includes(value) ? value : null;
1652
+ }
1653
+ function normalizeDocumentScriptFontHint(value) {
1654
+ return SCRIPT_FONT_HINTS.has(value) ? value : null;
1655
+ }
1656
+ function normalizeDocumentThemeFont(value) {
1657
+ return THEME_FONTS.has(value) ? value : null;
1658
+ }
1659
+ function documentScriptFontSlotFromHint(hint) {
1660
+ if ('eastAsia' === hint) return 'eastAsia';
1661
+ if ('cs' === hint) return 'complexScript';
1662
+ return 'ascii';
1663
+ }
1664
+ function documentFontNameFromCssFamily(value) {
1665
+ if ('string' != typeof value) return null;
1666
+ const source = value.trim();
1667
+ if (!source) return null;
1668
+ let family = '';
1669
+ const quote = source[0];
1670
+ if ('"' === quote || "'" === quote) {
1671
+ let closed = false;
1672
+ for(let index = 1; index < source.length; index += 1){
1673
+ const character = source[index];
1674
+ if (character === quote) {
1675
+ closed = true;
1676
+ break;
1677
+ }
1678
+ if ('\\' !== character) {
1679
+ family += character;
1680
+ continue;
1681
+ }
1682
+ const decoded = decodeCssEscape(source, index + 1);
1683
+ if (!decoded) return null;
1684
+ family += decoded.value;
1685
+ index = decoded.end - 1;
1686
+ }
1687
+ if (!closed) return null;
1688
+ } else family = source.split(',')[0] ?? '';
1689
+ return normalizeDocumentFontName(family);
1690
+ }
1691
+ function cssDocumentFontFamily(value) {
1692
+ const family = normalizeDocumentFontName(value);
1693
+ return family ? cssFontFamily(family) : null;
1694
+ }
1695
+ function normalizeDocumentFontName(value) {
1696
+ if ('string' != typeof value) return null;
1697
+ const normalized = value.trim();
1698
+ return normalized && normalized.length <= MAX_FONT_NAME_LENGTH && !/[\p{Cc}\p{Cs}]/u.test(normalized) ? normalized : null;
1699
+ }
1700
+ const scriptFontSlots = [
1701
+ 'ascii',
1702
+ 'highAnsi',
1703
+ 'eastAsia',
1704
+ 'complexScript'
1705
+ ];
1706
+ function normalizeDocumentScriptFontFace(source) {
1707
+ if (!work_document_script_fonts_isRecordWithKeys(source, SCRIPT_FONT_FACE_KEYS)) return null;
1708
+ const name = void 0 === source.name ? void 0 : normalizeDocumentFontName(source.name);
1709
+ const resolved = void 0 === source.resolved ? void 0 : normalizeDocumentFontName(source.resolved);
1710
+ const theme = void 0 === source.theme ? void 0 : normalizeDocumentThemeFont(source.theme);
1711
+ if (void 0 !== source.name && !name || void 0 !== source.resolved && !resolved || null === theme || !name && !theme && !resolved) return null;
1712
+ return {
1713
+ ...name ? {
1714
+ name
1715
+ } : {},
1716
+ ...theme ? {
1717
+ theme
1718
+ } : {},
1719
+ ...resolved ? {
1720
+ resolved
1721
+ } : {}
1722
+ };
1723
+ }
1724
+ function directFontFace(value) {
1725
+ if (null === value) return null;
1726
+ const name = documentFontNameFromCssFamily(value) ?? normalizeDocumentFontName(value);
1727
+ return name ? {
1728
+ name,
1729
+ resolved: name
1730
+ } : null;
1731
+ }
1732
+ function documentScriptFontFaceFamily(face) {
1733
+ return face?.resolved ?? face?.name;
1734
+ }
1735
+ function strongDocumentScriptFontSlot(character) {
1736
+ if (NEUTRAL_SCRIPT_CHARACTER.test(character)) return null;
1737
+ const codePoint = character.codePointAt(0);
1738
+ if (void 0 === codePoint) return null;
1739
+ if (isComplexScriptCodePoint(codePoint)) return 'complexScript';
1740
+ if (isEastAsianCodePoint(codePoint)) return 'eastAsia';
1741
+ return codePoint <= 0x7f ? 'ascii' : 'highAnsi';
1742
+ }
1743
+ function isComplexScriptCodePoint(codePoint) {
1744
+ return codePoint >= 0x0590 && codePoint <= 0x08ff || codePoint >= 0x0900 && codePoint <= 0x109f || codePoint >= 0x1780 && codePoint <= 0x18af || codePoint >= 0x1900 && codePoint <= 0x1cff || codePoint >= 0xa800 && codePoint <= 0xa8ff || codePoint >= 0xa980 && codePoint <= 0xa9df || codePoint >= 0xaa00 && codePoint <= 0xaa7f || codePoint >= 0xabc0 && codePoint <= 0xabff || codePoint >= 0xfb1d && codePoint <= 0xfdff || codePoint >= 0xfe70 && codePoint <= 0xfeff || codePoint >= 0x10a00 && codePoint <= 0x10fff || codePoint >= 0x11000 && codePoint <= 0x11fff || codePoint >= 0x1e900 && codePoint <= 0x1edff || codePoint >= 0x1ee00 && codePoint <= 0x1eeff;
1745
+ }
1746
+ function isEastAsianCodePoint(codePoint) {
1747
+ return codePoint >= 0x1100 && codePoint <= 0x11ff || codePoint >= 0x2e80 && codePoint <= 0xa4cf || codePoint >= 0xac00 && codePoint <= 0xd7af || codePoint >= 0xf900 && codePoint <= 0xfaff || codePoint >= 0xfe10 && codePoint <= 0xfe6f || codePoint >= 0xff00 && codePoint <= 0xffef || codePoint >= 0x20000 && codePoint <= 0x323af;
1748
+ }
1749
+ function cssFontFamily(value) {
1750
+ return /^(?:-?[\p{L}_])[\p{L}\p{N}_-]*$/u.test(value) ? value : `"${Array.from(value, cssStringCharacter).join('')}"`;
1751
+ }
1752
+ function cssStringCharacter(character) {
1753
+ return /[\\":;{}<>]/u.test(character) ? `\\${character.codePointAt(0)?.toString(16)} ` : character;
1754
+ }
1755
+ function safeCssFontFamilyList(value) {
1756
+ if ('string' != typeof value) return null;
1757
+ const source = value.trim();
1758
+ if (!source || source.length > 1024 || /[;{}]/u.test(source)) return null;
1759
+ const tokens = [];
1760
+ let start = 0;
1761
+ let quote = '';
1762
+ for(let index = 0; index < source.length; index += 1){
1763
+ const character = source[index] ?? '';
1764
+ if (quote) {
1765
+ if ('\\' === character) {
1766
+ index += 1;
1767
+ if (index >= source.length) return null;
1768
+ } else if (character === quote) quote = '';
1769
+ continue;
1770
+ }
1771
+ if ('"' === character || "'" === character) {
1772
+ quote = character;
1773
+ continue;
1774
+ }
1775
+ if (',' === character) {
1776
+ tokens.push(source.slice(start, index).trim());
1777
+ start = index + 1;
1778
+ }
1779
+ }
1780
+ if (quote) return null;
1781
+ tokens.push(source.slice(start).trim());
1782
+ return tokens.length && tokens.every(validCssFontFamilyToken) ? source : null;
1783
+ }
1784
+ function validCssFontFamilyToken(value) {
1785
+ if (!value) return false;
1786
+ if (value.startsWith('"')) return /^"(?:[^"\\\r\n\f]|\\(?:[\da-f]{1,6}\s?|[^\r\n\f]))*"$/iu.test(value) && null !== documentFontNameFromCssFamily(value);
1787
+ if (value.startsWith("'")) return /^'(?:[^'\\\r\n\f]|\\(?:[\da-f]{1,6}\s?|[^\r\n\f]))*'$/iu.test(value) && null !== documentFontNameFromCssFamily(value);
1788
+ return /[\p{L}_]/u.test(value) && /^[\p{L}_-][\p{L}\p{N}_ -]*$/u.test(value) && !/^(?:inherit|initial|revert(?:-layer)?|unset)$/iu.test(value);
1789
+ }
1790
+ function decodeCssEscape(source, start) {
1791
+ if (start >= source.length) return null;
1792
+ const hexadecimal = /^[\da-f]{1,6}/i.exec(source.slice(start))?.[0];
1793
+ if (hexadecimal) {
1794
+ const codePoint = Number.parseInt(hexadecimal, 16);
1795
+ if (0 === codePoint || codePoint > 0x10ffff || codePoint >= 0xd800 && codePoint <= 0xdfff) return null;
1796
+ let end = start + hexadecimal.length;
1797
+ if (/\s/u.test(source[end] ?? '')) end += 1;
1798
+ return {
1799
+ value: String.fromCodePoint(codePoint),
1800
+ end
1801
+ };
1802
+ }
1803
+ const value = source[start];
1804
+ return !value || /[\r\n\f]/u.test(value) ? null : {
1805
+ value,
1806
+ end: start + 1
1807
+ };
1808
+ }
1809
+ function work_document_script_fonts_isRecordWithKeys(value, allowed) {
1810
+ return 'object' == typeof value && null !== value && !Array.isArray(value) && Object.keys(value).every((key)=>allowed.has(key));
1811
+ }
1812
+ const DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE = 'data-office-proofing-languages';
1813
+ const DOCUMENT_NO_PROOF_ATTRIBUTE = 'data-office-no-proof';
1814
+ const PROOFING_LANGUAGE_KEYS = new Set([
1815
+ 'latin',
1816
+ 'eastAsia',
1817
+ 'bidi'
1818
+ ]);
1819
+ const PROOFING_LANGUAGE_ORDER = [
1820
+ 'latin',
1821
+ 'eastAsia',
1822
+ 'bidi'
1823
+ ];
1824
+ const MAX_LANGUAGE_TAG_LENGTH = 85;
1825
+ const MAX_SERIALIZED_PROOFING_LANGUAGES_BYTES = 384;
1826
+ function normalizeDocumentLanguageTag(source) {
1827
+ if ('string' != typeof source) return null;
1828
+ if (!source || source !== source.trim() || source.length > MAX_LANGUAGE_TAG_LENGTH || /[\p{Cc}\p{Cs}]/u.test(source)) return null;
1829
+ return /^(?:x-none|[a-z0-9]{1,8}(?:-[a-z0-9]{1,8})*)$/iu.test(source) ? source : null;
1830
+ }
1831
+ function normalizeDocumentProofingLanguages(source) {
1832
+ if (!isRecord(source)) return null;
1833
+ const keys = Object.keys(source);
1834
+ if (!keys.length || keys.some((key)=>!PROOFING_LANGUAGE_KEYS.has(key))) return null;
1835
+ const normalized = {};
1836
+ for (const key of PROOFING_LANGUAGE_ORDER){
1837
+ if (void 0 === source[key]) continue;
1838
+ const language = normalizeDocumentLanguageTag(source[key]);
1839
+ if (!language) return null;
1840
+ normalized[key] = language;
1841
+ }
1842
+ return Object.keys(normalized).length ? normalized : null;
1843
+ }
1844
+ function serializeDocumentProofingLanguages(source) {
1845
+ const normalized = normalizeDocumentProofingLanguages(source);
1846
+ if (!normalized) return;
1847
+ const serialized = JSON.stringify(normalized);
1848
+ return serialized.length <= MAX_SERIALIZED_PROOFING_LANGUAGES_BYTES ? serialized : void 0;
1849
+ }
1850
+ function parseDocumentProofingLanguages(source) {
1851
+ if ('string' != typeof source) return normalizeDocumentProofingLanguages(source);
1852
+ if (!source || source.length > MAX_SERIALIZED_PROOFING_LANGUAGES_BYTES) return null;
1853
+ try {
1854
+ const normalized = normalizeDocumentProofingLanguages(JSON.parse(source));
1855
+ return normalized && JSON.stringify(normalized) === source ? normalized : null;
1856
+ } catch {
1857
+ return null;
1858
+ }
1859
+ }
1860
+ function normalizeDocumentNoProof(source) {
1861
+ if (true === source || 'true' === source || '1' === source) return true;
1862
+ if (false === source || 'false' === source || '0' === source) return false;
1863
+ return null;
1864
+ }
1865
+ function documentProofingLanguagesFromElement(element) {
1866
+ return parseDocumentProofingLanguages(element.getAttribute(DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE));
1867
+ }
1868
+ function documentNoProofFromElement(element) {
1869
+ return normalizeDocumentNoProof(element.getAttribute(DOCUMENT_NO_PROOF_ATTRIBUTE));
1870
+ }
1871
+ function documentProofingLanguageForScript(source, slot) {
1872
+ const languages = normalizeDocumentProofingLanguages(source);
1873
+ if (!languages) return;
1874
+ if ('eastAsia' === slot) return languages.eastAsia ?? languages.latin;
1875
+ if ('complexScript' === slot) return languages.bidi ?? languages.latin;
1876
+ return languages.latin ?? languages.eastAsia ?? languages.bidi;
1877
+ }
1878
+ function documentProofingDomAttributes(languagesSource, noProofSource, slot) {
1879
+ const languages = normalizeDocumentProofingLanguages(languagesSource);
1880
+ const serialized = serializeDocumentProofingLanguages(languages);
1881
+ const noProof = normalizeDocumentNoProof(noProofSource);
1882
+ const language = documentProofingLanguageForScript(languages, slot);
1883
+ return {
1884
+ ...serialized ? {
1885
+ [DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE]: serialized
1886
+ } : {},
1887
+ ...null === noProof ? {} : {
1888
+ [DOCUMENT_NO_PROOF_ATTRIBUTE]: String(noProof)
1889
+ },
1890
+ ...slot ? {
1891
+ [DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE]: slot
1892
+ } : {},
1893
+ ...language && 'x-none' !== language ? {
1894
+ lang: language
1895
+ } : {},
1896
+ ...true === noProof ? {
1897
+ spellcheck: 'false'
1898
+ } : {}
1899
+ };
1900
+ }
1901
+ function patchDocumentProofingLanguages(source, patch) {
1902
+ const current = normalizeDocumentProofingLanguages(source) ?? {};
1903
+ const next = {
1904
+ ...current
1905
+ };
1906
+ for (const slot of PROOFING_LANGUAGE_ORDER){
1907
+ const value = patch[slot];
1908
+ if (void 0 === value) continue;
1909
+ if (null === value) {
1910
+ delete next[slot];
1911
+ continue;
1912
+ }
1913
+ const language = normalizeDocumentLanguageTag(value);
1914
+ if (!language) return null;
1915
+ next[slot] = language;
1916
+ }
1917
+ return Object.keys(next).length ? next : null;
1918
+ }
1919
+ function isRecord(source) {
1920
+ return 'object' == typeof source && null !== source && !Array.isArray(source);
1921
+ }
1922
+ const DOCUMENT_PARAGRAPH_ID_ATTRIBUTE = 'data-office-paragraph-id';
1923
+ const DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE = 'data-office-paragraph-text-id';
1924
+ const PARAGRAPH_ID_PATTERN = /^[0-9A-F]{8}$/;
1925
+ const MAX_PARAGRAPH_ID = 0x7fffffff;
1926
+ let fallbackIdentitySequence = 0;
1927
+ const DocumentParagraphIdentity = Extension.create({
1928
+ name: 'documentParagraphIdentity',
1929
+ addOptions () {
1930
+ return {
1931
+ rotateTextId: ()=>true,
1932
+ types: [
1933
+ 'paragraph',
1934
+ 'heading',
1935
+ 'documentCaption'
1936
+ ]
1937
+ };
1938
+ },
1939
+ addGlobalAttributes () {
1940
+ return [
1941
+ {
1942
+ types: this.options.types,
1943
+ attributes: {
1944
+ paragraphId: {
1945
+ default: null,
1946
+ parseHTML: (element)=>normalizeDocumentParagraphId(element.getAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE)),
1947
+ renderHTML: (attributes)=>{
1948
+ const value = normalizeDocumentParagraphId(attributes.paragraphId);
1949
+ return value ? {
1950
+ [DOCUMENT_PARAGRAPH_ID_ATTRIBUTE]: value
1951
+ } : {};
1952
+ }
1953
+ },
1954
+ textId: {
1955
+ default: null,
1956
+ parseHTML: (element)=>normalizeDocumentParagraphId(element.getAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE)),
1957
+ renderHTML: (attributes)=>{
1958
+ const value = normalizeDocumentParagraphId(attributes.textId);
1959
+ return value ? {
1960
+ [DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE]: value
1961
+ } : {};
1962
+ }
1963
+ }
1964
+ }
1965
+ }
1966
+ ];
1967
+ },
1968
+ addProseMirrorPlugins () {
1969
+ return [
1970
+ createDocumentParagraphIdentityPlugin(this.options.types, this.options.rotateTextId)
1971
+ ];
1972
+ }
1973
+ });
1974
+ function normalizeDocumentParagraphId(value) {
1975
+ if ('string' != typeof value) return null;
1976
+ const normalized = value.trim().toUpperCase();
1977
+ if (!PARAGRAPH_ID_PATTERN.test(normalized)) return null;
1978
+ const number = Number.parseInt(normalized, 16);
1979
+ return number > 0 && number <= MAX_PARAGRAPH_ID ? normalized : null;
1980
+ }
1981
+ function createDocumentParagraphIdentityRegistry() {
1982
+ return {
1983
+ paragraphIds: new Set()
1984
+ };
1985
+ }
1986
+ function normalizeDocumentParagraphIdentity(source) {
1987
+ const paragraphId = normalizeDocumentParagraphId(source.paragraphId);
1988
+ const textId = normalizeDocumentParagraphId(source.textId);
1989
+ return paragraphId && textId ? {
1990
+ paragraphId,
1991
+ textId
1992
+ } : null;
1993
+ }
1994
+ function documentParagraphIdentityFromElement(element) {
1995
+ return normalizeDocumentParagraphIdentity({
1996
+ paragraphId: element.getAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE),
1997
+ textId: element.getAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE)
1998
+ });
1999
+ }
2000
+ function applyDocumentParagraphIdentityToElement(element, source) {
2001
+ const identity = normalizeDocumentParagraphIdentity(source);
2002
+ if (!identity) {
2003
+ element.removeAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE);
2004
+ element.removeAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE);
2005
+ return null;
2006
+ }
2007
+ element.setAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE, identity.paragraphId);
2008
+ element.setAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE, identity.textId);
2009
+ return identity;
2010
+ }
2011
+ function createDocumentParagraphIdentityPlugin(types, rotateTextId) {
2012
+ const trackedTypes = new Set(types);
2013
+ return new Plugin({
2014
+ view (view) {
2015
+ const transaction = normalizeDocumentParagraphIdentities(view.state, trackedTypes, rotateTextId);
2016
+ if (transaction) {
2017
+ transaction.setMeta('addToHistory', false);
2018
+ view.dispatch(transaction);
2019
+ }
2020
+ return {};
2021
+ },
2022
+ appendTransaction (transactions, oldState, newState) {
2023
+ if (!transactions.some((transaction)=>transaction.docChanged)) return null;
2024
+ return normalizeDocumentParagraphIdentities(newState, trackedTypes, rotateTextId, oldState, transactions);
2025
+ }
2026
+ });
2027
+ }
2028
+ function normalizeDocumentParagraphIdentities(state, trackedTypes, rotateTextId, oldState, transactions = []) {
2029
+ if (!documentHasIntegrityFeature(state.doc, 16)) return null;
2030
+ const paragraphs = documentParagraphs(state.doc, trackedTypes);
2031
+ if (!paragraphs.length) return null;
2032
+ const retainedPositions = oldState ? retainedDocumentParagraphPositions(oldState, state, transactions, trackedTypes) : new Set();
2033
+ const editedPositions = oldState && rotateTextId() && !transactions.some(isHistoryTransaction) ? editedDocumentParagraphPositions(oldState, state, transactions, trackedTypes) : new Set();
2034
+ const ordered = [
2035
+ ...paragraphs.filter((item)=>retainedPositions.has(item.position)),
2036
+ ...paragraphs.filter((item)=>!retainedPositions.has(item.position))
2037
+ ];
2038
+ const registry = createDocumentParagraphIdentityRegistry();
2039
+ const updates = new Map();
2040
+ for (const paragraph of ordered){
2041
+ const current = paragraphIdentitySourceFromNode(paragraph.node);
2042
+ const source = editedPositions.has(paragraph.position) ? {
2043
+ ...current,
2044
+ textId: nextDocumentParagraphTextId(current.textId)
2045
+ } : current;
2046
+ const identity = uniqueDocumentParagraphIdentity(source, registry);
2047
+ if (!sameDocumentParagraphIdentity(current, identity)) updates.set(paragraph.position, identity);
2048
+ }
2049
+ if (!updates.size) return null;
2050
+ const transaction = state.tr;
2051
+ for (const paragraph of paragraphs){
2052
+ const identity = updates.get(paragraph.position);
2053
+ if (identity) transaction.setNodeMarkup(paragraph.position, void 0, {
2054
+ ...paragraph.node.attrs,
2055
+ ...identity
2056
+ });
2057
+ }
2058
+ if (!transaction.docChanged) return null;
2059
+ transaction.setMeta('addToHistory', false);
2060
+ return transaction;
2061
+ }
2062
+ function hasDocumentParagraphIdentityComponent(node) {
2063
+ return Boolean(normalizeDocumentParagraphId(node.attrs.paragraphId) || normalizeDocumentParagraphId(node.attrs.textId));
2064
+ }
2065
+ function retainedDocumentParagraphPositions(oldState, newState, transactions, trackedTypes) {
2066
+ const mapping = transactionMapping(transactions);
2067
+ const retained = new Set();
2068
+ for (const previous of documentParagraphs(oldState.doc, trackedTypes)){
2069
+ const paragraphId = normalizeDocumentParagraphId(previous.node.attrs.paragraphId);
2070
+ if (!paragraphId) continue;
2071
+ const mapped = mapping.mapResult(previous.position, 1);
2072
+ const current = newState.doc.nodeAt(mapped.pos);
2073
+ if (current && trackedTypes.has(current.type.name) && normalizeDocumentParagraphId(current.attrs.paragraphId) === paragraphId) retained.add(mapped.pos);
2074
+ }
2075
+ return retained;
2076
+ }
2077
+ function editedDocumentParagraphPositions(oldState, newState, transactions, trackedTypes) {
2078
+ const mapping = transactionMapping(transactions);
2079
+ const previousParagraphs = documentParagraphs(oldState.doc, trackedTypes);
2080
+ const currentParagraphs = documentParagraphs(newState.doc, trackedTypes);
2081
+ const previousById = paragraphsById(previousParagraphs);
2082
+ const currentById = paragraphsById(currentParagraphs);
2083
+ const edited = new Set();
2084
+ for (const previous of previousParagraphs){
2085
+ const identity = normalizeDocumentParagraphIdentity(paragraphIdentitySourceFromNode(previous.node));
2086
+ if (!identity) continue;
2087
+ const mapped = mapping.mapResult(previous.position, 1);
2088
+ const current = newState.doc.nodeAt(mapped.pos);
2089
+ if (current && trackedTypes.has(current.type.name) && normalizeDocumentParagraphId(current.attrs.paragraphId) === identity.paragraphId) {
2090
+ if (paragraphTextChanged(previous.node, current, identity.textId)) edited.add(mapped.pos);
2091
+ continue;
2092
+ }
2093
+ const previousMatches = previousById.get(identity.paragraphId) ?? [];
2094
+ const currentMatches = currentById.get(identity.paragraphId) ?? [];
2095
+ if (1 === previousMatches.length && 1 === currentMatches.length && paragraphTextChanged(previous.node, currentMatches[0].node, identity.textId)) edited.add(currentMatches[0].position);
2096
+ }
2097
+ return edited;
2098
+ }
2099
+ function paragraphTextChanged(previous, current, previousTextId) {
2100
+ return previous.textContent !== current.textContent && normalizeDocumentParagraphId(current.attrs.textId) === previousTextId;
2101
+ }
2102
+ function paragraphsById(paragraphs) {
2103
+ const result = new Map();
2104
+ for (const paragraph of paragraphs){
2105
+ const id = normalizeDocumentParagraphId(paragraph.node.attrs.paragraphId);
2106
+ if (!id) continue;
2107
+ const matches = result.get(id) ?? [];
2108
+ matches.push(paragraph);
2109
+ result.set(id, matches);
2110
+ }
2111
+ return result;
2112
+ }
2113
+ function documentParagraphs(document, trackedTypes) {
2114
+ const paragraphs = [];
2115
+ document.descendants((node, position)=>{
2116
+ if (trackedTypes.has(node.type.name) && hasDocumentParagraphIdentityComponent(node)) paragraphs.push({
2117
+ node,
2118
+ position
2119
+ });
2120
+ });
2121
+ return paragraphs;
2122
+ }
2123
+ function paragraphIdentitySourceFromNode(node) {
2124
+ return {
2125
+ paragraphId: node.attrs.paragraphId,
2126
+ textId: node.attrs.textId
2127
+ };
2128
+ }
2129
+ function uniqueDocumentParagraphIdentity(source, registry) {
2130
+ const preferred = normalizeDocumentParagraphIdentity(source);
2131
+ if (preferred && !registry.paragraphIds.has(preferred.paragraphId)) {
2132
+ registry.paragraphIds.add(preferred.paragraphId);
2133
+ return preferred;
2134
+ }
2135
+ for(let attempt = 0; attempt < 8; attempt += 1){
2136
+ const identity = createDocumentParagraphIdentity();
2137
+ if (!registry.paragraphIds.has(identity.paragraphId)) {
2138
+ registry.paragraphIds.add(identity.paragraphId);
2139
+ return identity;
2140
+ }
2141
+ }
2142
+ return sequentialDocumentParagraphIdentity(registry);
2143
+ }
2144
+ function createDocumentParagraphIdentity() {
2145
+ return {
2146
+ paragraphId: randomDocumentParagraphId(),
2147
+ textId: randomDocumentParagraphId()
2148
+ };
2149
+ }
2150
+ function sequentialDocumentParagraphIdentity(registry) {
2151
+ for(let value = 1; value <= MAX_PARAGRAPH_ID; value += 1){
2152
+ const paragraphId = formatDocumentParagraphId(value);
2153
+ if (!registry.paragraphIds.has(paragraphId)) {
2154
+ registry.paragraphIds.add(paragraphId);
2155
+ return {
2156
+ paragraphId,
2157
+ textId: randomDocumentParagraphId()
2158
+ };
2159
+ }
2160
+ }
2161
+ throw new Error('No unique Word paragraph identity is available.');
2162
+ }
2163
+ function nextDocumentParagraphTextId(value) {
2164
+ const current = normalizeDocumentParagraphId(value);
2165
+ if (!current) return randomDocumentParagraphId();
2166
+ const number = Number.parseInt(current, 16);
2167
+ return formatDocumentParagraphId(number >= MAX_PARAGRAPH_ID ? 1 : number + 1);
2168
+ }
2169
+ function randomDocumentParagraphId() {
2170
+ let value = 0;
2171
+ const cryptoApi = globalThis.crypto;
2172
+ if ('function' == typeof cryptoApi?.getRandomValues) {
2173
+ const values = new Uint32Array(1);
2174
+ cryptoApi.getRandomValues(values);
2175
+ value = values[0] ?? 0;
2176
+ } else if ('function' == typeof cryptoApi?.randomUUID) value = Number.parseInt(cryptoApi.randomUUID().replaceAll('-', '').slice(0, 8), 16);
2177
+ if (!value) {
2178
+ fallbackIdentitySequence += 1;
2179
+ value = stableIdentityHash(`${Date.now()}:${Math.random()}:${fallbackIdentitySequence}`);
2180
+ }
2181
+ return formatDocumentParagraphId(value || fallbackIdentitySequence || 1);
2182
+ }
2183
+ function stableIdentityHash(value) {
2184
+ let hash = 0x811c9dc5;
2185
+ for(let index = 0; index < value.length; index += 1){
2186
+ hash ^= value.charCodeAt(index);
2187
+ hash = Math.imul(hash, 0x01000193);
2188
+ }
2189
+ return hash >>> 0 || 1;
2190
+ }
2191
+ function formatDocumentParagraphId(value) {
2192
+ return (value >>> 0 & MAX_PARAGRAPH_ID || 1).toString(16).toUpperCase().padStart(8, '0');
2193
+ }
2194
+ function sameDocumentParagraphIdentity(source, identity) {
2195
+ return normalizeDocumentParagraphId(source.paragraphId) === identity.paragraphId && normalizeDocumentParagraphId(source.textId) === identity.textId;
2196
+ }
2197
+ function transactionMapping(transactions) {
2198
+ const mapping = new Mapping();
2199
+ for (const transaction of transactions)mapping.appendMapping(transaction.mapping);
2200
+ return mapping;
2201
+ }
2202
+ function collectWorkDocumentOutline(document) {
2203
+ const items = [];
2204
+ const hierarchy = [];
2205
+ document.descendants((node, position)=>{
2206
+ const level = workDocumentOutlineLevel(node);
2207
+ if (null === level) return;
2208
+ while((hierarchy.at(-1)?.level ?? 0) >= level)hierarchy.pop();
2209
+ const parent = hierarchy.at(-1);
2210
+ const from = position + 1;
2211
+ const paragraphId = normalizeDocumentParagraphId(node.attrs.paragraphId);
2212
+ const item = {
2213
+ id: paragraphId ? `heading-${paragraphId.toLowerCase()}` : `heading-${position}`,
2214
+ text: normalizedDocumentHeadingText(node.textContent),
2215
+ level,
2216
+ depth: hierarchy.length,
2217
+ from,
2218
+ to: from + node.content.size,
2219
+ ...parent ? {
2220
+ parentId: parent.id
2221
+ } : {}
2222
+ };
2223
+ items.push(item);
2224
+ hierarchy.push(item);
2225
+ });
2226
+ return items.map((item, index)=>({
2227
+ ...item,
2228
+ hasChildren: (items[index + 1]?.depth ?? -1) > item.depth
2229
+ }));
2230
+ }
2231
+ function workDocumentOutlineLevel(node) {
2232
+ if ('heading' === node.type.name) return documentHeadingLevel(node.attrs.level);
2233
+ if ('paragraph' !== node.type.name) return null;
2234
+ const value = node.attrs.outlineLevel;
2235
+ if (null == value || '' === value) return null;
2236
+ const outlineLevel = Number(value);
2237
+ return Number.isInteger(outlineLevel) && outlineLevel >= 0 && outlineLevel <= 8 ? outlineLevel + 1 : null;
2238
+ }
2239
+ function currentWorkDocumentOutlineItem(items, position) {
2240
+ let current = null;
2241
+ for (const item of items){
2242
+ if (item.from > position) break;
2243
+ current = item;
2244
+ }
2245
+ return current;
2246
+ }
2247
+ function visibleWorkDocumentOutlineItems(items, collapsedIds, rawQuery) {
2248
+ const query = normalizedDocumentOutlineQuery(rawQuery);
2249
+ if (query) return items.filter((item)=>normalizedDocumentOutlineQuery(item.text).includes(query));
2250
+ const visible = [];
2251
+ let hiddenBelowDepth = null;
2252
+ for (const item of items){
2253
+ if (null !== hiddenBelowDepth && item.depth <= hiddenBelowDepth) hiddenBelowDepth = null;
2254
+ if (null === hiddenBelowDepth) {
2255
+ visible.push(item);
2256
+ if (item.hasChildren && collapsedIds.has(item.id)) hiddenBelowDepth = item.depth;
2257
+ }
2258
+ }
2259
+ return visible;
2260
+ }
2261
+ function documentHeadingLevel(value) {
2262
+ return 'number' == typeof value && Number.isInteger(value) && value >= 1 && value <= 6 ? value : 1;
2263
+ }
2264
+ function normalizedDocumentHeadingText(value) {
2265
+ return value.replace(/\s+/g, ' ').trim() || '未命名标题';
2266
+ }
2267
+ function normalizedDocumentOutlineQuery(value) {
2268
+ return value.normalize('NFKC').trim().toLocaleLowerCase();
2269
+ }
2270
+ const DEFAULT_DOCUMENT_TABLE_OF_CONTENTS_OPTIONS = {
2271
+ minLevel: 1,
2272
+ maxLevel: 3,
2273
+ hyperlinks: true,
2274
+ showPageNumbers: true,
2275
+ rightAlignPageNumbers: true,
2276
+ leader: 'dot'
2277
+ };
2278
+ const MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES = 512;
2279
+ const TABLE_OF_CONTENTS_SELECTOR = '[data-document-table-of-contents]';
2280
+ const MAX_TABLE_OF_CONTENTS_TITLE_LENGTH = 512;
2281
+ const TABLE_OF_CONTENTS_ID_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,127}$/i;
2282
+ const TABLE_OF_CONTENTS_TARGET_PATTERN = /^heading-[a-z0-9._:-]{1,128}$/i;
2283
+ function normalizeDocumentTableOfContentsOptions(source) {
2284
+ const minLevel = boundedLevel(source?.minLevel, 1);
2285
+ const maxLevel = Math.max(minLevel, boundedLevel(source?.maxLevel, Math.max(3, minLevel)));
2286
+ const showPageNumbers = source?.showPageNumbers !== false;
2287
+ return {
2288
+ minLevel,
2289
+ maxLevel,
2290
+ hyperlinks: source?.hyperlinks !== false,
2291
+ showPageNumbers,
2292
+ rightAlignPageNumbers: showPageNumbers && source?.rightAlignPageNumbers !== false,
2293
+ leader: tableOfContentsLeader(source?.leader) ?? 'dot'
2294
+ };
2295
+ }
2296
+ function buildDocumentTableOfContentsEntries(document, options, buildOptions = {}) {
2297
+ const normalized = normalizeDocumentTableOfContentsOptions(options);
2298
+ const outline = collectWorkDocumentOutline(document).filter((item)=>item.text.length > 0 && item.level >= normalized.minLevel && item.level <= normalized.maxLevel);
2299
+ const entries = outline.slice(0, MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES).map((item)=>tableOfContentsEntryFromOutline(document, item, buildOptions.resolveContext));
2300
+ return {
2301
+ entries,
2302
+ truncated: outline.length > MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES
2303
+ };
2304
+ }
2305
+ function documentTableOfContentsHtml(source) {
2306
+ const value = normalizeDocumentTableOfContentsValue(source);
2307
+ const options = value.options;
2308
+ const rows = value.entries.length ? value.entries.map((entry)=>tableOfContentsEntryHtml(entry, options)) : [
2309
+ '<li class="work-document-table-of-contents-empty">没有符合级别范围的标题</li>'
2310
+ ];
2311
+ const status = value.truncated ? `仅显示前 ${MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES} 项` : `${value.entries.length} 项`;
2312
+ return [
2313
+ `<div data-document-table-of-contents="true" data-toc-id="${escapeHtmlAttribute(value.id)}" data-toc-min-level="${options.minLevel}" data-toc-max-level="${options.maxLevel}" data-toc-hyperlinks="${String(options.hyperlinks)}" data-toc-show-page-numbers="${String(options.showPageNumbers)}" data-toc-right-align-page-numbers="${String(options.rightAlignPageNumbers)}" data-toc-leader="${options.leader}" data-toc-entries="${escapeHtmlAttribute(JSON.stringify(value.entries))}" data-toc-truncated="${String(value.truncated)}" class="work-document-table-of-contents" contenteditable="false" aria-label="目录">`,
2314
+ '<div class="work-document-table-of-contents-header"><strong>目录</strong>',
2315
+ `<span>${status}</span></div>`,
2316
+ '<ol class="work-document-table-of-contents-list">',
2317
+ ...rows,
2318
+ '</ol></div>'
2319
+ ].join('');
2320
+ }
2321
+ function normalizeDocumentTableOfContentsHtml(source) {
2322
+ const document = new DOMParser().parseFromString(source, 'text/html');
2323
+ const usedIds = new Set();
2324
+ for (const [index, element] of Array.from(document.body.querySelectorAll(TABLE_OF_CONTENTS_SELECTOR)).entries()){
2325
+ const value = documentTableOfContentsValueFromElement(element, index + 1);
2326
+ value.id = uniqueTableOfContentsId(value.id, index + 1, usedIds);
2327
+ const replacement = document.createRange().createContextualFragment(documentTableOfContentsHtml(value));
2328
+ element.replaceWith(replacement);
2329
+ }
2330
+ return document.body.innerHTML;
2331
+ }
2332
+ function documentTableOfContentsValueFromElement(element, index = 1) {
2333
+ const entries = parseTableOfContentsEntries(element.dataset.tocEntries);
2334
+ return normalizeDocumentTableOfContentsValue({
2335
+ id: validTableOfContentsId(element.dataset.tocId) ?? `toc-${index}`,
2336
+ options: {
2337
+ minLevel: Number(element.dataset.tocMinLevel),
2338
+ maxLevel: Number(element.dataset.tocMaxLevel),
2339
+ hyperlinks: 'false' !== element.dataset.tocHyperlinks,
2340
+ showPageNumbers: 'false' !== element.dataset.tocShowPageNumbers,
2341
+ rightAlignPageNumbers: 'false' !== element.dataset.tocRightAlignPageNumbers,
2342
+ leader: tableOfContentsLeader(element.dataset.tocLeader) ?? 'dot'
2343
+ },
2344
+ entries,
2345
+ truncated: 'true' === element.dataset.tocTruncated
2346
+ });
2347
+ }
2348
+ function parseDocumentTableOfContentsInstruction(instruction) {
2349
+ const command = /^\s*TOC\b/i.exec(instruction);
2350
+ if (!command) return {
2351
+ supported: false,
2352
+ reason: 'not-table-of-contents'
2353
+ };
2354
+ const source = instruction.slice(command[0].length);
2355
+ const switches = new Map();
2356
+ const matcher = /\\([a-z])(?:\s+("([^"]*)"|([^\\\s]+)))?/gi;
2357
+ let cursor = 0;
2358
+ for(let match = matcher.exec(source); match; match = matcher.exec(source)){
2359
+ if (source.slice(cursor, match.index).trim()) return {
2360
+ supported: false,
2361
+ reason: 'invalid-instruction'
2362
+ };
2363
+ const name = match[1]?.toLowerCase() ?? '';
2364
+ if (!name || switches.has(name)) return {
2365
+ supported: false,
2366
+ reason: 'invalid-instruction'
2367
+ };
2368
+ switches.set(name, match[3] ?? match[4] ?? null);
2369
+ cursor = matcher.lastIndex;
2370
+ }
2371
+ if (source.slice(cursor).trim()) return {
2372
+ supported: false,
2373
+ reason: 'invalid-instruction'
2374
+ };
2375
+ for (const name of switches.keys())if (![
2376
+ 'o',
2377
+ 'h',
2378
+ 'z',
2379
+ 'u',
2380
+ 'n',
2381
+ 'p'
2382
+ ].includes(name)) return {
2383
+ supported: false,
2384
+ reason: 'unsupported-switch'
2385
+ };
2386
+ const range = switches.has('o') ? parseTableOfContentsRange(switches.get('o')) : {
2387
+ minLevel: 1,
2388
+ maxLevel: 3
2389
+ };
2390
+ if (!range) return {
2391
+ supported: false,
2392
+ reason: 'invalid-level-range'
2393
+ };
2394
+ const pageRange = switches.has('n') ? parseOptionalTableOfContentsRange(switches.get('n')) : null;
2395
+ if (switches.has('n') && void 0 === pageRange) return {
2396
+ supported: false,
2397
+ reason: 'invalid-level-range'
2398
+ };
2399
+ if (pageRange && (pageRange.minLevel !== range.minLevel || pageRange.maxLevel !== range.maxLevel)) return {
2400
+ supported: false,
2401
+ reason: 'unsupported-page-range'
2402
+ };
2403
+ const separator = switches.get('p');
2404
+ if (switches.has('p') && (null == separator || separator.trim())) return {
2405
+ supported: false,
2406
+ reason: 'unsupported-separator'
2407
+ };
2408
+ const showPageNumbers = !switches.has('n');
2409
+ const rightAlignPageNumbers = showPageNumbers && !switches.has('p');
2410
+ return {
2411
+ supported: true,
2412
+ options: {
2413
+ ...range,
2414
+ hyperlinks: switches.has('h'),
2415
+ showPageNumbers,
2416
+ rightAlignPageNumbers,
2417
+ leader: rightAlignPageNumbers ? 'dot' : 'none'
2418
+ }
2419
+ };
2420
+ }
2421
+ function tableOfContentsLeader(value) {
2422
+ return 'dot' === value || 'dash' === value || 'underline' === value || 'none' === value ? value : null;
2423
+ }
2424
+ function normalizeDocumentTableOfContentsValue(source) {
2425
+ return {
2426
+ id: validTableOfContentsId(source.id) ?? 'document-table-of-contents',
2427
+ options: normalizeDocumentTableOfContentsOptions(source.options),
2428
+ entries: normalizeTableOfContentsEntries(source.entries),
2429
+ truncated: Boolean(source.truncated)
2430
+ };
2431
+ }
2432
+ function tableOfContentsEntryFromOutline(document, item, resolveContext) {
2433
+ return {
2434
+ targetId: item.id,
2435
+ title: item.text.slice(0, MAX_TABLE_OF_CONTENTS_TITLE_LENGTH),
2436
+ level: item.level,
2437
+ pageNumber: positiveInteger(resolveContext?.(item.from)?.pageNumber) ?? fallbackDocumentPageNumber(document, item.from)
2438
+ };
2439
+ }
2440
+ function fallbackDocumentPageNumber(document, position) {
2441
+ let pageNumber = 1;
2442
+ document.descendants((node, offset)=>{
2443
+ if (offset >= position) return false;
2444
+ if ('pageBreak' === node.type.name) pageNumber += 1;
2445
+ return true;
2446
+ });
2447
+ return pageNumber;
2448
+ }
2449
+ function tableOfContentsEntryHtml(entry, options) {
2450
+ const title = escapeHtml(entry.title);
2451
+ const targetId = escapeHtmlAttribute(entry.targetId);
2452
+ const label = options.hyperlinks ? `<a href="#${targetId}" data-toc-target="${targetId}" tabindex="-1">${title}</a>` : `<span>${title}</span>`;
2453
+ const page = options.showPageNumbers ? `<span class="work-document-table-of-contents-page">${entry.pageNumber}</span>` : '';
2454
+ return `<li data-toc-target="${targetId}" data-toc-level="${entry.level}" style="--work-toc-level:${entry.level}">${label}<i aria-hidden="true"></i>${page}</li>`;
2455
+ }
2456
+ function parseTableOfContentsEntries(source) {
2457
+ if (!source) return [];
2458
+ try {
2459
+ const parsed = JSON.parse(source);
2460
+ return Array.isArray(parsed) ? normalizeTableOfContentsEntries(parsed) : [];
2461
+ } catch {
2462
+ return [];
2463
+ }
2464
+ }
2465
+ function normalizeTableOfContentsEntries(source) {
2466
+ const entries = [];
2467
+ for (const value of source.slice(0, MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES)){
2468
+ if (!value || 'object' != typeof value) continue;
2469
+ const candidate = value;
2470
+ const targetId = 'string' == typeof candidate.targetId ? candidate.targetId.trim() : '';
2471
+ const title = 'string' == typeof candidate.title ? candidate.title.replace(/\s+/g, ' ').trim() : '';
2472
+ const level = boundedLevel(candidate.level, 0);
2473
+ const pageNumber = positiveInteger(candidate.pageNumber);
2474
+ if (TABLE_OF_CONTENTS_TARGET_PATTERN.test(targetId) && title && level && pageNumber) entries.push({
2475
+ targetId,
2476
+ title: title.slice(0, MAX_TABLE_OF_CONTENTS_TITLE_LENGTH),
2477
+ level,
2478
+ pageNumber
2479
+ });
2480
+ }
2481
+ return entries;
2482
+ }
2483
+ function parseTableOfContentsRange(value) {
2484
+ if (null == value) return null;
2485
+ const match = /^([1-9])-([1-9])$/.exec(value.trim());
2486
+ if (!match) return null;
2487
+ const minLevel = Number(match[1]);
2488
+ const maxLevel = Number(match[2]);
2489
+ return minLevel <= maxLevel ? {
2490
+ minLevel,
2491
+ maxLevel
2492
+ } : null;
2493
+ }
2494
+ function parseOptionalTableOfContentsRange(value) {
2495
+ if (null === value) return null;
2496
+ return parseTableOfContentsRange(value) ?? void 0;
2497
+ }
2498
+ function boundedLevel(value, fallback) {
2499
+ const number = Number(value);
2500
+ return Number.isInteger(number) && number >= 1 && number <= 9 ? number : fallback;
2501
+ }
2502
+ function positiveInteger(value) {
2503
+ const number = Number(value);
2504
+ return Number.isSafeInteger(number) && number > 0 ? Math.min(999999, number) : null;
2505
+ }
2506
+ function validTableOfContentsId(value) {
2507
+ return 'string' == typeof value && TABLE_OF_CONTENTS_ID_PATTERN.test(value) ? value : null;
2508
+ }
2509
+ function uniqueTableOfContentsId(source, index, usedIds) {
2510
+ if (!usedIds.has(source)) {
2511
+ usedIds.add(source);
2512
+ return source;
2513
+ }
2514
+ let suffix = index;
2515
+ while(usedIds.has(`document-table-of-contents-${suffix}`))suffix += 1;
2516
+ const id = `document-table-of-contents-${suffix}`;
2517
+ usedIds.add(id);
2518
+ return id;
2519
+ }
2520
+ function escapeHtml(value) {
2521
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
2522
+ }
2523
+ function escapeHtmlAttribute(value) {
2524
+ return escapeHtml(value).replaceAll('"', '&quot;').replaceAll("'", '&#39;');
2525
+ }
2526
+ const WORK_TEMPLATES = [
2527
+ {
2528
+ id: 'blank-document',
2529
+ kind: 'document',
2530
+ name: '空白文字',
2531
+ description: '从一张干净的 A4 页面开始',
2532
+ accent: '#2f6fed'
2533
+ },
2534
+ {
2535
+ id: 'project-brief',
2536
+ kind: 'document',
2537
+ name: '项目方案',
2538
+ description: '目标、范围、里程碑与风险',
2539
+ accent: '#536de2'
2540
+ },
2541
+ {
2542
+ id: 'table-of-contents',
2543
+ kind: 'document',
2544
+ name: '可更新目录',
2545
+ description: '标题级别、超链接、页码、前导符与原生 DOCX 往返',
2546
+ accent: '#315f9f'
2547
+ },
2548
+ {
2549
+ id: 'text-effects',
2550
+ kind: 'document',
2551
+ name: '文字效果',
2552
+ description: '空心、阴影、阳文与阴文',
2553
+ accent: '#6b5bd2'
2554
+ },
2555
+ {
2556
+ id: 'run-borders',
2557
+ kind: 'document',
2558
+ name: '字符边框',
2559
+ description: '原生线型、颜色、宽度、间距与阴影',
2560
+ accent: '#4472c4'
2561
+ },
2562
+ {
2563
+ id: 'run-shading',
2564
+ kind: 'document',
2565
+ name: '字符底纹',
2566
+ description: '原生图案、前景色、背景色与显式重置',
2567
+ accent: '#70ad47'
2568
+ },
2569
+ {
2570
+ id: 'proofing-languages',
2571
+ kind: 'document',
2572
+ name: '校对语言',
2573
+ description: '拉丁、东亚、双向文字与校对排除',
2574
+ accent: '#2f6fed'
2575
+ },
2576
+ {
2577
+ id: 'blank-markdown',
2578
+ kind: 'markdown',
2579
+ name: '空白 Markdown',
2580
+ description: '用轻量标记编写结构化内容',
2581
+ accent: '#586574'
2582
+ },
2583
+ {
2584
+ id: 'blank-spreadsheet',
2585
+ kind: 'spreadsheet',
2586
+ name: '空白表格',
2587
+ description: '公式、表格、筛选与多工作表',
2588
+ accent: '#16a36a'
2589
+ },
2590
+ {
2591
+ id: 'quarterly-plan',
2592
+ kind: 'spreadsheet',
2593
+ name: '季度计划',
2594
+ description: '目标进度与预算跟踪',
2595
+ accent: '#168f72'
2596
+ },
2597
+ {
2598
+ id: 'data-validation',
2599
+ kind: 'spreadsheet',
2600
+ name: '数据验证',
2601
+ description: '下拉列表、输入提示与错误警告',
2602
+ accent: '#13795b'
2603
+ },
2604
+ {
2605
+ id: 'blank-presentation',
2606
+ kind: 'presentation',
2607
+ name: '空白演示',
2608
+ description: '16:9 宽屏演示文稿',
2609
+ accent: '#e16b3d'
2610
+ },
2611
+ {
2612
+ id: 'strategy-deck',
2613
+ kind: 'presentation',
2614
+ name: '策略汇报',
2615
+ description: '结论先行的三页汇报',
2616
+ accent: '#c85637'
2617
+ }
2618
+ ];
2619
+ function createWorkArtifact(templateId) {
2620
+ const template = WORK_TEMPLATES.find((item)=>item.id === templateId) ?? WORK_TEMPLATES[0];
2621
+ const now = Date.now();
2622
+ return {
2623
+ id: createWorkId('artifact'),
2624
+ kind: template.kind,
2625
+ title: initialTitle(template.id, template.kind),
2626
+ favorite: false,
2627
+ createdAt: now,
2628
+ updatedAt: now,
2629
+ lastOpenedAt: now,
2630
+ revision: 1,
2631
+ content: contentForTemplate(template.id)
2632
+ };
2633
+ }
2634
+ function createWorkId(prefix) {
2635
+ const random = "u" > typeof crypto && 'function' == typeof crypto.randomUUID ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
2636
+ return `${prefix}-${random}`;
2637
+ }
2638
+ function initialTitle(templateId, kind) {
2639
+ const titles = {
2640
+ 'project-brief': '新项目方案',
2641
+ 'table-of-contents': '可更新目录示例',
2642
+ 'text-effects': '文字效果示例',
2643
+ 'run-borders': '字符边框示例',
2644
+ 'run-shading': '字符底纹示例',
2645
+ 'proofing-languages': '校对语言示例',
2646
+ 'quarterly-plan': '季度执行计划',
2647
+ 'data-validation': '数据验证示例',
2648
+ 'strategy-deck': '业务策略汇报'
2649
+ };
2650
+ if (titles[templateId]) return titles[templateId];
2651
+ if ('document' === kind) return '无标题文字';
2652
+ if ('markdown' === kind) return '无标题 Markdown';
2653
+ if ('spreadsheet' === kind) return '无标题表格';
2654
+ return '无标题演示';
2655
+ }
2656
+ function contentForTemplate(templateId) {
2657
+ if ('project-brief' === templateId) return {
2658
+ type: 'document',
2659
+ pageSize: 'a4',
2660
+ html: "<h1>新项目方案</h1><p><strong>负责人:</strong>项目团队  <strong>更新日期:</strong>今天</p><blockquote><p>用一句话说明这项工作的目标,以及完成后会带来什么变化。</p></blockquote><h2>背景与目标</h2><p>描述当前情况、核心问题和可衡量的成功标准。</p><h2>工作范围</h2><ul><li><p>需要完成的关键交付物</p></li><li><p>明确不在本期范围内的事项</p></li></ul><h2>里程碑</h2><ol><li><p>方案确认</p></li><li><p>执行与评审</p></li><li><p>交付与复盘</p></li></ol><h2>风险与决策</h2><p>记录尚未解决的问题、依赖和决策负责人。</p>"
2661
+ };
2662
+ if ('table-of-contents' === templateId) return {
2663
+ type: 'document',
2664
+ pageSize: 'a4',
2665
+ html: [
2666
+ documentTableOfContentsHtml({
2667
+ id: 'playground-table-of-contents',
2668
+ options: {
2669
+ minLevel: 1,
2670
+ maxLevel: 3,
2671
+ hyperlinks: true,
2672
+ showPageNumbers: true,
2673
+ rightAlignPageNumbers: true,
2674
+ leader: 'dot'
2675
+ },
2676
+ entries: [
2677
+ {
2678
+ targetId: 'heading-00001001',
2679
+ title: '项目概述',
2680
+ level: 1,
2681
+ pageNumber: 1
2682
+ },
2683
+ {
2684
+ targetId: 'heading-00001002',
2685
+ title: '目标与范围',
2686
+ level: 2,
2687
+ pageNumber: 1
2688
+ },
2689
+ {
2690
+ targetId: 'heading-00001003',
2691
+ title: '实施计划',
2692
+ level: 1,
2693
+ pageNumber: 2
2694
+ }
2695
+ ]
2696
+ }),
2697
+ '<h1 data-office-paragraph-id="00001001" data-office-paragraph-text-id="00002001">项目概述</h1>',
2698
+ '<p>目录是一个可选择、不可直接改写的结构化块。请从“引用”选项卡自定义或更新它。</p>',
2699
+ '<h2 data-office-paragraph-id="00001002" data-office-paragraph-text-id="00002002">目标与范围</h2>',
2700
+ '<p>修改标题文字后,使用“更新目录”同步标题与当前分页页码。</p>',
2701
+ '<hr class="work-page-break" data-page-break="true">',
2702
+ '<h1 data-office-paragraph-id="00001003" data-office-paragraph-text-id="00002003">实施计划</h1>',
2703
+ '<p>导出 DOCX 后仍保留原生 TOC 域、缓存目录项、超链接和前导符。</p>'
2704
+ ].join('')
2705
+ };
2706
+ if ('text-effects' === templateId) return {
2707
+ type: 'document',
2708
+ pageSize: 'a4',
2709
+ html: '<h1>原生文字效果</h1><p>选择下面任一示例并打开字体高级设置,可以组合空心与阴影,或在互斥的阳文和阴文之间切换。</p><h2>可组合效果</h2><p><span data-office-legacy-text-outline="true" data-office-legacy-text-shadow="true">空心 + 阴影</span></p><p><span data-office-legacy-text-outline="true">空心</span></p><p><span data-office-legacy-text-shadow="true">阴影</span></p><h2>互斥效果</h2><p><span data-office-legacy-text-emboss="true">阳文</span></p><p><span data-office-legacy-text-imprint="true">阴文</span></p>'
2710
+ };
2711
+ if ('run-borders' === templateId) return {
2712
+ type: 'document',
2713
+ pageSize: 'a4',
2714
+ html: [
2715
+ '<h1>原生字符边框</h1>',
2716
+ '<p>选择任一示例,可从开始选项卡直接开关边框,或在字体高级设置中编辑完整的原生线型、颜色、宽度、文字间距、阴影和框架属性。</p>',
2717
+ '<h2>常用线型</h2>',
2718
+ `<p>${runBorderTemplateSpan({
2719
+ style: 'single',
2720
+ color: {
2721
+ value: '#4472c4'
2722
+ },
2723
+ size: 4,
2724
+ space: 1
2725
+ }, '单实线字符边框')}</p>`,
2726
+ `<p>${runBorderTemplateSpan({
2727
+ style: 'double',
2728
+ color: {
2729
+ value: '#c00000'
2730
+ },
2731
+ size: 8,
2732
+ space: 2
2733
+ }, '双线字符边框')}</p>`,
2734
+ `<p>${runBorderTemplateSpan({
2735
+ style: 'wave',
2736
+ color: {
2737
+ value: '#7030a0'
2738
+ },
2739
+ size: 8,
2740
+ space: 2
2741
+ }, '波浪字符边框')}</p>`,
2742
+ '<h2>高级属性</h2>',
2743
+ `<p>${runBorderTemplateSpan({
2744
+ style: 'thinThickMediumGap',
2745
+ color: {
2746
+ value: '#0070c0'
2747
+ },
2748
+ size: 16,
2749
+ space: 3,
2750
+ shadow: true,
2751
+ frame: true
2752
+ }, '阴影与框架字符边框')}</p>`
2753
+ ].join('')
2754
+ };
2755
+ if ('run-shading' === templateId) return {
2756
+ type: 'document',
2757
+ pageSize: 'a4',
2758
+ html: [
2759
+ '<h1>原生字符底纹</h1>',
2760
+ '<p>选择任一示例并打开字体高级设置,可以编辑完整的原生图案、前景色、背景色,或写入显式无底纹重置。</p>',
2761
+ '<h2>基本填充</h2>',
2762
+ `<p>${runShadingTemplateSpan({
2763
+ pattern: 'clear',
2764
+ fill: {
2765
+ value: '#fff2cc'
2766
+ }
2767
+ }, '清除图案使用背景色')}</p>`,
2768
+ `<p>${runShadingTemplateSpan({
2769
+ pattern: 'solid',
2770
+ color: {
2771
+ value: '#4472c4'
2772
+ }
2773
+ }, '实心图案使用前景色')}</p>`,
2774
+ '<h2>图案与密度</h2>',
2775
+ `<p>${runShadingTemplateSpan({
2776
+ pattern: 'diagCross',
2777
+ color: {
2778
+ value: '#c00000'
2779
+ },
2780
+ fill: {
2781
+ value: '#fce4d6'
2782
+ }
2783
+ }, '对角交叉字符底纹')}</p>`,
2784
+ `<p>${runShadingTemplateSpan({
2785
+ pattern: 'pct25',
2786
+ color: {
2787
+ value: '#4472c4'
2788
+ },
2789
+ fill: {
2790
+ value: '#ddebf7'
2791
+ }
2792
+ }, '25% 字符底纹')}</p>`,
2793
+ `<p>${runShadingTemplateSpan({
2794
+ pattern: 'thinHorzStripe',
2795
+ color: {
2796
+ value: '#70ad47'
2797
+ },
2798
+ fill: {
2799
+ value: '#e2f0d9'
2800
+ }
2801
+ }, '细水平条纹字符底纹')}</p>`
2802
+ ].join('')
2803
+ };
2804
+ if ('proofing-languages' === templateId) {
2805
+ const languages = {
2806
+ latin: 'en-US',
2807
+ eastAsia: 'zh-CN',
2808
+ bidi: 'ar-SA'
2809
+ };
2810
+ return {
2811
+ type: 'document',
2812
+ pageSize: 'a4',
2813
+ html: [
2814
+ '<h1>原生校对语言</h1>',
2815
+ '<p>在“审阅”选项卡中打开“设置校对语言”,可以独立编辑拉丁、东亚和双向文字语言,并决定文字是否参与拼写与语法检查。</p>',
2816
+ '<h2>按文字系统设置</h2>',
2817
+ `<p>${proofingLanguageTemplateSpan(languages, false, 'ascii', 'English proofing language')}</p>`,
2818
+ `<p>${proofingLanguageTemplateSpan(languages, false, 'eastAsia', '简体中文校对语言')}</p>`,
2819
+ `<p dir="rtl">${proofingLanguageTemplateSpan(languages, false, 'complexScript', 'لغة التدقيق العربية')}</p>`,
2820
+ '<h2>校对行为</h2>',
2821
+ `<p>${proofingLanguageTemplateSpan({
2822
+ latin: 'en-GB'
2823
+ }, false, 'ascii', 'This text participates in proofing.')}</p>`,
2824
+ `<p>${proofingLanguageTemplateSpan({
2825
+ latin: 'x-none'
2826
+ }, true, 'ascii', 'A3S-API-v2: this product identifier is excluded from proofing.')}</p>`
2827
+ ].join('')
2828
+ };
2829
+ }
2830
+ if ('quarterly-plan' === templateId) return {
2831
+ type: 'spreadsheet',
2832
+ sheets: quarterlyPlanSheets()
2833
+ };
2834
+ if ('data-validation' === templateId) return {
2835
+ type: 'spreadsheet',
2836
+ sheets: dataValidationTemplateSheets()
2837
+ };
2838
+ if ('strategy-deck' === templateId) return strategyPresentation();
2839
+ if ('blank-spreadsheet' === templateId) return {
2840
+ type: 'spreadsheet',
2841
+ sheets: [
2842
+ blankSheet()
2843
+ ]
2844
+ };
2845
+ if ('blank-markdown' === templateId) return {
2846
+ type: 'markdown',
2847
+ markdown: ''
2848
+ };
2849
+ if ('blank-presentation' === templateId) return {
2850
+ type: 'presentation',
2851
+ slides: [
2852
+ blankSlide()
2853
+ ]
2854
+ };
2855
+ return {
2856
+ type: 'document',
2857
+ pageSize: 'a4',
2858
+ html: '<p></p>'
2859
+ };
2860
+ }
2861
+ function runBorderTemplateSpan(border, text) {
2862
+ const attributes = documentRunBorderDomAttributes(border);
2863
+ return `<span ${DOCUMENT_RUN_BORDER_ATTRIBUTE}='${attributes[DOCUMENT_RUN_BORDER_ATTRIBUTE]}' style="${attributes.style}">${text}</span>`;
2864
+ }
2865
+ function runShadingTemplateSpan(shading, text) {
2866
+ const attributes = documentRunShadingDomAttributes(shading);
2867
+ return `<span ${DOCUMENT_RUN_SHADING_ATTRIBUTE}='${attributes[DOCUMENT_RUN_SHADING_ATTRIBUTE]}' style="${attributes.style}">${text}</span>`;
2868
+ }
2869
+ function proofingLanguageTemplateSpan(languages, noProof, slot, text) {
2870
+ const attributes = documentProofingDomAttributes(languages, noProof, slot);
2871
+ return `<span ${Object.entries(attributes).map(([name, value])=>`${name}='${value}'`).join(' ')}>${text}</span>`;
2872
+ }
2873
+ function blankSheet() {
2874
+ return {
2875
+ id: createWorkId('sheet'),
2876
+ name: '工作表1',
2877
+ status: 1,
2878
+ order: 0,
2879
+ row: 60,
2880
+ column: 26,
2881
+ data: emptyMatrix(60, 26)
2882
+ };
2883
+ }
2884
+ function quarterlyPlanSheets() {
2885
+ const data = emptyMatrix(40, 12);
2886
+ data[0][0] = styledCell('季度执行计划', {
2887
+ bl: 1,
2888
+ fs: 16,
2889
+ fc: '#ffffff',
2890
+ bg: '#168f72'
2891
+ });
2892
+ data[2][0] = headerCell('目标');
2893
+ data[2][1] = headerCell('负责人');
2894
+ data[2][2] = headerCell('一月');
2895
+ data[2][3] = headerCell('二月');
2896
+ data[2][4] = headerCell('三月');
2897
+ data[2][5] = headerCell('完成率');
2898
+ data[2][6] = headerCell('状态');
2899
+ const rows = [
2900
+ [
2901
+ '客户洞察报告',
2902
+ '林岚',
2903
+ 1,
2904
+ 1,
2905
+ 0,
2906
+ '=SUM(C4:E4)/3',
2907
+ '进行中'
2908
+ ],
2909
+ [
2910
+ '新版发布',
2911
+ '周启',
2912
+ 0.8,
2913
+ 0.6,
2914
+ 0,
2915
+ '=AVERAGE(C5:E5)',
2916
+ '有风险'
2917
+ ],
2918
+ [
2919
+ '渠道增长',
2920
+ '陈一',
2921
+ 1,
2922
+ 0.9,
2923
+ 0.7,
2924
+ '=AVERAGE(C6:E6)',
2925
+ '正常'
2926
+ ],
2927
+ [
2928
+ '团队能力建设',
2929
+ '项目组',
2930
+ 1,
2931
+ 1,
2932
+ 1,
2933
+ '=AVERAGE(C7:E7)',
2934
+ '已完成'
2935
+ ]
2936
+ ];
2937
+ rows.forEach((row, rowIndex)=>{
2938
+ row.forEach((value, columnIndex)=>{
2939
+ data[rowIndex + 3][columnIndex] = styledCell(value, {
2940
+ bg: rowIndex % 2 ? '#f7faf9' : '#ffffff',
2941
+ ...columnIndex >= 2 && columnIndex <= 5 ? {
2942
+ ct: {
2943
+ fa: '0%',
2944
+ t: 'n'
2945
+ },
2946
+ ...'number' == typeof value ? {
2947
+ m: `${Math.round(100 * value)}%`
2948
+ } : {}
2949
+ } : {}
2950
+ });
2951
+ });
2952
+ });
2953
+ return [
2954
+ {
2955
+ id: createWorkId('sheet'),
2956
+ name: '执行看板',
2957
+ status: 1,
2958
+ order: 0,
2959
+ row: 40,
2960
+ column: 12,
2961
+ data,
2962
+ config: {
2963
+ columnlen: {
2964
+ 0: 180,
2965
+ 1: 96,
2966
+ 2: 76,
2967
+ 3: 76,
2968
+ 4: 76,
2969
+ 5: 96,
2970
+ 6: 96
2971
+ },
2972
+ rowlen: {
2973
+ 0: 34,
2974
+ 2: 28
2975
+ },
2976
+ merge: {
2977
+ '0_0': {
2978
+ r: 0,
2979
+ c: 0,
2980
+ rs: 1,
2981
+ cs: 7
2982
+ }
2983
+ }
2984
+ }
2985
+ }
2986
+ ];
2987
+ }
2988
+ function dataValidationTemplateSheets() {
2989
+ const inputs = emptyMatrix(24, 8);
2990
+ [
2991
+ 'Task',
2992
+ 'State',
2993
+ 'Due date',
2994
+ 'Priority',
2995
+ 'Owner'
2996
+ ].forEach((value, column)=>{
2997
+ inputs[0][column] = headerCell(value);
2998
+ });
2999
+ const rows = [
3000
+ [
3001
+ 'Confirm requirements',
3002
+ 'Ready',
3003
+ '2026-09-05',
3004
+ 2,
3005
+ 'Avery'
3006
+ ],
3007
+ [
3008
+ 'Review integration',
3009
+ 'In review',
3010
+ '2026-09-12',
3011
+ 3,
3012
+ 'Morgan'
3013
+ ],
3014
+ [
3015
+ 'Resolve blockers',
3016
+ 'Blocked',
3017
+ '2026-09-18',
3018
+ 5,
3019
+ 'Riley'
3020
+ ],
3021
+ [
3022
+ 'Publish preview',
3023
+ 'Ready',
3024
+ '2026-09-24',
3025
+ 1,
3026
+ 'Jordan'
3027
+ ],
3028
+ [
3029
+ 'Ship release',
3030
+ 'In review',
3031
+ '2026-09-30',
3032
+ 4,
3033
+ 'Taylor'
3034
+ ]
3035
+ ];
3036
+ rows.forEach((row, rowIndex)=>{
3037
+ row.forEach((value, columnIndex)=>{
3038
+ inputs[rowIndex + 1][columnIndex] = styledCell(value, {
3039
+ bg: rowIndex % 2 ? '#f4faf7' : '#ffffff'
3040
+ });
3041
+ });
3042
+ });
3043
+ return [
3044
+ {
3045
+ id: createWorkId('sheet'),
3046
+ name: 'Inputs',
3047
+ status: 1,
3048
+ order: 0,
3049
+ row: 24,
3050
+ column: 8,
3051
+ data: inputs,
3052
+ dataValidationRanges: [
3053
+ {
3054
+ ranges: [
3055
+ {
3056
+ row: [
3057
+ 1,
3058
+ 5
3059
+ ],
3060
+ column: [
3061
+ 1,
3062
+ 1
3063
+ ]
3064
+ }
3065
+ ],
3066
+ item: dataValidationTemplateItem({
3067
+ type: 'dropdown',
3068
+ rangeTxt: 'B2:B6',
3069
+ value1: "'Lists'!A1:A3",
3070
+ allowBlank: false,
3071
+ showDropdownArrow: true,
3072
+ errorStyle: 'stop',
3073
+ errorTitle: 'Invalid state',
3074
+ errorMessage: 'Choose a state from the list.',
3075
+ hintShow: true,
3076
+ hintTitle: 'Workflow state',
3077
+ hintValue: 'Choose Ready, Blocked, or In review.'
3078
+ })
3079
+ },
3080
+ {
3081
+ ranges: [
3082
+ {
3083
+ row: [
3084
+ 1,
3085
+ 5
3086
+ ],
3087
+ column: [
3088
+ 2,
3089
+ 2
3090
+ ]
3091
+ }
3092
+ ],
3093
+ item: dataValidationTemplateItem({
3094
+ type: 'date',
3095
+ type2: 'between',
3096
+ rangeTxt: 'C2:C6',
3097
+ value1: '2026-01-01',
3098
+ value2: '2026-12-31',
3099
+ errorStyle: 'information',
3100
+ errorTitle: 'Date outside 2026',
3101
+ errorMessage: 'Enter a date in calendar year 2026.',
3102
+ hintShow: true,
3103
+ hintTitle: 'Due date',
3104
+ hintValue: 'Use a date between 2026-01-01 and 2026-12-31.'
3105
+ })
3106
+ },
3107
+ {
3108
+ ranges: [
3109
+ {
3110
+ row: [
3111
+ 1,
3112
+ 5
3113
+ ],
3114
+ column: [
3115
+ 3,
3116
+ 3
3117
+ ]
3118
+ }
3119
+ ],
3120
+ item: dataValidationTemplateItem({
3121
+ type: 'number_integer',
3122
+ type2: 'between',
3123
+ rangeTxt: 'D2:D6',
3124
+ value1: '1',
3125
+ value2: '5',
3126
+ allowBlank: false,
3127
+ errorStyle: 'warning',
3128
+ errorTitle: 'Priority outside range',
3129
+ errorMessage: 'Enter a whole number from 1 through 5.',
3130
+ hintShow: true,
3131
+ hintTitle: 'Priority',
3132
+ hintValue: '1 is highest priority; 5 is lowest.'
3133
+ })
3134
+ }
3135
+ ],
3136
+ luckysheet_select_save: [
3137
+ {
3138
+ row: [
3139
+ 1,
3140
+ 5
3141
+ ],
3142
+ column: [
3143
+ 1,
3144
+ 1
3145
+ ],
3146
+ row_focus: 1,
3147
+ column_focus: 1
3148
+ }
3149
+ ],
3150
+ config: {
3151
+ columnlen: {
3152
+ 0: 190,
3153
+ 1: 110,
3154
+ 2: 118,
3155
+ 3: 84,
3156
+ 4: 104
3157
+ },
3158
+ rowlen: {
3159
+ 0: 30
3160
+ }
3161
+ }
3162
+ },
3163
+ {
3164
+ id: createWorkId('sheet'),
3165
+ name: 'Lists',
3166
+ status: 0,
3167
+ order: 1,
3168
+ row: 12,
3169
+ column: 3,
3170
+ data: [
3171
+ [
3172
+ styledCell('Ready')
3173
+ ],
3174
+ [
3175
+ styledCell('Blocked')
3176
+ ],
3177
+ [
3178
+ styledCell('In review')
3179
+ ]
3180
+ ],
3181
+ config: {
3182
+ columnlen: {
3183
+ 0: 120
3184
+ }
3185
+ }
3186
+ }
3187
+ ];
3188
+ }
3189
+ function dataValidationTemplateItem(overrides) {
3190
+ return {
3191
+ type: 'dropdown',
3192
+ type2: '',
3193
+ rangeTxt: '',
3194
+ value1: '',
3195
+ value2: '',
3196
+ validity: '',
3197
+ remote: false,
3198
+ allowBlank: true,
3199
+ showDropdownArrow: true,
3200
+ prohibitInput: true,
3201
+ errorStyle: 'stop',
3202
+ errorTitle: '',
3203
+ errorMessage: '',
3204
+ hintShow: false,
3205
+ hintTitle: '',
3206
+ hintValue: '',
3207
+ checked: false,
3208
+ ...overrides
3209
+ };
3210
+ }
3211
+ function emptyMatrix(rows, columns) {
3212
+ return Array.from({
3213
+ length: rows
3214
+ }, ()=>Array(columns).fill(null));
3215
+ }
3216
+ function styledCell(value, style = {}) {
3217
+ const formula = 'string' == typeof value && value.startsWith('=') ? value : void 0;
3218
+ return {
3219
+ v: formula ? void 0 : value,
3220
+ m: formula ? '' : String(value),
3221
+ f: formula,
3222
+ ...style
3223
+ };
3224
+ }
3225
+ function headerCell(value) {
3226
+ return styledCell(value, {
3227
+ bl: 1,
3228
+ fc: '#215446',
3229
+ bg: '#dff3ec',
3230
+ ht: 0,
3231
+ vt: 0
3232
+ });
3233
+ }
3234
+ function blankSlide() {
3235
+ return {
3236
+ id: createWorkId('slide'),
3237
+ name: '标题幻灯片',
3238
+ background: '#ffffff',
3239
+ elements: [
3240
+ {
3241
+ id: createWorkId('element'),
3242
+ type: 'text',
3243
+ x: 12,
3244
+ y: 25,
3245
+ width: 76,
3246
+ height: 18,
3247
+ text: '',
3248
+ fontSize: 34,
3249
+ color: '#172033',
3250
+ fill: 'transparent',
3251
+ bold: true,
3252
+ align: 'center',
3253
+ placeholder: {
3254
+ key: 'title',
3255
+ type: 'title',
3256
+ prompt: '单击添加标题'
3257
+ }
3258
+ },
3259
+ {
3260
+ id: createWorkId('element'),
3261
+ type: 'text',
3262
+ x: 18,
3263
+ y: 49,
3264
+ width: 64,
3265
+ height: 10,
3266
+ text: '',
3267
+ fontSize: 17,
3268
+ color: '#727b8f',
3269
+ fill: 'transparent',
3270
+ bold: false,
3271
+ align: 'center',
3272
+ placeholder: {
3273
+ key: 'subtitle',
3274
+ type: 'subtitle',
3275
+ prompt: '添加副标题'
3276
+ }
3277
+ }
3278
+ ]
3279
+ };
3280
+ }
3281
+ function strategyPresentation() {
3282
+ const slides = [
3283
+ {
3284
+ id: createWorkId('slide'),
3285
+ name: '封面',
3286
+ background: '#16213d',
3287
+ elements: [
3288
+ {
3289
+ id: createWorkId('element'),
3290
+ type: 'shape',
3291
+ x: 8,
3292
+ y: 12,
3293
+ width: 9,
3294
+ height: 3,
3295
+ text: '',
3296
+ fontSize: 12,
3297
+ color: '#ffffff',
3298
+ fill: '#ffb15a',
3299
+ bold: false,
3300
+ align: 'left',
3301
+ radius: 2
3302
+ },
3303
+ {
3304
+ id: createWorkId('element'),
3305
+ type: 'text',
3306
+ x: 8,
3307
+ y: 30,
3308
+ width: 72,
3309
+ height: 24,
3310
+ text: '业务策略汇报',
3311
+ fontSize: 38,
3312
+ color: '#ffffff',
3313
+ fill: 'transparent',
3314
+ bold: true,
3315
+ align: 'left'
3316
+ },
3317
+ {
3318
+ id: createWorkId('element'),
3319
+ type: 'text',
3320
+ x: 8,
3321
+ y: 58,
3322
+ width: 62,
3323
+ height: 10,
3324
+ text: '把最重要的结论放在标题中',
3325
+ fontSize: 17,
3326
+ color: '#b8c4df',
3327
+ fill: 'transparent',
3328
+ bold: false,
3329
+ align: 'left'
3330
+ }
3331
+ ]
3332
+ },
3333
+ {
3334
+ id: createWorkId('slide'),
3335
+ name: '核心判断',
3336
+ background: '#f7f4ee',
3337
+ elements: [
3338
+ {
3339
+ id: createWorkId('element'),
3340
+ type: 'text',
3341
+ x: 8,
3342
+ y: 10,
3343
+ width: 84,
3344
+ height: 11,
3345
+ text: '01 核心判断',
3346
+ fontSize: 15,
3347
+ color: '#b44e34',
3348
+ fill: 'transparent',
3349
+ bold: true,
3350
+ align: 'left'
3351
+ },
3352
+ {
3353
+ id: createWorkId('element'),
3354
+ type: 'text',
3355
+ x: 8,
3356
+ y: 27,
3357
+ width: 76,
3358
+ height: 22,
3359
+ text: '用一句可以独立成立的话,说明我们看到了什么。',
3360
+ fontSize: 31,
3361
+ color: '#20273a',
3362
+ fill: 'transparent',
3363
+ bold: true,
3364
+ align: 'left'
3365
+ },
3366
+ {
3367
+ id: createWorkId('element'),
3368
+ type: 'shape',
3369
+ x: 8,
3370
+ y: 60,
3371
+ width: 84,
3372
+ height: 22,
3373
+ text: '关键证据或数据',
3374
+ fontSize: 18,
3375
+ color: '#ffffff',
3376
+ fill: '#b44e34',
3377
+ bold: true,
3378
+ align: 'center',
3379
+ radius: 3
3380
+ }
3381
+ ]
3382
+ },
3383
+ {
3384
+ id: createWorkId('slide'),
3385
+ name: '下一步',
3386
+ background: '#ffffff',
3387
+ elements: [
3388
+ {
3389
+ id: createWorkId('element'),
3390
+ type: 'text',
3391
+ x: 8,
3392
+ y: 10,
3393
+ width: 84,
3394
+ height: 12,
3395
+ text: '02 下一步',
3396
+ fontSize: 15,
3397
+ color: '#b44e34',
3398
+ fill: 'transparent',
3399
+ bold: true,
3400
+ align: 'left'
3401
+ },
3402
+ {
3403
+ id: createWorkId('element'),
3404
+ type: 'text',
3405
+ x: 8,
3406
+ y: 28,
3407
+ width: 84,
3408
+ height: 46,
3409
+ text: '1 确认优先级\n2 指定负责人\n3 设定可验证的里程碑',
3410
+ fontSize: 26,
3411
+ color: '#20273a',
3412
+ fill: '#f3f0ea',
3413
+ bold: false,
3414
+ align: 'left',
3415
+ radius: 3
3416
+ }
3417
+ ]
3418
+ }
3419
+ ];
3420
+ return {
3421
+ type: 'presentation',
3422
+ slides
3423
+ };
3424
+ }
3425
+ const OFFICE_KERNEL_SPREADSHEET_MAX_ROWS = 1048576;
3426
+ const spreadsheetErrors = new Set([
3427
+ '#BLOCKED!',
3428
+ '#BUSY!',
3429
+ '#CALC!',
3430
+ '#CONNECT!',
3431
+ '#DIV/0!',
3432
+ '#FIELD!',
3433
+ '#GETTING_DATA',
3434
+ '#N/A',
3435
+ '#NAME?',
3436
+ '#NULL!',
3437
+ '#NUM!',
3438
+ '#PYTHON!',
3439
+ '#REF!',
3440
+ '#SPILL!',
3441
+ '#UNKNOWN!',
3442
+ '#VALUE!'
3443
+ ]);
3444
+ new TextEncoder();
3445
+ function isOfficeKernelSpreadsheetError(value) {
3446
+ return 'string' == typeof value && spreadsheetErrors.has(value);
3447
+ }
3448
+ export { DEFAULT_DOCUMENT_TABLE_OF_CONTENTS_OPTIONS, DOCUMENT_HIGHLIGHT_ATTRIBUTE, DOCUMENT_NO_PROOF_ATTRIBUTE, DOCUMENT_PARAGRAPH_BORDERS_ATTRIBUTE, DOCUMENT_PARAGRAPH_BORDER_EDGES, DOCUMENT_PARAGRAPH_BORDER_STYLES, DOCUMENT_PARAGRAPH_ID_ATTRIBUTE, DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE, DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE, DOCUMENT_RUN_BORDER_ATTRIBUTE, DOCUMENT_RUN_BORDER_STYLES, DOCUMENT_RUN_SHADING_ATTRIBUTE, DOCUMENT_SCRIPT_FONTS_ATTRIBUTE, DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE, DocumentParagraphIdentity, DocxThemePatchCollector, OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, OoxmlPackage, WORK_TEMPLATES as officeTemplates, applyDocumentParagraphIdentityToElement, attribute, buildDocumentTableOfContentsEntries, bytesToDataUrl, childPath, collectWorkDocumentOutline, contentTypeForPart, createDocumentParagraphIdentity, createDocumentParagraphIdentityRegistry, createWorkArtifact as createArtifact, createWorkId as createOfficeId, cssDocumentFontFamily, currentWorkDocumentOutlineItem, decodeXmlBytes, descendants, directChild, directChildren, documentBorderPresentation, documentFontNameFromCssFamily, documentHasIntegrityFeature, documentHighlightCssColor, documentHighlightDomAttributes, documentHighlightForCssColor, documentHighlightFromDocxValue, documentHighlightFromElement, documentNoProofFromElement, documentParagraphBordersDomAttributes, documentParagraphIdentityFromElement, documentParagraphShadingDomAttributes, documentProofingDomAttributes, documentProofingLanguagesFromElement, documentRunBorderDomAttributes, documentRunBorderIsVisible, documentRunShadingDomAttributes, documentScriptFontDirectFamily, documentScriptFontFallbackSlots, documentScriptFontFamily, documentScriptFontFamilyForRendering, documentScriptFontSegments, documentScriptFontSlotFromElement, documentScriptFontSlotFromHint, documentScriptFontsDomAttributes, documentScriptFontsForAllText, documentScriptFontsFromElement, documentTableOfContentsHtml, documentTableOfContentsValueFromElement, firstDescendant, isDocumentParagraphArtBorderStyle, isOfficeKernelSpreadsheetError, normalizeCssColor, normalizeDocumentFontName, normalizeDocumentHighlight, normalizeDocumentLanguageTag, normalizeDocumentNoProof, normalizeDocumentParagraphBorder, normalizeDocumentParagraphBorders, normalizeDocumentParagraphId, normalizeDocumentParagraphIdentity, normalizeDocumentProofingLanguages, normalizeDocumentRunBorder, normalizeDocumentRunShading, normalizeDocumentScriptFontHint, normalizeDocumentScriptFontSlot, normalizeDocumentScriptFonts, normalizeDocumentTableOfContentsHtml, normalizeDocumentTableOfContentsOptions, normalizeDocumentTableOfContentsValue, normalizeDocumentThemeFont, parseDocumentParagraphBorders, parseDocumentParagraphBordersElement, parseDocumentParagraphShading, parseDocumentParagraphShadingElement, parseDocumentProofingLanguages, parseDocumentRunBorder, parseDocumentRunBorderElement, parseDocumentRunShading, parseDocumentRunShadingElement, parseDocumentScriptFonts, parseDocumentTableOfContentsInstruction, parseDocxThemeReference, parseXml, patchDocumentProofingLanguages, patchDocumentScriptFonts, patchDocxThemeReferences, primeDocumentIntegrityFeatures, resolvePartTarget, serializeDocumentParagraphBorders, serializeDocumentParagraphShading, serializeDocumentProofingLanguages, serializeDocumentRunBorder, serializeDocumentRunShading, serializeDocumentScriptFonts, serializeDocxThemeReference, serializeUtf8Xml, uniqueDocumentParagraphIdentity, visibleWorkDocumentOutlineItems, workDocumentOutlineLevel, work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS, xmlContainsAnyElement, xmlNamespacePrefix };