ooxml-core 1.2.1 → 1.3.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 (149) hide show
  1. package/dist/{PptxHandler-VQQS4VS6.mjs → PptxHandler-ZPJNHEZZ.mjs} +2 -2
  2. package/dist/automation/index.cjs +2235 -333
  3. package/dist/automation/index.mjs +2235 -333
  4. package/dist/{chunk-5U27IVB7.mjs → chunk-BB55ASTX.mjs} +3 -3
  5. package/dist/{chunk-V2BIGIH4.mjs → chunk-H4TPDZV4.mjs} +1 -1
  6. package/dist/{chunk-5VLNF4OX.mjs → chunk-IVDC75E5.mjs} +1 -1
  7. package/dist/{chunk-XBNSBDNT.mjs → chunk-QPQDLSJQ.mjs} +1 -1
  8. package/dist/{chunk-XSFHGZFH.mjs → chunk-XGLKW3JJ.mjs} +5 -3
  9. package/dist/pptx/automation/index.cjs +4 -2
  10. package/dist/pptx/automation/index.mjs +5 -5
  11. package/dist/pptx/cli/index.cjs +4 -2
  12. package/dist/pptx/cli/index.mjs +4 -4
  13. package/dist/pptx/converter/index.mjs +2 -2
  14. package/dist/pptx/index.cjs +4 -2
  15. package/dist/pptx/index.mjs +5 -5
  16. package/dist/teams/index.cjs +19 -10
  17. package/dist/teams/index.mjs +19 -10
  18. package/dist/visio/clipboard-resources.d.ts +11 -0
  19. package/dist/visio/clipboard-resources.d.ts.map +1 -0
  20. package/dist/visio/clipboard-types.d.ts +26 -0
  21. package/dist/visio/clipboard-types.d.ts.map +1 -0
  22. package/dist/visio/clipboard-xml.d.ts +8 -0
  23. package/dist/visio/clipboard-xml.d.ts.map +1 -0
  24. package/dist/visio/clipboard.d.ts +7 -0
  25. package/dist/visio/clipboard.d.ts.map +1 -0
  26. package/dist/visio/create-document.d.ts +8 -0
  27. package/dist/visio/create-document.d.ts.map +1 -0
  28. package/dist/visio/edit-commands.d.ts +19 -2
  29. package/dist/visio/edit-commands.d.ts.map +1 -1
  30. package/dist/visio/edit-delete.d.ts +9 -0
  31. package/dist/visio/edit-delete.d.ts.map +1 -0
  32. package/dist/visio/edit-duplicate-commands.d.ts +14 -0
  33. package/dist/visio/edit-duplicate-commands.d.ts.map +1 -0
  34. package/dist/visio/edit-duplicate-scope.d.ts +4 -0
  35. package/dist/visio/edit-duplicate-scope.d.ts.map +1 -0
  36. package/dist/visio/edit-duplicate.d.ts +10 -0
  37. package/dist/visio/edit-duplicate.d.ts.map +1 -0
  38. package/dist/visio/edit-formatting-cell-admission.d.ts +3 -0
  39. package/dist/visio/edit-formatting-cell-admission.d.ts.map +1 -0
  40. package/dist/visio/edit-formatting-commands.d.ts +46 -0
  41. package/dist/visio/edit-formatting-commands.d.ts.map +1 -0
  42. package/dist/visio/edit-formatting-font.d.ts +6 -0
  43. package/dist/visio/edit-formatting-font.d.ts.map +1 -0
  44. package/dist/visio/edit-formatting-paint-scope.d.ts +6 -0
  45. package/dist/visio/edit-formatting-paint-scope.d.ts.map +1 -0
  46. package/dist/visio/edit-formatting-paint.d.ts +6 -0
  47. package/dist/visio/edit-formatting-paint.d.ts.map +1 -0
  48. package/dist/visio/edit-formatting-rows.d.ts +14 -0
  49. package/dist/visio/edit-formatting-rows.d.ts.map +1 -0
  50. package/dist/visio/edit-formatting-scope.d.ts +6 -0
  51. package/dist/visio/edit-formatting-scope.d.ts.map +1 -0
  52. package/dist/visio/edit-formatting-text.d.ts +8 -0
  53. package/dist/visio/edit-formatting-text.d.ts.map +1 -0
  54. package/dist/visio/edit-formatting.d.ts +12 -0
  55. package/dist/visio/edit-formatting.d.ts.map +1 -0
  56. package/dist/visio/edit-geometry.d.ts.map +1 -1
  57. package/dist/visio/edit-paste-commands.d.ts +15 -0
  58. package/dist/visio/edit-paste-commands.d.ts.map +1 -0
  59. package/dist/visio/edit-paste.d.ts +5 -0
  60. package/dist/visio/edit-paste.d.ts.map +1 -0
  61. package/dist/visio/edit-recalculate.d.ts +3 -1
  62. package/dist/visio/edit-recalculate.d.ts.map +1 -1
  63. package/dist/visio/edit-resize-anchor.d.ts +8 -0
  64. package/dist/visio/edit-resize-anchor.d.ts.map +1 -0
  65. package/dist/visio/edit-scope.d.ts.map +1 -1
  66. package/dist/visio/edit-shape-create.d.ts +1 -1
  67. package/dist/visio/edit-shape-create.d.ts.map +1 -1
  68. package/dist/visio/edit-shape-order.d.ts +7 -0
  69. package/dist/visio/edit-shape-order.d.ts.map +1 -0
  70. package/dist/visio/edit-style-admission.d.ts +17 -0
  71. package/dist/visio/edit-style-admission.d.ts.map +1 -0
  72. package/dist/visio/edit-text-scope.d.ts +7 -0
  73. package/dist/visio/edit-text-scope.d.ts.map +1 -0
  74. package/dist/visio/edit-text.d.ts +1 -1
  75. package/dist/visio/edit-text.d.ts.map +1 -1
  76. package/dist/visio/edit.d.ts +1 -1
  77. package/dist/visio/edit.d.ts.map +1 -1
  78. package/dist/visio/index.cjs +3245 -1077
  79. package/dist/visio/index.d.ts +3 -1
  80. package/dist/visio/index.d.ts.map +1 -1
  81. package/dist/visio/index.mjs +3241 -1079
  82. package/dist/visio/line-pattern.d.ts +1 -1
  83. package/dist/visio/line-pattern.d.ts.map +1 -1
  84. package/dist/visio/line-style.d.ts.map +1 -1
  85. package/dist/visio/model.d.ts +23 -3
  86. package/dist/visio/model.d.ts.map +1 -1
  87. package/dist/visio/parser.d.ts.map +1 -1
  88. package/dist/visio/plain-text.d.ts +5 -0
  89. package/dist/visio/plain-text.d.ts.map +1 -0
  90. package/dist/visio/resize-anchor.d.ts +27 -0
  91. package/dist/visio/resize-anchor.d.ts.map +1 -0
  92. package/dist/visio/source-paint.d.ts +5 -0
  93. package/dist/visio/source-paint.d.ts.map +1 -0
  94. package/dist/visio/style.d.ts.map +1 -1
  95. package/dist/visio/theme-root.d.ts.map +1 -1
  96. package/dist/visio/ui/contract.d.ts +10 -6
  97. package/dist/visio/ui/contract.d.ts.map +1 -1
  98. package/dist/visio/ui/draw-plan.d.ts +32 -0
  99. package/dist/visio/ui/draw-plan.d.ts.map +1 -0
  100. package/dist/visio/ui/edit-commands.d.ts.map +1 -1
  101. package/dist/visio/ui/formatting.d.ts +28 -0
  102. package/dist/visio/ui/formatting.d.ts.map +1 -0
  103. package/dist/visio/ui/index.cjs +1305 -15
  104. package/dist/visio/ui/index.d.ts +15 -0
  105. package/dist/visio/ui/index.d.ts.map +1 -1
  106. package/dist/visio/ui/index.mjs +1261 -16
  107. package/dist/visio/ui/line-dash.d.ts +4 -0
  108. package/dist/visio/ui/line-dash.d.ts.map +1 -0
  109. package/dist/visio/ui/marquee.d.ts +15 -0
  110. package/dist/visio/ui/marquee.d.ts.map +1 -0
  111. package/dist/visio/ui/page-edit.d.ts.map +1 -1
  112. package/dist/visio/ui/scene-validation.d.ts.map +1 -1
  113. package/dist/visio/ui/selection.d.ts +12 -0
  114. package/dist/visio/ui/selection.d.ts.map +1 -0
  115. package/dist/visio/ui/shape-arrange.d.ts +17 -0
  116. package/dist/visio/ui/shape-arrange.d.ts.map +1 -0
  117. package/dist/visio/ui/shape-clipboard.d.ts +10 -0
  118. package/dist/visio/ui/shape-clipboard.d.ts.map +1 -0
  119. package/dist/visio/ui/shape-duplicate.d.ts +5 -0
  120. package/dist/visio/ui/shape-duplicate.d.ts.map +1 -0
  121. package/dist/visio/ui/shape-formatting.d.ts +14 -0
  122. package/dist/visio/ui/shape-formatting.d.ts.map +1 -0
  123. package/dist/visio/ui/shape-move.d.ts +14 -0
  124. package/dist/visio/ui/shape-move.d.ts.map +1 -0
  125. package/dist/visio/ui/shape-order.d.ts +4 -0
  126. package/dist/visio/ui/shape-order.d.ts.map +1 -0
  127. package/dist/visio/ui/shape-resize.d.ts +61 -0
  128. package/dist/visio/ui/shape-resize.d.ts.map +1 -0
  129. package/dist/visio/ui/size-position.d.ts +19 -0
  130. package/dist/visio/ui/size-position.d.ts.map +1 -0
  131. package/dist/visio/ui/snapshot-scene.d.ts.map +1 -1
  132. package/dist/visio/ui/svg-stroke.d.ts +8 -0
  133. package/dist/visio/ui/svg-stroke.d.ts.map +1 -0
  134. package/dist/visio/ui/text-replace-selection.d.ts +9 -0
  135. package/dist/visio/ui/text-replace-selection.d.ts.map +1 -0
  136. package/dist/visio/ui/text-replace-snapshot.d.ts +14 -0
  137. package/dist/visio/ui/text-replace-snapshot.d.ts.map +1 -0
  138. package/dist/visio/ui/text-replace-types.d.ts +48 -0
  139. package/dist/visio/ui/text-replace-types.d.ts.map +1 -0
  140. package/dist/visio/ui/text-replace.d.ts +18 -0
  141. package/dist/visio/ui/text-replace.d.ts.map +1 -0
  142. package/dist/xlsx/formula/lexemes.d.ts.map +1 -1
  143. package/dist/xlsx/index.cjs +18 -9
  144. package/dist/xlsx/index.mjs +18 -9
  145. package/dist/xlsx/load/index.cjs +18 -9
  146. package/dist/xlsx/load/index.mjs +18 -9
  147. package/dist/xlsx/ui/index.cjs +18 -9
  148. package/dist/xlsx/ui/index.mjs +18 -9
  149. package/package.json +1 -1
@@ -11,7 +11,8 @@ var eventKeys = [
11
11
  "document-error",
12
12
  "page-change",
13
13
  "zoom-change",
14
- "shape-select"
14
+ "shape-select",
15
+ "selection-change"
15
16
  ];
16
17
 
17
18
  // visio/ui/demo-document.ts
@@ -322,6 +323,259 @@ function textSearchStatus(search) {
322
323
  return result + (search.indexTruncated ? " \xB7 Partial text index" : "");
323
324
  }
