@a3s-lab/office 0.1.0 → 0.2.2

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 +101 -24
  2. package/dist/0~2582.js +485 -0
  3. package/dist/0~4595.js +14 -7
  4. package/dist/0~4750.js +939 -0
  5. package/dist/{0~work-document-paragraph-formatting.js → 0~5861.js} +174 -3
  6. package/dist/0~7048.js +8 -6
  7. package/dist/0~9512.js +7 -4
  8. package/dist/0~document-editor.js +3147 -531
  9. package/dist/0~markdown-editor.js +26 -1
  10. package/dist/0~presentation-editor.js +68 -12
  11. package/dist/0~spreadsheet-editor.js +37 -17
  12. package/dist/0~work-document-extensions.js +588 -13
  13. package/dist/0~work-document-model-codec.js +1 -1
  14. package/dist/0~work-docx-bibliography.js +1 -1
  15. package/dist/0~work-docx-export.js +116 -55
  16. package/dist/0~work-docx-import.js +766 -107
  17. package/dist/0~work-office-diagnostics.js +2 -2
  18. package/dist/{4704.js → 2881.js} +162 -71
  19. package/dist/4104.js +2 -62
  20. package/dist/internal/features/work/editors/document-comment-window.d.ts +37 -0
  21. package/dist/internal/features/work/editors/document-navigation-panel.d.ts +3 -1
  22. package/dist/internal/features/work/editors/document-navigation-window.d.ts +64 -0
  23. package/dist/internal/features/work/editors/document-outline-navigation.d.ts +11 -0
  24. package/dist/internal/features/work/editors/document-page-navigation.d.ts +11 -1
  25. package/dist/internal/features/work/editors/document-page-thumbnail.d.ts +31 -0
  26. package/dist/internal/features/work/editors/document-picture-properties-dialog-model.d.ts +28 -0
  27. package/dist/internal/features/work/editors/document-picture-properties-dialog.d.ts +4 -0
  28. package/dist/internal/features/work/editors/document-search-navigation.d.ts +12 -0
  29. package/dist/internal/features/work/editors/document-table-margins-popover.d.ts +4 -0
  30. package/dist/internal/features/work/editors/document-table-properties-dialog-model.d.ts +51 -0
  31. package/dist/internal/features/work/editors/document-table-properties-dialog-sections.d.ts +19 -0
  32. package/dist/internal/features/work/editors/document-table-properties-dialog.d.ts +8 -0
  33. package/dist/internal/features/work/editors/office-task-pane.d.ts +1 -1
  34. package/dist/internal/features/work/editors/presentation-chart-panel.d.ts +2 -1
  35. package/dist/internal/features/work/editors/presentation-comments-panel.d.ts +2 -1
  36. package/dist/internal/features/work/editors/spreadsheet-workbook-panel.d.ts +2 -1
  37. package/dist/internal/features/work/editors/use-document-pagination.d.ts +6 -0
  38. package/dist/internal/features/work/editors/use-presentation-review-commands.d.ts +1 -1
  39. package/dist/internal/features/work/work-document-image-layout.d.ts +11 -0
  40. package/dist/internal/features/work/work-document-page-capture.d.ts +15 -0
  41. package/dist/internal/features/work/work-document-paragraph-formatting.d.ts +4 -0
  42. package/dist/internal/features/work/work-document-section.d.ts +3 -1
  43. package/dist/internal/features/work/work-document-table-borders.d.ts +20 -0
  44. package/dist/internal/features/work/work-document-table-cell-formatting.d.ts +8 -5
  45. package/dist/internal/features/work/work-document-table-geometry.d.ts +41 -0
  46. package/dist/internal/features/work/work-document-table-property-changes.d.ts +25 -0
  47. package/dist/internal/features/work/work-document-table-sizing.d.ts +15 -2
  48. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +11 -0
  49. package/dist/internal/features/work/work-docx-document-layout.d.ts +2 -0
  50. package/dist/internal/features/work/work-docx-paragraph-alignment-import.d.ts +2 -1
  51. package/dist/internal/features/work/work-docx-paragraph-direction-import.d.ts +2 -1
  52. package/dist/internal/features/work/work-docx-paragraph-indent-import.d.ts +2 -1
  53. package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +2 -1
  54. package/dist/internal/features/work/work-docx-paragraph-spacing-import.d.ts +3 -2
  55. package/dist/internal/features/work/work-docx-paragraph-styles.d.ts +2 -2
  56. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +8 -1
  57. package/dist/internal/features/work/work-docx-tab-stop-import.d.ts +2 -1
  58. package/dist/internal/features/work/work-docx-table-cell-export.d.ts +1 -1
  59. package/dist/internal/features/work/work-docx-table-cell-import.d.ts +14 -4
  60. package/dist/internal/features/work/work-docx-table-sizing-export.d.ts +1 -1
  61. package/dist/internal/features/work/work-docx-table-sizing-import.d.ts +4 -3
  62. package/dist/internal/features/work/work-docx-table-styles.d.ts +22 -0
  63. package/dist/internal/features/work/work-types.d.ts +6 -0
  64. package/dist/office-kernel.wasm +0 -0
  65. package/dist/styles.css +1288 -233
  66. package/docs/{browser-editor-architecture.md → latest/en/browser-editor-architecture.md} +144 -35
  67. package/package.json +9 -5
  68. package/dist/0~6552.js +0 -787
  69. package/dist/0~8155.js +0 -299