324
325
 
326
+ // visio/package-common.ts
327
+ var VisioPackageError = class extends Error {
328
+ constructor(code, message) {
329
+ super(message);
330
+ this.code = code;
331
+ this.name = "VisioPackageError";
332
+ }
333
+ code;
334
+ };
335
+ function fail(code, message) {
336
+ throw new VisioPackageError(code, message);
337
+ }
338
+ new TextDecoder("utf-8", { fatal: true });
339
+ var crcTable = Uint32Array.from({ length: 256 }, (_, value) => {
340
+ for (let i = 0; i < 8; i++) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
341
+ return value >>> 0;
342
+ });
343
+ function crc32(bytes, crc = 4294967295) {
344
+ for (const byte of bytes) crc = (crcTable[(crc ^ byte) & 255] ?? 0) ^ crc >>> 8;
345
+ return crc >>> 0;
346
+ }
347
+ function decodePath(path) {
348
+ try {
349
+ return decodeURIComponent(path);
350
+ } catch {
351
+ return fail("UNSAFE_PATH", "Invalid percent encoding in package path");
352
+ }
353
+ }
354
+ function safePath(path, directory = false) {
355
+ const decoded = decodePath(path);
356
+ if (/%(?:2f|5c)/i.test(path)) fail("UNSAFE_PATH", "Encoded path separators are unsupported");
357
+ if (/[\\:#?\u0000-\u001f\u007f]/.test(path) || /[\\:#?%\u0000-\u001f\u007f]/.test(decoded))
358
+ fail("UNSAFE_PATH", `Unsafe package path: ${path}`);
359
+ for (const candidate of [path, decoded]) {
360
+ const name = directory && candidate.endsWith("/") ? candidate.slice(0, -1) : candidate;
361
+ if (!name || name.split("/").some((part) => !part || part === "." || part === ".."))
362
+ fail("UNSAFE_PATH", `Unsafe package path: ${path}`);
363
+ }
364
+ return path;
365
+ }
366
+
367
+ // visio/edit-formatting-commands.ts
368
+ var isVisioFormatEdit = (edit) => edit.type === "format-text" || edit.type === "format-shape";
369
+ function snapshotFormatting(edit) {
370
+ const result = { type: edit.type, pageId: edit.pageId, shapeId: edit.shapeId };
371
+ const points = (value, minimum, maximum) => {
372
+ if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum)
373
+ fail("INVALID_EDIT", "Formatting point size is outside supported limits.");
374
+ return value;
375
+ };
376
+ const color = (value, allowNone = false) => {
377
+ if (typeof value !== "string" || !(allowNone && value === "none") && !/^#[0-9a-f]{6}$/i.test(value))
378
+ fail("INVALID_EDIT", "Formatting colors require six hexadecimal digits.");
379
+ return value.toLowerCase();
380
+ };
381
+ if (edit.type === "format-text" && result.type === "format-text") {
382
+ if (edit.fontSize !== void 0) result.fontSize = points(edit.fontSize, 1, 1e3);
383
+ if (edit.fontColor !== void 0) result.fontColor = color(edit.fontColor);
384
+ if (edit.indentLeft !== void 0) result.indentLeft = points(edit.indentLeft, 0, 7200);
385
+ if (edit.fontFamily !== void 0) {
386
+ if (typeof edit.fontFamily !== "string" || !edit.fontFamily.trim() || edit.fontFamily.length > 256 || /[\u0000-\u001f\u007f]/.test(edit.fontFamily))
387
+ fail("INVALID_EDIT", "Invalid font family.");
388
+ result.fontFamily = edit.fontFamily;
389
+ }
390
+ for (const name of ["bold", "italic", "underline", "strikethrough", "bullets"]) {
391
+ if (edit[name] === void 0) continue;
392
+ if (typeof edit[name] !== "boolean") fail("INVALID_EDIT", "Text styles require booleans.");
393
+ result[name] = edit[name];
394
+ }
395
+ if (edit.horizontalAlign !== void 0) {
396
+ if (!["left", "center", "right", "justify"].includes(edit.horizontalAlign))
397
+ fail("INVALID_EDIT", "Invalid horizontal alignment.");
398
+ result.horizontalAlign = edit.horizontalAlign;
399
+ }
400
+ if (edit.verticalAlign !== void 0) {
401
+ if (!["top", "middle", "bottom"].includes(edit.verticalAlign))
402
+ fail("INVALID_EDIT", "Invalid vertical alignment.");
403
+ result.verticalAlign = edit.verticalAlign;
404
+ }
405
+ } else if (edit.type === "format-shape" && result.type === "format-shape") {
406
+ if (edit.fillColor !== void 0) result.fillColor = color(edit.fillColor, true);
407
+ if (edit.lineColor !== void 0) result.lineColor = color(edit.lineColor);
408
+ if (edit.lineWeight !== void 0) result.lineWeight = points(edit.lineWeight, 0, 100);
409
+ for (const [name, maximum] of [
410
+ ["linePattern", 23],
411
+ ["fillPattern", 24]
412
+ ]) {
413
+ if (edit[name] === void 0) continue;
414
+ const value = points(edit[name], 0, maximum);
415
+ if (!Number.isInteger(value)) fail("INVALID_EDIT", "Paint patterns require integers.");
416
+ result[name] = value;
417
+ }
418
+ for (const name of ["lineTransparency", "fillTransparency"])
419
+ if (edit[name] !== void 0) result[name] = Math.round(points(edit[name], 0, 100) * 2) / 2;
420
+ if (edit.fillBackgroundColor !== void 0)
421
+ result.fillBackgroundColor = color(edit.fillBackgroundColor);
422
+ if (result.fillColor === "none" && result.fillPattern !== void 0 && result.fillPattern !== 0)
423
+ fail("INVALID_EDIT", "No fill conflicts with a visible fill pattern.");
424
+ }
425
+ if (Object.keys(result).length === 3)
426
+ fail("INVALID_EDIT", "Formatting requires at least one property.");
427
+ return result;
428
+ }
429
+
430
+ // visio/edit-duplicate-commands.ts
431
+ function snapshotDuplicateShapes(edit) {
432
+ if (!Array.isArray(edit.copies) || !edit.copies.length || edit.copies.length > 1e3)
433
+ fail("INVALID_EDIT", "Duplication requires between one and 1000 shape mappings.");
434
+ if ([edit.offsetX, edit.offsetY].some(
435
+ (value) => typeof value !== "number" || !Number.isFinite(value) || Math.abs(value) > 1e6
436
+ ))
437
+ fail("INVALID_EDIT", "Duplication offsets require bounded finite drawing inches.");
438
+ const sources = /* @__PURE__ */ new Set(), targets = /* @__PURE__ */ new Set();
439
+ const id = (value) => {
440
+ if (typeof value !== "string" || !/^(0|[1-9]\d{0,9})$/.test(value) || Number(value) > 4294967295)
441
+ fail("INVALID_EDIT", "Duplicate shape IDs require canonical unsigned integers.");
442
+ return value;
443
+ };
444
+ const copies = edit.copies.map((copy) => {
445
+ if (!copy || typeof copy !== "object") fail("INVALID_EDIT", "Invalid duplicate shape mapping.");
446
+ const shapeId = id(copy.shapeId), newShapeId = id(copy.newShapeId);
447
+ if (sources.has(shapeId) || targets.has(newShapeId))
448
+ fail("INVALID_EDIT", "Duplicate shape mappings must have unique sources and targets.");
449
+ sources.add(shapeId);
450
+ targets.add(newShapeId);
451
+ return { shapeId, newShapeId };
452
+ });
453
+ return {
454
+ type: edit.type,
455
+ pageId: edit.pageId,
456
+ copies,
457
+ offsetX: edit.offsetX,
458
+ offsetY: edit.offsetY
459
+ };
460
+ }
461
+
462
+ // visio/clipboard-types.ts
463
+ var VISIO_CLIPBOARD_MAX_CHARS = 8 * 1024 * 1024;
464
+ function clipboardId(value) {
465
+ if (typeof value !== "string" || !/^(0|[1-9]\d{0,9})$/.test(value) || Number(value) > 4294967295)
466
+ fail("INVALID_CLIPBOARD", "Clipboard IDs require canonical unsigned integers.");
467
+ return value;
468
+ }
469
+ function snapshotVisioClipboard(value) {
470
+ if (!value || typeof value !== "object" || value.format !== "ooxml.visio-shapes" || value.version !== 1)
471
+ fail("INVALID_CLIPBOARD", "Unsupported Visio clipboard format or version.");
472
+ const sourcePageId = clipboardId(value.sourcePageId), sourceDrawingScale = value.sourceDrawingScale;
473
+ if (!Number.isFinite(sourceDrawingScale) || sourceDrawingScale <= 0 || sourceDrawingScale > 1e6)
474
+ fail("INVALID_CLIPBOARD", "Invalid clipboard drawing ratio.");
475
+ let characters = 0;
476
+ const text = (input) => {
477
+ if (typeof input !== "string" || (characters += input.length) > VISIO_CLIPBOARD_MAX_CHARS)
478
+ fail("LIMIT_CLIPBOARD", "Clipboard XML exceeds bounded text limits.");
479
+ if (/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/.test(input))
480
+ fail("INVALID_CLIPBOARD", "Clipboard XML must contain well-formed Unicode.");
481
+ return input;
482
+ };
483
+ const list = (input, max) => {
484
+ if (!Array.isArray(input) || !input.length || input.length > max)
485
+ fail("INVALID_CLIPBOARD", "Invalid clipboard array length.");
486
+ return input;
487
+ };
488
+ const selectionIds = list(value.selectionIds, 1e3).map(clipboardId);
489
+ const shapes = list(value.shapes, 1e3).map((shape) => {
490
+ if (!shape || typeof shape !== "object") fail("INVALID_CLIPBOARD", "Invalid captured shape.");
491
+ return { shapeId: clipboardId(shape.shapeId), xml: text(shape.xml) };
492
+ });
493
+ const resources = list(value.resources, 64).map((resource) => {
494
+ const path = resource?.path;
495
+ if (!resource || typeof resource !== "object" || typeof path !== "string" || path.length > 1024 || !/^visio\/(?:document\.xml|_rels\/document\.xml\.rels|theme\/[^/]+\.(?:xml|rels)|theme\/_rels\/[^/]+\.rels)$/.test(
496
+ path
497
+ ))
498
+ fail("INVALID_CLIPBOARD", "Invalid clipboard resource path.");
499
+ return { path: text(safePath(path)), xml: text(resource.xml) };
500
+ });
501
+ if (new Set(selectionIds).size !== selectionIds.length || new Set(shapes.map((shape) => shape.shapeId)).size !== shapes.length || selectionIds.length !== shapes.length || selectionIds.some((id) => !shapes.some((shape) => shape.shapeId === id)) || new Set(resources.map((resource) => resource.path)).size !== resources.length)
502
+ fail("INVALID_CLIPBOARD", "Clipboard mappings and resources must be unique and complete.");
503
+ return {
504
+ format: "ooxml.visio-shapes",
505
+ version: 1,
506
+ sourcePageId,
507
+ sourceDrawingScale,
508
+ selectionIds,
509
+ shapes,
510
+ resources: resources.sort((a, b) => a.path.localeCompare(b.path)),
511
+ pageContext: text(value.pageContext)
512
+ };
513
+ }
514
+
515
+ // visio/edit-paste-commands.ts
516
+ function snapshotPasteShapes(edit) {
517
+ const clipboard = snapshotVisioClipboard(edit.clipboard);
518
+ const copies = snapshotDuplicateShapes({
519
+ type: "duplicate-shapes",
520
+ pageId: edit.pageId,
521
+ copies: edit.copies,
522
+ offsetX: edit.offsetX,
523
+ offsetY: edit.offsetY
524
+ });
525
+ if (copies.copies.length !== clipboard.shapes.length || copies.copies.some((copy) => !clipboard.selectionIds.includes(copy.shapeId)))
526
+ fail("INVALID_CLIPBOARD", "Paste mappings must cover every captured shape exactly once.");
527
+ return {
528
+ type: "paste-shapes",
529
+ pageId: copies.pageId,
530
+ copies: copies.copies,
531
+ offsetX: copies.offsetX,
532
+ offsetY: copies.offsetY,
533
+ clipboard
534
+ };
535
+ }
536
+
537
+ // visio/resize-anchor.ts
538
+ function snapshotResizeAnchor(value) {
539
+ if (value === void 0) return void 0;
540
+ if (!value || typeof value !== "object") fail("INVALID_EDIT", "Invalid resize anchor.");
541
+ const { x, y } = value;
542
+ if (![0, 0.5, 1].includes(x) || ![0, 0.5, 1].includes(y))
543
+ fail("INVALID_EDIT", "Resize anchor coordinates must be 0, 0.5 or 1.");
544
+ return { x, y };
545
+ }
546
+ function visioAnchoredResizeGeometry(current, size, anchor) {
547
+ const [a, b, c, d, e, f] = current.transform;
548
+ const determinant = a * d - b * c;
549
+ if (![0, 0.5, 1].includes(anchor.x) || ![0, 0.5, 1].includes(anchor.y) || ![
550
+ current.width,
551
+ current.height,
552
+ current.pinX,
553
+ current.pinY,
554
+ ...current.transform,
555
+ size.width,
556
+ size.height,
557
+ anchor.x,
558
+ anchor.y
559
+ ].every(Number.isFinite) || !(current.width > 0 && current.height > 0 && size.width > 0 && size.height > 0) || Math.abs(Math.abs(determinant) - 1) > 1e-8 || Math.abs(a * a + b * b - 1) > 1e-8 || Math.abs(c * c + d * d - 1) > 1e-8 || Math.abs(a * c + b * d) > 1e-8)
560
+ return void 0;
561
+ const offsetX = current.pinX - e, offsetY = current.pinY - f;
562
+ const oldX = (d * offsetX - c * offsetY) / determinant;
563
+ const oldY = (-b * offsetX + a * offsetY) / determinant;
564
+ const locPinX = oldX / current.width * size.width, locPinY = oldY / current.height * size.height;
565
+ const deltaX = anchor.x * (current.width - size.width) - oldX + locPinX;
566
+ const deltaY = anchor.y * (current.height - size.height) - oldY + locPinY;
567
+ const pinX = current.pinX + a * deltaX + c * deltaY, pinY = current.pinY + b * deltaX + d * deltaY;
568
+ const matrix2 = [
569
+ a,
570
+ b,
571
+ c,
572
+ d,
573
+ pinX - a * locPinX - c * locPinY,
574
+ pinY - b * locPinX - d * locPinY
575
+ ];
576
+ return [pinX, pinY, locPinX, locPinY, ...matrix2].every(Number.isFinite) ? { pinX, pinY, locPinX, locPinY, transform: matrix2 } : void 0;
577
+ }
578
+
325
579
  // visio/ui/edit-commands.ts
326
580
  function snapshotEdits(edits) {
327
581
  if (!Array.isArray(edits) || edits.length > 1e3)
@@ -330,6 +584,8 @@ function snapshotEdits(edits) {
330
584
  return edits.map((command) => {
331
585
  if (!command || typeof command.pageId !== "string" || !command.pageId || command.pageId.length > 256)
332
586
  throw new Error("Invalid edit command.");
587
+ if (command.type === "duplicate-shapes") return snapshotDuplicateShapes(command);
588
+ if (command.type === "paste-shapes") return snapshotPasteShapes(command);
333
589
  if (command.type === "reorder-page") {
334
590
  if (!Number.isSafeInteger(command.index) || command.index < 0 || command.index > 1e6)
335
591
  throw new Error("Invalid page order index.");
@@ -362,7 +618,23 @@ function snapshotEdits(edits) {
362
618
  if (typeof command.shapeId !== "string" || !command.shapeId || command.shapeId.length > 256)
363
619
  throw new Error("Invalid edit shape target.");
364
620
  const target = { pageId: command.pageId, shapeId: command.shapeId };
621
+ if (isVisioFormatEdit(command)) return snapshotFormatting(command);
365
622
  switch (command.type) {
623
+ case "create-text-box":
624
+ numbers(command.x, command.y, command.width, command.height);
625
+ return {
626
+ type: command.type,
627
+ ...target,
628
+ x: command.x,
629
+ y: command.y,
630
+ width: command.width,
631
+ height: command.height,
632
+ text: text(command.text)
633
+ };
634
+ case "reorder-shape":
635
+ if (!["front", "back", "forward", "backward"].includes(command.order))
636
+ throw new Error("Invalid shape order.");
637
+ return { ...target, type: command.type, order: command.order };
366
638
  case "create-line":
367
639
  numbers(command.beginX, command.beginY, command.endX, command.endY);
368
640
  return {
@@ -398,9 +670,17 @@ function snapshotEdits(edits) {
398
670
  x: command.x,
399
671
  y: command.y
400
672
  };
401
- case "resize-shape":
673
+ case "resize-shape": {
402
674
  numbers(command.width, command.height);
403
- return { type: command.type, ...target, width: command.width, height: command.height };
675
+ const anchor = snapshotResizeAnchor(command.anchor);
676
+ return {
677
+ type: command.type,
678
+ ...target,
679
+ width: command.width,
680
+ height: command.height,
681
+ ...anchor === void 0 ? {} : { anchor }
682
+ };
683
+ }
404
684
  case "create-rectangle":
405
685
  case "create-ellipse":
406
686
  numbers(command.x, command.y, command.width, command.height);
@@ -428,15 +708,6 @@ function editErrorMessage(error) {
428
708
  function isEditCancellation(error) {
429
709
  return !!error && typeof error === "object" && "name" in error && error.name === "AbortError";
430
710
  }
431
- new TextDecoder("utf-8", { fatal: true });
432
- var crcTable = Uint32Array.from({ length: 256 }, (_, value) => {
433
- for (let i = 0; i < 8; i++) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
434
- return value >>> 0;
435
- });
436
- function crc32(bytes, crc = 4294967295) {
437
- for (const byte of bytes) crc = (crcTable[(crc ^ byte) & 255] ?? 0) ^ crc >>> 8;
438
- return crc >>> 0;
439
- }
440
711
 
441
712
  // visio/foreign-vector-types.ts
442
713
  var VISIO_FOREIGN_VECTOR_LIMITS = Object.freeze({
@@ -1376,6 +1647,29 @@ function transform(x, y, localX, localY, angle, flipX = false, flipY = false) {
1376
1647
  return [a, b, c, d, x - a * localX - c * localY, y - b * localX - d * localY];
1377
1648
  }
1378
1649
 
1650
+ // visio/parser.ts
1651
+ function getVisioPageLayers(document, pageId) {
1652
+ const result = [], seen = /* @__PURE__ */ new Set();
1653
+ const pages = new Map(document.pages.map((page) => [page.id, page]));
1654
+ let current = pages.get(pageId);
1655
+ while (current && !seen.has(current.id)) {
1656
+ seen.add(current.id);
1657
+ result.push(current);
1658
+ current = current.backgroundPageId === void 0 ? void 0 : pages.get(current.backgroundPageId);
1659
+ }
1660
+ return result.reverse();
1661
+ }
1662
+
1663
+ // visio/visibility.ts
1664
+ var VISIO_VISIBILITY_LIMITS = Object.freeze({
1665
+ maxShapes: 25e3,
1666
+ maxDepth: 64,
1667
+ maxLayers: 25e3,
1668
+ maxMemberships: 1e5,
1669
+ maxMembershipsPerShape: 1024,
1670
+ maxLayerIdLength: 256
1671
+ });
1672
+
1379
1673
  // visio/ui/foreign-vector-budget.ts
1380
1674
  var FOREIGN_VECTOR_SCENE_LIMITS = Object.freeze({
1381
1675
  maxNodes: 1e5,
@@ -1573,6 +1867,11 @@ function assertViewableDocument(model) {
1573
1867
  metadataBytes += value.length;
1574
1868
  if (metadataBytes > 1e6) throw new Error("The scene exceeds aggregate metadata limits.");
1575
1869
  };
1870
+ if (model.fontFamilies !== void 0) {
1871
+ if (!Array.isArray(model.fontFamilies) || model.fontFamilies.length > 1e4)
1872
+ throw new Error("The scene has an invalid font family list.");
1873
+ for (const family of model.fontFamilies) label(family, 1024);
1874
+ }
1576
1875
  for (const diagnostic of model.diagnostics) {
1577
1876
  label(diagnostic.code, 256);
1578
1877
  label(diagnostic.message);
@@ -1618,7 +1917,9 @@ function assertViewableDocument(model) {
1618
1917
  member(shape.kind, ["shape", "group", "connector", "foreign"], "shape kind");
1619
1918
  if (shape.groupDisplayMode !== void 0)
1620
1919
  member(shape.groupDisplayMode, [0, 1, 2], "group display mode");
1621
- member(shape.text.horizontalAlign, ["left", "center", "right"], "text alignment");
1920
+ member(shape.text.horizontalAlign, ["left", "center", "right", "justify"], "text alignment");
1921
+ for (const key of ["bold", "italic", "underline", "strikethrough"])
1922
+ if (shape.text[key] !== void 0) member(shape.text[key], [true, false], "text style");
1622
1923
  member(shape.text.verticalAlign, ["top", "middle", "bottom"], "text alignment");
1623
1924
  label(shape.name);
1624
1925
  label(shape.text.fontFamily, 1024);
@@ -1657,7 +1958,7 @@ function assertViewableDocument(model) {
1657
1958
  const dash = shape.style.lineDash;
1658
1959
  if (!Array.isArray(dash) || dash.length < 2 || dash.length > 6 || dash.length % 2 !== 0)
1659
1960
  throw new Error("The scene has an invalid normalized line dash.");
1660
- for (const value of dash) finite2(value, "line dash length", 0, 27);
1961
+ for (const value of dash) finite2(value, "line dash length", 0, 40);
1661
1962
  if (!dash.some((value) => value > 0))
1662
1963
  throw new Error("The scene has an empty line dash pattern.");
1663
1964
  }
@@ -1672,6 +1973,21 @@ function assertViewableDocument(model) {
1672
1973
  throw new Error("The scene has an invalid normalized line cap.");
1673
1974
  finite2(shape.style.fillOpacity, "fill opacity", 0, 1);
1674
1975
  finite2(shape.style.lineOpacity, "line opacity", 0, 1);
1976
+ if (shape.style.lineDashDotLength !== void 0)
1977
+ finite2(shape.style.lineDashDotLength, "line dash dot length", 0, 1e6);
1978
+ for (const name of [
1979
+ "fillForegroundOpacity",
1980
+ "fillBackgroundOpacity",
1981
+ "lineColorOpacity"
1982
+ ])
1983
+ if (shape.style[name] !== void 0) finite2(shape.style[name], "source paint opacity", 0, 1);
1984
+ if (shape.style.fillPatternIndex !== void 0) {
1985
+ finite2(shape.style.fillPatternIndex, "source fill pattern", 0, 65535);
1986
+ if (!Number.isInteger(shape.style.fillPatternIndex))
1987
+ throw new Error("The scene has an invalid source fill pattern.");
1988
+ }
1989
+ if (shape.style.fillBackgroundColor !== void 0 && (typeof shape.style.fillBackgroundColor !== "string" || !/^#[0-9a-f]{6}$/i.test(shape.style.fillBackgroundColor)))
1990
+ throw new Error("The scene has an invalid source fill background color.");
1675
1991
  if (shape.style.fillPattern) {
1676
1992
  const tile = shape.style.fillPattern;
1677
1993
  finite2(tile.width, "fill pattern width", 1 / 12, 1 / 12);
@@ -1694,6 +2010,8 @@ function assertViewableDocument(model) {
1694
2010
  if (!Array.isArray(shape.text.runs) || runCount + shape.text.runs.length > 1e5)
1695
2011
  throw new Error("The scene exceeds safe text run limits or has an invalid run list.");
1696
2012
  for (const run of shape.text.runs) {
2013
+ if (run.strikethrough !== void 0)
2014
+ member(run.strikethrough, [true, false], "strikethrough style");
1697
2015
  label(run.fontFamily, 1024);
1698
2016
  label(run.color, 256);
1699
2017
  if (run.opacity !== void 0) finite2(run.opacity, "text run opacity", 0, 1);
@@ -1866,10 +2184,16 @@ function copySnapshotScene(model) {
1866
2184
  const style = (source) => {
1867
2185
  const result = fields(source, [
1868
2186
  "fill",
2187
+ "fillPatternIndex",
2188
+ "fillForegroundOpacity",
2189
+ "fillBackgroundColor",
2190
+ "fillBackgroundOpacity",
1869
2191
  "lineColor",
1870
2192
  "lineWidth",
1871
2193
  "lineCap",
1872
2194
  "linePattern",
2195
+ "lineDashDotLength",
2196
+ "lineColorOpacity",
1873
2197
  "fillOpacity",
1874
2198
  "lineOpacity",
1875
2199
  "startArrow",
@@ -1948,6 +2272,10 @@ function copySnapshotScene(model) {
1948
2272
  const text = (source) => ({
1949
2273
  ...fields(source, [
1950
2274
  "plainText",
2275
+ "bold",
2276
+ "italic",
2277
+ "underline",
2278
+ "strikethrough",
1951
2279
  "backgroundColor",
1952
2280
  "backgroundOpacity",
1953
2281
  "opacity",
@@ -1965,7 +2293,8 @@ function copySnapshotScene(model) {
1965
2293
  ...fields(run, ["text", "fontFamily", "fontSize", "color", "opacity"]),
1966
2294
  bold: !!run.bold,
1967
2295
  italic: !!run.italic,
1968
- underline: !!run.underline
2296
+ underline: !!run.underline,
2297
+ ...run.strikethrough === void 0 ? {} : { strikethrough: !!run.strikethrough }
1969
2298
  })),
1970
2299
  ...source.paragraphs === void 0 ? {} : { paragraphs: list(source.paragraphs, "paragraphs", 5e4, paragraph) }
1971
2300
  });
@@ -1997,6 +2326,12 @@ function copySnapshotScene(model) {
1997
2326
  };
1998
2327
  return {
1999
2328
  format: "vsdx",
2329
+ ...model.fontFamilies === void 0 ? {} : {
2330
+ fontFamilies: list(model.fontFamilies, "font families", 1e4, (font) => {
2331
+ if (typeof font !== "string" || font.length > 1024) throw invalid2();
2332
+ return font;
2333
+ })
2334
+ },
2000
2335
  diagnostics: list(
2001
2336
  model.diagnostics,
2002
2337
  "diagnostics",
@@ -2051,6 +2386,7 @@ function visioPageEditToDrawing(page, edit) {
2051
2386
  return edit;
2052
2387
  case "create-rectangle":
2053
2388
  case "create-ellipse":
2389
+ case "create-text-box":
2054
2390
  return {
2055
2391
  ...edit,
2056
2392
  x: coordinate(edit.x),
@@ -2098,6 +2434,103 @@ function visioNextShapeId(page) {
2098
2434
  return String(max + 1);
2099
2435
  }
2100
2436
 
2437
+ // visio/ui/formatting.ts
2438
+ function visioStyleFormattingShape(page, shapeId) {
2439
+ const candidates = page.shapes.filter((shape2) => shape2.id === shapeId);
2440
+ if (candidates.length !== 1) return void 0;
2441
+ const shape = candidates[0];
2442
+ if (shape.hidden || shape.masterId || shape.layerIds?.length || shape.children.length || !["shape", "connector"].includes(shape.kind) || shape.image || shape.foreignVector)
2443
+ return void 0;
2444
+ return shape;
2445
+ }
2446
+ function visioFormattingShape(page, shapeId) {
2447
+ return visioStyleFormattingShape(page, shapeId);
2448
+ }
2449
+ function visioFontFamilies(document) {
2450
+ return [...new Set(document.fontFamilies ?? [])].sort((left, right) => left.localeCompare(right));
2451
+ }
2452
+ function visioTextFormattingState(shapes) {
2453
+ const common = (values) => values.length && values.every((value) => value === values[0]) ? values[0] : void 0;
2454
+ const runs = shapes.flatMap(
2455
+ (shape) => shape.text.runs.length ? shape.text.runs : [shape.text]
2456
+ );
2457
+ const styled = (key) => !!runs.length && runs.every((run) => !!run[key]);
2458
+ const paragraphs = shapes.flatMap((shape) => shape.text.paragraphs ?? []);
2459
+ const alignment = common(
2460
+ shapes.flatMap(
2461
+ (shape) => shape.text.paragraphs?.length ? shape.text.paragraphs.map((paragraph) => paragraph.horizontalAlign) : [shape.text.horizontalAlign]
2462
+ )
2463
+ );
2464
+ return {
2465
+ bold: styled("bold"),
2466
+ italic: styled("italic"),
2467
+ underline: styled("underline"),
2468
+ strikethrough: styled("strikethrough"),
2469
+ bullets: !!shapes.length && shapes.every(
2470
+ (shape) => !!shape.text.paragraphs?.length && shape.text.paragraphs.every((paragraph) => !!paragraph.bullet)
2471
+ ),
2472
+ fontFamily: common(runs.map((run) => run.fontFamily)),
2473
+ fontSize: common(runs.map((run) => run.fontSize)),
2474
+ fontColor: common(runs.map((run) => run.color)),
2475
+ horizontalAlign: alignment === "distributed" ? void 0 : alignment,
2476
+ verticalAlign: common(shapes.map((shape) => shape.text.verticalAlign)),
2477
+ canIndentDecrease: paragraphs.some((paragraph) => paragraph.indentLeft > 0)
2478
+ };
2479
+ }
2480
+ function visioTextIndentCommand(page, shapeId, direction) {
2481
+ const shape = visioFormattingShape(page, shapeId);
2482
+ if (!shape || !["increase", "decrease"].includes(direction)) return void 0;
2483
+ const paragraphs = shape.text.paragraphs ?? [];
2484
+ const left = paragraphs[0]?.indentLeft ?? 0;
2485
+ if (!Number.isFinite(left) || left < 0 || paragraphs.some((paragraph) => paragraph.indentLeft !== left))
2486
+ return void 0;
2487
+ const points = left * 72;
2488
+ const indentLeft = Math.min(7200, Math.max(0, points + (direction === "increase" ? 18 : -18)));
2489
+ return { type: "format-text", pageId: page.id, shapeId, indentLeft };
2490
+ }
2491
+ function visioTextFontStepCommand(page, shapeId, direction) {
2492
+ const shape = visioFormattingShape(page, shapeId);
2493
+ if (!shape || !["increase", "decrease"].includes(direction)) return void 0;
2494
+ const sizes = shape.text.runs.length ? shape.text.runs.map((run) => run.fontSize) : [shape.text.fontSize];
2495
+ const size = sizes[0];
2496
+ if (!Number.isFinite(size) || sizes.some((value) => Math.abs(value - size) > 1e-10))
2497
+ return void 0;
2498
+ const current = size * 72;
2499
+ if (current < 1 || current > 1e3) return void 0;
2500
+ const steps = [6, 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 72];
2501
+ const fontSize = direction === "increase" ? steps.find((value) => value > current + 1e-3) ?? Math.min(1e3, Math.ceil(current * 1.2)) : steps.reverse().find((value) => value < current - 1e-3) ?? Math.max(1, Math.floor(current / 1.2));
2502
+ return { type: "format-text", pageId: page.id, shapeId, fontSize };
2503
+ }
2504
+
2505
+ // visio/ui/shape-duplicate.ts
2506
+ function visioDuplicateCommand(page, shapeIds) {
2507
+ if (!shapeIds.length || shapeIds.length > 1e3 || new Set(shapeIds).size !== shapeIds.length || shapeIds.some((id) => {
2508
+ const shape = visioStyleFormattingShape(page, id);
2509
+ return !shape || shape.kind !== "shape" || !(shape.width > 0) || !(shape.height > 0) || page.connectors.some(
2510
+ (connection) => connection.fromShapeId === id || connection.toShapeId === id
2511
+ );
2512
+ }))
2513
+ return void 0;
2514
+ let next;
2515
+ try {
2516
+ next = Number(visioNextShapeId(page));
2517
+ } catch {
2518
+ return void 0;
2519
+ }
2520
+ if (next + shapeIds.length - 1 > 4294967295) return void 0;
2521
+ const selected = new Set(shapeIds);
2522
+ const mapping = new Map(
2523
+ page.shapes.filter((shape) => selected.has(shape.id)).map((shape) => [shape.id, String(next++)])
2524
+ );
2525
+ return {
2526
+ type: "duplicate-shapes",
2527
+ pageId: page.id,
2528
+ copies: shapeIds.map((shapeId) => ({ shapeId, newShapeId: mapping.get(shapeId) })),
2529
+ offsetX: 0.33,
2530
+ offsetY: -0.33
2531
+ };
2532
+ }
2533
+
2101
2534
  // visio/ui/fill-pattern-transform.ts
2102
2535
  function visioFillPatternTransform(world, pageHeight = 0) {
2103
2536
  const determinant = world[0] * world[3] - world[1] * world[2];
@@ -2157,4 +2590,816 @@ function visioQuarterTurnCommand(page, shapeId, direction) {
2157
2590
  };
2158
2591
  }
2159
2592
 
2160
- export { DocumentHistory, EDIT_HISTORY_LIMITS, EMPTY_EDIT_STATE, EMPTY_TEXT_SEARCH, FOREIGN_VECTOR_SCENE_LIMITS, ForeignVectorBudget, MAX_INPUT_BYTES, TEXT_SEARCH_LIMITS, IDENTITY_AFFINE as VISIO_IDENTITY_TRANSFORM, assertShapeDetails, assertViewableDocument, compatibilityNotes, compatibilityText, composeAffine as composeVisioTransform, copySnapshotScene, demoDocument, editErrorMessage, eventKeys, indexDocumentText, inspectForeignVectorResource, isEditCancellation, propertyKeys, searchDocumentText, snapshotEdits, textSearchStatus, validateSearchQuery, visioFillPatternTransform, visioGradientInstances, visioLocalRotationShape, visioNextShapeId, visioPageEditToDrawing, visioPageInsertCommand, visioQuarterTurnCommand, visioRenderedGradientStopCount, visioRenderedGradientStops, visioRotationPreviewTransform, visioStraightLineHandles, visioStrokeGradient };
2593
+ // visio/ui/shape-order.ts
2594
+ function visioOrderingShape(page, shapeId) {
2595
+ if (page.shapes.some(
2596
+ (shape2) => shape2.kind !== "shape" || shape2.masterId || shape2.children.length || shape2.image || shape2.foreignVector
2597
+ ))
2598
+ return void 0;
2599
+ const shape = page.shapes.find((candidate) => candidate.id === shapeId);
2600
+ return shape && !shape.hidden && !shape.layerIds?.length ? shape : void 0;
2601
+ }
2602
+
2603
+ // geometry/align-distribute.ts
2604
+ function usesSlideReference(elementCount, options) {
2605
+ if (!options?.slideSize) {
2606
+ return false;
2607
+ }
2608
+ return options.reference === "slide";
2609
+ }
2610
+ function resolveAlignReferenceBox(elements, options) {
2611
+ if (elements.length === 0) {
2612
+ return null;
2613
+ }
2614
+ if (usesSlideReference(elements.length, options)) {
2615
+ return { minX: 0, minY: 0, maxX: options.slideSize.width, maxY: options.slideSize.height };
2616
+ }
2617
+ if (elements.length < 2) {
2618
+ return null;
2619
+ }
2620
+ return {
2621
+ minX: Math.min(...elements.map((e) => e.x)),
2622
+ minY: Math.min(...elements.map((e) => e.y)),
2623
+ maxX: Math.max(...elements.map((e) => e.x + e.width)),
2624
+ maxY: Math.max(...elements.map((e) => e.y + e.height))
2625
+ };
2626
+ }
2627
+ function alignElements(elements, edge, options) {
2628
+ const result = /* @__PURE__ */ new Map();
2629
+ const ref = resolveAlignReferenceBox(elements, options);
2630
+ if (!ref) {
2631
+ return result;
2632
+ }
2633
+ const { minX, minY, maxX, maxY } = ref;
2634
+ const centerX = (minX + maxX) / 2;
2635
+ const centerY = (minY + maxY) / 2;
2636
+ for (const el of elements) {
2637
+ switch (edge) {
2638
+ case "left":
2639
+ result.set(el.id, { x: minX });
2640
+ break;
2641
+ case "right":
2642
+ result.set(el.id, { x: maxX - el.width });
2643
+ break;
2644
+ case "centerH":
2645
+ result.set(el.id, { x: centerX - el.width / 2 });
2646
+ break;
2647
+ case "top":
2648
+ result.set(el.id, { y: minY });
2649
+ break;
2650
+ case "bottom":
2651
+ result.set(el.id, { y: maxY - el.height });
2652
+ break;
2653
+ case "middle":
2654
+ result.set(el.id, { y: centerY - el.height / 2 });
2655
+ break;
2656
+ }
2657
+ }
2658
+ return result;
2659
+ }
2660
+
2661
+ // visio/ui/shape-arrange.ts
2662
+ function distributeBoxes(boxes, axis) {
2663
+ const horizontal = axis === "horizontal";
2664
+ const start = (box2) => horizontal ? box2.x : -box2.y - box2.height;
2665
+ const size = (box2) => horizontal ? box2.width : box2.height;
2666
+ const center = (box2) => start(box2) + size(box2) / 2;
2667
+ const sorted = [...boxes].sort((left, right) => center(left) - center(right));
2668
+ const first = sorted[0], last = sorted.at(-1);
2669
+ const total = sorted.reduce((sum, box2) => sum + size(box2), 0);
2670
+ const gap = (start(last) + size(last) - start(first) - total) / (sorted.length - 1);
2671
+ let cursor = start(first);
2672
+ const positions = /* @__PURE__ */ new Map();
2673
+ for (const box2 of sorted) {
2674
+ positions.set(box2.id, horizontal ? { x: cursor } : { y: -cursor - box2.height });
2675
+ cursor += size(box2) + gap;
2676
+ }
2677
+ return positions;
2678
+ }
2679
+ function alignmentBox(shape) {
2680
+ if (!shape.rotation || shape.kind !== "shape" || !(shape.width > 0 && shape.height > 0))
2681
+ return void 0;
2682
+ const [a, b, c, d, e, f] = shape.transform;
2683
+ if (![a, b, c, d, e, f, shape.rotation.pinX, shape.rotation.pinY, shape.width, shape.height].every(
2684
+ Number.isFinite
2685
+ ))
2686
+ return void 0;
2687
+ const points = [
2688
+ [0, 0],
2689
+ [shape.width, 0],
2690
+ [0, shape.height],
2691
+ [shape.width, shape.height]
2692
+ ];
2693
+ const xs = points.map(([x2, y]) => a * x2 + c * y + e);
2694
+ const ys = points.map(([x2, y]) => b * x2 + d * y + f);
2695
+ const x = Math.min(...xs), top = Math.max(...ys);
2696
+ const width = Math.max(...xs) - x, height = top - Math.min(...ys);
2697
+ if (![x, top, width, height].every(Number.isFinite) || width <= 0 || height <= 0)
2698
+ return void 0;
2699
+ return { id: shape.id, x, y: -top, width, height };
2700
+ }
2701
+ function visioArrangeCommands(page, shapeIds, action) {
2702
+ const minimum = action.type === "align" ? 2 : 3;
2703
+ if (shapeIds.length < minimum || shapeIds.length > 1e3 || new Set(shapeIds).size !== shapeIds.length)
2704
+ return void 0;
2705
+ if (action.type === "align" ? !["left", "center", "right", "top", "middle", "bottom"].includes(action.edge) : action.type !== "distribute" || !["horizontal", "vertical"].includes(action.axis))
2706
+ return void 0;
2707
+ const shapes = [];
2708
+ const boxes = [];
2709
+ for (const id of shapeIds) {
2710
+ const shape = visioStyleFormattingShape(page, id);
2711
+ const box2 = shape && alignmentBox(shape);
2712
+ if (!shape || !box2 || page.connectors.some(
2713
+ (connection) => connection.fromShapeId === id || connection.toShapeId === id
2714
+ ))
2715
+ return void 0;
2716
+ shapes.push(shape);
2717
+ boxes.push(box2);
2718
+ }
2719
+ const reference = boxes[0];
2720
+ const normalized = boxes.map((box2) => ({
2721
+ ...box2,
2722
+ x: box2.x - reference.x,
2723
+ y: box2.y - reference.y
2724
+ }));
2725
+ const edge = action.type === "align" ? action.edge === "center" ? "centerH" : action.edge : void 0;
2726
+ const positions = action.type === "align" ? alignElements(normalized, edge, {
2727
+ reference: "slide",
2728
+ slideSize: { width: reference.width, height: reference.height }
2729
+ }) : distributeBoxes(normalized, action.axis);
2730
+ const commands = [];
2731
+ try {
2732
+ for (let index = 0; index < shapes.length; index++) {
2733
+ const shape = shapes[index], box2 = normalized[index];
2734
+ const position = positions.get(shape.id);
2735
+ if (!position) return void 0;
2736
+ const dx = (position.x ?? box2.x) - box2.x, dy = -((position.y ?? box2.y) - box2.y);
2737
+ if (Math.abs(dx) < 1e-10 && Math.abs(dy) < 1e-10) continue;
2738
+ commands.push(
2739
+ visioPageEditToDrawing(page, {
2740
+ type: "move-shape",
2741
+ pageId: page.id,
2742
+ shapeId: shape.id,
2743
+ x: shape.rotation.pinX + dx,
2744
+ y: shape.rotation.pinY + dy
2745
+ })
2746
+ );
2747
+ }
2748
+ } catch {
2749
+ return void 0;
2750
+ }
2751
+ return commands;
2752
+ }
2753
+
2754
+ // visio/ui/selection.ts
2755
+ var EMPTY_SELECTION = Object.freeze([]);
2756
+ var selectionKey = (shape, pageId) => JSON.stringify([shape.pageId ?? pageId, shape.id]);
2757
+ function visioSelectionIsOnPage(selection, pageId) {
2758
+ return !!selection && (selection.pageId === void 0 || selection.pageId === pageId);
2759
+ }
2760
+ function sameSelection(left, right) {
2761
+ return left.length === right.length && left.every((shape, index) => {
2762
+ const other = right[index];
2763
+ return shape.id === other.id && shape.pageId === other.pageId && shape.name === other.name;
2764
+ });
2765
+ }
2766
+ function snapshotSelection(model, pageIndex, input, visible) {
2767
+ if (!Array.isArray(input)) throw new Error("Selection requires an array.");
2768
+ const length = input.length;
2769
+ if (length > VISIO_VISIBILITY_LIMITS.maxShapes)
2770
+ throw new Error("Selection exceeds the supported shape count.");
2771
+ const page = model?.pages[pageIndex];
2772
+ const candidates = /* @__PURE__ */ new Map();
2773
+ for (let index = 0; index < length; index++) {
2774
+ const item = input[index];
2775
+ const id = item?.id, name = item?.name, pageId = item?.pageId;
2776
+ if (typeof id !== "string" || typeof name !== "string" || id.length > 1024 || name.length > 4096 || pageId !== void 0 && (typeof pageId !== "string" || pageId.length > 256))
2777
+ throw new Error("Selection requires shape IDs, names and optional page IDs.");
2778
+ const copied = Object.freeze({ id, name, ...pageId === void 0 ? {} : { pageId } });
2779
+ const key = selectionKey(copied, page?.id ?? "");
2780
+ if (!candidates.has(key)) candidates.set(key, copied);
2781
+ }
2782
+ if (!model || !page || !length) return EMPTY_SELECTION;
2783
+ const accepted = /* @__PURE__ */ new Map();
2784
+ const content = /* @__PURE__ */ new WeakMap();
2785
+ for (const source of getVisioPageLayers(model, page.id)) {
2786
+ const pending = source.shapes.map((shape) => ({ shape, ancestors: [] }));
2787
+ while (pending.length) {
2788
+ const { shape, ancestors } = pending.pop();
2789
+ const key = selectionKey({ id: shape.id, pageId: source.id }, page.id);
2790
+ if (candidates.has(key) && hasVisibleShapeContent(shape, visible, content))
2791
+ accepted.set(key, ancestors);
2792
+ for (const child of shape.children)
2793
+ pending.push({ shape: child, ancestors: [...ancestors, key] });
2794
+ }
2795
+ }
2796
+ const result = [];
2797
+ for (const [key, item] of candidates) {
2798
+ const ancestors = accepted.get(key);
2799
+ if (!ancestors || ancestors.some((ancestor) => accepted.has(ancestor))) continue;
2800
+ result.push(item);
2801
+ }
2802
+ return result.length ? Object.freeze(result) : EMPTY_SELECTION;
2803
+ }
2804
+ function hasVisibleShapeContent(shape, visible, cache = /* @__PURE__ */ new WeakMap()) {
2805
+ const cached = cache.get(shape);
2806
+ if (cached !== void 0) return cached;
2807
+ const own = !(shape.kind === "group" && shape.groupDisplayMode === 0) && (shape.geometry.length > 0 || !!shape.image || !!shape.foreignVector || !!shape.text.plainText || shape.kind === "foreign");
2808
+ const renderable = (visible?.get(shape) ?? !shape.hidden) && (own || shape.children.some((child) => hasVisibleShapeContent(child, visible, cache)));
2809
+ cache.set(shape, renderable);
2810
+ return renderable;
2811
+ }
2812
+
2813
+ // visio/ui/shape-clipboard.ts
2814
+ function visioClipboardShape(page, shapeId) {
2815
+ const shape = visioStyleFormattingShape(page, shapeId);
2816
+ if (!shape || shape.kind !== "shape" || !(shape.width > 0) || !(shape.height > 0) || page.connectors.some(
2817
+ (connection) => connection.fromShapeId === shapeId || connection.toShapeId === shapeId
2818
+ ))
2819
+ return void 0;
2820
+ return shape;
2821
+ }
2822
+ function visioPasteCommand(page, value, offset = { x: 0.33, y: -0.33 }) {
2823
+ try {
2824
+ const clipboard = snapshotVisioClipboard(value);
2825
+ if ((page.drawingToPageScale ?? 1) !== clipboard.sourceDrawingScale || [offset.x, offset.y].some((number) => !Number.isFinite(number) || Math.abs(number) > 1e6))
2826
+ return void 0;
2827
+ let next = Number(visioNextShapeId(page));
2828
+ if (next + clipboard.shapes.length - 1 > 4294967295) return void 0;
2829
+ const ids = new Map(clipboard.shapes.map((shape) => [shape.shapeId, String(next++)]));
2830
+ return {
2831
+ type: "paste-shapes",
2832
+ pageId: page.id,
2833
+ clipboard,
2834
+ copies: clipboard.selectionIds.map((shapeId) => ({ shapeId, newShapeId: ids.get(shapeId) })),
2835
+ offsetX: offset.x,
2836
+ offsetY: offset.y
2837
+ };
2838
+ } catch {
2839
+ return void 0;
2840
+ }
2841
+ }
2842
+
2843
+ // visio/ui/shape-move.ts
2844
+ function visioMovementShape(page, id) {
2845
+ const shape = visioStyleFormattingShape(page, id);
2846
+ if (!shape || shape.kind !== "shape" || !shape.rotation || !(shape.width > 0 && shape.height > 0) || ![
2847
+ shape.width,
2848
+ shape.height,
2849
+ shape.rotation.pinX,
2850
+ shape.rotation.pinY,
2851
+ ...shape.transform
2852
+ ].every(Number.isFinite) || page.connectors.some(
2853
+ (connection) => connection.fromShapeId === id || connection.toShapeId === id
2854
+ ))
2855
+ return void 0;
2856
+ return shape;
2857
+ }
2858
+ function visioPageDragDelta(start, end) {
2859
+ return { x: end.x - start.x, y: start.y - end.y };
2860
+ }
2861
+ function visioMovePreviewTransform(shape, delta) {
2862
+ if (![delta.x, delta.y, ...shape.transform].every(Number.isFinite)) return void 0;
2863
+ const [a, b, c, d, e, f] = shape.transform;
2864
+ const result = [a, b, c, d, e + delta.x, f + delta.y];
2865
+ return result.every(Number.isFinite) ? result : void 0;
2866
+ }
2867
+ function visioMoveCommands(page, ids, delta) {
2868
+ if (!ids.length || ids.length > 1e3 || new Set(ids).size !== ids.length || ![delta.x, delta.y].every(Number.isFinite))
2869
+ return void 0;
2870
+ const shapes = ids.map((id) => visioMovementShape(page, id));
2871
+ if (shapes.some((shape) => !shape)) return void 0;
2872
+ if (delta.x === 0 && delta.y === 0) return [];
2873
+ try {
2874
+ const edits = shapes.map(
2875
+ (shape) => visioPageEditToDrawing(page, {
2876
+ type: "move-shape",
2877
+ pageId: page.id,
2878
+ shapeId: shape.id,
2879
+ x: shape.rotation.pinX + delta.x,
2880
+ y: shape.rotation.pinY + delta.y
2881
+ })
2882
+ );
2883
+ return edits.every(
2884
+ (edit) => edit.type === "move-shape" && Number.isFinite(edit.x) && Number.isFinite(edit.y)
2885
+ ) ? edits : void 0;
2886
+ } catch {
2887
+ return void 0;
2888
+ }
2889
+ }
2890
+
2891
+ // visio/ui/size-position.ts
2892
+ var bounded = (value) => Number.isFinite(value) && Math.abs(value) <= 1e6;
2893
+ function visioSizePositionState(page, id) {
2894
+ const shape = visioMovementShape(page, id), ratio = page.drawingToPageScale ?? 1;
2895
+ if (!shape || !Number.isFinite(ratio) || ratio <= 0) return void 0;
2896
+ const rotation = shape.rotation;
2897
+ const state = {
2898
+ pageId: page.id,
2899
+ shapeId: id,
2900
+ x: rotation.pinX / ratio,
2901
+ y: rotation.pinY / ratio,
2902
+ width: shape.width / ratio,
2903
+ height: shape.height / ratio,
2904
+ angle: rotation.angle * 180 / Math.PI
2905
+ };
2906
+ if (![state.x, state.y, state.width, state.height, rotation.angle].every(bounded) || !Number.isFinite(state.angle))
2907
+ return void 0;
2908
+ return Object.freeze(state);
2909
+ }
2910
+ function visioSizePositionCommand(page, id, field, value) {
2911
+ const state = visioSizePositionState(page, id);
2912
+ if (!state || !Number.isFinite(value)) return void 0;
2913
+ if (!["x", "y", "width", "height", "angle"].includes(field)) return void 0;
2914
+ if (value === state[field]) return [];
2915
+ const target = { pageId: page.id, shapeId: id };
2916
+ if (field === "angle") {
2917
+ const angle = value * Math.PI / 180;
2918
+ return bounded(angle) ? [{ type: "rotate-shape", ...target, angle }] : void 0;
2919
+ }
2920
+ if (!bounded(value)) return void 0;
2921
+ if (field === "x" || field === "y")
2922
+ return [
2923
+ {
2924
+ type: "move-shape",
2925
+ ...target,
2926
+ x: field === "x" ? value : state.x,
2927
+ y: field === "y" ? value : state.y
2928
+ }
2929
+ ];
2930
+ if (value <= 0) return void 0;
2931
+ return [
2932
+ {
2933
+ type: "resize-shape",
2934
+ ...target,
2935
+ width: field === "width" ? value : state.width,
2936
+ height: field === "height" ? value : state.height
2937
+ }
2938
+ ];
2939
+ }
2940
+
2941
+ // visio/ui/marquee.ts
2942
+ function visioMarqueeBox(start, end) {
2943
+ if (![start.x, start.y, end.x, end.y].every(Number.isFinite)) return void 0;
2944
+ const box2 = {
2945
+ x: Math.min(start.x, end.x),
2946
+ y: Math.min(start.y, end.y),
2947
+ width: Math.abs(end.x - start.x),
2948
+ height: Math.abs(end.y - start.y)
2949
+ };
2950
+ return Object.values(box2).every(Number.isFinite) ? box2 : void 0;
2951
+ }
2952
+ function visioShapePageBox(page, shape) {
2953
+ if (![page.height, shape.width, shape.height, ...shape.transform].every(Number.isFinite) || shape.width < 0 || shape.height < 0)
2954
+ return void 0;
2955
+ const [a, b, c, d, e, f] = shape.transform;
2956
+ const corners = [
2957
+ [0, 0],
2958
+ [shape.width, 0],
2959
+ [0, shape.height],
2960
+ [shape.width, shape.height]
2961
+ ];
2962
+ const xs = corners.map(([x, y]) => a * x + c * y + e), ys = corners.map(([x, y]) => b * x + d * y + f);
2963
+ const left = Math.min(...xs), right = Math.max(...xs), bottom = Math.min(...ys), top = Math.max(...ys);
2964
+ const box2 = { x: left, y: page.height - top, width: right - left, height: top - bottom };
2965
+ return Object.values(box2).every(Number.isFinite) ? box2 : void 0;
2966
+ }
2967
+ function visioMarqueeSelection(page, box2, visible) {
2968
+ if (![box2.x, box2.y, box2.width, box2.height].every(Number.isFinite) || box2.width <= 0 || box2.height <= 0)
2969
+ return [];
2970
+ const cache = /* @__PURE__ */ new WeakMap();
2971
+ return page.shapes.flatMap((shape) => {
2972
+ const extent = visioShapePageBox(page, shape);
2973
+ return extent && hasVisibleShapeContent(shape, visible, cache) && extent.x >= box2.x && extent.y >= box2.y && extent.x + extent.width <= box2.x + box2.width && extent.y + extent.height <= box2.y + box2.height ? [{ id: shape.id, name: shape.name, pageId: page.id }] : [];
2974
+ });
2975
+ }
2976
+
2977
+ // visio/ui/shape-resize.ts
2978
+ var VISIO_RESIZE_HANDLES = [
2979
+ { id: "sw", x: 0, y: 0 },
2980
+ { id: "s", x: 0.5, y: 0 },
2981
+ { id: "se", x: 1, y: 0 },
2982
+ { id: "e", x: 1, y: 0.5 },
2983
+ { id: "ne", x: 1, y: 1 },
2984
+ { id: "n", x: 0.5, y: 1 },
2985
+ { id: "nw", x: 0, y: 1 },
2986
+ { id: "w", x: 0, y: 0.5 }
2987
+ ];
2988
+ function visioResizeShape(page, id) {
2989
+ const shape = visioMovementShape(page, id);
2990
+ return shape && visioResizeFrame(shape, { width: shape.width, height: shape.height }, { x: 0, y: 0 }) ? shape : void 0;
2991
+ }
2992
+ function visioResizeFrame(shape, size, anchor) {
2993
+ if (!shape.rotation) return void 0;
2994
+ const geometry = visioAnchoredResizeGeometry(
2995
+ { ...shape, pinX: shape.rotation.pinX, pinY: shape.rotation.pinY },
2996
+ size,
2997
+ anchor
2998
+ );
2999
+ return geometry ? {
3000
+ width: size.width,
3001
+ height: size.height,
3002
+ transform: geometry.transform,
3003
+ pinX: geometry.pinX,
3004
+ pinY: geometry.pinY
3005
+ } : void 0;
3006
+ }
3007
+ function visioResizeDrag(page, id, handle, start, end) {
3008
+ const shape = visioResizeShape(page, id), location = VISIO_RESIZE_HANDLES.find((item) => item.id === handle);
3009
+ if (!shape || !location) return void 0;
3010
+ const delta = visioPageDragDelta(start, end), [a, b, c, d] = shape.transform, determinant = a * d - b * c;
3011
+ const x = (d * delta.x - c * delta.y) / determinant, y = (-b * delta.x + a * delta.y) / determinant;
3012
+ const size = {
3013
+ width: location.x === 0.5 ? shape.width : Math.max(Math.min(1 / 16, shape.width), shape.width + (location.x === 1 ? x : -x)),
3014
+ height: location.y === 0.5 ? shape.height : Math.max(Math.min(1 / 16, shape.height), shape.height + (location.y === 1 ? y : -y))
3015
+ };
3016
+ const anchor = {
3017
+ x: 1 - location.x,
3018
+ y: 1 - location.y
3019
+ };
3020
+ const frame = visioResizeFrame(shape, size, anchor);
3021
+ if (!frame) return void 0;
3022
+ try {
3023
+ const command = visioPageEditToDrawing(page, {
3024
+ type: "resize-shape",
3025
+ pageId: page.id,
3026
+ shapeId: id,
3027
+ ...size,
3028
+ anchor
3029
+ });
3030
+ return command.type === "resize-shape" && command.width <= 1e6 && command.height <= 1e6 ? { frame, command } : void 0;
3031
+ } catch {
3032
+ return void 0;
3033
+ }
3034
+ }
3035
+
3036
+ // visio/ui/draw-plan.ts
3037
+ var SNAP = 1 / 16;
3038
+ var boundedNumber = (value) => Number.isFinite(value) && Math.abs(value) <= 1e6;
3039
+ function visioDrawingPoint(page, point, options = {}) {
3040
+ if (![point.x, point.y, page.width, page.height].every(boundedNumber) || page.width <= 0 || page.height <= 0)
3041
+ return void 0;
3042
+ const coordinate = (value, maximum) => {
3043
+ const bounded2 = options.bounded === false ? value : Math.max(0, Math.min(maximum, value));
3044
+ return options.snap === false ? bounded2 : Math.round(bounded2 / SNAP) * SNAP;
3045
+ };
3046
+ return { x: coordinate(point.x, page.width), y: coordinate(point.y, page.height) };
3047
+ }
3048
+ function visioDrawBounds(start, end) {
3049
+ if (![start.x, start.y, end.x, end.y].every(boundedNumber))
3050
+ throw new Error("Invalid drawing bounds.");
3051
+ return {
3052
+ x: Math.min(start.x, end.x),
3053
+ y: Math.min(start.y, end.y),
3054
+ width: Math.abs(end.x - start.x),
3055
+ height: Math.abs(end.y - start.y),
3056
+ centerX: (start.x + end.x) / 2,
3057
+ centerY: (start.y + end.y) / 2,
3058
+ radiusX: Math.abs(end.x - start.x) / 2,
3059
+ radiusY: Math.abs(end.y - start.y) / 2
3060
+ };
3061
+ }
3062
+ function visioBoxCreationCommand(page, kind, centre, size, text) {
3063
+ if (!["rectangle", "ellipse", "text"].includes(kind) || ![centre.x, centre.y, size.width, size.height].every(boundedNumber) || size.width <= 0 || size.height <= 0)
3064
+ throw new Error("Invalid box creation geometry or tool.");
3065
+ const box2 = {
3066
+ pageId: page.id,
3067
+ shapeId: visioNextShapeId(page),
3068
+ x: centre.x,
3069
+ y: page.height - centre.y,
3070
+ width: size.width,
3071
+ height: size.height
3072
+ };
3073
+ const command = kind === "text" ? { ...box2, type: "create-text-box", text: text ?? "" } : {
3074
+ ...box2,
3075
+ type: kind === "ellipse" ? "create-ellipse" : "create-rectangle",
3076
+ ...text === void 0 ? {} : { text }
3077
+ };
3078
+ return drawingCommand(page, command);
3079
+ }
3080
+ function drawingCommand(page, command) {
3081
+ const result = visioPageEditToDrawing(page, command);
3082
+ if (Object.values(result).some((value) => typeof value === "number" && !boundedNumber(value)))
3083
+ throw new Error("Drawing coordinates exceed finite limits.");
3084
+ return result;
3085
+ }
3086
+ function visioLineCreationCommand(page, begin, end) {
3087
+ if (![begin.x, begin.y, end.x, end.y].every(boundedNumber))
3088
+ throw new Error("Invalid line creation geometry.");
3089
+ return drawingCommand(page, {
3090
+ type: "create-line",
3091
+ pageId: page.id,
3092
+ shapeId: visioNextShapeId(page),
3093
+ beginX: begin.x,
3094
+ beginY: page.height - begin.y,
3095
+ endX: end.x,
3096
+ endY: page.height - end.y
3097
+ });
3098
+ }
3099
+ function visioDrawIsLargeEnough(kind, start, end) {
3100
+ if (!["rectangle", "ellipse", "line", "text"].includes(kind) || ![start.x, start.y, end.x, end.y].every(boundedNumber))
3101
+ return false;
3102
+ const bounds = visioDrawBounds(start, end);
3103
+ return kind === "line" ? Math.hypot(bounds.width, bounds.height) >= SNAP : bounds.width >= SNAP && bounds.height >= SNAP;
3104
+ }
3105
+ function visioDrawPlan(page, kind, start, end, text) {
3106
+ if (!visioDrawIsLargeEnough(kind, start, end)) return void 0;
3107
+ const bounds = visioDrawBounds(start, end);
3108
+ return kind === "line" ? visioLineCreationCommand(page, start, end) : visioBoxCreationCommand(page, kind, { x: bounds.centerX, y: bounds.centerY }, bounds, text);
3109
+ }
3110
+
3111
+ // visio/ui/line-dash.ts
3112
+ function visioLineDashLengths(style) {
3113
+ return style.lineDash?.map(
3114
+ (length, index) => length === 0 && index % 2 === 0 ? style.lineDashDotLength ?? 0 : length * style.lineWidth
3115
+ );
3116
+ }
3117
+
3118
+ // visio/ui/shape-formatting.ts
3119
+ function visioShapeFormattingState(shapes) {
3120
+ const common = (values) => values.length && values.every((value) => value === values[0]) ? values[0] : void 0;
3121
+ const percent = (opacity) => opacity === void 0 || !Number.isFinite(opacity) || opacity < 0 || opacity > 1 ? void 0 : Math.round((1 - opacity) * 200) / 2;
3122
+ const foreground = shapes.map(
3123
+ (shape) => percent(
3124
+ shape.style.fillForegroundOpacity ?? (shape.style.fillGradient || shape.style.fillPattern ? void 0 : shape.style.fillOpacity)
3125
+ )
3126
+ );
3127
+ const background = shapes.map((shape) => percent(shape.style.fillBackgroundOpacity));
3128
+ return {
3129
+ linePattern: common(shapes.map((shape) => shape.style.linePattern)),
3130
+ fillPatternIndex: common(shapes.map((shape) => shape.style.fillPatternIndex)),
3131
+ fillBackgroundColor: common(shapes.map((shape) => shape.style.fillBackgroundColor)),
3132
+ fillForegroundTransparency: common(foreground),
3133
+ fillBackgroundTransparency: common(background),
3134
+ fillTransparency: common([...foreground, ...background]),
3135
+ lineTransparency: common(
3136
+ shapes.map(
3137
+ (shape) => percent(
3138
+ shape.style.lineColorOpacity ?? (shape.style.lineGradient ? void 0 : shape.style.lineOpacity)
3139
+ )
3140
+ )
3141
+ )
3142
+ };
3143
+ }
3144
+
3145
+ // visio/ui/text-replace-types.ts
3146
+ var VISIO_TEXT_REPLACE_LIMITS = Object.freeze({
3147
+ query: 256,
3148
+ replacement: 32768,
3149
+ text: 2e6,
3150
+ names: 1e6,
3151
+ output: 1e6,
3152
+ matches: 1e4,
3153
+ commands: 1e3,
3154
+ shapes: 25e3,
3155
+ pages: 256,
3156
+ depth: 64
3157
+ });
3158
+ var textReplaceError = (message) => {
3159
+ throw new Error(message);
3160
+ };
3161
+ function replaceString(value, maximum, label) {
3162
+ if (typeof value !== "string" || value.length > maximum)
3163
+ return textReplaceError(`Replace ${label} exceeds supported string limits.`);
3164
+ return value;
3165
+ }
3166
+ function replaceIdentity(value) {
3167
+ const id = replaceString(value, 256, "identity");
3168
+ if (!id) textReplaceError("Replace requires nonempty identities.");
3169
+ return id;
3170
+ }
3171
+
3172
+ // visio/ui/text-replace-snapshot.ts
3173
+ function snapshotReplaceScope(input) {
3174
+ const query = replaceString(input.query, VISIO_TEXT_REPLACE_LIMITS.query, "query");
3175
+ const scope = input.scope, pageId = replaceIdentity(input.pageId), matchCase = input.matchCase;
3176
+ if (!query || matchCase !== true || !["selection", "current-page", "all-pages"].includes(scope))
3177
+ textReplaceError(
3178
+ "Replace requires a nonempty literal query, Match case, and an explicit scope."
3179
+ );
3180
+ let selection;
3181
+ const original = input.selection;
3182
+ if (original !== void 0) {
3183
+ const length = original.length;
3184
+ if (!Array.isArray(original) || !Number.isSafeInteger(length) || length > VISIO_TEXT_REPLACE_LIMITS.shapes || length < 0)
3185
+ textReplaceError("Replace selection exceeds supported limits.");
3186
+ selection = [];
3187
+ for (let index = 0; index < length; index++) {
3188
+ const item = original[index], id = replaceIdentity(item.id), page = item.pageId;
3189
+ selection.push(
3190
+ Object.freeze({ id, ...page === void 0 ? {} : { pageId: replaceIdentity(page) } })
3191
+ );
3192
+ }
3193
+ Object.freeze(selection);
3194
+ }
3195
+ return Object.freeze({ query, scope, pageId, matchCase, ...selection ? { selection } : {} });
3196
+ }
3197
+ function replaceEntries(model, scope, requirePage = true) {
3198
+ const pages = model.pages;
3199
+ const count = pages.length;
3200
+ if (!Array.isArray(pages) || !Number.isSafeInteger(count) || count > VISIO_TEXT_REPLACE_LIMITS.pages || count < 0)
3201
+ textReplaceError("Replace page list exceeds supported limits.");
3202
+ const all = [], identities = /* @__PURE__ */ new Map(), pageIds = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set();
3203
+ let characters = 0, names = 0;
3204
+ for (let pageIndex = 0; pageIndex < count; pageIndex++) {
3205
+ const page = pages[pageIndex], pageId = replaceIdentity(page.id), ids = /* @__PURE__ */ new Set();
3206
+ if (pageIds.has(pageId)) textReplaceError("Replace page identities are ambiguous.");
3207
+ pageIds.add(pageId);
3208
+ const walk = (source, depth) => {
3209
+ const length = source.length;
3210
+ if (!Array.isArray(source) || !Number.isSafeInteger(length) || length < 0 || length > 0 && depth > VISIO_TEXT_REPLACE_LIMITS.depth || length > VISIO_TEXT_REPLACE_LIMITS.shapes)
3211
+ textReplaceError("Replace shape list exceeds supported limits.");
3212
+ for (let index = 0; index < length; index++) {
3213
+ const shape = source[index], shapeId = replaceIdentity(shape.id);
3214
+ if (seen.has(shape) || ids.has(shapeId) || seen.size >= VISIO_TEXT_REPLACE_LIMITS.shapes)
3215
+ textReplaceError("Replace shape identities, depth or cycles are invalid.");
3216
+ seen.add(shape);
3217
+ ids.add(shapeId);
3218
+ const text = replaceString(shape.text.plainText, VISIO_TEXT_REPLACE_LIMITS.text, "source text");
3219
+ const name = replaceString(shape.name, 4096, "shape name");
3220
+ names += name.length;
3221
+ if (names > VISIO_TEXT_REPLACE_LIMITS.names) textReplaceError("Replace shape names exceed aggregate limits.");
3222
+ characters += text.length;
3223
+ if (characters > VISIO_TEXT_REPLACE_LIMITS.text) textReplaceError("Replace text exceeds aggregate limits.");
3224
+ const entry = { pageId, shapeId, name, pageIndex, text, end: 0 };
3225
+ identities.set(JSON.stringify([pageId, shapeId]), all.length);
3226
+ all.push(entry);
3227
+ walk(shape.children, depth + 1);
3228
+ entry.end = all.length;
3229
+ }
3230
+ };
3231
+ walk(page.shapes, 0);
3232
+ }
3233
+ if (requirePage && !pageIds.has(scope.pageId))
3234
+ textReplaceError("Replace current page does not exist.");
3235
+ if (scope.scope === "all-pages") return all;
3236
+ if (scope.scope === "current-page") return all.filter((entry) => entry.pageId === scope.pageId);
3237
+ const result = [], added = /* @__PURE__ */ new Set();
3238
+ for (const selected of scope.selection ?? []) {
3239
+ const pageId = selected.pageId ?? scope.pageId;
3240
+ const start = identities.get(JSON.stringify([pageId, selected.id]));
3241
+ if (start === void 0) return textReplaceError("Replace selected shape does not exist.");
3242
+ for (let index = start; index < all[start].end; index++) {
3243
+ const entry = all[index];
3244
+ if (added.has(entry)) {
3245
+ index = entry.end - 1;
3246
+ continue;
3247
+ }
3248
+ result.push(entry);
3249
+ added.add(entry);
3250
+ }
3251
+ }
3252
+ return result;
3253
+ }
3254
+
3255
+ // visio/ui/text-replace-selection.ts
3256
+ function visioTextOccurrenceSelection(model, occurrence) {
3257
+ const pageId = replaceIdentity(occurrence.pageId), shapeId = replaceIdentity(occurrence.shapeId), start = occurrence.start, end = occurrence.end;
3258
+ if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end <= start)
3259
+ return void 0;
3260
+ const entries = replaceEntries(
3261
+ model,
3262
+ { pageId, scope: "all-pages"},
3263
+ false
3264
+ );
3265
+ const entry = entries.find((item) => item.pageId === pageId && item.shapeId === shapeId);
3266
+ if (!entry || end > entry.text.length) return void 0;
3267
+ return Object.freeze({
3268
+ pageIndex: entry.pageIndex,
3269
+ selection: Object.freeze({ id: shapeId, name: entry.name, pageId })
3270
+ });
3271
+ }
3272
+
3273
+ // visio/ui/text-replace.ts
3274
+ function occurrences(entries, query) {
3275
+ const result = [];
3276
+ for (const entry of entries) {
3277
+ let start = entry.text.indexOf(query);
3278
+ while (start >= 0) {
3279
+ if (result.length >= VISIO_TEXT_REPLACE_LIMITS.matches)
3280
+ textReplaceError("Replace occurrence count exceeds limits.");
3281
+ result.push(
3282
+ Object.freeze({
3283
+ pageId: entry.pageId,
3284
+ shapeId: entry.shapeId,
3285
+ start,
3286
+ end: start + query.length
3287
+ })
3288
+ );
3289
+ start = entry.text.indexOf(query, start + query.length);
3290
+ }
3291
+ }
3292
+ return Object.freeze(result);
3293
+ }
3294
+ function visioTextReplaceOccurrences(model, input) {
3295
+ const scope = snapshotReplaceScope(input);
3296
+ return occurrences(replaceEntries(model, scope), scope.query);
3297
+ }
3298
+ function visioTextReplaceFindNext(model, input, current) {
3299
+ const saved = snapshotOccurrence(current);
3300
+ const found = visioTextReplaceOccurrences(model, input);
3301
+ if (saved === void 0) return found[0];
3302
+ const index = found.findIndex((match) => sameOccurrence(match, saved));
3303
+ if (index < 0) return textReplaceError("Find occurrence is stale or outside the scope.");
3304
+ return found[(index + 1) % found.length];
3305
+ }
3306
+ var records = /* @__PURE__ */ new WeakMap();
3307
+ var sameOccurrence = (a, b) => a.pageId === b.pageId && a.shapeId === b.shapeId && a.start === b.start && a.end === b.end;
3308
+ var sameTarget = (entry, match) => entry.pageId === match.pageId && entry.shapeId === match.shapeId;
3309
+ function snapshotOccurrence(original) {
3310
+ if (original === void 0) return void 0;
3311
+ const current = {
3312
+ pageId: replaceIdentity(original.pageId),
3313
+ shapeId: replaceIdentity(original.shapeId),
3314
+ start: original.start,
3315
+ end: original.end
3316
+ };
3317
+ if (!Number.isSafeInteger(current.start) || !Number.isSafeInteger(current.end) || current.start < 0 || current.end <= current.start || current.end > VISIO_TEXT_REPLACE_LIMITS.text)
3318
+ textReplaceError("Invalid replacement occurrence range.");
3319
+ return current;
3320
+ }
3321
+ function visioTextReplacePlan(model, input) {
3322
+ const scope = snapshotReplaceScope(input), replacement = replaceString(input.replacement, VISIO_TEXT_REPLACE_LIMITS.replacement, "replacement"), mode = input.mode, current = snapshotOccurrence(input.current);
3323
+ if (mode !== "current" && mode !== "all") textReplaceError("Invalid replacement mode.");
3324
+ if (/[\u0000-\u0008\u000b\u000c\u000d\u000e-\u001f\ufffe\uffff]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/u.test(
3325
+ replacement
3326
+ ))
3327
+ textReplaceError("Replacement contains invalid XML text characters.");
3328
+ const entries = replaceEntries(model, scope), found = occurrences(entries, scope.query);
3329
+ const active = current === void 0 ? found[0] : found.find((match) => sameOccurrence(match, current));
3330
+ if (current !== void 0 && !active)
3331
+ textReplaceError("Replace occurrence is stale or outside the scope.");
3332
+ const selected = mode === "all" ? found : active ? [active] : [];
3333
+ const targets = /* @__PURE__ */ new Map();
3334
+ for (const match of selected) {
3335
+ const key = JSON.stringify([match.pageId, match.shapeId]);
3336
+ const list = targets.get(key) ?? [];
3337
+ list.push(match);
3338
+ targets.set(key, list);
3339
+ }
3340
+ if (targets.size > VISIO_TEXT_REPLACE_LIMITS.commands) textReplaceError("Replace command count exceeds limits.");
3341
+ const edits = [], updated = [];
3342
+ let outputCharacters = 0;
3343
+ for (const entry of entries) {
3344
+ const matches = targets.get(JSON.stringify([entry.pageId, entry.shapeId]));
3345
+ let text = entry.text;
3346
+ if (matches) {
3347
+ const length = text.length + matches.length * (replacement.length - scope.query.length);
3348
+ outputCharacters += length;
3349
+ if (length > VISIO_TEXT_REPLACE_LIMITS.output || outputCharacters > VISIO_TEXT_REPLACE_LIMITS.output)
3350
+ textReplaceError("Replace output exceeds aggregate command text limits.");
3351
+ const parts = [];
3352
+ let from = 0;
3353
+ for (const match of matches) {
3354
+ parts.push(text.slice(from, match.start), replacement);
3355
+ from = match.end;
3356
+ }
3357
+ parts.push(text.slice(from));
3358
+ text = parts.join("");
3359
+ edits.push(
3360
+ Object.freeze({
3361
+ type: "replace-plain-text",
3362
+ pageId: entry.pageId,
3363
+ shapeId: entry.shapeId,
3364
+ text
3365
+ })
3366
+ );
3367
+ }
3368
+ updated.push({ ...entry, text });
3369
+ }
3370
+ const remaining = mode === "current" ? occurrences(updated, scope.query) : [];
3371
+ const activeEntry = active ? entries.findIndex((entry) => sameTarget(entry, active)) : -1;
3372
+ const entryIndices = new Map(
3373
+ entries.map((entry, index) => [JSON.stringify([entry.pageId, entry.shapeId]), index])
3374
+ );
3375
+ const nextOccurrence = active ? remaining.find((match) => {
3376
+ const index = entryIndices.get(JSON.stringify([match.pageId, match.shapeId]));
3377
+ return index > activeEntry || index === activeEntry && match.start >= active.start + replacement.length;
3378
+ }) ?? remaining[0] : remaining[0];
3379
+ const plan = Object.freeze({
3380
+ occurrences: found,
3381
+ replacementCount: selected.length,
3382
+ edits: Object.freeze(edits),
3383
+ nextOccurrence
3384
+ });
3385
+ records.set(plan, { scope, entries });
3386
+ return plan;
3387
+ }
3388
+ function visioTextReplaceCommands(model, plan) {
3389
+ const record2 = records.get(plan);
3390
+ if (!record2) return textReplaceError("Replace plan was not produced by this planner.");
3391
+ const current = replaceEntries(model, record2.scope);
3392
+ if (current.length !== record2.entries.length || current.some((entry, index) => {
3393
+ const saved = record2.entries[index];
3394
+ return entry.pageId !== saved.pageId || entry.shapeId !== saved.shapeId || entry.text !== saved.text;
3395
+ }))
3396
+ textReplaceError("Replace plan is stale. Search the current drawing again.");
3397
+ return plan.edits.map((edit) => ({ ...edit }));
3398
+ }
3399
+
3400
+ // visio/ui/svg-stroke.ts
3401
+ function visioSvgStrokeStyle(style) {
3402
+ return style.lineWidth === 0 ? { ...style, lineWidth: 0.75 / 72 } : style;
3403
+ }
3404
+
3405
+ export { DocumentHistory, EDIT_HISTORY_LIMITS, EMPTY_EDIT_STATE, EMPTY_SELECTION, EMPTY_TEXT_SEARCH, FOREIGN_VECTOR_SCENE_LIMITS, ForeignVectorBudget, MAX_INPUT_BYTES, TEXT_SEARCH_LIMITS, IDENTITY_AFFINE as VISIO_IDENTITY_TRANSFORM, VISIO_RESIZE_HANDLES, VISIO_TEXT_REPLACE_LIMITS, assertShapeDetails, assertViewableDocument, compatibilityNotes, compatibilityText, composeAffine as composeVisioTransform, copySnapshotScene, demoDocument, editErrorMessage, eventKeys, hasVisibleShapeContent, indexDocumentText, inspectForeignVectorResource, isEditCancellation, propertyKeys, sameSelection, searchDocumentText, selectionKey, snapshotEdits, snapshotSelection, textSearchStatus, validateSearchQuery, visioArrangeCommands, visioBoxCreationCommand, visioClipboardShape, visioDrawBounds, visioDrawIsLargeEnough, visioDrawPlan, visioDrawingPoint, visioDuplicateCommand, visioFillPatternTransform, visioFontFamilies, visioFormattingShape, visioGradientInstances, visioLineCreationCommand, visioLineDashLengths, visioLocalRotationShape, visioMarqueeBox, visioMarqueeSelection, visioMoveCommands, visioMovePreviewTransform, visioMovementShape, visioNextShapeId, visioOrderingShape, visioPageDragDelta, visioPageEditToDrawing, visioPageInsertCommand, visioPasteCommand, visioQuarterTurnCommand, visioRenderedGradientStopCount, visioRenderedGradientStops, visioResizeDrag, visioResizeFrame, visioResizeShape, visioRotationPreviewTransform, visioSelectionIsOnPage, visioShapeFormattingState, visioShapePageBox, visioSizePositionCommand, visioSizePositionState, visioStraightLineHandles, visioStrokeGradient, visioStyleFormattingShape, visioSvgStrokeStyle, visioTextFontStepCommand, visioTextFormattingState, visioTextIndentCommand, visioTextOccurrenceSelection, visioTextReplaceCommands, visioTextReplaceFindNext, visioTextReplaceOccurrences, visioTextReplacePlan };