package/dist/0~4750.js ADDED
@@ -0,0 +1,939 @@
1
+ import { Extension, ResizableNodeView, mergeAttributes } from "@tiptap/core";
2
+ import extension_image from "@tiptap/extension-image";
3
+ import { closeHistory } from "@tiptap/pm/history";
4
+ import { NodeSelection } from "@tiptap/pm/state";
5
+ import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
6
+ const DEFAULT_IMAGE_LAYOUT = 'inline';
7
+ const DEFAULT_IMAGE_ALIGNMENT = 'center';
8
+ const DEFAULT_WRAP_DISTANCE_MILLIMETERS = 3;
9
+ const MAX_WRAP_DISTANCE_MILLIMETERS = 25;
10
+ const DEFAULT_LOCK_ASPECT_RATIO = true;
11
+ const DocumentImage = extension_image.extend({
12
+ addCommands () {
13
+ return {
14
+ ...this.parent?.() ?? {},
15
+ setDocumentImageProperties: (value, options = {})=>({ chain, state, tr })=>{
16
+ if (!isDocumentImageSelection(state.selection)) return false;
17
+ const attributes = documentImageAttributesForChanges(value);
18
+ if (!Object.keys(attributes).length) return false;
19
+ closeHistory(tr);
20
+ let commandChain = chain();
21
+ if (false !== options.restoreFocus) commandChain = commandChain.focus();
22
+ return commandChain.updateAttributes('image', attributes).run();
23
+ },
24
+ setDocumentImageAlternativeText: (alternativeText, options = {})=>({ commands })=>commands.setDocumentImageProperties({
25
+ alternativeText
26
+ }, options),
27
+ setDocumentImageLayoutOptions: (value, options = {})=>({ commands })=>commands.setDocumentImageProperties(value, options)
28
+ };
29
+ },
30
+ addAttributes () {
31
+ return {
32
+ ...this.parent?.(),
33
+ layout: {
34
+ default: DEFAULT_IMAGE_LAYOUT,
35
+ parseHTML: (element)=>normalizeDocumentImageLayout(element.getAttribute('data-office-image-layout')),
36
+ renderHTML: (attributes)=>({
37
+ 'data-office-image-layout': normalizeDocumentImageLayout(attributes.layout)
38
+ })
39
+ },
40
+ alignment: {
41
+ default: DEFAULT_IMAGE_ALIGNMENT,
42
+ parseHTML: (element)=>normalizeDocumentImageAlignment(element.getAttribute('data-office-image-alignment')),
43
+ renderHTML: (attributes)=>({
44
+ 'data-office-image-alignment': normalizeDocumentImageAlignment(attributes.alignment)
45
+ })
46
+ },
47
+ wrapDistance: {
48
+ default: DEFAULT_WRAP_DISTANCE_MILLIMETERS,
49
+ parseHTML: (element)=>normalizeDocumentImageWrapDistance(element.getAttribute('data-office-image-wrap-distance')),
50
+ renderHTML: (attributes)=>{
51
+ const distance = normalizeDocumentImageWrapDistance(attributes.wrapDistance);
52
+ return {
53
+ 'data-office-image-wrap-distance': formatImageLayoutNumber(distance),
54
+ style: `--work-document-image-wrap-distance:${formatImageLayoutNumber(distance)}mm`
55
+ };
56
+ }
57
+ },
58
+ lockAspectRatio: {
59
+ default: DEFAULT_LOCK_ASPECT_RATIO,
60
+ parseHTML: (element)=>normalizeDocumentImageLockAspectRatio(element.getAttribute('data-office-image-lock-aspect-ratio')),
61
+ renderHTML: (attributes)=>({
62
+ 'data-office-image-lock-aspect-ratio': String(normalizeDocumentImageLockAspectRatio(attributes.lockAspectRatio))
63
+ })
64
+ }
65
+ };
66
+ },
67
+ addNodeView () {
68
+ const resize = this.options.resize;
69
+ if (false === resize || !resize.enabled || "u" < typeof document) return null;
70
+ const { directions, minWidth, minHeight, alwaysPreserveAspectRatio } = resize;
71
+ return ({ node, getPos, HTMLAttributes, editor })=>{
72
+ const element = document.createElement('img');
73
+ element.draggable = false;
74
+ applyInitialImageHtmlAttributes(element, HTMLAttributes);
75
+ element.style.visibility = 'hidden';
76
+ element.style.pointerEvents = 'none';
77
+ const reveal = ()=>{
78
+ element.style.visibility = '';
79
+ element.style.pointerEvents = '';
80
+ };
81
+ element.addEventListener('load', reveal);
82
+ element.addEventListener('error', reveal);
83
+ let container = null;
84
+ const sync = (updatedNode)=>{
85
+ syncDocumentImageNodeView(element, container, updatedNode.attrs);
86
+ };
87
+ const nodeView = new ResizableNodeView({
88
+ element,
89
+ editor,
90
+ node,
91
+ getPos,
92
+ onResize: (width, height)=>{
93
+ element.style.width = `${width}px`;
94
+ element.style.height = `${height}px`;
95
+ },
96
+ onCommit: (width, height)=>{
97
+ const position = getPos();
98
+ if (void 0 === position) return;
99
+ editor.chain().setNodeSelection(position).updateAttributes(this.name, {
100
+ width,
101
+ height
102
+ }).run();
103
+ },
104
+ onUpdate: (updatedNode)=>{
105
+ if (updatedNode.type !== node.type) return false;
106
+ if (!sameDocumentImageResizeConfiguration(node, updatedNode)) return false;
107
+ sync(updatedNode);
108
+ return true;
109
+ },
110
+ options: {
111
+ directions,
112
+ min: {
113
+ width: minWidth,
114
+ height: minHeight
115
+ },
116
+ preserveAspectRatio: null === node.attrs.lockAspectRatio || void 0 === node.attrs.lockAspectRatio ? true === alwaysPreserveAspectRatio : normalizeDocumentImageLockAspectRatio(node.attrs.lockAspectRatio)
117
+ }
118
+ });
119
+ container = nodeView.dom;
120
+ sync(node);
121
+ if (element.complete) reveal();
122
+ return nodeView;
123
+ };
124
+ }
125
+ });
126
+ function documentImageLayoutOptions(editor) {
127
+ const attributes = editor.getAttributes('image');
128
+ return normalizeDocumentImageLayoutOptions(attributes);
129
+ }
130
+ function documentImageProperties(editor) {
131
+ const attributes = editor.getAttributes('image');
132
+ return {
133
+ ...normalizeDocumentImageLayoutOptions(attributes),
134
+ width: normalizeDocumentImageDimension(attributes.width),
135
+ height: normalizeDocumentImageDimension(attributes.height),
136
+ lockAspectRatio: normalizeDocumentImageLockAspectRatio(attributes.lockAspectRatio),
137
+ alternativeText: documentImageAlternativeText(editor)
138
+ };
139
+ }
140
+ function documentImageAlternativeText(editor) {
141
+ if (!editor.isActive('image')) return '';
142
+ const attributes = editor.getAttributes('image');
143
+ const value = 'string' == typeof attributes.alt ? attributes.alt : 'string' == typeof attributes.title ? attributes.title : '';
144
+ return value.trim();
145
+ }
146
+ function documentImageLayoutFromElement(element) {
147
+ return normalizeDocumentImageLayoutOptions({
148
+ layout: element.getAttribute('data-office-image-layout'),
149
+ alignment: element.getAttribute('data-office-image-alignment'),
150
+ wrapDistance: element.getAttribute('data-office-image-wrap-distance')
151
+ });
152
+ }
153
+ function normalizeDocumentImageLayoutOptions(value) {
154
+ return {
155
+ layout: normalizeDocumentImageLayout(value.layout),
156
+ alignment: normalizeDocumentImageAlignment(value.alignment),
157
+ wrapDistance: normalizeDocumentImageWrapDistance(value.wrapDistance)
158
+ };
159
+ }
160
+ function normalizeDocumentImageLayout(value) {
161
+ return 'square' === value || 'topBottom' === value ? value : DEFAULT_IMAGE_LAYOUT;
162
+ }
163
+ function normalizeDocumentImageAlignment(value) {
164
+ return 'left' === value || 'right' === value ? value : DEFAULT_IMAGE_ALIGNMENT;
165
+ }
166
+ function normalizeDocumentImageWrapDistance(value) {
167
+ const number = 'number' == typeof value ? value : 'string' == typeof value && value.trim() ? Number(value) : DEFAULT_WRAP_DISTANCE_MILLIMETERS;
168
+ if (!Number.isFinite(number)) return DEFAULT_WRAP_DISTANCE_MILLIMETERS;
169
+ return Math.round(2 * Math.min(MAX_WRAP_DISTANCE_MILLIMETERS, Math.max(0, number))) / 2;
170
+ }
171
+ function normalizeDocumentImageDimension(value) {
172
+ if (null == value || '' === value) return null;
173
+ const number = 'number' == typeof value ? value : Number(value);
174
+ return Number.isFinite(number) && number > 0 ? Math.round(100 * number) / 100 : null;
175
+ }
176
+ function normalizeDocumentImageLockAspectRatio(value) {
177
+ return false === value || 'false' === value || 0 === value || '0' === value ? false : DEFAULT_LOCK_ASPECT_RATIO;
178
+ }
179
+ function formatImageLayoutNumber(value) {
180
+ return Number(value.toFixed(2)).toString();
181
+ }
182
+ function documentImageAttributesForChanges(value) {
183
+ const attributes = {};
184
+ if (Object.hasOwn(value, 'width')) attributes.width = normalizeDocumentImageDimension(value.width);
185
+ if (Object.hasOwn(value, 'height')) attributes.height = normalizeDocumentImageDimension(value.height);
186
+ if (Object.hasOwn(value, 'lockAspectRatio')) attributes.lockAspectRatio = normalizeDocumentImageLockAspectRatio(value.lockAspectRatio);
187
+ if (Object.hasOwn(value, 'layout')) attributes.layout = normalizeDocumentImageLayout(value.layout);
188
+ if (Object.hasOwn(value, 'alignment')) attributes.alignment = normalizeDocumentImageAlignment(value.alignment);
189
+ if (Object.hasOwn(value, 'wrapDistance')) attributes.wrapDistance = normalizeDocumentImageWrapDistance(value.wrapDistance);
190
+ if (Object.hasOwn(value, 'alternativeText')) {
191
+ const alternativeText = value.alternativeText?.trim() ?? '';
192
+ attributes.alt = alternativeText || null;
193
+ attributes.title = alternativeText || null;
194
+ }
195
+ return attributes;
196
+ }
197
+ function isDocumentImageSelection(selection) {
198
+ return selection instanceof NodeSelection && 'image' === selection.node.type.name;
199
+ }
200
+ function sameDocumentImageResizeConfiguration(initial, current) {
201
+ return normalizeDocumentImageDimension(initial.attrs.width) === normalizeDocumentImageDimension(current.attrs.width) && normalizeDocumentImageDimension(initial.attrs.height) === normalizeDocumentImageDimension(current.attrs.height) && normalizeDocumentImageLockAspectRatio(initial.attrs.lockAspectRatio) === normalizeDocumentImageLockAspectRatio(current.attrs.lockAspectRatio);
202
+ }
203
+ function applyInitialImageHtmlAttributes(element, attributes) {
204
+ const merged = mergeAttributes(attributes);
205
+ for (const [name, value] of Object.entries(merged))if (null != value && 'width' !== name && 'height' !== name) element.setAttribute(name, String(value));
206
+ }
207
+ function syncDocumentImageNodeView(element, container, attributes) {
208
+ const layout = normalizeDocumentImageLayout(attributes.layout);
209
+ const alignment = normalizeDocumentImageAlignment(attributes.alignment);
210
+ const wrapDistance = normalizeDocumentImageWrapDistance(attributes.wrapDistance);
211
+ const lockAspectRatio = normalizeDocumentImageLockAspectRatio(attributes.lockAspectRatio);
212
+ setOptionalImageAttribute(element, 'src', attributes.src);
213
+ setOptionalImageAttribute(element, 'alt', attributes.alt);
214
+ setOptionalImageAttribute(element, 'title', attributes.title);
215
+ element.dataset.officeImageLayout = layout;
216
+ element.dataset.officeImageAlignment = alignment;
217
+ element.dataset.officeImageWrapDistance = formatImageLayoutNumber(wrapDistance);
218
+ element.dataset.officeImageLockAspectRatio = String(lockAspectRatio);
219
+ element.style.setProperty('--work-document-image-wrap-distance', `${formatImageLayoutNumber(wrapDistance)}mm`);
220
+ syncImageDimension(element, 'width', attributes.width);
221
+ syncImageDimension(element, 'height', attributes.height);
222
+ if (!container) return;
223
+ container.dataset.officeImageLayout = layout;
224
+ container.dataset.officeImageAlignment = alignment;
225
+ container.dataset.officeImageWrapDistance = formatImageLayoutNumber(wrapDistance);
226
+ container.dataset.officeImageLockAspectRatio = String(lockAspectRatio);
227
+ container.style.setProperty('--work-document-image-wrap-distance', `${formatImageLayoutNumber(wrapDistance)}mm`);
228
+ }
229
+ function setOptionalImageAttribute(element, name, value) {
230
+ if ('string' == typeof value && value) element.setAttribute(name, value);
231
+ else element.removeAttribute(name);
232
+ }
233
+ function syncImageDimension(element, dimension, value) {
234
+ const pixels = 'number' == typeof value ? value : Number(value);
235
+ if (Number.isFinite(pixels) && pixels > 0) {
236
+ element.style[dimension] = `${pixels}px`;
237
+ element.setAttribute(dimension, String(Math.round(pixels)));
238
+ return;
239
+ }
240
+ element.style.removeProperty(dimension);
241
+ element.removeAttribute(dimension);
242
+ }
243
+ const MAX_DOCUMENT_TAB_POSITION_PX = 4096;
244
+ const MAX_DOCUMENT_TAB_STOPS = 64;
245
+ const DocumentParagraphTabStops = Extension.create({
246
+ name: 'documentParagraphTabStops',
247
+ addGlobalAttributes () {
248
+ return [
249
+ {
250
+ types: [
251
+ 'paragraph',
252
+ 'heading'
253
+ ],
254
+ attributes: {
255
+ tabStops: {
256
+ default: null,
257
+ parseHTML: (element)=>normalizeDocumentTabStops(element.dataset.officeTabStops),
258
+ renderHTML: (attributes)=>{
259
+ const tabStops = normalizeDocumentTabStops(attributes.tabStops);
260
+ return tabStops.length ? {
261
+ 'data-office-tab-stops': serializeDocumentTabStops(tabStops)
262
+ } : {};
263
+ }
264
+ }
265
+ }
266
+ }
267
+ ];
268
+ },
269
+ addCommands () {
270
+ return {
271
+ setDocumentParagraphTabStops: (tabStops, options = {})=>({ chain, editor })=>{
272
+ const nodeTypes = activeParagraphNodeTypes(editor);
273
+ if (!nodeTypes.length) return false;
274
+ const normalized = normalizeDocumentTabStops(tabStops);
275
+ let commandChain = chain();
276
+ if (false !== options.restoreFocus) commandChain = commandChain.focus();
277
+ for (const nodeType of nodeTypes)commandChain = commandChain.updateAttributes(nodeType, {
278
+ tabStops: normalized.length ? normalized : null
279
+ });
280
+ return commandChain.run();
281
+ }
282
+ };
283
+ }
284
+ });
285
+ function documentParagraphTabStops(editor) {
286
+ return normalizeDocumentTabStops(activeParagraphAttributes(editor).tabStops);
287
+ }
288
+ function normalizeDocumentTabStops(value) {
289
+ const source = parsedTabStopSource(value);
290
+ const byPosition = new Map();
291
+ for (const candidate of source.slice(0, 4 * MAX_DOCUMENT_TAB_STOPS)){
292
+ if (!isRecord(candidate)) continue;
293
+ const rawPosition = Number(candidate.position);
294
+ if (!Number.isFinite(rawPosition) || rawPosition <= 0) continue;
295
+ const position = normalizedTabPosition(rawPosition);
296
+ if (!(position <= 0)) byPosition.set(position, {
297
+ position,
298
+ alignment: normalizedTabAlignment(candidate.alignment),
299
+ leader: normalizedTabLeader(candidate.leader)
300
+ });
301
+ }
302
+ return Array.from(byPosition.values()).sort((left, right)=>left.position - right.position).slice(0, MAX_DOCUMENT_TAB_STOPS);
303
+ }
304
+ function serializeDocumentTabStops(value) {
305
+ return JSON.stringify(normalizeDocumentTabStops(value));
306
+ }
307
+ function normalizedTabPosition(value) {
308
+ if (!Number.isFinite(value)) return 0;
309
+ return Math.min(MAX_DOCUMENT_TAB_POSITION_PX, Math.max(0, Math.round(100 * value) / 100));
310
+ }
311
+ function nextDocumentTabAlignment(alignment) {
312
+ if ('left' === alignment) return 'center';
313
+ if ('center' === alignment) return 'right';
314
+ if ('right' === alignment) return 'decimal';
315
+ return 'left';
316
+ }
317
+ function parsedTabStopSource(value) {
318
+ if (Array.isArray(value)) return value;
319
+ if ('string' != typeof value || !value.trim()) return [];
320
+ try {
321
+ const parsed = JSON.parse(value);
322
+ return Array.isArray(parsed) ? parsed : [];
323
+ } catch {
324
+ return [];
325
+ }
326
+ }
327
+ function normalizedTabAlignment(value) {
328
+ return 'center' === value || 'right' === value || 'decimal' === value ? value : 'left';
329
+ }
330
+ function normalizedTabLeader(value) {
331
+ return 'dot' === value || 'hyphen' === value || 'underscore' === value || 'middleDot' === value ? value : 'none';
332
+ }
333
+ function activeParagraphAttributes(editor) {
334
+ return editor.isActive('heading') ? editor.getAttributes('heading') : editor.getAttributes('paragraph');
335
+ }
336
+ function activeParagraphNodeTypes(editor) {
337
+ const types = [];
338
+ if (editor.isActive('paragraph')) types.push('paragraph');
339
+ if (editor.isActive('heading')) types.push('heading');
340
+ return types;
341
+ }
342
+ function isRecord(value) {
343
+ return 'object' == typeof value && null !== value && !Array.isArray(value);
344
+ }
345
+ const BORDER_EDGES = [
346
+ 'top',
347
+ 'right',
348
+ 'bottom',
349
+ 'left'
350
+ ];
351
+ function uniformDocumentTableBorders(border) {
352
+ return {
353
+ top: {
354
+ ...border
355
+ },
356
+ right: {
357
+ ...border
358
+ },
359
+ bottom: {
360
+ ...border
361
+ },
362
+ left: {
363
+ ...border
364
+ }
365
+ };
366
+ }
367
+ function documentTableBordersFromAttributes(attributes, fallback) {
368
+ const candidate = attributes.borders;
369
+ if (!candidate || 'object' != typeof candidate || Array.isArray(candidate)) return uniformDocumentTableBorders(fallback);
370
+ const record = candidate;
371
+ return {
372
+ top: normalizeDocumentTableBorder(record.top) ?? {
373
+ ...fallback
374
+ },
375
+ right: normalizeDocumentTableBorder(record.right) ?? {
376
+ ...fallback
377
+ },
378
+ bottom: normalizeDocumentTableBorder(record.bottom) ?? {
379
+ ...fallback
380
+ },
381
+ left: normalizeDocumentTableBorder(record.left) ?? {
382
+ ...fallback
383
+ }
384
+ };
385
+ }
386
+ function documentTableBordersFromElement(element, fallback) {
387
+ const uniform = documentTableBorderFromElement(element, fallback);
388
+ return {
389
+ top: documentTableEdgeFromElement(element, 'top', uniform),
390
+ right: documentTableEdgeFromElement(element, 'right', uniform),
391
+ bottom: documentTableEdgeFromElement(element, 'bottom', uniform),
392
+ left: documentTableEdgeFromElement(element, 'left', uniform)
393
+ };
394
+ }
395
+ function renderDocumentTableBorders(borders) {
396
+ const normalized = documentTableBordersFromAttributes({
397
+ borders
398
+ }, borders.top);
399
+ const representative = uniformDocumentTableBorder(normalized) ?? normalized.top;
400
+ const attributes = {
401
+ 'data-office-cell-border-color': representative.color,
402
+ 'data-office-cell-border-style': representative.style,
403
+ 'data-office-cell-border-width': String(representative.width)
404
+ };
405
+ for (const edge of BORDER_EDGES){
406
+ const border = normalized[edge];
407
+ attributes[`data-office-cell-border-${edge}-color`] = border.color;
408
+ attributes[`data-office-cell-border-${edge}-style`] = border.style;
409
+ attributes[`data-office-cell-border-${edge}-width`] = String(border.width);
410
+ }
411
+ const uniform = uniformDocumentTableBorder(normalized);
412
+ attributes.style = uniform ? `border: ${documentTableBorderCss(uniform)}` : BORDER_EDGES.map((edge)=>`border-${edge}: ${documentTableBorderCss(normalized[edge])}`).join('; ');
413
+ return attributes;
414
+ }
415
+ function uniformDocumentTableBorder(borders) {
416
+ const first = borders.top;
417
+ return BORDER_EDGES.every((edge)=>sameDocumentTableBorder(borders[edge], first)) ? first : null;
418
+ }
419
+ function normalizeDocumentTableBorder(value) {
420
+ if (!value || 'object' != typeof value || Array.isArray(value)) return null;
421
+ const record = value;
422
+ const color = normalizeTableColor(String(record.color ?? ''));
423
+ const style = normalizeDocumentTableBorderStyle(String(record.style ?? ''));
424
+ const width = normalizeDocumentTableBorderWidth(record.width);
425
+ if (!color || !style || null === width) return null;
426
+ return {
427
+ color,
428
+ style,
429
+ width: 'none' === style ? 0 : width
430
+ };
431
+ }
432
+ function normalizeTableColor(value) {
433
+ const trimmed = value?.trim().toLowerCase();
434
+ if (!trimmed) return null;
435
+ if (/^#[0-9a-f]{3}$/.test(trimmed)) return `#${trimmed.slice(1).split('').map((part)=>`${part}${part}`).join('')}`;
436
+ if (/^#[0-9a-f]{6}$/.test(trimmed)) return trimmed;
437
+ const rgb = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/.exec(trimmed);
438
+ if (!rgb) return null;
439
+ const channels = rgb.slice(1, 4).map(Number);
440
+ if (channels.some((channel)=>channel < 0 || channel > 255)) return null;
441
+ return `#${channels.map((channel)=>channel.toString(16).padStart(2, '0')).join('')}`;
442
+ }
443
+ function normalizeDocumentTableBorderStyle(value) {
444
+ if ('solid' === value || 'dashed' === value || 'dotted' === value || 'double' === value || 'none' === value) return value;
445
+ return null;
446
+ }
447
+ function normalizeDocumentTableBorderWidth(value) {
448
+ const width = 'number' == typeof value ? value : Number.parseFloat(String(value ?? '').replace(/px$/i, ''));
449
+ if (!Number.isFinite(width) || width < 0 || width > 6) return null;
450
+ return Math.round(2 * width) / 2;
451
+ }
452
+ function setSelectedDocumentTableBorders({ dispatch, state }, target, requestedBorder) {
453
+ const border = normalizeDocumentTableBorder(requestedBorder);
454
+ const context = selectedTableBorderContext(state);
455
+ if (!border || !context) return false;
456
+ const transaction = state.tr;
457
+ const positions = context.map.cellsInRect(context.rectangle);
458
+ for (const relativePosition of positions){
459
+ const position = context.tableStart + relativePosition;
460
+ const cell = transaction.doc.nodeAt(position);
461
+ if (!cell || !isTableCell(cell)) continue;
462
+ const cellRectangle = context.map.findCell(relativePosition);
463
+ const edges = documentTableBorderTargetEdges(target, cellRectangle, context.rectangle);
464
+ if (!edges.length) continue;
465
+ const fallback = documentTableBorderFromAttributes(cell.attrs);
466
+ const borders = documentTableBordersFromAttributes(cell.attrs, fallback);
467
+ for (const edge of edges)borders[edge] = {
468
+ ...border
469
+ };
470
+ const representative = uniformDocumentTableBorder(borders) ?? borders.top;
471
+ transaction.setNodeMarkup(position, void 0, {
472
+ ...cell.attrs,
473
+ borderColor: representative.color,
474
+ borderStyle: representative.style,
475
+ borderWidth: representative.width,
476
+ borders
477
+ });
478
+ }
479
+ if (dispatch && transaction.docChanged) dispatch(transaction.scrollIntoView());
480
+ return true;
481
+ }
482
+ function selectedTableBorderContext(state) {
483
+ const selection = state.selection;
484
+ if (selection instanceof NodeSelection && 'table' === selection.node.type.spec.tableRole) {
485
+ const map = TableMap.get(selection.node);
486
+ return {
487
+ tableStart: selection.from + 1,
488
+ map,
489
+ rectangle: {
490
+ left: 0,
491
+ right: map.width,
492
+ top: 0,
493
+ bottom: map.height
494
+ }
495
+ };
496
+ }
497
+ if (!isInTable(state)) return null;
498
+ const rectangle = selectedRect(state);
499
+ return {
500
+ tableStart: rectangle.tableStart,
501
+ map: rectangle.map,
502
+ rectangle
503
+ };
504
+ }
505
+ function documentTableBorderTargetEdges(target, cell, selection) {
506
+ if ('all' === target) return [
507
+ ...BORDER_EDGES
508
+ ];
509
+ const edges = [];
510
+ const outside = 'outside' === target;
511
+ const inside = 'inside' === target;
512
+ if ('top' === target && cell.top === selection.top || outside && cell.top === selection.top || (inside || 'insideHorizontal' === target) && cell.top > selection.top) edges.push('top');
513
+ if ('right' === target && cell.right === selection.right || outside && cell.right === selection.right || (inside || 'insideVertical' === target) && cell.right < selection.right) edges.push('right');
514
+ if ('bottom' === target && cell.bottom === selection.bottom || outside && cell.bottom === selection.bottom || (inside || 'insideHorizontal' === target) && cell.bottom < selection.bottom) edges.push('bottom');
515
+ if ('left' === target && cell.left === selection.left || outside && cell.left === selection.left || (inside || 'insideVertical' === target) && cell.left > selection.left) edges.push('left');
516
+ return edges;
517
+ }
518
+ function documentTableBorderFromAttributes(attributes) {
519
+ return {
520
+ color: normalizeTableColor(String(attributes.borderColor ?? '')) ?? '#cfd5df',
521
+ style: normalizeDocumentTableBorderStyle(String(attributes.borderStyle ?? '')) ?? 'solid',
522
+ width: normalizeDocumentTableBorderWidth(attributes.borderWidth) ?? 1
523
+ };
524
+ }
525
+ function documentTableBorderFromElement(element, fallback) {
526
+ const style = normalizeDocumentTableBorderStyle(element.dataset.officeCellBorderStyle || element.style.borderStyle) ?? fallback.style;
527
+ return {
528
+ color: normalizeTableColor(element.dataset.officeCellBorderColor || element.style.borderColor) ?? fallback.color,
529
+ style,
530
+ width: 'none' === style ? 0 : normalizeDocumentTableBorderWidth(element.dataset.officeCellBorderWidth || element.style.borderWidth) ?? fallback.width
531
+ };
532
+ }
533
+ function documentTableEdgeFromElement(element, edge, fallback) {
534
+ const datasetPrefix = `officeCellBorder${capitalize(edge)}`;
535
+ const style = normalizeDocumentTableBorderStyle(element.dataset[`${datasetPrefix}Style`] || element.style.getPropertyValue(`border-${edge}-style`)) ?? fallback.style;
536
+ return {
537
+ color: normalizeTableColor(element.dataset[`${datasetPrefix}Color`] || element.style.getPropertyValue(`border-${edge}-color`)) ?? fallback.color,
538
+ style,
539
+ width: 'none' === style ? 0 : normalizeDocumentTableBorderWidth(element.dataset[`${datasetPrefix}Width`] || element.style.getPropertyValue(`border-${edge}-width`)) ?? fallback.width
540
+ };
541
+ }
542
+ function documentTableBorderCss(border) {
543
+ return 'none' === border.style || 0 === border.width ? '0px none transparent' : `${border.width}px ${border.style} ${border.color}`;
544
+ }
545
+ function sameDocumentTableBorder(left, right) {
546
+ return left.color === right.color && left.style === right.style && left.width === right.width;
547
+ }
548
+ function isTableCell(node) {
549
+ return 'cell' === node.type.spec.tableRole || 'header_cell' === node.type.spec.tableRole;
550
+ }
551
+ function capitalize(value) {
552
+ return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
553
+ }
554
+ const MAX_TABLE_SIZE = 100000;
555
+ const MAX_CELL_MARGIN = 1000;
556
+ const TABLE_MARGIN_DATASET_KEYS = {
557
+ top: 'officeTableCellMarginTop',
558
+ right: 'officeTableCellMarginRight',
559
+ bottom: 'officeTableCellMarginBottom',
560
+ left: 'officeTableCellMarginLeft'
561
+ };
562
+ const CELL_MARGIN_DATASET_KEYS = {
563
+ top: 'officeCellMarginTop',
564
+ right: 'officeCellMarginRight',
565
+ bottom: 'officeCellMarginBottom',
566
+ left: 'officeCellMarginLeft'
567
+ };
568
+ const TABLE_MARGIN_CSS_PROPERTIES = {
569
+ top: '--work-table-cell-margin-top',
570
+ right: '--work-table-cell-margin-right',
571
+ bottom: '--work-table-cell-margin-bottom',
572
+ left: '--work-table-cell-margin-left'
573
+ };
574
+ const CELL_PADDING_STYLE_PROPERTIES = {
575
+ top: 'paddingTop',
576
+ right: 'paddingRight',
577
+ bottom: 'paddingBottom',
578
+ left: 'paddingLeft'
579
+ };
580
+ const DEFAULT_DOCUMENT_TABLE_CELL_MARGINS = {
581
+ top: 0,
582
+ right: 7.2,
583
+ bottom: 0,
584
+ left: 7.2
585
+ };
586
+ const DEFAULT_DOCUMENT_TABLE_GEOMETRY = {
587
+ layout: 'autofit',
588
+ width: {
589
+ type: 'percent',
590
+ value: 100
591
+ },
592
+ alignment: 'left',
593
+ indent: 0,
594
+ cellMargins: DEFAULT_DOCUMENT_TABLE_CELL_MARGINS
595
+ };
596
+ function normalizeDocumentTableGeometry(value, legacyLayoutMode) {
597
+ if (!work_document_table_geometry_isRecord(value)) return geometryForLegacyLayoutMode(legacyLayoutMode);
598
+ const layout = normalizeDocumentTableLayoutAlgorithm(value.layout);
599
+ const width = normalizeDocumentTablePreferredWidth(value.width);
600
+ const alignment = normalizeDocumentTableAlignment(value.alignment);
601
+ const indent = normalizeDimension(value.indent, MAX_TABLE_SIZE);
602
+ const cellMargins = normalizeDocumentTableCellMargins(value.cellMargins);
603
+ return {
604
+ layout: layout ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.layout,
605
+ width: width ?? clonePreferredWidth(DEFAULT_DOCUMENT_TABLE_GEOMETRY.width),
606
+ alignment: alignment ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.alignment,
607
+ indent: indent ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.indent,
608
+ cellMargins: cellMargins ?? cloneCellMargins(DEFAULT_DOCUMENT_TABLE_CELL_MARGINS)
609
+ };
610
+ }
611
+ function normalizeDocumentTableLayoutMode(value) {
612
+ return 'contents' === value || 'fixed' === value ? value : 'window';
613
+ }
614
+ function normalizeDocumentTableLayoutAlgorithm(value) {
615
+ return 'autofit' === value || 'fixed' === value ? value : null;
616
+ }
617
+ function normalizeDocumentTableAlignment(value) {
618
+ return 'center' === value || 'right' === value || 'left' === value ? value : null;
619
+ }
620
+ function normalizeDocumentTableProperties(value) {
621
+ if (!work_document_table_geometry_isRecord(value)) return null;
622
+ const width = normalizeDocumentTablePreferredWidth(value.width);
623
+ const alignment = normalizeDocumentTableAlignment(value.alignment);
624
+ const indent = normalizeDimension(value.indent, MAX_TABLE_SIZE);
625
+ return width && alignment && null !== indent ? {
626
+ width,
627
+ alignment,
628
+ indent
629
+ } : null;
630
+ }
631
+ function normalizeDocumentTableCellMargins(value) {
632
+ if (!work_document_table_geometry_isRecord(value)) return null;
633
+ const margins = normalizeDocumentTableCellMarginOverrides(value);
634
+ if (!margins || !hasAllMarginSides(margins)) return null;
635
+ return margins;
636
+ }
637
+ function normalizeDocumentTableCellMarginOverrides(value) {
638
+ if (!work_document_table_geometry_isRecord(value)) return null;
639
+ const margins = {};
640
+ for (const side of marginSides()){
641
+ const normalized = normalizeDimension(value[side], MAX_CELL_MARGIN);
642
+ if (null !== normalized) margins[side] = normalized;
643
+ }
644
+ return Object.keys(margins).length ? margins : null;
645
+ }
646
+ function documentTableLayoutMode(geometry) {
647
+ if ('autofit' === geometry.layout && 'auto' === geometry.width.type) return 'contents';
648
+ if ('autofit' === geometry.layout && 'percent' === geometry.width.type && 100 === geometry.width.value) return 'window';
649
+ return 'fixed';
650
+ }
651
+ function documentTableGeometryForLayoutMode(mode, current, renderedTableWidth) {
652
+ if ('contents' === mode) return {
653
+ ...current,
654
+ layout: 'autofit',
655
+ width: {
656
+ type: 'auto',
657
+ value: null
658
+ }
659
+ };
660
+ if ('window' === mode) return {
661
+ ...current,
662
+ layout: 'autofit',
663
+ width: {
664
+ type: 'percent',
665
+ value: 100
666
+ }
667
+ };
668
+ const rendered = normalizePositiveDimension(renderedTableWidth, MAX_TABLE_SIZE);
669
+ return {
670
+ ...current,
671
+ layout: 'fixed',
672
+ width: rendered ? {
673
+ type: 'pixels',
674
+ value: rendered
675
+ } : 'pixels' === current.width.type ? clonePreferredWidth(current.width) : {
676
+ type: 'auto',
677
+ value: null
678
+ }
679
+ };
680
+ }
681
+ function documentTableGeometryFromElement(table) {
682
+ const rawLayout = table.dataset.officeTableLayout;
683
+ const exactLayout = normalizeDocumentTableLayoutAlgorithm(rawLayout);
684
+ const legacyMode = 'window' === rawLayout || 'contents' === rawLayout || 'fixed' === rawLayout ? rawLayout : void 0;
685
+ const width = preferredWidthFromElement(table, legacyMode);
686
+ const margins = tableCellMarginsFromElement(table);
687
+ const alignment = normalizeDocumentTableAlignment(table.dataset.officeTableAlignment);
688
+ const indent = normalizeDimension(table.dataset.officeTableIndent, MAX_TABLE_SIZE);
689
+ const hasGeometryAttributes = Boolean(rawLayout || table.dataset.officeTableWidthType || table.dataset.officeTableWidth || table.dataset.officeTableAlignment || table.dataset.officeTableIndent || margins);
690
+ if (!hasGeometryAttributes) return cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY);
691
+ return {
692
+ layout: exactLayout ?? ('fixed' === legacyMode ? 'fixed' : 'autofit'),
693
+ width,
694
+ alignment: alignment ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.alignment,
695
+ indent: indent ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.indent,
696
+ cellMargins: margins ?? cloneCellMargins(DEFAULT_DOCUMENT_TABLE_CELL_MARGINS)
697
+ };
698
+ }
699
+ function renderDocumentTableGeometry(value, legacyLayoutMode) {
700
+ const geometry = normalizeDocumentTableGeometry(value, legacyLayoutMode);
701
+ return {
702
+ 'data-office-table-layout': geometry.layout,
703
+ 'data-office-table-width-type': geometry.width.type,
704
+ ...null === geometry.width.value ? {} : {
705
+ 'data-office-table-width': formatNumber(geometry.width.value)
706
+ },
707
+ 'data-office-table-alignment': geometry.alignment,
708
+ 'data-office-table-indent': formatNumber(geometry.indent),
709
+ 'data-office-table-cell-margin-top': formatNumber(geometry.cellMargins.top),
710
+ 'data-office-table-cell-margin-right': formatNumber(geometry.cellMargins.right),
711
+ 'data-office-table-cell-margin-bottom': formatNumber(geometry.cellMargins.bottom),
712
+ 'data-office-table-cell-margin-left': formatNumber(geometry.cellMargins.left),
713
+ style: documentTableGeometryStyle(geometry)
714
+ };
715
+ }
716
+ function applyDocumentTableGeometryToElement(table, value, legacyLayoutMode) {
717
+ const geometry = normalizeDocumentTableGeometry(value, legacyLayoutMode);
718
+ const rendered = renderDocumentTableGeometry(geometry);
719
+ for (const attributeName of tableGeometryAttributeNames())table.removeAttribute(attributeName);
720
+ for (const [name, attributeValue] of Object.entries(rendered))if ('style' !== name) table.setAttribute(name, attributeValue);
721
+ table.style.removeProperty('table-layout');
722
+ table.style.removeProperty('width');
723
+ table.style.removeProperty('margin-left');
724
+ table.style.removeProperty('margin-right');
725
+ for (const property of Object.values(TABLE_MARGIN_CSS_PROPERTIES))table.style.removeProperty(property);
726
+ for (const declaration of rendered.style.split(';').map((part)=>part.trim()).filter(Boolean)){
727
+ const separator = declaration.indexOf(':');
728
+ if (!(separator < 0)) table.style.setProperty(declaration.slice(0, separator).trim(), declaration.slice(separator + 1).trim());
729
+ }
730
+ if ('auto' !== geometry.width.type) table.style.removeProperty('min-width');
731
+ }
732
+ function documentTableCellMarginOverridesFromElement(cell) {
733
+ const margins = {};
734
+ for (const side of marginSides()){
735
+ const datasetValue = cell.dataset[CELL_MARGIN_DATASET_KEYS[side]];
736
+ const styleValue = cell.style[CELL_PADDING_STYLE_PROPERTIES[side]];
737
+ const normalized = normalizeDimension(datasetValue, MAX_CELL_MARGIN) ?? cssPixels(styleValue);
738
+ if (null !== normalized) margins[side] = normalized;
739
+ }
740
+ return Object.keys(margins).length ? margins : null;
741
+ }
742
+ function renderDocumentTableCellMarginOverrides(value) {
743
+ const margins = normalizeDocumentTableCellMarginOverrides(value);
744
+ if (!margins) return {};
745
+ const attributes = {};
746
+ const styles = [];
747
+ for (const side of marginSides()){
748
+ const margin = margins[side];
749
+ if (void 0 !== margin) {
750
+ attributes[`data-office-cell-margin-${side}`] = formatNumber(margin);
751
+ styles.push(`padding-${side}: ${formatNumber(margin)}px`);
752
+ }
753
+ }
754
+ return {
755
+ ...attributes,
756
+ style: styles.join('; ')
757
+ };
758
+ }
759
+ function preferredWidthFromElement(table, legacyMode) {
760
+ const type = normalizePreferredWidthType(table.dataset.officeTableWidthType);
761
+ const value = normalizePositiveDimension(table.dataset.officeTableWidth, MAX_TABLE_SIZE);
762
+ if ('auto' === type) return {
763
+ type,
764
+ value: null
765
+ };
766
+ if (type && null !== value) return {
767
+ type,
768
+ value
769
+ };
770
+ const styleWidth = cssPreferredWidth(table.style.width);
771
+ if (styleWidth) return styleWidth;
772
+ if ('contents' === legacyMode) return {
773
+ type: 'auto',
774
+ value: null
775
+ };
776
+ if ('fixed' === legacyMode) {
777
+ const columnWidth = firstRowColumnWidth(table);
778
+ return null === columnWidth ? {
779
+ type: 'auto',
780
+ value: null
781
+ } : {
782
+ type: 'pixels',
783
+ value: columnWidth
784
+ };
785
+ }
786
+ return clonePreferredWidth(DEFAULT_DOCUMENT_TABLE_GEOMETRY.width);
787
+ }
788
+ function tableCellMarginsFromElement(table) {
789
+ const margins = {};
790
+ for (const side of marginSides()){
791
+ const datasetValue = table.dataset[TABLE_MARGIN_DATASET_KEYS[side]];
792
+ const cssValue = table.style.getPropertyValue(TABLE_MARGIN_CSS_PROPERTIES[side]);
793
+ const normalized = normalizeDimension(datasetValue, MAX_CELL_MARGIN) ?? cssPixels(cssValue);
794
+ if (null !== normalized) margins[side] = normalized;
795
+ }
796
+ return hasAllMarginSides(margins) ? margins : null;
797
+ }
798
+ function documentTableGeometryStyle(geometry) {
799
+ const styles = [
800
+ `table-layout: ${'fixed' === geometry.layout ? 'fixed' : 'auto'}`
801
+ ];
802
+ if ('percent' === geometry.width.type && null !== geometry.width.value) styles.push(`width: ${formatNumber(geometry.width.value)}%`);
803
+ else if ('pixels' === geometry.width.type && null !== geometry.width.value) styles.push(`width: ${formatNumber(geometry.width.value)}px`);
804
+ if ('center' === geometry.alignment) styles.push('margin-left: auto', 'margin-right: auto');
805
+ else if ('right' === geometry.alignment) styles.push('margin-left: auto', 'margin-right: 0px');
806
+ else styles.push(`margin-left: ${formatNumber(geometry.indent)}px`, 'margin-right: auto');
807
+ for (const side of marginSides())styles.push(`${TABLE_MARGIN_CSS_PROPERTIES[side]}: ${formatNumber(geometry.cellMargins[side])}px`);
808
+ return styles.join('; ');
809
+ }
810
+ function geometryForLegacyLayoutMode(value) {
811
+ const mode = normalizeDocumentTableLayoutMode(value);
812
+ if ('contents' === mode) return {
813
+ ...cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY),
814
+ width: {
815
+ type: 'auto',
816
+ value: null
817
+ }
818
+ };
819
+ if ('fixed' === mode) return {
820
+ ...cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY),
821
+ layout: 'fixed',
822
+ width: {
823
+ type: 'auto',
824
+ value: null
825
+ }
826
+ };
827
+ return cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY);
828
+ }
829
+ function normalizeDocumentTablePreferredWidth(value) {
830
+ if (!work_document_table_geometry_isRecord(value)) return null;
831
+ const type = normalizePreferredWidthType(value.type);
832
+ if (!type) return null;
833
+ if ('auto' === type) return {
834
+ type,
835
+ value: null
836
+ };
837
+ const width = normalizePositiveDimension(value.value, MAX_TABLE_SIZE);
838
+ return null === width ? null : {
839
+ type,
840
+ value: width
841
+ };
842
+ }
843
+ function normalizePreferredWidthType(value) {
844
+ return 'auto' === value || 'percent' === value || 'pixels' === value ? value : null;
845
+ }
846
+ function normalizeDimension(value, maximum) {
847
+ const numeric = 'number' == typeof value ? value : 'string' == typeof value && value.trim() ? Number(value) : NaN;
848
+ if (!Number.isFinite(numeric) || numeric < 0 || numeric > maximum) return null;
849
+ return Math.round(100 * numeric) / 100;
850
+ }
851
+ function normalizePositiveDimension(value, maximum) {
852
+ const normalized = normalizeDimension(value, maximum);
853
+ return null !== normalized && normalized > 0 ? normalized : null;
854
+ }
855
+ function cssPixels(value) {
856
+ const match = /^(-?\d+(?:\.\d+)?)px$/i.exec(value.trim());
857
+ return match ? normalizeDimension(match[1], MAX_CELL_MARGIN) : null;
858
+ }
859
+ function cssPreferredWidth(value) {
860
+ const normalized = value.trim();
861
+ const percentage = /^(\d+(?:\.\d+)?)%$/.exec(normalized);
862
+ if (percentage) {
863
+ const width = normalizePositiveDimension(percentage[1], MAX_TABLE_SIZE);
864
+ return null === width ? null : {
865
+ type: 'percent',
866
+ value: width
867
+ };
868
+ }
869
+ const pixels = /^(\d+(?:\.\d+)?)px$/.exec(normalized);
870
+ if (pixels) {
871
+ const width = normalizePositiveDimension(pixels[1], MAX_TABLE_SIZE);
872
+ return null === width ? null : {
873
+ type: 'pixels',
874
+ value: width
875
+ };
876
+ }
877
+ return 'auto' === normalized ? {
878
+ type: 'auto',
879
+ value: null
880
+ } : null;
881
+ }
882
+ function firstRowColumnWidth(table) {
883
+ const row = table.querySelector('tr');
884
+ if (!row) return null;
885
+ let total = 0;
886
+ for (const cell of Array.from(row.querySelectorAll(':scope > th, :scope > td'))){
887
+ const raw = cell.getAttribute('colwidth');
888
+ if (!raw) return null;
889
+ const widths = raw.split(',').map((part)=>normalizePositiveDimension(part, MAX_TABLE_SIZE));
890
+ if (!widths.length || widths.some((width)=>null === width)) return null;
891
+ total += widths.reduce((sum, width)=>sum + Number(width), 0);
892
+ }
893
+ return total > 0 ? Math.round(100 * total) / 100 : null;
894
+ }
895
+ function tableGeometryAttributeNames() {
896
+ return [
897
+ 'data-office-table-layout',
898
+ 'data-office-table-width-type',
899
+ 'data-office-table-width',
900
+ 'data-office-table-alignment',
901
+ 'data-office-table-indent',
902
+ ...marginSides().map((side)=>`data-office-table-cell-margin-${side}`)
903
+ ];
904
+ }
905
+ function marginSides() {
906
+ return [
907
+ 'top',
908
+ 'right',
909
+ 'bottom',
910
+ 'left'
911
+ ];
912
+ }
913
+ function hasAllMarginSides(value) {
914
+ return marginSides().every((side)=>void 0 !== value[side]);
915
+ }
916
+ function cloneGeometry(value) {
917
+ return {
918
+ ...value,
919
+ width: clonePreferredWidth(value.width),
920
+ cellMargins: cloneCellMargins(value.cellMargins)
921
+ };
922
+ }
923
+ function clonePreferredWidth(value) {
924
+ return {
925
+ ...value
926
+ };
927
+ }
928
+ function cloneCellMargins(value) {
929
+ return {
930
+ ...value
931
+ };
932
+ }
933
+ function formatNumber(value) {
934
+ return String(Math.round(100 * value) / 100);
935
+ }
936
+ function work_document_table_geometry_isRecord(value) {
937
+ return 'object' == typeof value && null !== value && !Array.isArray(value);
938
+ }
939
+ export { DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DEFAULT_DOCUMENT_TABLE_GEOMETRY, DocumentImage, DocumentParagraphTabStops, applyDocumentTableGeometryToElement, documentImageLayoutFromElement, documentImageLayoutOptions, documentImageProperties, documentParagraphTabStops, documentTableBordersFromAttributes, documentTableBordersFromElement, documentTableCellMarginOverridesFromElement, documentTableGeometryForLayoutMode, documentTableGeometryFromElement, documentTableLayoutMode, nextDocumentTabAlignment, normalizeDocumentImageAlignment, normalizeDocumentImageLayoutOptions, normalizeDocumentTabStops, normalizeDocumentTableAlignment, normalizeDocumentTableBorderStyle, normalizeDocumentTableBorderWidth, normalizeDocumentTableCellMarginOverrides, normalizeDocumentTableCellMargins, normalizeDocumentTableGeometry, normalizeDocumentTableProperties, normalizeTableColor, normalizedTabPosition, renderDocumentTableBorders, renderDocumentTableCellMarginOverrides, renderDocumentTableGeometry, serializeDocumentTabStops, setSelectedDocumentTableBorders, uniformDocumentTableBorder, uniformDocumentTableBorders };