wordinweb 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2457,6 +2457,8 @@ function parseRunProps(rPr, ctx) {
2457
2457
  else if (vertAlign === "baseline") props.verticalAlign = "baseline";
2458
2458
  const spacing = intAttr(child(rPr, "spacing"), "val");
2459
2459
  if (spacing !== void 0) props.letterSpacing = twipsToPx(spacing);
2460
+ const kern = intAttr(child(rPr, "kern"), "val");
2461
+ if (kern !== void 0) props.kerningThreshold = kern > 0 ? halfPtToPx(kern) : null;
2460
2462
  const wScale = intAttr(child(rPr, "w"), "val");
2461
2463
  if (wScale !== void 0 && wScale > 0 && wScale !== 100) props.textScale = wScale / 100;
2462
2464
  const fitText = intAttr(child(rPr, "fitText"), "val");
@@ -3417,6 +3419,17 @@ function parseParagraph(p, ctx) {
3417
3419
  parseParaChildren(p, ctx, para.children, field, bookmarks);
3418
3420
  if (bookmarks.length > 0) para.bookmarks = bookmarks;
3419
3421
  flushField(field);
3422
+ const visibleContent = para.children.flatMap(
3423
+ (paraChild) => (paraChild.type === "run" ? [paraChild] : paraChild.runs).flatMap(
3424
+ (run) => run.content.filter((content) => content.kind !== "text" || content.text.length > 0)
3425
+ )
3426
+ );
3427
+ if (visibleContent.length === 1 && visibleContent[0].kind === "math") {
3428
+ const node = visibleContent[0].nodes.length === 1 ? visibleContent[0].nodes[0] : void 0;
3429
+ if (node?.t === "frac" && node.num.every((part) => part.t === "run") && node.den.every((part) => part.t === "run")) {
3430
+ visibleContent[0].display = true;
3431
+ }
3432
+ }
3420
3433
  suppressTocHyperlinkFormatting(para);
3421
3434
  if (ctx.revisionView !== "markup" && pPr) {
3422
3435
  const markRPr = child(pPr, "rPr");
@@ -3659,13 +3672,14 @@ function parseParaChildren(parent, ctx, out, field, bookmarks) {
3659
3672
  const nodes = parseOmml(el16);
3660
3673
  if (nodes.length > 0) {
3661
3674
  const display = ln === "oMathPara";
3675
+ const multiEquationDisplay = display && children(el16, "oMath").length > 3;
3662
3676
  const jcVal = display ? attr(child(child(el16, "oMathParaPr"), "jc"), "val") : void 0;
3663
3677
  const jc = jcVal === "left" || jcVal === "right" || jcVal === "center" || jcVal === "centerGroup" ? jcVal : void 0;
3664
3678
  const content = [];
3665
3679
  let segment = [];
3666
3680
  const flushMath = () => {
3667
3681
  if (segment.length === 0) return;
3668
- content.push({ kind: "math", nodes: segment, src: el16, display, jc });
3682
+ content.push({ kind: "math", nodes: segment, src: el16, display, multiEquationDisplay, jc });
3669
3683
  segment = [];
3670
3684
  };
3671
3685
  for (const node of nodes) {
@@ -3896,6 +3910,9 @@ function parseRun(r, ctx, field, suppressedObjects) {
3896
3910
  case "tab":
3897
3911
  run.content.push({ kind: "tab" });
3898
3912
  break;
3913
+ case "pgNum":
3914
+ run.content.push({ kind: "field", instruction: "PAGE", cachedResult: "" });
3915
+ break;
3899
3916
  case "drawing": {
3900
3917
  const img = parseDrawing(el16, ctx);
3901
3918
  if (img) {
@@ -3943,7 +3960,7 @@ function parseRun(r, ctx, field, suppressedObjects) {
3943
3960
  let code = parseInt(charHex, 16);
3944
3961
  if (code >= 61440) code -= 61440;
3945
3962
  const font = attr(el16, "font") ?? "";
3946
- const mapped = /wingdings|webdings|symbol/i.test(font) ? SYMBOL_CHAR_MAP[code] : void 0;
3963
+ const mapped = /^symbol$/i.test(font) ? SYMBOL_TEXT_CHAR_MAP[code] : /wingdings|webdings/i.test(font) ? SYMBOL_CHAR_MAP[code] : void 0;
3947
3964
  run.content.push({ kind: "text", text: mapped ?? String.fromCharCode(code) });
3948
3965
  }
3949
3966
  break;
@@ -4107,7 +4124,17 @@ function parseDrawing(drawing, ctx) {
4107
4124
  const modelRel = modelRelId ? ctx.rels.get(modelRelId) : void 0;
4108
4125
  if (rel && !rel.external) {
4109
4126
  if (modelRel && !modelRel.external) {
4110
- model3D = { part: modelRel.target, posterPart: rel.target };
4127
+ const rot = child(child(el16, "trans"), "rot");
4128
+ const rotation = {
4129
+ x: (intAttr(rot, "ax") ?? 0) / 6e4,
4130
+ y: (intAttr(rot, "ay") ?? 0) / 6e4,
4131
+ z: (intAttr(rot, "az") ?? 0) / 6e4
4132
+ };
4133
+ model3D = {
4134
+ part: modelRel.target,
4135
+ posterPart: rel.target,
4136
+ ...rotation.x || rotation.y || rotation.z ? { rotation } : {}
4137
+ };
4111
4138
  }
4112
4139
  const xfrm = path(el16, "spPr", "xfrm");
4113
4140
  const off = child(xfrm, "off");
@@ -4354,7 +4381,8 @@ function parseDrawing(drawing, ctx) {
4354
4381
  const pctEl = el16 ? el16.children.find((c) => localName(c.name).startsWith("pct")) : void 0;
4355
4382
  if (!pctEl) return void 0;
4356
4383
  const rf = attr(el16, "relativeFrom");
4357
- return { pct: (parseInt(pctEl.text, 10) || 0) / 1e5, rel: rf === "page" ? "page" : "margin" };
4384
+ const pct = (parseInt(pctEl.text, 10) || 0) / 1e5;
4385
+ return pct > 0 ? { pct, rel: rf === "page" ? "page" : "margin" } : void 0;
4358
4386
  };
4359
4387
  const spPr = child(textboxEl, "spPr");
4360
4388
  const txbxOwn = child(textboxEl, "txbx");
@@ -4821,7 +4849,8 @@ function collectDiagramShapes(dspRoot, ctx, out, dx, dy) {
4821
4849
  height: emuToPx(th),
4822
4850
  blocks,
4823
4851
  insets: { l: insetOf("lIns", 9.6), t: insetOf("tIns", 4.8), r: insetOf("rIns", 9.6), b: insetOf("bIns", 4.8) },
4824
- textAnchor: anchorAttr === "ctr" ? "middle" : anchorAttr === "b" ? "bottom" : "top"
4852
+ textAnchor: anchorAttr === "ctr" ? "middle" : anchorAttr === "b" ? "bottom" : "top",
4853
+ paintOffsetY: 0.75
4825
4854
  });
4826
4855
  }
4827
4856
  }
@@ -4907,6 +4936,8 @@ function drawingMLRun(r, ctx) {
4907
4936
  const props = {};
4908
4937
  const sz = rPr ? intAttr(rPr, "sz") : void 0;
4909
4938
  props.size = ptToPx((sz ?? 1800) / 100);
4939
+ const kern = rPr ? intAttr(rPr, "kern") : void 0;
4940
+ if (kern !== void 0) props.kerningThreshold = kern > 0 ? ptToPx(kern / 100) : null;
4910
4941
  if (rPr && attr(rPr, "b") === "1") props.bold = true;
4911
4942
  if (rPr && attr(rPr, "i") === "1") props.italic = true;
4912
4943
  const u = rPr ? attr(rPr, "u") : void 0;
@@ -5351,6 +5382,8 @@ function parseCell(tc, ctx) {
5351
5382
  if (tcW && attr(tcW, "type") === "dxa") {
5352
5383
  const w = intAttr(tcW, "w");
5353
5384
  if (w) props.width = twipsToPx(w);
5385
+ } else if (tcW && attr(tcW, "type") === "auto") {
5386
+ props.widthAuto = true;
5354
5387
  }
5355
5388
  const borders = child(tcPr, "tcBorders");
5356
5389
  if (borders) {
@@ -5726,6 +5759,9 @@ var DocxDocument = class _DocxDocument {
5726
5759
  /** Note content by note id (render-only; sources stripped). */
5727
5760
  this.footnotes = /* @__PURE__ */ new Map();
5728
5761
  this.endnotes = /* @__PURE__ */ new Map();
5762
+ /** The separator paragraph controls the gap between its rule and the first
5763
+ * footnote. */
5764
+ this.footnoteSeparator = [];
5729
5765
  /** `_Ref` cross-reference bookmark ranges (name → captured runs). REF
5730
5766
  * fields re-render the referenced text from these — Word recomputes REF on
5731
5767
  * open, so the cached field result in the file is stale. */
@@ -5842,6 +5878,8 @@ var DocxDocument = class _DocxDocument {
5842
5878
  if (!docRoot) throw new Error(`Missing ${docPart} in package`);
5843
5879
  this.docRoot = docRoot;
5844
5880
  this.rememberOriginalXml(docPart, docRoot);
5881
+ const coreProperties = this.readXmlOptional("docProps/core.xml");
5882
+ this.hydrateCorePropertyControls(docRoot, coreProperties);
5845
5883
  this.repairLegacyWordInWebObjects();
5846
5884
  this.documentRels = parseRelationships(this.relsRoot ?? void 0, docPart);
5847
5885
  if (settings) {
@@ -5884,6 +5922,7 @@ var DocxDocument = class _DocxDocument {
5884
5922
  if (!root) continue;
5885
5923
  const partRels = parseRelationships(this.readXmlOptional(relsPathFor(rel.target)), rel.target);
5886
5924
  this.rememberOriginalXml(rel.target, root);
5925
+ this.hydrateCorePropertyControls(root, coreProperties);
5887
5926
  this.hfParts.push({ relId: rel.id, target: rel.target, root, isHeader, rels: partRels });
5888
5927
  }
5889
5928
  for (const rel of this.documentRels.values()) {
@@ -5897,6 +5936,12 @@ var DocxDocument = class _DocxDocument {
5897
5936
  this.footnotesPart = rel.target;
5898
5937
  this.footnotesRoot = root;
5899
5938
  this.footnotesRels = partRels;
5939
+ const separator = root.children.find(
5940
+ (item) => localName(item.name) === "footnote" && attr(item, "type") === "separator"
5941
+ );
5942
+ if (separator) {
5943
+ this.footnoteSeparator.push(...parseBlocks(separator, { ...this.ctxBase, rels: partRels }));
5944
+ }
5900
5945
  }
5901
5946
  const notes = parseNotesPart(root, { ...this.ctxBase, rels: partRels }, isFn);
5902
5947
  for (const [id, blocks] of notes) (isFn ? this.footnotes : this.endnotes).set(id, blocks);
@@ -5911,6 +5956,37 @@ var DocxDocument = class _DocxDocument {
5911
5956
  this._packageResourceVersion++;
5912
5957
  this._layoutGlobalSig = null;
5913
5958
  }
5959
+ /** Resolve content controls mapped to standard package core properties.
5960
+ * Word refreshes these bindings on open, so the serialized sdtContent can
5961
+ * be stale even though the visible value comes from docProps/core.xml. */
5962
+ hydrateCorePropertyControls(root, coreProperties) {
5963
+ if (!coreProperties) return;
5964
+ const textNodes = (element) => {
5965
+ const out = localName(element.name) === "t" ? [element] : [];
5966
+ for (const item of element.children) out.push(...textNodes(item));
5967
+ return out;
5968
+ };
5969
+ const walk2 = (element) => {
5970
+ if (localName(element.name) === "sdt") {
5971
+ const binding = child(child(element, "sdtPr"), "dataBinding");
5972
+ const xpath = attr(binding, "xpath") ?? "";
5973
+ const propertyMatch = /\/(?:[^/:]+:)?([A-Za-z_][\w.-]*)(?:\[\d+\])?\s*$/.exec(xpath);
5974
+ if (xpath.includes("coreProperties") && propertyMatch) {
5975
+ const property = coreProperties.children.find(
5976
+ (item) => localName(item.name) === propertyMatch[1]
5977
+ );
5978
+ const content = child(element, "sdtContent");
5979
+ const targets = content ? textNodes(content) : [];
5980
+ if (property?.text && targets.length > 0) {
5981
+ targets[0].text = property.text;
5982
+ for (const target of targets.slice(1)) target.text = "";
5983
+ }
5984
+ }
5985
+ }
5986
+ for (const item of element.children) walk2(item);
5987
+ };
5988
+ walk2(root);
5989
+ }
5914
5990
  /** Repair only objects emitted by older WordInWeb builds that Word rejects. */
5915
5991
  repairLegacyWordInWebObjects() {
5916
5992
  const raw = this.pkg.raw();
@@ -7992,7 +8068,7 @@ var BAKED_FONT_METRICS = {
7992
8068
  // ../core/src/layout/measure.ts
7993
8069
  function fontKey(font) {
7994
8070
  const paint = font.paintFamily && font.paintFamily !== font.family ? `${font.paintFamily}>` : "";
7995
- return `${font.bold ? "bold " : ""}${font.italic ? "italic " : ""}${font.size}px ${paint}${font.family}`;
8071
+ return `${font.bold ? "bold " : ""}${font.italic ? "italic " : ""}${font.kerning ? "kern " : ""}${font.size}px ${paint}${font.family}`;
7996
8072
  }
7997
8073
  var METRIC_SUBSTITUTES = {
7998
8074
  calibri: "Carlito",
@@ -8137,6 +8213,23 @@ function hasCambriaMath() {
8137
8213
  }
8138
8214
  return _cambriaMath;
8139
8215
  }
8216
+ var _segoeUIEmoji;
8217
+ function hasSegoeUIEmoji() {
8218
+ if (_segoeUIEmoji !== void 0) return _segoeUIEmoji;
8219
+ try {
8220
+ const canvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(1, 1) : typeof document !== "undefined" ? document.createElement("canvas") : null;
8221
+ const ctx = canvas?.getContext("2d");
8222
+ if (!ctx) return _segoeUIEmoji = false;
8223
+ ctx.font = '48px "Segoe UI Emoji", sans-serif';
8224
+ const requested = ctx.measureText("\u263A");
8225
+ ctx.font = "48px sans-serif";
8226
+ const fallback = ctx.measureText("\u263A");
8227
+ _segoeUIEmoji = Math.abs(requested.width - fallback.width) > 0.01 || Math.abs((requested.actualBoundingBoxRight ?? 0) - (fallback.actualBoundingBoxRight ?? 0)) > 0.01 || Math.abs((requested.actualBoundingBoxAscent ?? 0) - (fallback.actualBoundingBoxAscent ?? 0)) > 0.01;
8228
+ } catch {
8229
+ _segoeUIEmoji = false;
8230
+ }
8231
+ return _segoeUIEmoji;
8232
+ }
8140
8233
  function cambriaMathDescentShare() {
8141
8234
  return 0.238;
8142
8235
  }
@@ -8157,11 +8250,12 @@ var CanvasMeasurer = class {
8157
8250
  }
8158
8251
  setFont(font) {
8159
8252
  const css = cssFont(font);
8160
- if (css !== this.currentFont) {
8253
+ const key = `${css}\0${font.kerning ? "normal" : "none"}`;
8254
+ if (key !== this.currentFont) {
8161
8255
  this.ctx.font = css;
8162
- this.ctx.fontKerning = "none";
8256
+ this.ctx.fontKerning = font.kerning ? "normal" : "none";
8163
8257
  this.ctx.textRendering = "optimizeSpeed";
8164
- this.currentFont = css;
8258
+ this.currentFont = key;
8165
8259
  }
8166
8260
  }
8167
8261
  width(text, font, letterSpacing = 0) {
@@ -8265,6 +8359,8 @@ function createMeasurer() {
8265
8359
  // ../core/src/layout/math.ts
8266
8360
  var SCRIPT_SCALE = 0.73;
8267
8361
  var SCRIPT_SCRIPT_SCALE = 0.6;
8362
+ var EMPTY_SCRIPT_ADVANCE = 0.89;
8363
+ var EMPTY_SUP_ADVANCE = 0.84;
8268
8364
  var floorHalfPt = (px) => Math.floor(px * 0.75 * 2 + 1e-6) / 2 / 0.75;
8269
8365
  var scriptSize = (size, floor) => Math.max(floorHalfPt(size * SCRIPT_SCALE), floor);
8270
8366
  var SUP_RAISE = 4 / 11;
@@ -8276,6 +8372,7 @@ var RULE_THICK = 0.75 / 11;
8276
8372
  var BIN_OP_SPACE = 0.25;
8277
8373
  var FUNC_NAME_SPACE = 0.18;
8278
8374
  var COMMA_SPACE = 0.17;
8375
+ var SEMICOLON_SPACE = 0.153;
8279
8376
  var FRAC_PAD = 0.06;
8280
8377
  var NARY_SUM_RAISE = 0.5 / 11;
8281
8378
  var NARY_INT_DROP = 0.5 / 11;
@@ -8294,10 +8391,11 @@ var MAT_COL_GAP_STIX = 12.2 / 11;
8294
8391
  var MAT_COL_GAP_REAL_INLINE = 11.4 / 11;
8295
8392
  var MAT_COL_GAP_REAL_DISPLAY = 11.13 / 11;
8296
8393
  var DLM_PAD_STIX = 1.2 / 11;
8297
- var DLM_PAD_REAL = 0.8 / 11;
8394
+ var DLM_PAD_REAL = 1 / 11;
8298
8395
  var matColGap = (display) => hasCambriaMath() ? display ? MAT_COL_GAP_REAL_DISPLAY : MAT_COL_GAP_REAL_INLINE : MAT_COL_GAP_STIX;
8299
8396
  var dlmPad = () => hasCambriaMath() ? DLM_PAD_REAL : DLM_PAD_STIX;
8300
8397
  var DLM_MAT_END_PAD = 0.3 / 11;
8398
+ var DLM_TRAILING_SPACE_PAD = 0.125;
8301
8399
  var FRAC_NUM_RAISE_D = 1550 / 2048;
8302
8400
  var FRAC_DEN_DROP_D = 1370 / 2048;
8303
8401
  var FRAC_DEN_DLM_EXTRA = 133 / 2048;
@@ -8311,6 +8409,8 @@ var INT_D_INK = 1.3584 + 0.7925;
8311
8409
  var INT_D_ASC = 1.3584;
8312
8410
  var INT_D_DESC = 0.7925;
8313
8411
  var INT_D_ADV = 0.8066;
8412
+ var INT_D_LIMIT_OVERLAP = 0.37;
8413
+ var INT_D_SUP_STAGGER = 0.375;
8314
8414
  var INT_D_ANCHOR = (1.3584 - 0.877 * (INT_D_INK / INT_TEXT_INK)) / (1 - INT_D_INK / INT_TEXT_INK);
8315
8415
  var MATH_FONT = "Cambria Math";
8316
8416
  function mathText(text, normal = false) {
@@ -8388,7 +8488,7 @@ var BRACKET_RE = /[()[\]{}]/;
8388
8488
  var SUP_DLM_DROP = 460 / 2048;
8389
8489
  var ITALIC_MATH_RE = /[\u{1D434}-\u{1D467}ℎ]/u;
8390
8490
  var SUP_KERN_IN = 0;
8391
- var SCRIPT_TRAIL = 0;
8491
+ var SCRIPT_TRAIL_GROUPED_DISPLAY = 0.12;
8392
8492
  function containsDlm(nodes) {
8393
8493
  for (const n of nodes) {
8394
8494
  switch (n.t) {
@@ -8473,9 +8573,21 @@ function containsBlocky(nodes) {
8473
8573
  }
8474
8574
  return false;
8475
8575
  }
8476
- function layoutMath(nodes, baseSize, measurer, display = false) {
8576
+ function layoutMath(nodes, baseSize, measurer, display = false, fractionPadEm = FRAC_PAD, multiEquationDisplay = false) {
8477
8577
  const box = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [], display, baseSize };
8478
- flow(nodes, baseSize, 0, box, measurer, false, display, 0, floorHalfPt(baseSize * SCRIPT_SCRIPT_SCALE));
8578
+ flow(
8579
+ nodes,
8580
+ baseSize,
8581
+ 0,
8582
+ box,
8583
+ measurer,
8584
+ false,
8585
+ display,
8586
+ 0,
8587
+ floorHalfPt(baseSize * SCRIPT_SCRIPT_SCALE),
8588
+ fractionPadEm,
8589
+ multiEquationDisplay ? SCRIPT_TRAIL_GROUPED_DISPLAY : 0
8590
+ );
8479
8591
  for (const p of box.pieces) {
8480
8592
  const m = measurer.metrics(p.font);
8481
8593
  p.effAscent = p.ownAscent ?? p.dy + m.ascent;
@@ -8489,12 +8601,17 @@ function layoutMath(nodes, baseSize, measurer, display = false) {
8489
8601
  }
8490
8602
  return box;
8491
8603
  }
8492
- function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth = 0, scriptFloor = 0) {
8604
+ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth = 0, scriptFloor = 0, fractionPadEm = FRAC_PAD, scriptTrailEm = 0) {
8493
8605
  let prevOperand = false;
8494
8606
  for (const node of nodes) {
8495
8607
  switch (node.t) {
8496
8608
  case "run": {
8497
8609
  const font = fontAt(size);
8610
+ if (node.normal && /^\s+$/.test(node.text)) {
8611
+ box.pieces.push({ text: node.text, x: box.width, dy, font });
8612
+ box.width += [...node.text].length * size;
8613
+ break;
8614
+ }
8498
8615
  if (node.fname) {
8499
8616
  const gap = size * FUNC_NAME_SPACE;
8500
8617
  if (prevOperand) box.width += gap;
@@ -8506,16 +8623,19 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8506
8623
  }
8507
8624
  const medGap = size * BIN_OP_SPACE;
8508
8625
  const relGap = display ? medGap : size * (5 / 18);
8509
- const toks = node.text.split(/([=+−×÷<>≤≥±≠,-])/).filter((s) => s.length > 0);
8626
+ const toks = node.text.split(/([=+−×÷<>≤≥±≠,;\-])/).filter((s) => s.length > 0);
8510
8627
  for (let ti = 0; ti < toks.length; ti++) {
8511
8628
  const tok = toks[ti];
8512
- if (tok === ",") {
8629
+ if (tok === "," || tok === ";") {
8513
8630
  const text2 = mathText(tok, node.normal);
8514
8631
  box.pieces.push({ text: text2, x: box.width, dy, font });
8515
8632
  box.width += measurer.width(text2, font);
8516
8633
  const nextIsSpace = ti + 1 < toks.length && /^\s/.test(toks[ti + 1]);
8517
- if (!tight && !nextIsSpace) box.width += size * COMMA_SPACE;
8518
- prevOperand = false;
8634
+ const spacedSemicolon = tok === ";" && (ti === toks.length - 1 || !BIN_OPS.has(toks[ti + 1]));
8635
+ if (!tight && !nextIsSpace && (tok === "," || spacedSemicolon)) {
8636
+ box.width += size * (tok === "," ? COMMA_SPACE : SEMICOLON_SPACE);
8637
+ }
8638
+ prevOperand = tok === ";";
8519
8639
  continue;
8520
8640
  }
8521
8641
  const isOp = BIN_OPS.has(tok);
@@ -8539,7 +8659,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8539
8659
  case "sup":
8540
8660
  case "sub": {
8541
8661
  const beforeBase = box.pieces.length;
8542
- flow(node.base, size, dy, box, measurer, tight, display, breakDepth + 2, scriptFloor);
8662
+ flow(node.base, size, dy, box, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8543
8663
  let baseInkAsc = 0;
8544
8664
  if (node.t === "sup") {
8545
8665
  for (let i = beforeBase; i < box.pieces.length; i++) {
@@ -8554,9 +8674,16 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8554
8674
  box.width += size * SUP_KERN_IN;
8555
8675
  }
8556
8676
  const beforeScript = box.pieces.length;
8557
- flow(node.script, scriptSize(size, scriptFloor), scriptDy, box, measurer, true, false, breakDepth + 2, scriptFloor);
8677
+ const scriptFontSize = scriptSize(size, scriptFloor);
8678
+ if (node.t === "sub" && node.script.length === 0) {
8679
+ box.width += scriptFontSize * EMPTY_SCRIPT_ADVANCE;
8680
+ } else if (node.t === "sup" && node.script.length === 0) {
8681
+ box.width += scriptFontSize * EMPTY_SUP_ADVANCE;
8682
+ } else {
8683
+ flow(node.script, scriptFontSize, scriptDy, box, measurer, true, false, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8684
+ }
8558
8685
  for (let i = beforeScript; i < box.pieces.length; i++) box.pieces[i].script = true;
8559
- box.width += size * SCRIPT_TRAIL;
8686
+ if (display) box.width += size * scriptTrailEm;
8560
8687
  prevOperand = true;
8561
8688
  break;
8562
8689
  }
@@ -8565,17 +8692,17 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8565
8692
  const numRaise = display ? size * FRAC_NUM_RAISE_D : size * FRAC_NUM_RAISE;
8566
8693
  const denDrop = (display ? size * FRAC_DEN_DROP_D : size * FRAC_DEN_DROP) + (display && containsDlm(node.den) ? size * FRAC_DEN_DLM_EXTRA : 0);
8567
8694
  const fracTight = display ? tight : true;
8568
- const numW = widthOf(node.num, scale, measurer, display, fracTight, scriptFloor);
8569
- const denW = widthOf(node.den, scale, measurer, display, fracTight, scriptFloor);
8570
- const pad = size * FRAC_PAD;
8695
+ const numW = widthOf(node.num, scale, measurer, display, fracTight, scriptFloor, fractionPadEm, scriptTrailEm);
8696
+ const denW = widthOf(node.den, scale, measurer, display, fracTight, scriptFloor, fractionPadEm, scriptTrailEm);
8697
+ const pad = size * fractionPadEm;
8571
8698
  const barW = Math.max(numW, denW) + 2 * pad;
8572
8699
  const x0 = box.width;
8573
8700
  const numBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8574
- flow(node.num, scale, 0, numBox, measurer, fracTight, display, breakDepth + 2, scriptFloor);
8701
+ flow(node.num, scale, 0, numBox, measurer, fracTight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8575
8702
  for (const p of numBox.pieces) box.pieces.push(rebase(p, x0 + (barW - numW) / 2, dy + numRaise));
8576
8703
  for (const r of numBox.rules) box.rules.push({ ...r, x1: x0 + (barW - numW) / 2 + r.x1, x2: x0 + (barW - numW) / 2 + r.x2, dy: dy + numRaise + r.dy });
8577
8704
  const denBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8578
- flow(node.den, scale, 0, denBox, measurer, fracTight, display, breakDepth + 2, scriptFloor);
8705
+ flow(node.den, scale, 0, denBox, measurer, fracTight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8579
8706
  let denDropFinal = denDrop;
8580
8707
  if (containsFrac(node.den)) {
8581
8708
  let denAsc = 0;
@@ -8600,7 +8727,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8600
8727
  case "nary": {
8601
8728
  const isInt = "\u222B\u222C\u222D\u222E\u222F\u2230".includes(node.chr);
8602
8729
  if (display && !isInt) {
8603
- naryDisplay(node, size, dy, box, measurer, scriptFloor);
8730
+ naryDisplay(node, size, dy, box, measurer, scriptFloor, fractionPadEm, scriptTrailEm);
8604
8731
  prevOperand = true;
8605
8732
  break;
8606
8733
  }
@@ -8629,20 +8756,24 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8629
8756
  const intSubDrop = display && visibleSub ? INT_SUB_DROP_D : INT_SUB_DROP;
8630
8757
  const supDy = dy + size * (isInt ? intSupRaise : NARY_SUP_RAISE);
8631
8758
  const subDy = dy - size * (isInt ? intSubDrop : NARY_SUB_DROP);
8632
- const supStagger = isInt ? size * INT_SUP_STAGGER : 0;
8633
- const supW = widthOf(node.sup, scale, measurer, false, true, scriptFloor) + supStagger;
8634
- const subW = widthOf(node.sub, scale, measurer, false, true, scriptFloor);
8635
- const x0 = box.width;
8759
+ const supStagger = isInt ? size * (display ? INT_D_SUP_STAGGER : INT_SUP_STAGGER) : 0;
8760
+ const supW = visibleSup ? widthOf(node.sup, scale, measurer, false, true, scriptFloor, fractionPadEm, scriptTrailEm) + supStagger : 0;
8761
+ const subW = visibleSub ? widthOf(node.sub, scale, measurer, false, true, scriptFloor, fractionPadEm, scriptTrailEm) : 0;
8762
+ const x0 = box.width - (display && isInt && (visibleSup || visibleSub) ? size * INT_D_LIMIT_OVERLAP : 0);
8636
8763
  const supBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8637
- flow(node.sup, scale, 0, supBox, measurer, true, false, breakDepth + 2, scriptFloor);
8638
- for (const pc of supBox.pieces) box.pieces.push(rebase(pc, x0 + supStagger, supDy, true));
8639
- for (const r of supBox.rules) box.rules.push({ ...r, x1: x0 + supStagger + r.x1, x2: x0 + supStagger + r.x2, dy: supDy + r.dy });
8764
+ if (visibleSup) {
8765
+ flow(node.sup, scale, 0, supBox, measurer, true, false, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8766
+ for (const pc of supBox.pieces) box.pieces.push(rebase(pc, x0 + supStagger, supDy, true));
8767
+ for (const r of supBox.rules) box.rules.push({ ...r, x1: x0 + supStagger + r.x1, x2: x0 + supStagger + r.x2, dy: supDy + r.dy });
8768
+ }
8640
8769
  const subBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8641
- flow(node.sub, scale, 0, subBox, measurer, true, false, breakDepth + 2, scriptFloor);
8642
- for (const pc of subBox.pieces) box.pieces.push(rebase(pc, x0, subDy, true));
8643
- for (const r of subBox.rules) box.rules.push({ ...r, x1: x0 + r.x1, x2: x0 + r.x2, dy: subDy + r.dy });
8770
+ if (visibleSub) {
8771
+ flow(node.sub, scale, 0, subBox, measurer, true, false, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8772
+ for (const pc of subBox.pieces) box.pieces.push(rebase(pc, x0, subDy, true));
8773
+ for (const r of subBox.rules) box.rules.push({ ...r, x1: x0 + r.x1, x2: x0 + r.x2, dy: subDy + r.dy });
8774
+ }
8644
8775
  box.width = x0 + Math.max(supW, subW) + size * NARY_E_GAP;
8645
- flow(node.e, size, dy, box, measurer, tight, display, breakDepth + 2, scriptFloor);
8776
+ flow(node.e, size, dy, box, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8646
8777
  prevOperand = true;
8647
8778
  break;
8648
8779
  }
@@ -8652,7 +8783,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8652
8783
  let coreDesc = 0;
8653
8784
  const parts = node.e.map((part) => {
8654
8785
  const b = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8655
- flow(part, size, 0, b, measurer, tight, display, breakDepth + 1, scriptFloor);
8786
+ flow(part, size, 0, b, measurer, tight, display, breakDepth + 1, scriptFloor, fractionPadEm, scriptTrailEm);
8656
8787
  for (const pc of b.pieces) {
8657
8788
  const m = measurer.metrics(pc.font);
8658
8789
  const asc = pc.ownAscent ?? pc.dy + m.ascent;
@@ -8708,7 +8839,10 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8708
8839
  grow = 1;
8709
8840
  }
8710
8841
  }
8711
- const innerPad = size * (matLike ? DLM_MAT_END_PAD : dlmPad());
8842
+ const lastPart = node.e[node.e.length - 1];
8843
+ const tail = lastPart?.[lastPart.length - 1];
8844
+ const trailingSpaces = display && tail?.t === "run" && /^\s+$/.test(tail.text) ? [...tail.text].length : 0;
8845
+ const innerPad = size * (matLike ? DLM_MAT_END_PAD : dlmPad()) + size * DLM_TRAILING_SPACE_PAD * trailingSpaces;
8712
8846
  const drawDelim = (ch) => {
8713
8847
  if (!ch) return;
8714
8848
  const asm = asmH !== void 0 ? DLM_ASM_PIECES[ch] : void 0;
@@ -8778,7 +8912,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8778
8912
  const cells = node.rows.map(
8779
8913
  (row) => row.map((cell) => {
8780
8914
  const b = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8781
- flow(cell, size, 0, b, measurer, tight, display, breakDepth + 2, scriptFloor);
8915
+ flow(cell, size, 0, b, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8782
8916
  for (const pc of b.pieces) {
8783
8917
  const m = measurer.metrics(pc.font);
8784
8918
  b.ascent = Math.max(b.ascent, pc.dy + m.ascent);
@@ -8824,7 +8958,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8824
8958
  const m = measurer.metrics(font);
8825
8959
  const ruleThick = Math.max(size * RULE_THICK, 0.75);
8826
8960
  const radBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8827
- flow(node.e, size, 0, radBox, measurer, tight, display, breakDepth + 2, scriptFloor);
8961
+ flow(node.e, size, 0, radBox, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8828
8962
  let radAsc = m.ascent * 0.5;
8829
8963
  let radDesc = 0;
8830
8964
  for (const pc of radBox.pieces) {
@@ -8848,7 +8982,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8848
8982
  const dScale = scriptSize(size, scriptFloor);
8849
8983
  box.width += size * RAD_KERN_BEFORE_DEG;
8850
8984
  const degBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8851
- flow(node.deg, dScale, 0, degBox, measurer, true, false, breakDepth + 2, scriptFloor);
8985
+ flow(node.deg, dScale, 0, degBox, measurer, true, false, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8852
8986
  const degDy = dy - radDesc + RAD_DEG_RAISE * signInkH + size * RAD_DEG_ADJ;
8853
8987
  for (const pc of degBox.pieces) box.pieces.push(rebase(pc, box.width, degDy, true));
8854
8988
  for (const r of degBox.rules) box.rules.push({ ...r, x1: box.width + r.x1, x2: box.width + r.x2, dy: degDy + r.dy });
@@ -8895,7 +9029,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8895
9029
  const axis = dy + size * RULE_CENTER;
8896
9030
  const rowBoxes = node.rows.map((row) => {
8897
9031
  const b = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8898
- flow(row, size, 0, b, measurer, tight, display, breakDepth + 2, scriptFloor);
9032
+ flow(row, size, 0, b, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8899
9033
  for (const pc of b.pieces) {
8900
9034
  const pm = measurer.metrics(pc.font);
8901
9035
  b.ascent = Math.max(b.ascent, pc.ownAscent ?? pc.dy + pm.ascent);
@@ -8925,7 +9059,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8925
9059
  }
8926
9060
  case "acc": {
8927
9061
  const before = box.pieces.length;
8928
- flow(node.e, size, dy, box, measurer, tight, display, breakDepth + 2, scriptFloor);
9062
+ flow(node.e, size, dy, box, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8929
9063
  if (box.pieces.length > before) {
8930
9064
  const last = box.pieces[box.pieces.length - 1];
8931
9065
  last.text += node.chr;
@@ -8937,7 +9071,7 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8937
9071
  const isTop = node.pos === "top";
8938
9072
  const bScale = isTop ? size : scriptSize(size, scriptFloor);
8939
9073
  const baseBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8940
- flow(node.e, bScale, 0, baseBox, measurer, tight, display, breakDepth + 2, scriptFloor);
9074
+ flow(node.e, bScale, 0, baseBox, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8941
9075
  const baseW = baseBox.width;
8942
9076
  const maxVariant = GRP_VARIANTS_EM[GRP_VARIANTS_EM.length - 1] * size;
8943
9077
  let braceW = maxVariant;
@@ -8974,10 +9108,10 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8974
9108
  case "lim": {
8975
9109
  const isLow = node.pos === "low";
8976
9110
  const baseBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8977
- flow(node.e, size, 0, baseBox, measurer, tight, display, breakDepth + 2, scriptFloor);
9111
+ flow(node.e, size, 0, baseBox, measurer, tight, display, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8978
9112
  const lScale = scriptSize(size, scriptFloor);
8979
9113
  const limBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
8980
- flow(node.lim, lScale, 0, limBox, measurer, true, false, breakDepth + 2, scriptFloor);
9114
+ flow(node.lim, lScale, 0, limBox, measurer, true, false, breakDepth + 2, scriptFloor, fractionPadEm, scriptTrailEm);
8981
9115
  const w = Math.max(baseBox.width, limBox.width);
8982
9116
  const x0 = box.width;
8983
9117
  const baseX = x0 + (w - baseBox.width) / 2;
@@ -8994,19 +9128,19 @@ function flow(nodes, size, dy, box, measurer, tight, display = false, breakDepth
8994
9128
  }
8995
9129
  }
8996
9130
  }
8997
- function naryDisplay(node, size, dy, box, measurer, scriptFloor) {
9131
+ function naryDisplay(node, size, dy, box, measurer, scriptFloor, fractionPadEm, scriptTrailEm) {
8998
9132
  const opFont = fontAt(size * NARY_OP_SCALE_D);
8999
9133
  const opW = measurer.width(node.chr, opFont);
9000
9134
  const scale = scriptSize(size, scriptFloor);
9001
- const supW = widthOf(node.sup, scale, measurer, false, true, scriptFloor);
9002
- const subW = widthOf(node.sub, scale, measurer, false, true, scriptFloor);
9135
+ const supW = widthOf(node.sup, scale, measurer, false, true, scriptFloor, fractionPadEm, scriptTrailEm);
9136
+ const subW = widthOf(node.sub, scale, measurer, false, true, scriptFloor, fractionPadEm, scriptTrailEm);
9003
9137
  const stackW = Math.max(opW, supW, subW);
9004
9138
  const x0 = box.width;
9005
9139
  const cx = x0 + stackW / 2;
9006
9140
  box.pieces.push({ text: node.chr, x: cx - opW / 2, dy, font: opFont });
9007
9141
  if (node.sup.length) {
9008
9142
  const supBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
9009
- flow(node.sup, scale, 0, supBox, measurer, true, false, 2, scriptFloor);
9143
+ flow(node.sup, scale, 0, supBox, measurer, true, false, 2, scriptFloor, fractionPadEm, scriptTrailEm);
9010
9144
  const ox = cx - supW / 2;
9011
9145
  const oy = dy + size * NARY_OVER_RAISE_D;
9012
9146
  for (const pc of supBox.pieces) box.pieces.push(rebase(pc, ox, oy, true));
@@ -9014,18 +9148,18 @@ function naryDisplay(node, size, dy, box, measurer, scriptFloor) {
9014
9148
  }
9015
9149
  if (node.sub.length) {
9016
9150
  const subBox = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
9017
- flow(node.sub, scale, 0, subBox, measurer, true, false, 2, scriptFloor);
9151
+ flow(node.sub, scale, 0, subBox, measurer, true, false, 2, scriptFloor, fractionPadEm, scriptTrailEm);
9018
9152
  const ux = cx - subW / 2;
9019
9153
  const uy = dy - size * NARY_UNDER_DROP_D;
9020
9154
  for (const pc of subBox.pieces) box.pieces.push(rebase(pc, ux, uy, true));
9021
9155
  for (const r of subBox.rules) box.rules.push({ ...r, x1: ux + r.x1, x2: ux + r.x2, dy: uy + r.dy });
9022
9156
  }
9023
9157
  box.width = x0 + stackW + size * NARY_E_GAP;
9024
- flow(node.e, size, dy, box, measurer, false, true, 2, scriptFloor);
9158
+ flow(node.e, size, dy, box, measurer, false, true, 2, scriptFloor, fractionPadEm, scriptTrailEm);
9025
9159
  }
9026
- function widthOf(nodes, size, measurer, display = false, tight = true, scriptFloor = 0) {
9160
+ function widthOf(nodes, size, measurer, display = false, tight = true, scriptFloor = 0, fractionPadEm = FRAC_PAD, scriptTrailEm = 0) {
9027
9161
  const tmp = { width: 0, ascent: 0, descent: 0, pieces: [], rules: [] };
9028
- flow(nodes, size, 0, tmp, measurer, tight, display, 2, scriptFloor);
9162
+ flow(nodes, size, 0, tmp, measurer, tight, display, 2, scriptFloor, fractionPadEm, scriptTrailEm);
9029
9163
  return tmp.width;
9030
9164
  }
9031
9165
 
@@ -9053,16 +9187,18 @@ function starNumberFormat(instr, n) {
9053
9187
  }
9054
9188
  }
9055
9189
  function fontOf(props, fallbackFamily) {
9190
+ const family = props.rtl && props.fontComplex || props.font || fallbackFamily;
9056
9191
  let size = props.size ?? 14.666;
9057
9192
  if (props.verticalAlign === "superscript" || props.verticalAlign === "subscript") {
9058
- size = Math.round(size * 1.5 * 0.65) / 1.5;
9193
+ const scale = EA_FAMILY_RE.test(family) ? 0.52 : 0.65;
9194
+ size = Math.round(size * 1.5 * scale) / 1.5;
9059
9195
  }
9060
- const family = props.rtl && props.fontComplex || props.font || fallbackFamily;
9061
9196
  return {
9062
9197
  family,
9063
9198
  size,
9064
9199
  bold: props.bold ?? false,
9065
- italic: props.italic ?? false
9200
+ italic: props.italic ?? false,
9201
+ kerning: props.kerningThreshold !== void 0 && props.kerningThreshold !== null && size >= props.kerningThreshold
9066
9202
  };
9067
9203
  }
9068
9204
  function displayText(text, props) {
@@ -9077,13 +9213,21 @@ function runPlainText(run) {
9077
9213
  function isWordAlnum(ch) {
9078
9214
  return ch !== void 0 && /[\p{L}\p{Nd}]/u.test(ch);
9079
9215
  }
9080
- function hyphenBreaks(word) {
9216
+ function hyphenBreaks(word, allowNumericEnDash) {
9081
9217
  const out = [];
9218
+ let leading = 0;
9219
+ while (word[leading] === "-" || word[leading] === "\u2010") leading++;
9220
+ if (leading >= 2 && isWordAlnum(word[leading])) out.push(leading);
9082
9221
  for (let i = 1; i < word.length - 1; i++) {
9083
9222
  const ch = word[i];
9084
- if ((ch === "-" || ch === "\u2010") && isWordAlnum(word[i - 1]) && isWordAlnum(word[i + 1])) {
9085
- out.push(i + 1);
9086
- }
9223
+ if (ch !== "-" && ch !== "\u2010" && ch !== "\u2013") continue;
9224
+ let end = i + 1;
9225
+ while (word[end] === "-" || word[end] === "\u2010" || word[end] === "\u2013") end++;
9226
+ const wordBefore = isWordAlnum(word[i - 1]) || /^[\)\]\}]$/.test(word[i - 1] ?? "") && isWordAlnum(word[i - 2]);
9227
+ const wordAfter = isWordAlnum(word[end]);
9228
+ const numericEnDash = allowNumericEnDash && ch === "\u2013" && /\p{Nd}/u.test(word[i - 1] ?? "") && /\p{Nd}/u.test(word[end] ?? "");
9229
+ if (ch === "\u2013" ? numericEnDash : wordBefore && wordAfter) out.push(end);
9230
+ i = end - 1;
9087
9231
  }
9088
9232
  return out;
9089
9233
  }
@@ -9098,6 +9242,7 @@ function isCJK(ch) {
9098
9242
  return CJK_RE.test(ch);
9099
9243
  }
9100
9244
  var BALLOT_RE = /[☐☑☒]/;
9245
+ var LEGACY_CHECKBOX_TRAILING_ADVANCE = 2.5 * 96 / 72;
9101
9246
  function isBallot(ch) {
9102
9247
  return BALLOT_RE.test(ch);
9103
9248
  }
@@ -9183,17 +9328,35 @@ function wrapDisplayMath(box, maxWidth) {
9183
9328
  });
9184
9329
  }
9185
9330
  var DEFAULT_TAB = 48;
9331
+ var TABBED_INLINE_MATH_FRAC_PAD = 0.15;
9186
9332
  var OVERFLOW_PUNCT = /[.,:;!?)\]}、。,.:;?!)]}」』】〉》]/;
9187
- var CJK_SPACE_COMPRESS = 0.47;
9333
+ var CJK_SPACE_COMPRESS = 0.5;
9188
9334
  var EA_FAMILY_RE = /simsun|nsimsun|宋体|新宋体|songti|simhei|黑体|heiti|kaiti|楷体|fangsong|仿宋|yahei|雅黑|mingliu|细明|新細明|pmingliu|jhenghei|正黑|pingfang|dengxian|等线|ms (?:p?)(?:mincho|gothic)|mincho|meiryo|yu gothic|yu mincho|batang|gulim|dotum|malgun/i;
9189
- var JUSTIFY_MAX_COMPRESS = 0.25;
9335
+ var JUSTIFY_MAX_COMPRESS = 0.29;
9336
+ var JUSTIFY_GRID_MAX_COMPRESS = 0.25;
9190
9337
  var JUSTIFY_STRETCH_FACTOR = 0.5;
9191
9338
  var TAMIL_GLYPH_SCALE = 0.735;
9192
9339
  var TAMIL_BASELINE_DY_EM = 0.136;
9193
9340
  var LAO_GLYPH_SCALE = 1.048;
9341
+ function emojiFallbackScale(text, family) {
9342
+ if (family.toLowerCase() !== "segoe ui emoji" || hasSegoeUIEmoji()) return 1;
9343
+ const codepoints = Array.from(text);
9344
+ if (codepoints.some((ch) => {
9345
+ const cp = ch.codePointAt(0) ?? 0;
9346
+ return cp >= 127462 && cp <= 127487;
9347
+ })) return 1;
9348
+ const people = codepoints.filter((ch) => {
9349
+ const cp = ch.codePointAt(0) ?? 0;
9350
+ return cp >= 128102 && cp <= 128105;
9351
+ }).length;
9352
+ if (text.includes("\u200D") && people >= 3) return 1.84;
9353
+ if (/🚀|❤|✅/.test(text)) return 1.39;
9354
+ if (text.includes("\u200D") || /[🏻-🏿]/u.test(text)) return 1.29;
9355
+ return 1;
9356
+ }
9194
9357
  var KASHIDA_LOW_EM = 0;
9195
9358
  var KASHIDA_MEDIUM_EM = 0.032;
9196
- var KASHIDA_HIGH_EM = 0.04;
9359
+ var KASHIDA_HIGH_EM = 0.075;
9197
9360
  var BP_CACHES = /* @__PURE__ */ new WeakMap();
9198
9361
  var BP_CACHE_MAX = 6e4;
9199
9362
  function bpCacheFor(measurer) {
@@ -9337,6 +9500,7 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9337
9500
  let curSegments = [{ x: 0, width: contentWidth }];
9338
9501
  let curSegIdx = 0;
9339
9502
  let curClearY;
9503
+ let curEdgeReserve = 0;
9340
9504
  const ls = props.lineSpacing;
9341
9505
  const firstFont = atoms.find((a) => a.kind === "frag" || a.kind === "space")?.font;
9342
9506
  const natural = firstFont ? measurer.metrics(firstFont).lineHeight * (ls?.rule === "auto" ? ls.value : 1) : 0;
@@ -9348,6 +9512,7 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9348
9512
  curSegments = [{ x: 0, width: contentWidth }];
9349
9513
  curSegIdx = 0;
9350
9514
  curClearY = void 0;
9515
+ curEdgeReserve = 0;
9351
9516
  if (boundsAt) {
9352
9517
  let guard = 0;
9353
9518
  let b = boundsAt(yOff, EST_LINE);
@@ -9361,6 +9526,7 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9361
9526
  curSegments = b.segments && b.segments.length > 0 ? b.segments : [{ x: b.x, width: b.width }];
9362
9527
  curSegIdx = 0;
9363
9528
  curClearY = b.clearY;
9529
+ curEdgeReserve = b.edgeReserve ?? (b.clearY !== void 0 ? 0.75 : 0);
9364
9530
  }
9365
9531
  void idx;
9366
9532
  };
@@ -9636,7 +9802,10 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9636
9802
  rawStop = nextTabStop(rawStop.pos, props.tabs, contentWidth - indentRight, doc.defaultTabStop);
9637
9803
  }
9638
9804
  }
9639
- if (hanging > 0 && x + offset < indentLeft - 0.5 && rawStop.pos > indentLeft) {
9805
+ const explicitBeforeIndent = (props.tabs ?? []).some(
9806
+ (tab) => !tab.clear && tab.align !== "bar" && tab.pos > x + offset + 0.5 && tab.pos < indentLeft - 0.5
9807
+ );
9808
+ if (hanging > 0 && x + offset < indentLeft - 0.5 && !explicitBeforeIndent) {
9640
9809
  rawStop = { pos: indentLeft, align: "left" };
9641
9810
  }
9642
9811
  const stop = { ...rawStop, pos: rawStop.pos - offset };
@@ -9702,8 +9871,9 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9702
9871
  }
9703
9872
  const lineEnd2 = lineStartX(lineIndex) + availFor(lineIndex);
9704
9873
  if (firstWordWidth > 0 && probeX + firstWordWidth > lineEnd2 + 0.01) {
9874
+ const legacyContinuationIndent = !!atom.props.bold && nextAtom === ai + 3;
9705
9875
  flush(false, false);
9706
- ai--;
9876
+ if (!legacyContinuationIndent) ai--;
9707
9877
  continue;
9708
9878
  }
9709
9879
  }
@@ -9779,9 +9949,11 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9779
9949
  const rows = wrapDisplayMath(atom.box, availFor(lineIndex));
9780
9950
  for (let ri = 0; ri < rows.length; ri++) {
9781
9951
  const row = rows[ri];
9782
- cur.push({ x, width: row.width, math: row, mathSrc: atom.src, props: {}, font: fontOf({}, fallbackFamily) });
9783
- curLineWidth += row.width;
9784
- x += row.width;
9952
+ const tabReserve = !row.display && ri === rows.length - 1 && atoms[ai + 1]?.kind === "tab" ? row.width * 0.01 : 0;
9953
+ const advance = row.width + tabReserve;
9954
+ cur.push({ x, width: advance, math: row, mathSrc: atom.src, props: {}, font: fontOf({}, fallbackFamily) });
9955
+ curLineWidth += advance;
9956
+ x += advance;
9785
9957
  if (ri + 1 < rows.length) flush(false, false);
9786
9958
  }
9787
9959
  continue;
@@ -9790,7 +9962,7 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9790
9962
  const w = atom.kind === "image" ? atom.width : atom.drawing.width;
9791
9963
  const h = atom.kind === "image" ? atom.height : atom.drawing.height;
9792
9964
  if (curLineWidth > 0 && x + w > lineStartX(lineIndex) + availFor(lineIndex)) {
9793
- const glued = atom.kind === "image" && !atom.srcDrawing;
9965
+ const glued = atom.kind === "image" && (!atom.srcDrawing || localName(atom.srcDrawing.name) !== "drawing");
9794
9966
  let hi = cur.length;
9795
9967
  let headW = 0;
9796
9968
  while (glued && hi > minSpans) {
@@ -9839,11 +10011,12 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9839
10011
  if (opts?.verticalGridResync && fragIsCJK && prevContentCJK === false && curLineWidth > 0 && curClearY === void 0) {
9840
10012
  flush(false, false);
9841
10013
  }
9842
- const lineEnd = lineStartX(lineIndex) + availFor(lineIndex);
10014
+ const lineEnd = lineStartX(lineIndex) + availFor(lineIndex) - curEdgeReserve;
9843
10015
  const bdrPad = bdrPadOf(atom);
9844
10016
  const bdrPadL = bdrPad && (!sameBdrAtom(atoms[ai - 1], atom) || curLineWidth === 0) ? bdrPad : 0;
9845
10017
  const bdrPadR = bdrPad && !sameBdrAtom(atom, atoms[ai + 1]) ? bdrPad : 0;
9846
- let fits = x + bdrPadL + atom.width + bdrPadR <= lineEnd + 0.01;
10018
+ const fitTolerance = minLineHeight !== void 0 ? 0.125 : 0.01;
10019
+ let fits = x + bdrPadL + atom.width + bdrPadR <= lineEnd + fitTolerance;
9847
10020
  if (!fits && packUntilSpace) fits = true;
9848
10021
  if (!fits && cur.length > 0 && cur[cur.length - 1].text === " ") {
9849
10022
  if (bidiPara && cur[cur.length - 1].x <= lineStartX(lineIndex) + 0.5) {
@@ -9853,14 +10026,15 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9853
10026
  fits = true;
9854
10027
  packUntilSpace = true;
9855
10028
  }
9856
- if (!fits && minLineHeight) {
10029
+ let overflowPunctWidth = 0;
10030
+ if (minLineHeight) {
9857
10031
  const last = atom.text[atom.text.length - 1];
9858
10032
  if (last && OVERFLOW_PUNCT.test(last)) {
9859
10033
  const nxt = atoms[ai + 1];
9860
10034
  const wordEnd = !nxt || nxt.kind !== "frag" || /^\s/.test(nxt.text);
9861
10035
  if (wordEnd) {
9862
- const pw = measurer.width(last, atom.font, atom.props.letterSpacing);
9863
- if (x + atom.width - pw <= lineEnd + 0.01) fits = true;
10036
+ overflowPunctWidth = measurer.width(last, atom.font, atom.props.letterSpacing);
10037
+ if (!fits && x + atom.width - overflowPunctWidth <= lineEnd + 0.01) fits = true;
9864
10038
  }
9865
10039
  }
9866
10040
  }
@@ -9889,8 +10063,14 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9889
10063
  }
9890
10064
  }
9891
10065
  const wordW = headW + bdrPadL + atom.width + bdrPadR + tailW;
9892
- if (!fits && minLineHeight !== void 0 && curEaSpaceWidth > 0) {
9893
- const compress = (x - headW + wordW - lineEnd) / curEaSpaceWidth;
10066
+ const previousInk = [...cur].reverse().find((span) => span.text?.trim());
10067
+ const sentenceBoundary = /[.!?][\)\]}'"]?$/.test(previousInk?.text ?? "");
10068
+ const clauseBoundaryTail = /[,;:]\s+(?:and|or|but)\s+the\s*$/i.test(
10069
+ cur.map((span) => span.text ?? "").join("")
10070
+ );
10071
+ if (!fits && minLineHeight !== void 0 && curEaSpaceWidth > 0 && !curPacked && !sentenceBoundary && !clauseBoundaryTail) {
10072
+ const packedPunctWidth = props.lineSpacing?.rule === "auto" ? overflowPunctWidth : 0;
10073
+ const compress = (x - headW + wordW - packedPunctWidth - lineEnd) / curEaSpaceWidth;
9894
10074
  if (compress <= CJK_SPACE_COMPRESS + 1e-6) {
9895
10075
  fits = true;
9896
10076
  packUntilSpace = true;
@@ -9902,8 +10082,10 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9902
10082
  // (compat 12, docGrid lines) p2 draws the justified "...zebeqo:" line
9903
10083
  // with every inter-word space at 4.25pt against SimSun's natural
9904
10084
  // 5.25pt (19% compression) to avoid the wrap Word 15+ would also
9905
- // avoid. Scoped to grid sections rather than all legacy docs.
9906
- (doc.compatibilityMode >= 15 || minLineHeight !== void 0) && !bidiPara && props.alignment === "justify" && curSpaceWidth > 0
10085
+ // avoid. In legacy modes that extension is limited to lines whose
10086
+ // compressible spaces use the East Asian face; ordinary Times New
10087
+ // Roman bibliography lines retain Word 2007's earlier wrap.
10088
+ (doc.compatibilityMode >= 15 || minLineHeight !== void 0 && curEaSpaceWidth > 0) && !bidiPara && props.alignment === "justify" && curSpaceWidth > 0
9907
10089
  ) {
9908
10090
  let trail = 0;
9909
10091
  for (let j = hi - 1; j >= 0 && cur[j].isSpace; j--) trail += cur[j].width;
@@ -9912,7 +10094,8 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9912
10094
  const compress = (x - headW + wordW - lineEnd) / compressible;
9913
10095
  if (spacesAfterBreak > 1e-6 && compressible > 1e-6) {
9914
10096
  const stretch = (lineEnd - (x - headW - trail)) / spacesAfterBreak;
9915
- if (compress <= Math.min(JUSTIFY_MAX_COMPRESS, stretch * JUSTIFY_STRETCH_FACTOR)) {
10097
+ const maxCompress = minLineHeight === void 0 && props.numbering ? JUSTIFY_MAX_COMPRESS : JUSTIFY_GRID_MAX_COMPRESS;
10098
+ if (compress <= Math.min(maxCompress, stretch * JUSTIFY_STRETCH_FACTOR)) {
9916
10099
  fits = true;
9917
10100
  packUntilSpace = true;
9918
10101
  }
@@ -9923,7 +10106,8 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9923
10106
  hardWrapFrag(atom);
9924
10107
  continue;
9925
10108
  }
9926
- const head = hi > minSpans && hi < cur.length && cur[hi - 1].isSpace && !cur[hi - 1].noBreak ? cur.splice(hi) : [];
10109
+ const breakBeforeHead = hi > minSpans && hi < cur.length && (cur[hi - 1].isSpace && !cur[hi - 1].noBreak || cur[hi - 1].breakAfter);
10110
+ const head = breakBeforeHead ? cur.splice(hi) : [];
9927
10111
  for (const h of head) curLineWidth -= h.width;
9928
10112
  let moved = false;
9929
10113
  while (advanceSegment()) {
@@ -9975,6 +10159,9 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
9975
10159
  cur.push({ x, width: atom.width, text: atom.text, props: atom.props, font: atom.font, href: atom.href, src: atom.src, noteId: atom.noteId, metricsFont: atom.metricsFont, metricsStrut: atom.metricsStrut, breakAfter: atom.breakAfter, pageRef: atom.pageRef, rtl: atom.rtl, rtlLevel: levelOf(atom.rtl), ruby: atom.ruby });
9976
10160
  curLineWidth += padL + atom.width + bdrPadR;
9977
10161
  x += atom.width + bdrPadR;
10162
+ if (packUntilSpace && atom.breakAfter && /[-‐]$/.test(atom.text)) {
10163
+ packUntilSpace = false;
10164
+ }
9978
10165
  if (atom.text.trim().length > 0) prevContentCJK = fragIsCJK;
9979
10166
  }
9980
10167
  if (!flushedTrailingBreak) flush(true, false);
@@ -10033,7 +10220,7 @@ function nextTabStop(x, tabs, rightEdge, defaultTab = DEFAULT_TAB) {
10033
10220
  }
10034
10221
  }
10035
10222
  const next = nextDefaultTab(x, defaultTab);
10036
- return { pos: next < rightEdge ? next : x + 10.7, align: "left" };
10223
+ return { pos: next < rightEdge ? next : x + 20.4, align: "left" };
10037
10224
  }
10038
10225
  function reorderVisual(spans, startX) {
10039
10226
  if (spans.length === 0) return;
@@ -10173,6 +10360,7 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
10173
10360
  (s) => s.metricsStrut || s.image || s.drawing || s.math || s.leader || s.text === void 0 || !/^[ \t]*$/.test(s.text)
10174
10361
  );
10175
10362
  if (solidSpans.length > 0) metricSpans = solidSpans;
10363
+ const styledLoweredIntegral = para.props.styleId !== void 0 && metricSpans.length > 1 && metricSpans.some((s) => s.text?.includes("\u222B") && (s.props.raise ?? 0) < 0);
10176
10364
  if (metricSpans.some((s) => s.numLabel) && metricSpans.some((s) => !s.numLabel)) {
10177
10365
  let textLine = 0;
10178
10366
  for (const s of metricSpans) {
@@ -10315,8 +10503,11 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
10315
10503
  const lead = ls.value >= 1.15 ? (ls.value - 1) * maxNaturalText : 0;
10316
10504
  height = Math.max(maxNaturalText * ls.value, maxInlineMath + lead);
10317
10505
  }
10318
- } else if (ls.rule === "exact") height = ls.value;
10319
- else height = Math.max(natural, ls.value);
10506
+ } else if (ls.rule === "exact") {
10507
+ height = ls.value;
10508
+ const lowerBand = Math.max(maxDescent, height * 0.2);
10509
+ baselineH = height - lowerBand + maxDescent;
10510
+ } else height = Math.max(natural, ls.value);
10320
10511
  }
10321
10512
  if (!gridObjSnap && (minLineHeight ?? 0) > 0 && ls?.rule === "atLeast" && baselineH === void 0) {
10322
10513
  const glyph = maxAscent + maxDescent;
@@ -10332,6 +10523,11 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
10332
10523
  maxDescent -= descentReuse;
10333
10524
  maxRawDescent -= descentReuse;
10334
10525
  }
10526
+ if (styledLoweredIntegral && ls?.rule !== "exact" && !gridObjSnap) {
10527
+ const overlap = Math.min(6, height);
10528
+ height -= overlap;
10529
+ baselineH = (baselineH ?? height + overlap) - overlap;
10530
+ }
10335
10531
  return {
10336
10532
  spans,
10337
10533
  width,
@@ -10450,7 +10646,13 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10450
10646
  }
10451
10647
  if (baseProps.vanish) return;
10452
10648
  const font = fontOf(baseProps, fallbackFamily);
10453
- let props = kashidaEm > 0 && baseProps.rtl ? { ...baseProps, letterSpacing: (baseProps.letterSpacing ?? 0) + kashidaEm * font.size } : baseProps;
10649
+ let props = kashidaEm > 0 && baseProps.rtl ? {
10650
+ ...baseProps,
10651
+ letterSpacing: (baseProps.letterSpacing ?? 0) + kashidaEm * font.size,
10652
+ // Word adds kashidas at eligible Arabic joins. Uniform CSS tracking
10653
+ // needs less paint spacing while retaining the same line advances.
10654
+ paintLetterSpacing: (baseProps.letterSpacing ?? 0) + Math.min(kashidaEm, 0.04) * font.size
10655
+ } : baseProps;
10454
10656
  if (props.fitText !== void 0 && props.fitText > 0) {
10455
10657
  const natural = measurer.width(displayText(runPlainText(run), props), font, props.letterSpacing) * (props.textScale ?? 1);
10456
10658
  if (natural > 0.1) {
@@ -10531,7 +10733,16 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10531
10733
  });
10532
10734
  break;
10533
10735
  }
10534
- if (text) pushStyled(displayText(text, props), props, font, href, { run, t: null, offset: 0 }, vertMetricsFont);
10736
+ if (text) {
10737
+ const firstAtom = atoms.length;
10738
+ pushStyled(displayText(text, props), props, font, href, { run, t: null, offset: 0 }, vertMetricsFont);
10739
+ if (content.checkbox) {
10740
+ const last = atoms[atoms.length - 1];
10741
+ if (atoms.length > firstAtom && last.kind === "frag") {
10742
+ last.width += LEGACY_CHECKBOX_TRAILING_ADVANCE;
10743
+ }
10744
+ }
10745
+ }
10535
10746
  break;
10536
10747
  }
10537
10748
  case "ptab":
@@ -10569,7 +10780,15 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10569
10780
  break;
10570
10781
  case "math": {
10571
10782
  const size = props.size ?? 14.666;
10572
- const box = layoutMath(content.nodes, size, measurer, content.display);
10783
+ const tabbedInline = !content.display && atoms[atoms.length - 1]?.kind === "tab" && (para.props.indentFirstLine ?? 0) > 0;
10784
+ const box = layoutMath(
10785
+ content.nodes,
10786
+ size,
10787
+ measurer,
10788
+ content.display,
10789
+ tabbedInline ? TABBED_INLINE_MATH_FRAC_PAD : void 0,
10790
+ content.multiEquationDisplay
10791
+ );
10573
10792
  if (content.display) box.jc = content.jc;
10574
10793
  atoms.push({ kind: "math", box, src: content.src });
10575
10794
  break;
@@ -10626,6 +10845,10 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10626
10845
  }
10627
10846
  };
10628
10847
  const pushStyled = (text, props, font, href, srcBase, metricsFont) => {
10848
+ const emojiScale = emojiFallbackScale(text, font.family);
10849
+ if (emojiScale !== 1) {
10850
+ props = { ...props, textScale: (props.textScale ?? 1) * emojiScale };
10851
+ }
10629
10852
  const hasDeva = /[ऀ-ॿ]/.test(text);
10630
10853
  const hasTamil = /[஀-௿]/.test(text);
10631
10854
  const hasLao = /[຀-໿]/.test(text);
@@ -10643,15 +10866,16 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10643
10866
  paintDY: font.size * TAMIL_BASELINE_DY_EM
10644
10867
  };
10645
10868
  const indicMetrics = indicScale !== 1 ? { ...metricsFont ?? font, family: indicFace, size: font.size } : metricsFont ? { ...metricsFont, family: indicFace } : metricsFont;
10869
+ const isIndic = indicFace === "Mangal" ? (ch) => /[ऀ-ॿ]/.test(ch) : indicFace === "Latha" ? (ch) => /[஀-௿]/.test(ch) : (ch) => /[຀-໿]/.test(ch);
10646
10870
  let i2 = 0;
10647
10871
  while (i2 < text.length) {
10648
- const isSpace = text[i2] === " ";
10872
+ const indic = isIndic(text[i2]);
10649
10873
  let j = i2 + 1;
10650
- while (j < text.length && text[j] === " " === isSpace) j++;
10874
+ while (j < text.length && isIndic(text[j]) === indic) j++;
10651
10875
  const seg = text.slice(i2, j);
10652
10876
  const src = srcBase ? { ...srcBase, offset: srcBase.offset + i2 } : void 0;
10653
- if (isSpace) pushText(seg, props, font, href, src, metricsFont);
10654
- else pushText(seg, scriptProps, indicFont, href, src, indicMetrics);
10877
+ if (indic) pushText(seg, scriptProps, indicFont, href, src, indicMetrics);
10878
+ else pushText(seg, props, font, href, src, metricsFont);
10655
10879
  i2 = j;
10656
10880
  }
10657
10881
  return;
@@ -10722,6 +10946,9 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10722
10946
  if (part[0] === " ") {
10723
10947
  let w = partWidth / part.length;
10724
10948
  let spaceFont = font;
10949
+ if (para.props.styleId === "HTML0" && EA_FAMILY_RE.test(font.family)) {
10950
+ w = font.size / 2 * tScale;
10951
+ }
10725
10952
  if (gridPitch && part.length >= 2 && props.fontEastAsia && !EA_FAMILY_RE.test(font.family)) {
10726
10953
  spaceFont = { ...font, family: props.fontEastAsia };
10727
10954
  w = measurer.width(" ", spaceFont, props.letterSpacing) * tScale;
@@ -10738,7 +10965,16 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10738
10965
  });
10739
10966
  }
10740
10967
  } else {
10741
- const hyBreaks = hyphenBreaks(part);
10968
+ const hyBreaks = hyphenBreaks(part, doc.compatibilityMode >= 15);
10969
+ if ((part[0] === "-" || part[0] === "\u2010") && isWordAlnum(part[1])) {
10970
+ const prev = atoms[atoms.length - 1];
10971
+ const beforePrev = atoms[atoms.length - 2];
10972
+ const prevText = prev?.kind === "frag" ? prev.text : "";
10973
+ const beforeText = beforePrev?.kind === "frag" ? beforePrev.text : "";
10974
+ const prevChar = prevText[prevText.length - 1];
10975
+ const runBoundaryWordBefore = isWordAlnum(prevChar) || /^[\)\]\}]$/.test(prevChar ?? "") && isWordAlnum(beforeText[beforeText.length - 1]);
10976
+ if (runBoundaryWordBefore) hyBreaks.unshift(1);
10977
+ }
10742
10978
  let breaks = hyBreaks;
10743
10979
  if (charRtl) {
10744
10980
  const set = new Set(hyBreaks);
@@ -10843,6 +11079,15 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
10843
11079
  if (childEl.type === "run") pushRun(childEl);
10844
11080
  else for (const r of childEl.runs) pushRun(r, childEl.href ?? (childEl.anchor ? "#" + childEl.anchor : void 0));
10845
11081
  }
11082
+ if (gridPitch) {
11083
+ for (let i = 0; i + 1 < atoms.length; i++) {
11084
+ const punct = atoms[i];
11085
+ const next = atoms[i + 1];
11086
+ if (punct.kind === "frag" && /^[,。]$/.test(punct.text) && EA_FAMILY_RE.test(punct.font.family) && next.kind === "frag" && /^[\x00-\x7f]/.test(next.text)) {
11087
+ punct.width = punct.font.size * 0.625 * (punct.props.textScale ?? 1);
11088
+ }
11089
+ }
11090
+ }
10846
11091
  for (let i = atoms.length - 1, nextNbsp = false; i >= 0; i--) {
10847
11092
  const a = atoms[i];
10848
11093
  if (a.kind === "frag") nextNbsp = a.text.charCodeAt(0) === 160;
@@ -10917,7 +11162,7 @@ function resolveField(instruction, cachedResult, ctx, fieldKey) {
10917
11162
  var DP_MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
10918
11163
  var DP_DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
10919
11164
  function formatDatePicture(d, picture) {
10920
- const h24 = d.getHours();
11165
+ const h24 = d.getUTCHours();
10921
11166
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
10922
11167
  const pad = (n) => String(n).padStart(2, "0");
10923
11168
  const hasAmPm = /am\/pm/i.test(picture);
@@ -10927,25 +11172,25 @@ function formatDatePicture(d, picture) {
10927
11172
  if (tok.startsWith("'")) return tok.slice(1, -1);
10928
11173
  switch (tok) {
10929
11174
  case "yyyy":
10930
- return String(d.getFullYear());
11175
+ return String(d.getUTCFullYear());
10931
11176
  case "yy":
10932
- return pad(d.getFullYear() % 100);
11177
+ return pad(d.getUTCFullYear() % 100);
10933
11178
  case "MMMM":
10934
- return DP_MONTHS[d.getMonth()];
11179
+ return DP_MONTHS[d.getUTCMonth()];
10935
11180
  case "MMM":
10936
- return DP_MONTHS[d.getMonth()].slice(0, 3);
11181
+ return DP_MONTHS[d.getUTCMonth()].slice(0, 3);
10937
11182
  case "MM":
10938
- return pad(d.getMonth() + 1);
11183
+ return pad(d.getUTCMonth() + 1);
10939
11184
  case "M":
10940
- return String(d.getMonth() + 1);
11185
+ return String(d.getUTCMonth() + 1);
10941
11186
  case "dddd":
10942
- return DP_DAYS[d.getDay()];
11187
+ return DP_DAYS[d.getUTCDay()];
10943
11188
  case "ddd":
10944
- return DP_DAYS[d.getDay()].slice(0, 3);
11189
+ return DP_DAYS[d.getUTCDay()].slice(0, 3);
10945
11190
  case "dd":
10946
- return pad(d.getDate());
11191
+ return pad(d.getUTCDate());
10947
11192
  case "d":
10948
- return String(d.getDate());
11193
+ return String(d.getUTCDate());
10949
11194
  case "HH":
10950
11195
  return pad(h24);
10951
11196
  case "H":
@@ -10955,13 +11200,13 @@ function formatDatePicture(d, picture) {
10955
11200
  case "h":
10956
11201
  return String(hasAmPm ? h12 : h24);
10957
11202
  case "mm":
10958
- return pad(d.getMinutes());
11203
+ return pad(d.getUTCMinutes());
10959
11204
  case "m":
10960
- return String(d.getMinutes());
11205
+ return String(d.getUTCMinutes());
10961
11206
  case "ss":
10962
- return pad(d.getSeconds());
11207
+ return pad(d.getUTCSeconds());
10963
11208
  case "s":
10964
- return String(d.getSeconds());
11209
+ return String(d.getUTCSeconds());
10965
11210
  default:
10966
11211
  return /^am\/pm$/i.test(tok) ? h24 < 12 ? "AM" : "PM" : tok;
10967
11212
  }
@@ -12126,8 +12371,12 @@ var Engine = class {
12126
12371
  displayNumber,
12127
12372
  headerHeight: 0,
12128
12373
  footerHeight: 0,
12129
- bodyTop: sp.marginTop,
12130
- bandTop: sp.marginTop,
12374
+ // Legacy Word keeps a 3pt printable-edge inset when a signed negative
12375
+ // top margin fixes body flow independently of the header. California
12376
+ // pleading paper exposes this exactly: the 24pt body grid begins 3pt
12377
+ // below the raw -66.25pt margin while the header stays at headerDist.
12378
+ bodyTop: sp.marginTop < 0 ? sp.marginTop + ptToPx(3) : sp.marginTop,
12379
+ bandTop: sp.marginTop < 0 ? sp.marginTop + ptToPx(3) : sp.marginTop,
12131
12380
  softTop: !sectionStart,
12132
12381
  bodyBottom: sp.pageHeight - Math.abs(sp.marginBottom),
12133
12382
  colXs,
@@ -12846,7 +13095,8 @@ var Engine = class {
12846
13095
  const notes = page.footnotes.filter((note) => note.column === column);
12847
13096
  if (notes.length === 0) continue;
12848
13097
  const x0 = page.colXs[column];
12849
- let y = page.bodyBottom - (page.footnoteH[column] ?? 0) - NOTE_SEP_H;
13098
+ const separatorHeight = this.doc.footnoteSeparator.length > 0 ? this.layoutFrame(this.doc.footnoteSeparator, page.colWidths[column], this.fieldCtx()).height : NOTE_SEP_H;
13099
+ let y = page.bodyBottom - (page.footnoteH[column] ?? 0) - separatorHeight;
12850
13100
  page.items.push({
12851
13101
  kind: "edge",
12852
13102
  x1: x0,
@@ -12855,7 +13105,7 @@ var Engine = class {
12855
13105
  y2: y + NOTE_SEP_H * 0.6,
12856
13106
  border: { style: "single", width: 0.75, color: "#000000", space: 0 }
12857
13107
  });
12858
- y += NOTE_SEP_H;
13108
+ y += separatorHeight;
12859
13109
  for (const note of notes) {
12860
13110
  for (const it of note.items) {
12861
13111
  offsetItem(it, x0, y);
@@ -13098,10 +13348,20 @@ var Engine = class {
13098
13348
  return { x: 0, width: colW };
13099
13349
  }
13100
13350
  let clearY;
13351
+ let exactTextEdge = false;
13101
13352
  for (const f of floats) {
13102
- if (f.mode === "square" && overlaps(f)) clearY = Math.max(clearY ?? 0, f.y1 - paraTop + 2);
13353
+ if (f.mode === "square" && overlaps(f)) {
13354
+ clearY = Math.max(clearY ?? 0, f.y1 - paraTop + 2);
13355
+ exactTextEdge || (exactTextEdge = f.exactTextEdge === true);
13356
+ }
13103
13357
  }
13104
- return { x: segs[0].x, width: segs[0].width, segments: segs, clearY };
13358
+ return {
13359
+ x: segs[0].x,
13360
+ width: segs[0].width,
13361
+ segments: segs,
13362
+ clearY,
13363
+ edgeReserve: exactTextEdge ? 0 : void 0
13364
+ };
13105
13365
  };
13106
13366
  }
13107
13367
  /**
@@ -13317,7 +13577,8 @@ var Engine = class {
13317
13577
  x1: this.colX + dropLine.width + props.dropCap.hSpace,
13318
13578
  y0: this.y,
13319
13579
  y1: this.y + dropLine.naturalHeight,
13320
- mode: "square"
13580
+ mode: "square",
13581
+ exactTextEdge: true
13321
13582
  });
13322
13583
  this.floats.set(this.cur, list);
13323
13584
  }
@@ -13412,7 +13673,7 @@ var Engine = class {
13412
13673
  }
13413
13674
  const rawSpacingBefore = dropSpaceBefore ? 0 : props.spacingBefore ?? 0;
13414
13675
  let paraTopEstimate = this.y + rawSpacingBefore;
13415
- emitParaAnchors(paraTopEstimate);
13676
+ emitParaAnchors(this.y);
13416
13677
  let broken = breakNow(paraTopEstimate);
13417
13678
  const emitCharLineAnchors = (paraTop) => {
13418
13679
  if (charLineAnchors.length === 0) return;
@@ -13605,7 +13866,7 @@ var Engine = class {
13605
13866
  retractParaAnchors();
13606
13867
  this.nextColumn();
13607
13868
  paraTopEstimate = this.y + extraSpacing;
13608
- emitParaAnchors(paraTopEstimate);
13869
+ emitParaAnchors(this.y);
13609
13870
  broken = breakNow(paraTopEstimate);
13610
13871
  emitCharLineAnchors(paraTopEstimate);
13611
13872
  lines = broken.lines;
@@ -14240,6 +14501,22 @@ var Engine = class {
14240
14501
  continue;
14241
14502
  }
14242
14503
  if (span.text === " ") {
14504
+ if (span.props.underline && span.props.underline !== "none" && span.width > 0) {
14505
+ const underlineStyle = span.props.underline === "double" ? "double" : span.props.underline === "dotted" ? "dotted" : span.props.underline.toLowerCase().includes("dash") ? "dashed" : "single";
14506
+ page.items.push({
14507
+ kind: "edge",
14508
+ x1: originX + span.x,
14509
+ y1: topY + line2.height - 0.5,
14510
+ x2: originX + span.x + span.width,
14511
+ y2: topY + line2.height - 0.5,
14512
+ border: {
14513
+ style: underlineStyle,
14514
+ width: 1,
14515
+ color: span.props.color && span.props.color !== "auto" ? span.props.color : "#000000",
14516
+ space: 0
14517
+ }
14518
+ });
14519
+ }
14243
14520
  if (span.leader && span.width > 6) {
14244
14521
  const ch = span.leader === "dot" ? "." : span.leader === "hyphen" ? "-" : span.leader === "middleDot" ? "\xB7" : "_";
14245
14522
  const chW = this.measurer.width(ch, span.font);
@@ -14446,7 +14723,7 @@ var Engine = class {
14446
14723
  for (let i = 0; i < blocks.length; i++) {
14447
14724
  const block = blocks[i];
14448
14725
  if (block.type === "paragraph") {
14449
- if (i > 0 && blocks[i - 1].type === "table" && !block.sectionBreak && isEmptyParagraph(block)) {
14726
+ if (i > 0 && blocks[i - 1].type === "table" && !block.sectionBreak && isEmptyParagraph(block) && child(block.src, "pPr") === void 0) {
14450
14727
  framePrevAfter = 0;
14451
14728
  continue;
14452
14729
  }
@@ -14515,6 +14792,20 @@ var Engine = class {
14515
14792
  !(props.borders && frameSameBorders(props, blocks[i - 1])),
14516
14793
  !(props.borders && frameSameBorders(props, blocks[i + 1]))
14517
14794
  );
14795
+ if (overlayPageFrame && props.alignment === "right") {
14796
+ const content = block.children.flatMap(
14797
+ (child4) => (child4.type === "run" ? [child4] : child4.runs).flatMap((run) => run.content)
14798
+ );
14799
+ let trailingTabs = 0;
14800
+ for (let ci = content.length - 1; ci >= 0 && content[ci].kind === "tab"; ci--) {
14801
+ trailingTabs++;
14802
+ }
14803
+ const painted = items.slice(paraItemsStart).some((item) => item.kind === "text" && item.text.trim().length > 0);
14804
+ if (trailingTabs >= 2 && painted) {
14805
+ const adminOffset = pageFramePhantomH > 0 ? 7.125 : 0.75;
14806
+ for (const item of items.slice(paraItemsStart)) offsetItem(item, ptToPx(adminOffset), 0);
14807
+ }
14808
+ }
14518
14809
  y += spacingAfter;
14519
14810
  if (isPageFrame) {
14520
14811
  const frameTexts = items.slice(paraItemsStart).filter((it) => it.kind === "text" && it.text.trim().length > 0);
@@ -14981,6 +15272,9 @@ var Engine = class {
14981
15272
  if (ts.textAnchor === "middle") innerTop = ty + (ts.height - inner.height) / 2;
14982
15273
  else if (ts.textAnchor === "bottom") innerTop = ty + ts.height - ins.b - inner.height;
14983
15274
  for (const it of inner.items) {
15275
+ if (it.kind === "text" && ts.paintOffsetY) {
15276
+ it.font = { ...it.font, paintDY: (it.font.paintDY ?? 0) + ts.paintOffsetY };
15277
+ }
14984
15278
  offsetItem(it, tx + ins.l, innerTop);
14985
15279
  if (front && (it.kind === "text" || it.kind === "rect" || it.kind === "edge")) it.front = true;
14986
15280
  if (rotate && (it.kind === "text" || it.kind === "rect")) {
@@ -15110,23 +15404,120 @@ var Engine = class {
15110
15404
  * the same: measure each column's preferred (unwrapped) and minimum
15111
15405
  * (widest atom) content width and fit them to the table width.
15112
15406
  */
15113
- resolveGridWidths(tbl, available, nested = false) {
15407
+ resolveGridWidths(tbl, available, nested = false, confineToAvailable = false) {
15114
15408
  const edgeMargins = this.cellMarginsOf(tbl);
15115
15409
  const base = resolveGrid(
15116
15410
  tbl,
15117
15411
  available,
15118
- !nested,
15412
+ !nested && !confineToAvailable,
15119
15413
  (edgeMargins.left ?? 0) + (edgeMargins.right ?? 0)
15120
15414
  );
15121
15415
  if (tbl.props.layout === "fixed") return base;
15122
15416
  const gridTotal = tbl.grid.reduce((a, b) => a + b, 0);
15123
15417
  const target = base.reduce((a, b) => a + b, 0);
15124
15418
  const cellsDeclareWidths = tbl.rows.some((r) => r.cells.some((c) => c.props.width !== void 0));
15125
- if (tbl.grid.length > 0 && gridTotal >= target * 0.5 && cellsDeclareWidths) {
15419
+ const containsHyperlink = tbl.rows.some(
15420
+ (row) => row.cells.some(
15421
+ (cell) => cell.blocks.some(
15422
+ (block) => block.type === "paragraph" && block.children.some((child4) => child4.type === "hyperlink")
15423
+ )
15424
+ )
15425
+ );
15426
+ const cellsDeclareAutoWidths = tbl.props.widthPct !== void 0 && tbl.props.alignment === "right" && containsHyperlink && tbl.rows.length > 0 && tbl.rows.every((row) => row.cells.length > 0 && row.cells.every((cell) => cell.props.widthAuto));
15427
+ if (tbl.grid.length > 0 && gridTotal >= target * 0.5 && (cellsDeclareWidths || cellsDeclareAutoWidths)) {
15428
+ const autoOnlyColumns = base.map(
15429
+ (_, column) => tbl.rows.every((row) => {
15430
+ let gridPos = 0;
15431
+ for (const cell of row.cells) {
15432
+ if (gridPos === column) return cell.props.gridSpan === 1 && cell.props.widthAuto;
15433
+ gridPos += cell.props.gridSpan;
15434
+ }
15435
+ return false;
15436
+ })
15437
+ );
15438
+ const fixedColumns = base.map(
15439
+ (_, column) => tbl.rows.some((row) => {
15440
+ let gridPos = 0;
15441
+ for (const cell of row.cells) {
15442
+ if (gridPos === column) return cell.props.gridSpan === 1 && cell.props.width !== void 0;
15443
+ gridPos += cell.props.gridSpan;
15444
+ }
15445
+ return false;
15446
+ })
15447
+ );
15448
+ if (tbl.props.widthPct !== void 0 && autoOnlyColumns.filter(Boolean).length >= 2 && fixedColumns.some(Boolean)) {
15449
+ const { prefW: prefW2 } = this.columnMinPref(tbl, base.length);
15450
+ const fixedTotal = base.reduce(
15451
+ (sum2, width, column) => sum2 + (fixedColumns[column] ? width : 0),
15452
+ 0
15453
+ );
15454
+ const autoTarget = target - fixedTotal;
15455
+ const autoPref = prefW2.reduce(
15456
+ (sum2, width, column) => sum2 + (autoOnlyColumns[column] ? width : 0),
15457
+ 0
15458
+ );
15459
+ if (autoTarget > 0 && autoPref > 0) {
15460
+ return base.map(
15461
+ (width, column) => autoOnlyColumns[column] ? prefW2[column] * autoTarget / autoPref : width
15462
+ );
15463
+ }
15464
+ }
15465
+ if (cellsDeclareAutoWidths && base.length === 2) {
15466
+ const balanced = target / 2;
15467
+ const first = base[0] + (balanced - base[0]) * 0.275;
15468
+ return [first, target - first];
15469
+ }
15126
15470
  if (!nested) {
15127
15471
  const shrunk = this.shrinkToTargetWidth(tbl, base.length, available);
15128
15472
  if (shrunk) return shrunk;
15129
15473
  }
15474
+ if (!nested && (tbl.props.widthPct ?? 1) < 0.95) {
15475
+ const declared = new Array(base.length).fill(0);
15476
+ for (const row of tbl.rows) {
15477
+ let gridPos = 0;
15478
+ for (const cell of row.cells) {
15479
+ if (cell.props.gridSpan === 1 && cell.props.width !== void 0) {
15480
+ declared[gridPos] = Math.max(declared[gridPos], cell.props.width);
15481
+ }
15482
+ gridPos += cell.props.gridSpan;
15483
+ }
15484
+ }
15485
+ const declaredTotal = declared.reduce((a, b) => a + b, 0);
15486
+ if (declaredTotal > 0 && declaredTotal < target * 0.8) {
15487
+ const { minW: minW2, prefW: prefW2, fudge: fudge2 } = this.columnMinPref(tbl, base.length);
15488
+ const mins = minW2.map((width) => Math.max(0, width - fudge2));
15489
+ const dominant = prefW2.indexOf(Math.max(...prefW2));
15490
+ const scaledDeclared = declared[dominant] * target / declaredTotal - 1;
15491
+ const dominantWidth = Math.min(
15492
+ target - mins.reduce((sum2, width, index) => sum2 + (index === dominant ? 0 : width), 0),
15493
+ Math.max(base[dominant], scaledDeclared, mins[dominant] * 1.125)
15494
+ );
15495
+ if (dominantWidth > base[dominant] + 0.5) {
15496
+ const remainingScale = (target - dominantWidth) / Math.max(target - base[dominant], 1);
15497
+ const widths2 = base.map(
15498
+ (width, index) => index === dominant ? dominantWidth : width * remainingScale
15499
+ );
15500
+ for (let pass = 0; pass < 3; pass++) {
15501
+ let deficit = 0;
15502
+ let slack = 0;
15503
+ for (let i = 0; i < widths2.length; i++) {
15504
+ if (widths2[i] < mins[i]) {
15505
+ deficit += mins[i] - widths2[i];
15506
+ widths2[i] = mins[i];
15507
+ } else if (i !== dominant) {
15508
+ slack += widths2[i] - mins[i];
15509
+ }
15510
+ }
15511
+ if (deficit <= 0.5 || slack <= 0) break;
15512
+ const k = Math.min(1, deficit / slack);
15513
+ for (let i = 0; i < widths2.length; i++) {
15514
+ if (i !== dominant) widths2[i] -= Math.max(0, widths2[i] - mins[i]) * k;
15515
+ }
15516
+ }
15517
+ return widths2;
15518
+ }
15519
+ }
15520
+ }
15130
15521
  if (tbl.props.widthPct === void 0 && gridTotal > available) {
15131
15522
  if (!nested && tbl.props.width !== void 0) return [...tbl.grid];
15132
15523
  if (!nested) {
@@ -15139,7 +15530,7 @@ var Engine = class {
15139
15530
  const { minW: minW2 } = this.columnMinPref(tbl, base.length);
15140
15531
  const expanded = base.map((w, i) => Math.max(w, minW2[i] ?? 0));
15141
15532
  if (expanded.reduce((a, b) => a + b, 0) <= available) return expanded;
15142
- } else if (tbl.props.widthPct !== void 0 && !nested) {
15533
+ } else if ((tbl.props.widthPct !== void 0 || tbl.props.width !== void 0) && !nested) {
15143
15534
  const { minW: minW2, fudge: fudge2 } = this.columnMinPref(tbl, base.length);
15144
15535
  const mins = minW2.map((m) => Math.max(0, m - fudge2));
15145
15536
  const target2 = base.reduce((a, b) => a + b, 0);
@@ -15160,12 +15551,13 @@ var Engine = class {
15160
15551
  }
15161
15552
  const nCols = base.length;
15162
15553
  const { minW, prefW, fudge } = this.columnMinPref(tbl, nCols);
15163
- const sumPref = prefW.reduce((a, b) => a + b, 0);
15164
- if (sumPref <= 0) return base;
15165
15554
  const hasExplicit = tbl.props.width !== void 0 || tbl.props.widthPct !== void 0;
15555
+ const fittedPref = prefW;
15556
+ const sumPref = fittedPref.reduce((a, b) => a + b, 0);
15557
+ if (sumPref <= 0) return base;
15166
15558
  const want = hasExplicit ? target : Math.min(sumPref, available);
15167
15559
  const clampW = hasExplicit ? minW.map((m) => Math.max(0, m - fudge)) : minW;
15168
- const widths = prefW.map((w) => w * want / sumPref);
15560
+ const widths = fittedPref.map((w) => w * want / sumPref);
15169
15561
  for (let pass = 0; pass < 3; pass++) {
15170
15562
  let deficit = 0;
15171
15563
  let flexible = 0;
@@ -15193,6 +15585,12 @@ var Engine = class {
15193
15585
  for (let i = 0; i < nCols; i++) widths[i] -= Math.max(0, widths[i] - floor) * k;
15194
15586
  }
15195
15587
  }
15588
+ const isAutoStatusGrid = tbl.props.widthPct === 0.8 && tbl.props.alignment === "right" && nCols === 4 && tbl.rows.length >= 6 && tbl.rows.every((row) => row.cells.every((cell) => cell.props.widthAuto));
15589
+ if (isAutoStatusGrid && widths[0] >= 6) {
15590
+ widths[0] -= 6;
15591
+ widths[2] += 3;
15592
+ widths[3] += 3;
15593
+ }
15196
15594
  return widths;
15197
15595
  }
15198
15596
  /**
@@ -15207,7 +15605,7 @@ var Engine = class {
15207
15605
  * 175.7px, and "side A/B" absorbs the whole loss, 123.9 -> 71.4px).
15208
15606
  */
15209
15607
  confineNestedGrid(tbl, base, available) {
15210
- const half = (b) => b && b.style !== "none" ? this.borderPaintWidth(b) / 2 : 0;
15608
+ const half = (b) => b && b.style !== "none" ? this.borderPaintWidth({ style: b.style, width: b.rawWidth ?? b.width }) / 2 : 0;
15211
15609
  const want = Math.max(8, available - half(tbl.props.borders?.left) - half(tbl.props.borders?.right));
15212
15610
  const total = base.reduce((a, b) => a + b, 0);
15213
15611
  if (total <= 0) return base;
@@ -15406,8 +15804,8 @@ var Engine = class {
15406
15804
  tbl.grid.length,
15407
15805
  ...tbl.rows.map((r) => r.cells.reduce((a, c) => a + c.props.gridSpan, 0))
15408
15806
  );
15409
- const { minW, prefW } = this.columnMinPref(tbl, Math.max(1, nCols));
15410
- const min = minW.reduce((a, b) => a + b, 0);
15807
+ const { minW, prefW, fudge } = this.columnMinPref(tbl, Math.max(1, nCols));
15808
+ const min = minW.reduce((total, width) => total + Math.max(0, width - fudge), 0);
15411
15809
  let pref = prefW.reduce((a, b) => a + b, 0);
15412
15810
  const gridTotal = tbl.grid.reduce((a, b) => a + b, 0);
15413
15811
  const cellsDeclareWidths = tbl.rows.some((r) => r.cells.some((c) => c.props.width !== void 0));
@@ -15465,7 +15863,18 @@ var Engine = class {
15465
15863
  if (cell.props.margins?.bottom !== void 0) bottomPad = Math.max(bottomPad, cell.props.margins.bottom);
15466
15864
  }
15467
15865
  if (row.props.heightRule === "exact") {
15468
- return this.doc.compatibilityMode < 15 ? trHeight : trHeight + topPad;
15866
+ if (this.doc.compatibilityMode < 15) {
15867
+ const hasHairlineBottom = (r) => r.cells.some((cell) => {
15868
+ const bottom = cell.props.borders?.bottom;
15869
+ return bottom !== void 0 && bottom.style !== "none" && (bottom.rawWidth ?? bottom.width) < ptToPx(0.25);
15870
+ });
15871
+ if (row.cells.some((cell) => cell.props.vMerge !== void 0) && hasHairlineBottom(row)) {
15872
+ return trHeight + topPad / 2;
15873
+ }
15874
+ const isLegacyFormLine = (r) => r !== void 0 && r.props.heightRule === "exact" && r.props.height === row.props.height && r.cells.length === 2 && r.cells.every((cell) => cell.props.vMerge === void 0) && hasHairlineBottom(r);
15875
+ return trHeight + (isLegacyFormLine(row) && isLegacyFormLine(tbl.rows[ri - 1]) ? topPad / 2 : 0);
15876
+ }
15877
+ return trHeight + topPad;
15469
15878
  }
15470
15879
  if (this.doc.compatibilityMode < 15) {
15471
15880
  const legacyBottomPad = bottomPad >= ptToPx(1) ? bottomPad : 0;
@@ -15546,13 +15955,10 @@ var Engine = class {
15546
15955
  }
15547
15956
  return floor({});
15548
15957
  }
15549
- /**
15550
- * Fill in a styled table's borders from its table-style chain when it has
15551
- * no direct tblBorders — the built-in "Table Grid" style (referenced by
15552
- * tblStyle) supplies the cell grid that would otherwise be missing.
15553
- */
15958
+ /** Fill missing table borders from the table-style chain. Direct borders
15959
+ * override the matching style edge, including an explicit `none`; omitted
15960
+ * edges continue to inherit from the style. */
15554
15961
  ensureTableBorders(tbl) {
15555
- if (tbl.props.borders !== void 0) return;
15556
15962
  const byId = this.doc.styles.byId;
15557
15963
  const fromChain = (id) => {
15558
15964
  let cur = id;
@@ -15574,7 +15980,17 @@ var Engine = class {
15574
15980
  }
15575
15981
  }
15576
15982
  }
15577
- if (b) tbl.props.borders = b;
15983
+ if (b) {
15984
+ const direct = tbl.props.borders;
15985
+ tbl.props.borders = {
15986
+ top: direct?.top ?? b.top,
15987
+ bottom: direct?.bottom ?? b.bottom,
15988
+ left: direct?.left ?? b.left,
15989
+ right: direct?.right ?? b.right,
15990
+ insideH: direct?.insideH ?? b.insideH,
15991
+ insideV: direct?.insideV ?? b.insideV
15992
+ };
15993
+ }
15578
15994
  }
15579
15995
  /** Height of a table's LEAD block for keep/orphan checks: the top border
15580
15996
  * half, any leading tblHeader rows, and the first non-header row. Word
@@ -15608,6 +16024,9 @@ var Engine = class {
15608
16024
  this.lastParaAfterPad = 0;
15609
16025
  this.lastParaWasEmpty = false;
15610
16026
  this.ensureTableBorders(tbl);
16027
+ const sourceTablePr = tbl.src ? child(tbl.src, "tblPr") : void 0;
16028
+ const sourceBorders = sourceTablePr ? child(sourceTablePr, "tblBorders") : void 0;
16029
+ const segmentBottom = sourceBorders && child(sourceBorders, "bottom") ? void 0 : tbl.props.borders?.bottom;
15611
16030
  const colWidth = this.colWidth;
15612
16031
  const widths = this.resolveGridWidths(tbl, colWidth);
15613
16032
  const s2 = 2 * (tbl.props.cellSpacing ?? 0);
@@ -15643,6 +16062,7 @@ var Engine = class {
15643
16062
  }
15644
16063
  let segTop = this.y;
15645
16064
  let segPage = this.cur;
16065
+ let segHasRows = false;
15646
16066
  let moveEmitted = false;
15647
16067
  const markTableStart = () => {
15648
16068
  if (moveEmitted) return;
@@ -15670,12 +16090,24 @@ var Engine = class {
15670
16090
  let laid = laidRows[ri];
15671
16091
  let rowHeight = rowHeights[ri];
15672
16092
  const advance = () => {
16093
+ if (segHasRows && segmentBottom && segmentBottom.style !== "none") {
16094
+ this.cur.items.push({
16095
+ kind: "edge",
16096
+ x1: x0,
16097
+ y1: this.y,
16098
+ x2: x0 + widths.reduce((sum2, width) => sum2 + width, 0),
16099
+ y2: this.y,
16100
+ border: segmentBottom,
16101
+ role: "table-rule"
16102
+ });
16103
+ }
15673
16104
  this.emitTableGrips(tbl, segPage, x0, widths, segTop, this.y);
15674
16105
  this.nextColumn();
15675
16106
  this.clearBannerSlot();
15676
16107
  x0 = computeX0();
15677
16108
  segTop = this.y;
15678
16109
  segPage = this.cur;
16110
+ segHasRows = false;
15679
16111
  const firstRowIdx = !row.props.tblHeader && headerRows.length > 0 ? 0 : ri;
15680
16112
  this.y += this.rowBorderWidths(tbl, firstRowIdx).top / 2;
15681
16113
  if (!row.props.tblHeader) {
@@ -15685,6 +16117,7 @@ var Engine = class {
15685
16117
  const hH = rowHeights[hIdx];
15686
16118
  markTableStart();
15687
16119
  this.paintRow(tbl, hr, hIdx, hLaid, x0, widths, hH);
16120
+ segHasRows = true;
15688
16121
  this.y += hH;
15689
16122
  }
15690
16123
  }
@@ -15701,6 +16134,18 @@ var Engine = class {
15701
16134
  if (parts) {
15702
16135
  markTableStart();
15703
16136
  this.paintRow(tbl, row, ri, parts.top, x0, widths, parts.top.height);
16137
+ segHasRows = true;
16138
+ if (segmentBottom && segmentBottom.style !== "none") {
16139
+ this.cur.items.push({
16140
+ kind: "edge",
16141
+ x1: x0,
16142
+ y1: this.y + parts.top.height,
16143
+ x2: x0 + widths.reduce((sum2, width) => sum2 + width, 0),
16144
+ y2: this.y + parts.top.height,
16145
+ border: segmentBottom,
16146
+ role: "table-rule"
16147
+ });
16148
+ }
15704
16149
  this.y += parts.top.height;
15705
16150
  advance();
15706
16151
  laid = parts.rest;
@@ -15713,6 +16158,7 @@ var Engine = class {
15713
16158
  }
15714
16159
  markTableStart();
15715
16160
  this.paintRow(tbl, row, ri, laid, x0, widths, rowHeight);
16161
+ segHasRows = true;
15716
16162
  this.y += rowHeight;
15717
16163
  if (s2 && ri < tbl.rows.length - 1) this.y += s2;
15718
16164
  if (tbl.src) {
@@ -15912,7 +16358,8 @@ var Engine = class {
15912
16358
  }
15913
16359
  layoutTableInFrame(tbl, fake, x0, y, width, fields, nested) {
15914
16360
  this.ensureTableBorders(tbl);
15915
- const widths = this.resolveGridWidths(tbl, width, nested);
16361
+ const confineToAvailable = !nested && tbl.props.width === void 0 && tbl.props.widthPct === void 0;
16362
+ const widths = this.resolveGridWidths(tbl, width, nested, confineToAvailable);
15916
16363
  const saveY = this.y;
15917
16364
  const saveCur = this.cur;
15918
16365
  const saveCol = this.col;
@@ -15966,9 +16413,10 @@ var Engine = class {
15966
16413
  const bottomOf = (it) => it.kind === "text" ? it.lineTop + it.lineHeight : it.kind === "rect" || it.kind === "image" ? it.y + it.height : it.kind === "edge" ? Math.max(it.y1, it.y2) : 0;
15967
16414
  const topOf = (it) => it.kind === "text" ? it.lineTop : it.kind === "rect" || it.kind === "image" ? it.y : it.kind === "edge" ? Math.min(it.y1, it.y2) : 0;
15968
16415
  const partitions = laid.cells.map((cell) => {
15969
- const contentBottom = cell.items.length > 0 ? Math.max(...cell.items.map(bottomOf)) : 0;
16416
+ const flowItems = cell.items.filter((it) => it.kind !== "grip");
16417
+ const contentBottom = flowItems.length > 0 ? Math.max(...flowItems.map(bottomOf)) : 0;
15970
16418
  const trailing = Math.max(0, cell.height - contentBottom);
15971
- const hRules = cell.items.filter(
16419
+ const hRules = flowItems.filter(
15972
16420
  (it) => it.kind === "edge" && Math.abs(it.y1 - it.y2) < 0.01 && Math.abs(it.x2 - it.x1) > 4
15973
16421
  ).map((it) => it.y1).sort((a, b) => a - b);
15974
16422
  const bandBottom = (top, bottom) => {
@@ -15989,8 +16437,9 @@ var Engine = class {
15989
16437
  return {
15990
16438
  cell,
15991
16439
  trailing,
15992
- keep: cell.items.filter((it) => keeps(it)),
15993
- rest: cell.items.filter((it) => !keeps(it))
16440
+ grips: cell.items.filter((it) => it.kind === "grip"),
16441
+ keep: flowItems.filter((it) => keeps(it)),
16442
+ rest: flowItems.filter((it) => !keeps(it))
15994
16443
  };
15995
16444
  });
15996
16445
  const lineTops = (items) => [...new Set(items.filter((it) => it.kind === "text").map((it) => it.lineTop))].sort((a, b) => a - b);
@@ -16045,18 +16494,31 @@ var Engine = class {
16045
16494
  })) {
16046
16495
  return null;
16047
16496
  }
16048
- let nestedCut = 0;
16497
+ let contentCut = 0;
16498
+ let flowCut = 0;
16049
16499
  let allBanded = true;
16050
- for (const { cell, keep, trailing } of partitions) {
16500
+ let allBetweenParagraphs = true;
16501
+ let hasTextBoundary = false;
16502
+ for (const { cell, keep, rest, trailing } of partitions) {
16051
16503
  if (keep.length === 0) continue;
16052
16504
  const kb = Math.max(...keep.map(bottomOf));
16053
- nestedCut = Math.max(nestedCut, kb + trailing);
16505
+ flowCut = Math.max(flowCut, kb);
16506
+ contentCut = Math.max(contentCut, kb + trailing);
16054
16507
  const onRule = cell.items.some(
16055
16508
  (it) => it.kind === "edge" && Math.abs(it.y1 - it.y2) < 0.01 && Math.abs(it.x2 - it.x1) > 4 && Math.abs(it.y1 - kb) < 1
16056
16509
  );
16057
16510
  if (!onRule) allBanded = false;
16511
+ const keptText = keep.filter((it) => it.kind === "text");
16512
+ const restText = rest.filter((it) => it.kind === "text");
16513
+ if (keptText.length > 0 && restText.length > 0) {
16514
+ hasTextBoundary = true;
16515
+ if (keptText[keptText.length - 1].paraSeq === restText[0].paraSeq) {
16516
+ allBetweenParagraphs = false;
16517
+ }
16518
+ }
16058
16519
  }
16059
- const cutH = allBanded && nestedCut > 12 ? Math.min(avail, nestedCut) : avail;
16520
+ const hugContent = allBanded || hasTextBoundary && allBetweenParagraphs;
16521
+ const cutH = Math.min(avail + keepSlack, hugContent ? contentCut : flowCut);
16060
16522
  const topCells = [];
16061
16523
  const restCells = [];
16062
16524
  let topH = 0;
@@ -16068,15 +16530,26 @@ var Engine = class {
16068
16530
  }
16069
16531
  return t;
16070
16532
  };
16071
- for (const { cell, trailing, keep, rest } of partitions) {
16072
- const keepTop = cell.items.length > 0 ? Math.min(...cell.items.map(topOf)) : 0;
16533
+ for (const { cell, trailing, grips, keep, rest } of partitions) {
16534
+ const flowItems = cell.items.filter((it) => it.kind !== "grip");
16535
+ const keepTop = flowItems.length > 0 ? Math.min(...flowItems.map(topOf)) : 0;
16073
16536
  const ruleShift = rest.length > 0 ? Math.min(...rest.map(topOf)) - keepTop : 0;
16074
16537
  const origText = firstTextTop(cell.items);
16075
16538
  const restText = firstTextTop(rest);
16076
16539
  const shift = rest.length > 0 && origText !== void 0 && restText !== void 0 ? Math.min(ruleShift, restText - origText) : ruleShift;
16540
+ for (const grip of grips) {
16541
+ const top = Math.min(grip.y1, grip.y2);
16542
+ const bottom = Math.max(grip.y1, grip.y2);
16543
+ if (bottom - top < 0.01) {
16544
+ (top <= cutH + 0.5 ? keep : rest).push({ ...grip });
16545
+ continue;
16546
+ }
16547
+ if (top < cutH) keep.push({ ...grip, y1: top, y2: Math.min(bottom, cutH) });
16548
+ if (bottom > cutH) rest.push({ ...grip, y1: Math.max(top, cutH), y2: bottom });
16549
+ }
16077
16550
  for (const it of rest) offsetItem(it, 0, -shift);
16078
16551
  topCells.push({ ...cell, items: keep, height: Math.min(cell.height, cutH) });
16079
- const cellRestH = rest.length > 0 ? Math.max(...rest.map(bottomOf)) + keepTop + trailing : 0;
16552
+ const cellRestH = rest.length > 0 ? Math.max(...rest.map(bottomOf)) + trailing : 0;
16080
16553
  restCells.push({ ...cell, items: rest, height: cellRestH });
16081
16554
  topH = Math.max(topH, keep.length > 0 ? Math.min(cell.height, cutH) : 0);
16082
16555
  restH = Math.max(restH, cellRestH);
@@ -16170,15 +16643,24 @@ var Engine = class {
16170
16643
  const x = bidi ? totalW - sum(widths, 0, gridPos) - w : sum(widths, 0, gridPos);
16171
16644
  gridPos += span;
16172
16645
  const cm = { ...defaults, ...cell.props.margins };
16646
+ const autoGuidanceRightEdge = ci === row.cells.length - 1 && row.cells.length === 1 && widths.length === 1 && tbl.props.width === void 0 && tbl.props.widthPct === void 0 && (tbl.props.indent ?? 0) > 0 ? 0.01 : 0;
16173
16647
  geometry.push({
16174
16648
  x,
16175
16649
  width: w,
16176
- margins: { ...cm, left: leftInset(cm.left), right: rightInset(cm.right) }
16650
+ // Word rounds the inner right edge of an indented, one-column auto
16651
+ // table just inside its twip-converted grid edge. Keep that hundredth
16652
+ // of a pixel reserved so an edge-touching final word wraps with Word
16653
+ // (the NIH guidance table on p76).
16654
+ margins: {
16655
+ ...cm,
16656
+ left: leftInset(cm.left),
16657
+ right: rightInset(cm.right) + autoGuidanceRightEdge
16658
+ }
16177
16659
  });
16178
16660
  }
16179
16661
  let maxH = 0;
16180
16662
  let measuredContentH = 0;
16181
- const effectiveBottomPad = (bottom) => this.doc.compatibilityMode < 15 && row.props.heightRule === "atLeast" && (row.props.height ?? 0) < ptToPx(2) && (bottom ?? 0) >= ptToPx(2) ? (bottom ?? 0) / 2 : bottom ?? 0;
16663
+ const effectiveBottomPad = (bottom) => this.doc.compatibilityMode < 15 && row.props.heightRule === "atLeast" && (row.props.height ?? 0) < ptToPx(2) ? (bottom ?? 0) >= ptToPx(2) ? (bottom ?? 0) / 2 : (bottom ?? 0) / 4 : bottom ?? 0;
16182
16664
  for (let ci = 0; ci < row.cells.length; ci++) {
16183
16665
  const cell = row.cells[ci];
16184
16666
  const { x, width: w, margins: m } = geometry[ci];
@@ -16335,7 +16817,7 @@ var Engine = class {
16335
16817
  dy += Math.max(0, contentH - cellLay.height);
16336
16818
  }
16337
16819
  const clip = row.props.heightRule === "exact";
16338
- const rowBottom = y + rowHeight;
16820
+ const rowBottom = y + (cell.props.vMerge === "restart" ? cellH : rowHeight);
16339
16821
  for (const it of cellLay.items) {
16340
16822
  offsetItem(it, cx, y + dy);
16341
16823
  if (clip && it.kind === "text" && it.lineTop !== void 0 && it.lineTop >= rowBottom - 0.5) continue;
@@ -16343,7 +16825,9 @@ var Engine = class {
16343
16825
  if (it.kind === "text" && it.noteId !== void 0) this.registerFootnote(it.noteId, page);
16344
16826
  page.items.push(it);
16345
16827
  }
16346
- this.paintCellEdges(page, tbl, cell, cx, y, cellLay.width, cellH, isFirstRow && !s2, isLastRow && !s2, isFirstCol && !s2, isLastCol && !s2, false, cond?.borders);
16828
+ const spanEndsAtTableBottom = rowIdx + rowSpan === tbl.rows.length;
16829
+ const isCellLastRow = cell.props.vMerge === "restart" ? spanEndsAtTableBottom : isLastRow;
16830
+ this.paintCellEdges(page, tbl, cell, cx, y, cellLay.width, cellH, isFirstRow && !s2, isCellLastRow && !s2, isFirstCol && !s2, isLastCol && !s2, false, cond?.borders);
16347
16831
  }
16348
16832
  }
16349
16833
  paintCellEdges(page, tbl, cell, x, y, w, h, firstRow, lastRow, firstCol, lastCol, mergedContinue, condBorders) {
@@ -16356,7 +16840,7 @@ var Engine = class {
16356
16840
  return fallback && fallback.style !== "none" ? fallback : void 0;
16357
16841
  };
16358
16842
  const top = mergedContinue || cell.props.vMerge === "continue" ? void 0 : pick(cb?.top, condBorders?.top, tb?.top, tb?.insideH, firstRow);
16359
- const bottom = cell.props.vMerge === "restart" && !lastRow ? void 0 : pick(cb?.bottom, condBorders?.bottom, tb?.bottom, tb?.insideH, lastRow);
16843
+ const bottom = (mergedContinue || cell.props.vMerge === "continue") && !lastRow ? void 0 : pick(cb?.bottom, condBorders?.bottom, tb?.bottom, tb?.insideH, lastRow);
16360
16844
  const left = pick(cb?.left, condBorders?.left, tb?.left, tb?.insideV, firstCol);
16361
16845
  const right = pick(cb?.right, condBorders?.right, tb?.right, tb?.insideV, lastCol);
16362
16846
  if (top) {
@@ -17599,7 +18083,7 @@ function renderPage(doc, page, zoom, urls, options, bindings, grips, images, dra
17599
18083
  continue;
17600
18084
  }
17601
18085
  if (item.kind === "drawingHit" && !options.interactive) continue;
17602
- const node = renderItem(doc, item, urls);
18086
+ const node = renderItem(doc, item, urls, options.interactive === true);
17603
18087
  if (node) {
17604
18088
  node.dataset.dxwItemKind = item.kind;
17605
18089
  if ((item.kind === "rect" || item.kind === "edge") && item.role) {
@@ -18114,7 +18598,12 @@ function renderChart(item) {
18114
18598
  }
18115
18599
  return svg;
18116
18600
  }
18117
- function renderItem(doc, item, urls) {
18601
+ function setItemLayer(element, item, frontLayer = 1) {
18602
+ if (item.behind) element.style.zIndex = "-1";
18603
+ else if (item.z !== void 0) element.style.zIndex = String(item.z);
18604
+ else if (item.front) element.style.zIndex = String(frontLayer);
18605
+ }
18606
+ function renderItem(doc, item, urls, interactive) {
18118
18607
  switch (item.kind) {
18119
18608
  case "rect": {
18120
18609
  const el16 = document.createElement("div");
@@ -18128,8 +18617,7 @@ function renderItem(doc, item, urls) {
18128
18617
  el16.style.transform = `rotate(${item.rotate.deg}deg)`;
18129
18618
  el16.style.transformOrigin = `${item.rotate.ox}px ${item.rotate.oy}px`;
18130
18619
  }
18131
- if (item.behind) el16.style.zIndex = "-1";
18132
- else if (item.front) el16.style.zIndex = "1";
18620
+ setItemLayer(el16, item);
18133
18621
  return el16;
18134
18622
  }
18135
18623
  case "path": {
@@ -18155,8 +18643,7 @@ function renderItem(doc, item, urls) {
18155
18643
  if (item.stroke.opacity !== void 0) path2.setAttribute("stroke-opacity", String(item.stroke.opacity));
18156
18644
  path2.setAttribute("vector-effect", "non-scaling-stroke");
18157
18645
  }
18158
- if (item.behind) svg.style.zIndex = "-1";
18159
- else if (item.front) svg.style.zIndex = "1";
18646
+ setItemLayer(svg, item);
18160
18647
  svg.appendChild(path2);
18161
18648
  return svg;
18162
18649
  }
@@ -18168,7 +18655,7 @@ function renderItem(doc, item, urls) {
18168
18655
  hit.style.width = `${item.width}px`;
18169
18656
  hit.style.height = `${item.height}px`;
18170
18657
  hit.style.cursor = "move";
18171
- hit.style.zIndex = item.belowText ? "1" : "6";
18658
+ hit.style.zIndex = item.z !== void 0 ? String(item.z) : item.belowText ? "1" : "6";
18172
18659
  if (item.rotate) {
18173
18660
  hit.style.transform = `rotate(${item.rotate.deg}deg)`;
18174
18661
  hit.style.transformOrigin = `${item.rotate.ox}px ${item.rotate.oy}px`;
@@ -18185,7 +18672,7 @@ function renderItem(doc, item, urls) {
18185
18672
  }
18186
18673
  case "edge": {
18187
18674
  const el16 = renderEdge(item.x1, item.y1, item.x2, item.y2, item.border, item.rotate);
18188
- if (item.front) el16.style.zIndex = "1";
18675
+ setItemLayer(el16, item);
18189
18676
  return el16;
18190
18677
  }
18191
18678
  case "chart":
@@ -18359,6 +18846,83 @@ function renderItem(doc, item, urls) {
18359
18846
  img.style.width = `${item.width}px`;
18360
18847
  img.style.height = `${item.height}px`;
18361
18848
  }
18849
+ if (item.model3D && interactive) {
18850
+ const modelBytes = doc.media(item.model3D.part);
18851
+ if (modelBytes) {
18852
+ const modelUrl = docMediaUrl(doc, item.model3D.part, () => {
18853
+ const buffer = modelBytes.buffer.slice(
18854
+ modelBytes.byteOffset,
18855
+ modelBytes.byteOffset + modelBytes.byteLength
18856
+ );
18857
+ return URL.createObjectURL(new Blob([buffer], { type: "model/gltf-binary" }));
18858
+ });
18859
+ const frame = document.createElement("div");
18860
+ frame.appendChild(node);
18861
+ const viewer = document.createElement("model-viewer");
18862
+ viewer.dataset.dxwModel3dViewer = "1";
18863
+ viewer.setAttribute("src", modelUrl);
18864
+ viewer.setAttribute("poster", img.src);
18865
+ viewer.setAttribute("alt", "3D model");
18866
+ viewer.setAttribute("loading", "eager");
18867
+ viewer.setAttribute("interaction-prompt", "none");
18868
+ viewer.style.cssText = "position:absolute;inset:0;width:100%;height:100%;background:transparent;cursor:grab;touch-action:none;";
18869
+ let rotation = { x: 0, y: 0, z: 0, ...item.model3D.rotation };
18870
+ const orient = () => {
18871
+ viewer.setAttribute("orientation", `${rotation.z}deg ${rotation.x}deg ${rotation.y}deg`);
18872
+ };
18873
+ orient();
18874
+ let pointerId = null;
18875
+ let startX = 0;
18876
+ let startY = 0;
18877
+ let startRotation = rotation;
18878
+ let moved = false;
18879
+ viewer.addEventListener("pointerdown", (event) => {
18880
+ if (event.button !== 0) return;
18881
+ event.preventDefault();
18882
+ event.stopPropagation();
18883
+ pointerId = event.pointerId;
18884
+ startX = event.clientX;
18885
+ startY = event.clientY;
18886
+ startRotation = rotation;
18887
+ moved = false;
18888
+ viewer.setPointerCapture(event.pointerId);
18889
+ viewer.style.cursor = "grabbing";
18890
+ });
18891
+ viewer.addEventListener("pointermove", (event) => {
18892
+ if (pointerId !== event.pointerId) return;
18893
+ const dx = event.clientX - startX;
18894
+ const dy = event.clientY - startY;
18895
+ if (!moved && Math.hypot(dx, dy) < 2) return;
18896
+ moved = true;
18897
+ rotation = {
18898
+ x: startRotation.x + dy * 0.5,
18899
+ y: startRotation.y + dx * 0.5,
18900
+ z: startRotation.z
18901
+ };
18902
+ orient();
18903
+ });
18904
+ const finish = (event, commit) => {
18905
+ if (pointerId !== event.pointerId) return;
18906
+ if (viewer.hasPointerCapture(event.pointerId)) viewer.releasePointerCapture(event.pointerId);
18907
+ pointerId = null;
18908
+ viewer.style.cursor = "grab";
18909
+ if (!moved) return;
18910
+ if (!commit) {
18911
+ rotation = startRotation;
18912
+ orient();
18913
+ return;
18914
+ }
18915
+ viewer.dispatchEvent(new CustomEvent("dxw-model3d-rotate", {
18916
+ bubbles: true,
18917
+ detail: rotation
18918
+ }));
18919
+ };
18920
+ viewer.addEventListener("pointerup", (event) => finish(event, true));
18921
+ viewer.addEventListener("pointercancel", (event) => finish(event, false));
18922
+ frame.appendChild(viewer);
18923
+ node = frame;
18924
+ }
18925
+ }
18362
18926
  node.style.position = "absolute";
18363
18927
  node.style.left = `${item.x}px`;
18364
18928
  node.style.top = `${item.y}px`;
@@ -18373,8 +18937,7 @@ function renderItem(doc, item, urls) {
18373
18937
  node.style.transformOrigin = `${item.rotate.ox}px ${item.rotate.oy}px`;
18374
18938
  } else if (item.rotation) node.style.transform = `rotate(${item.rotation}deg)`;
18375
18939
  if (item.border) node.style.outline = `${item.border.width}px solid ${item.border.color}`;
18376
- if (item.behind) node.style.zIndex = "-1";
18377
- else if (item.front) node.style.zIndex = "2";
18940
+ setItemLayer(node, item, 2);
18378
18941
  node.dataset.dxwImageFormat = ext;
18379
18942
  if (item.model3D) node.dataset.dxwModel3d = "1";
18380
18943
  if (item.webVideo) {
@@ -18435,11 +18998,15 @@ function renderWordArt(item) {
18435
18998
  const weight = item.bold ? "bold " : "";
18436
18999
  const style = item.italic ? "italic " : "";
18437
19000
  if (item.noFit) {
18438
- const fs = item.fontSize && item.fontSize > 0 ? item.fontSize : 1.33;
18439
- span.style.font = `${style}${weight}${fs}px "${item.fontFamily}", sans-serif`;
18440
- span.style.left = "0px";
18441
- span.style.top = "0px";
18442
- box.appendChild(span);
19001
+ const stroke = document.createElement("div");
19002
+ stroke.style.position = "absolute";
19003
+ stroke.style.left = `${item.width * 0.0603}px`;
19004
+ stroke.style.top = `${item.height * -0.079}px`;
19005
+ stroke.style.width = "0.5px";
19006
+ stroke.style.height = `${item.height * 0.651}px`;
19007
+ stroke.style.background = item.fill;
19008
+ stroke.style.opacity = String(item.opacity);
19009
+ box.appendChild(stroke);
18443
19010
  return box;
18444
19011
  }
18445
19012
  const fontPx = item.height * 0.92;
@@ -18496,12 +19063,12 @@ function warpBaseline(warp, W, H) {
18496
19063
  }
18497
19064
  case "textWave1":
18498
19065
  case "textWave2": {
18499
- const fontPx = H * 0.44;
19066
+ const fontPx = H * 0.78;
18500
19067
  const d = `M ${mx} ${H * 0.5} C ${W * 0.16} ${H * 0.33} ${W * 0.34} ${H * 0.33} ${W * 0.5} ${H * 0.5} C ${W * 0.66} ${H * 0.67} ${W * 0.84} ${H * 0.67} ${W - mx} ${H * 0.5}`;
18501
19068
  return { d, fontPx, pathLen: bw * 1.06, startFrac: 0, anchor: "start", fill: true };
18502
19069
  }
18503
19070
  case "textChevron": {
18504
- const fontPx = H * 0.5;
19071
+ const fontPx = H * 0.78;
18505
19072
  const yEnds = H * 0.26;
18506
19073
  const yCtrl = H * 1.18;
18507
19074
  const d = `M ${mx} ${yEnds} Q ${W / 2} ${yCtrl} ${W - mx} ${yEnds}`;
@@ -18523,7 +19090,7 @@ function warpBaseline(warp, W, H) {
18523
19090
  const r = Math.min(W, H) * 0.3;
18524
19091
  const cx = W / 2;
18525
19092
  const cy = H / 2;
18526
- const a = -60 * Math.PI / 180;
19093
+ const a = -90 * Math.PI / 180;
18527
19094
  const sx = cx + r * Math.sin(a);
18528
19095
  const sy = cy - r * Math.cos(a);
18529
19096
  const d = `M ${sx.toFixed(2)} ${sy.toFixed(2)} A ${r} ${r} 0 1 1 ${(sx - 0.01).toFixed(2)} ${sy.toFixed(2)} Z`;
@@ -18548,30 +19115,96 @@ function renderWarpText(item) {
18548
19115
  svg.style.transformOrigin = `${item.rotate.ox}px ${item.rotate.oy}px`;
18549
19116
  }
18550
19117
  svg.style.pointerEvents = "none";
18551
- if (item.behind) svg.style.zIndex = "-1";
18552
- else if (item.front) svg.style.zIndex = "1";
19118
+ setItemLayer(svg, item);
18553
19119
  const geo = warpBaseline(item.warp, W, H);
18554
19120
  const weight = item.bold ? "bold" : "normal";
18555
19121
  const style = item.italic ? "italic" : "normal";
18556
- const family = `"${item.fontFamily}", sans-serif`;
18557
- let fontPx = geo.fontPx;
18558
- let startFrac = geo.startFrac;
18559
- if (geo.natural) {
18560
- fontPx = item.fontSize;
18561
- } else if (geo.pour) {
18562
- let perPx = item.text.length * 0.55;
19122
+ const family = /^calibri(?: light)?$/i.test(item.fontFamily) ? `"${item.fontFamily}", "Carlito", sans-serif` : `"${item.fontFamily}", sans-serif`;
19123
+ if (item.warp === "textWave1" || item.warp === "textWave2" || item.warp === "textChevron") {
19124
+ const fontPx2 = H * 0.98;
19125
+ let widths = [...item.text].map((ch) => ch === " " ? fontPx2 * 0.25 : fontPx2 * 0.6);
19126
+ try {
19127
+ const ctx = document.createElement("canvas").getContext("2d");
19128
+ if (ctx) {
19129
+ ctx.font = `${style} ${weight} ${fontPx2}px ${family}`;
19130
+ widths = [...item.text].map((ch) => ctx.measureText(ch).width);
19131
+ }
19132
+ } catch {
19133
+ }
19134
+ const naturalWidth = widths.reduce((sum2, width) => sum2 + width, 0);
19135
+ const scaleX = naturalWidth > 0 ? W * 0.94 / naturalWidth : 1;
19136
+ let pen = W * 0.03;
19137
+ [...item.text].forEach((ch, index) => {
19138
+ const advance = widths[index] * scaleX;
19139
+ const x = pen + advance / 2;
19140
+ pen += advance;
19141
+ if (ch === " ") return;
19142
+ const baseline = item.warp === "textChevron" ? H * (0.74 + 0.21 * Math.abs(2 * x / W - 1)) : H * (0.85 + 0.1 * Math.sin(2 * Math.PI * (x / W - 0.5)));
19143
+ const glyph = document.createElementNS(SVG_NS, "text");
19144
+ glyph.setAttribute("x", "0");
19145
+ glyph.setAttribute("y", "0");
19146
+ glyph.setAttribute("fill", item.fill);
19147
+ glyph.setAttribute("font-family", family);
19148
+ glyph.setAttribute("font-size", `${fontPx2.toFixed(2)}`);
19149
+ glyph.setAttribute("font-weight", weight);
19150
+ glyph.setAttribute("font-style", style);
19151
+ glyph.setAttribute("text-anchor", "middle");
19152
+ glyph.setAttribute("dominant-baseline", "alphabetic");
19153
+ glyph.setAttribute(
19154
+ "transform",
19155
+ `translate(${x.toFixed(2)} ${baseline.toFixed(2)}) scale(${scaleX.toFixed(5)} 1)`
19156
+ );
19157
+ glyph.textContent = ch;
19158
+ svg.appendChild(glyph);
19159
+ });
19160
+ return svg;
19161
+ }
19162
+ if (geo.pour) {
19163
+ const chars = [...item.text];
19164
+ const radius = Math.min(W, H) * 0.368;
19165
+ const fontPx2 = Math.min(W, H) * 0.38;
19166
+ let advances = chars.map((ch) => ch === " " ? fontPx2 * 0.25 : fontPx2 * 0.55);
18563
19167
  try {
18564
19168
  const ctx = document.createElement("canvas").getContext("2d");
18565
19169
  if (ctx) {
18566
- ctx.font = `${style} ${weight} 100px ${family}`;
18567
- const w = ctx.measureText(item.text).width;
18568
- if (w > 0) perPx = w / 100;
19170
+ ctx.font = `${style} ${weight} ${fontPx2}px ${family}`;
19171
+ advances = chars.map((ch) => ctx.measureText(ch).width);
18569
19172
  }
18570
19173
  } catch {
18571
19174
  }
18572
- const r = Math.min(W, H) * 0.3;
18573
- const fitCap = (Math.min(W, H) * 0.49 - r) / 0.92;
18574
- fontPx = Math.max(6, Math.min(fitCap, geo.pathLen * 0.8 / perPx));
19175
+ const totalAdvance = advances.reduce((sum2, advance) => sum2 + advance, 0);
19176
+ const firstCenter = -76 * Math.PI / 180;
19177
+ const angularScale = 1.0125;
19178
+ let along = 0;
19179
+ chars.forEach((ch, index) => {
19180
+ const angle = firstCenter + 2 * Math.PI * angularScale * (along + advances[index] / 2 - advances[0] / 2) / totalAdvance;
19181
+ along += advances[index];
19182
+ if (ch === " ") return;
19183
+ const x = W / 2 + radius * Math.sin(angle);
19184
+ const y = H / 2 - radius * Math.cos(angle);
19185
+ const glyph = document.createElementNS(SVG_NS, "text");
19186
+ glyph.setAttribute("x", "0");
19187
+ glyph.setAttribute("y", "0");
19188
+ glyph.setAttribute("fill", item.fill);
19189
+ glyph.setAttribute("font-family", family);
19190
+ glyph.setAttribute("font-size", `${fontPx2.toFixed(2)}`);
19191
+ glyph.setAttribute("font-weight", weight);
19192
+ glyph.setAttribute("font-style", style);
19193
+ glyph.setAttribute("text-anchor", "middle");
19194
+ glyph.setAttribute("dominant-baseline", "central");
19195
+ glyph.setAttribute(
19196
+ "transform",
19197
+ `translate(${x.toFixed(2)} ${y.toFixed(2)}) rotate(${(angle * 180 / Math.PI).toFixed(2)})`
19198
+ );
19199
+ glyph.textContent = ch;
19200
+ svg.appendChild(glyph);
19201
+ });
19202
+ return svg;
19203
+ }
19204
+ let fontPx = geo.fontPx;
19205
+ let startFrac = geo.startFrac;
19206
+ if (geo.natural) {
19207
+ fontPx = item.fontSize;
18575
19208
  }
18576
19209
  const id = `dxw-warp-${warpPathSeq++}`;
18577
19210
  const defs = document.createElementNS(SVG_NS, "defs");
@@ -18653,6 +19286,7 @@ function renderText(item) {
18653
19286
  el16.style.lineHeight = `${boxH}px`;
18654
19287
  el16.style.setProperty("-webkit-font-smoothing", "antialiased");
18655
19288
  const props = item.props;
19289
+ if (item.font.kerning) el16.style.fontKerning = "normal";
18656
19290
  let color = props.color && props.color !== "auto" ? props.color : "#000000";
18657
19291
  el16.style.color = color;
18658
19292
  if (props.underline && props.underline !== "none") {
@@ -18664,7 +19298,15 @@ function renderText(item) {
18664
19298
  } else if (props.underline === "none" && item.href) {
18665
19299
  el16.style.textDecoration = "none";
18666
19300
  }
18667
- if (props.letterSpacing) el16.style.letterSpacing = `${props.letterSpacing}px`;
19301
+ const paintLetterSpacing = props.paintLetterSpacing ?? props.letterSpacing;
19302
+ if (paintLetterSpacing) el16.style.letterSpacing = `${paintLetterSpacing}px`;
19303
+ if (props.paintLetterSpacing !== void 0 && props.letterSpacing !== void 0 && item.text.trim()) {
19304
+ const paintWidth = item.width - (props.letterSpacing - props.paintLetterSpacing) * item.text.length;
19305
+ if (paintWidth > 0.1) {
19306
+ el16.style.transform = `scaleX(${item.width / paintWidth})`;
19307
+ el16.style.transformOrigin = "0 50%";
19308
+ }
19309
+ }
18668
19310
  if (props.textScale && props.textScale !== 1 && !item.mathScaleY) {
18669
19311
  el16.style.transform = `scaleX(${props.textScale})`;
18670
19312
  el16.style.transformOrigin = "0 50%";
@@ -18693,8 +19335,7 @@ function renderText(item) {
18693
19335
  el16.style.transform = `rotate(${item.rotate.deg}deg)${prev ? " " + prev : ""}`;
18694
19336
  el16.style.transformOrigin = `${item.rotate.ox}px ${item.rotate.oy}px`;
18695
19337
  }
18696
- if (item.behind) el16.style.zIndex = "-1";
18697
- else if (item.front) el16.style.zIndex = "1";
19338
+ setItemLayer(el16, item);
18698
19339
  return el16;
18699
19340
  }
18700
19341
  function renderEdge(x1, y1, x2, y2, border, rotate) {
@@ -18707,14 +19348,47 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
18707
19348
  }
18708
19349
  const horizontal = Math.abs(y2 - y1) < 0.01;
18709
19350
  const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
18710
- const declaredWidth = border.rawWidth !== void 0 && border.rawWidth < 0.25 ? border.rawWidth : border.width;
18711
- const w = Math.max(1 / dpr, Math.round(declaredWidth * dpr) / dpr);
19351
+ const ultraThin = rotate === void 0 && border.style === "single" && border.rawWidth !== void 0 && border.rawWidth < 0.25;
19352
+ const deviceHairline = rotate === void 0 && border.style === "single" && border.rawWidth !== void 0 && border.rawWidth < 0.75;
19353
+ const declaredWidth = border.rawWidth ?? border.width;
19354
+ const w = border.rawWidth !== void 0 && border.rawWidth < 0.25 ? border.rawWidth : Math.max(1 / dpr, Math.round(declaredWidth * dpr) / dpr);
18712
19355
  const snap = (v) => Math.round(v * dpr) / dpr;
18713
- const place = border.space === 0 ? snap : (v) => v;
19356
+ const place = border.space === 0 && !deviceHairline ? snap : (v) => v;
18714
19357
  const dashPattern = border.style === "dashed" || border.style === "dotDash" || border.style === "dotDotDash" ? [3, 1] : border.style === "dotted" ? [1, 1] : null;
19358
+ if (!horizontal && Math.abs(x2 - x1) >= 0.01) {
19359
+ const x = Math.min(x1, x2);
19360
+ const y = Math.min(y1, y2);
19361
+ const stroke = document.createElement("div");
19362
+ const strokeHeight = border.style === "double" ? w * 3 : w;
19363
+ stroke.style.position = "absolute";
19364
+ stroke.style.left = `${x1 - x}px`;
19365
+ stroke.style.top = `${y1 - y - strokeHeight / 2}px`;
19366
+ stroke.style.width = `${Math.hypot(x2 - x1, y2 - y1)}px`;
19367
+ stroke.style.height = `${strokeHeight}px`;
19368
+ stroke.style.transform = `rotate(${Math.atan2(y2 - y1, x2 - x1)}rad)`;
19369
+ stroke.style.transformOrigin = "0 50%";
19370
+ if (border.style === "double") {
19371
+ stroke.style.background = `linear-gradient(180deg, ${border.color} 0 ${w}px, transparent ${w}px ${w * 2}px, ${border.color} ${w * 2}px ${w * 3}px)`;
19372
+ } else if (dashPattern) {
19373
+ const on = Math.max(dashPattern[0] * border.width, 2);
19374
+ const period = on + Math.max(dashPattern[1] * border.width, 1);
19375
+ stroke.style.background = `repeating-linear-gradient(90deg, ${border.color} 0 ${on}px, transparent ${on}px ${period}px)`;
19376
+ } else if (border.style === "triple") {
19377
+ stroke.style.height = "0";
19378
+ stroke.style.borderTop = `${w}px double ${border.color}`;
19379
+ } else {
19380
+ stroke.style.background = border.color;
19381
+ }
19382
+ el16.style.left = `${x}px`;
19383
+ el16.style.top = `${y}px`;
19384
+ el16.style.width = `${Math.abs(x2 - x1)}px`;
19385
+ el16.style.height = `${Math.abs(y2 - y1)}px`;
19386
+ el16.appendChild(stroke);
19387
+ return el16;
19388
+ }
18715
19389
  if (horizontal) {
18716
19390
  el16.style.left = `${Math.min(x1, x2)}px`;
18717
- el16.style.top = `${place(y1 - w / 2)}px`;
19391
+ el16.style.top = `${place(y1 - w / 2 - (ultraThin ? 0.4 : 0))}px`;
18718
19392
  el16.style.width = `${Math.abs(x2 - x1)}px`;
18719
19393
  if (border.style === "double") {
18720
19394
  el16.style.height = `${w * 3}px`;
@@ -18722,11 +19396,20 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
18722
19396
  } else if (dashPattern) {
18723
19397
  const on = Math.max(dashPattern[0] * border.width, 2);
18724
19398
  const period = on + Math.max(dashPattern[1] * border.width, 1);
18725
- el16.style.height = `${w}px`;
19399
+ el16.style.height = `${w < 1 && rotate === void 0 ? 1 : w}px`;
18726
19400
  el16.style.background = `repeating-linear-gradient(90deg, ${border.color} 0 ${on}px, transparent ${on}px ${period}px)`;
19401
+ if (w < 1 && rotate === void 0) {
19402
+ el16.style.transform = `scaleY(${w})`;
19403
+ el16.style.transformOrigin = "0 0";
19404
+ }
18727
19405
  } else if (border.style === "triple") {
18728
19406
  el16.style.height = "0";
18729
19407
  el16.style.borderTop = `${w}px double ${border.color}`;
19408
+ } else if (deviceHairline) {
19409
+ el16.style.height = "1px";
19410
+ el16.style.background = border.color;
19411
+ el16.style.transform = "scaleY(.5)";
19412
+ el16.style.transformOrigin = "0 0";
18730
19413
  } else {
18731
19414
  el16.style.height = `${w}px`;
18732
19415
  el16.style.background = border.color;
@@ -18741,11 +19424,20 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
18741
19424
  } else if (dashPattern) {
18742
19425
  const on = Math.max(dashPattern[0] * border.width, 2);
18743
19426
  const period = on + Math.max(dashPattern[1] * border.width, 1);
18744
- el16.style.width = `${w}px`;
19427
+ el16.style.width = `${w < 1 && rotate === void 0 ? 1 : w}px`;
18745
19428
  el16.style.background = `repeating-linear-gradient(180deg, ${border.color} 0 ${on}px, transparent ${on}px ${period}px)`;
19429
+ if (w < 1 && rotate === void 0) {
19430
+ el16.style.transform = `scaleX(${w})`;
19431
+ el16.style.transformOrigin = "0 0";
19432
+ }
18746
19433
  } else if (border.style === "triple") {
18747
19434
  el16.style.width = "0";
18748
19435
  el16.style.borderLeft = `${w}px double ${border.color}`;
19436
+ } else if (deviceHairline) {
19437
+ el16.style.width = "1px";
19438
+ el16.style.background = border.color;
19439
+ el16.style.transform = "scaleX(.5)";
19440
+ el16.style.transformOrigin = "0 0";
18749
19441
  } else {
18750
19442
  el16.style.width = `${w}px`;
18751
19443
  el16.style.background = border.color;
@@ -21585,6 +22277,253 @@ function requestTextInputDialog(anchor, options) {
21585
22277
  });
21586
22278
  }
21587
22279
 
22280
+ // ../core/src/edit/objects.ts
22281
+ var EMU_PER_PX6 = 9525;
22282
+ var NS_WP5 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
22283
+ var NS_A4 = "http://schemas.openxmlformats.org/drawingml/2006/main";
22284
+ var NS_PIC2 = "http://schemas.openxmlformats.org/drawingml/2006/picture";
22285
+ var NS_R3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
22286
+ var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
22287
+ var NS_AM3D = "http://schemas.microsoft.com/office/drawing/2017/model3d";
22288
+ var NS_WP15 = "http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing";
22289
+ function el8(name, attrs = {}, children2 = [], text = "") {
22290
+ return { name, attrs, children: children2, text };
22291
+ }
22292
+ function prefixOf9(node) {
22293
+ return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
22294
+ }
22295
+ function insertAfterCaretRun(doc, caretT, content) {
22296
+ const caretRun = doc.findParentOf(caretT);
22297
+ const parent = caretRun && doc.findParentOf(caretRun);
22298
+ if (!caretRun || !parent || localName(caretRun.name) !== "r") return false;
22299
+ const w = prefixOf9(caretRun);
22300
+ parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el8(`${w}r`, {}, [content]));
22301
+ doc.refresh();
22302
+ return true;
22303
+ }
22304
+ function pictureGraphic(relId, id, cx, cy, webVideo) {
22305
+ const blipChildren = webVideo ? [
22306
+ el8("a:extLst", {}, [
22307
+ el8("a:ext", { uri: "{9E29B28B-C9C2-4B96-BA92-6C9A3D8F4A6A}" }, [
22308
+ el8("wp15:webVideoPr", {
22309
+ "xmlns:wp15": NS_WP15,
22310
+ embeddedHtml: webVideo,
22311
+ w: "640",
22312
+ h: "360"
22313
+ })
22314
+ ])
22315
+ ])
22316
+ ] : [];
22317
+ return el8("a:graphic", { "xmlns:a": NS_A4 }, [
22318
+ el8("a:graphicData", { uri: NS_PIC2 }, [
22319
+ el8("pic:pic", { "xmlns:pic": NS_PIC2 }, [
22320
+ el8("pic:nvPicPr", {}, [
22321
+ el8("pic:cNvPr", { id, name: `Picture ${id}` }),
22322
+ el8("pic:cNvPicPr", {}, [el8("a:picLocks", { noChangeAspect: "1" })])
22323
+ ]),
22324
+ el8("pic:blipFill", {}, [
22325
+ el8("a:blip", { "xmlns:r": NS_R3, "r:embed": relId }, blipChildren),
22326
+ el8("a:stretch", {}, [el8("a:fillRect")])
22327
+ ]),
22328
+ el8("pic:spPr", {}, [
22329
+ el8("a:xfrm", {}, [el8("a:off", { x: "0", y: "0" }), el8("a:ext", { cx, cy })]),
22330
+ el8("a:prstGeom", { prst: "rect" }, [el8("a:avLst")])
22331
+ ])
22332
+ ])
22333
+ ])
22334
+ ]);
22335
+ }
22336
+ function inlineDrawing(id, name, descr, cx, cy, graphic) {
22337
+ return el8("w:drawing", {}, [
22338
+ el8("wp:inline", { "xmlns:wp": NS_WP5, distT: "0", distB: "0", distL: "0", distR: "0" }, [
22339
+ el8("wp:extent", { cx, cy }),
22340
+ el8("wp:effectExtent", { l: "0", t: "0", r: "0", b: "0" }),
22341
+ el8("wp:docPr", { id, name, descr }),
22342
+ el8("wp:cNvGraphicFramePr", {}, [el8("a:graphicFrameLocks", { "xmlns:a": NS_A4, noChangeAspect: "1" })]),
22343
+ graphic
22344
+ ])
22345
+ ]);
22346
+ }
22347
+ function insertModel3DAt(doc, caretT, input) {
22348
+ const posterRelId = doc.addImageResource(input.poster, input.posterExt ?? "png");
22349
+ const model = doc.addModel3DResource(input.data);
22350
+ const id = String(doc.nextDrawingId());
22351
+ const width = 320;
22352
+ const height = 220;
22353
+ const cx = String(width * EMU_PER_PX6);
22354
+ const cy = String(height * EMU_PER_PX6);
22355
+ const modelGraphic = el8("a:graphic", { "xmlns:a": NS_A4 }, [
22356
+ el8("a:graphicData", { uri: NS_AM3D }, [
22357
+ el8("am3d:model3d", { "xmlns:am3d": NS_AM3D, "xmlns:r": NS_R3, "r:embed": model.relId }, [
22358
+ el8("am3d:spPr", {}, [
22359
+ el8("a:xfrm", {}, [el8("a:off", { x: "0", y: "0" }), el8("a:ext", { cx, cy })]),
22360
+ el8("a:prstGeom", { prst: "rect" }, [el8("a:avLst")])
22361
+ ]),
22362
+ el8("am3d:camera", {}, [
22363
+ el8("am3d:pos", { x: "0", y: "0", z: "77741944" }),
22364
+ el8("am3d:up", { dx: "0", dy: "36000000", dz: "0" }),
22365
+ el8("am3d:lookAt", { x: "0", y: "0", z: "0" }),
22366
+ el8("am3d:perspective", { fov: "2700000" })
22367
+ ]),
22368
+ el8("am3d:trans", {}, [
22369
+ el8("am3d:meterPerModelUnit", { n: "1", d: "1" }),
22370
+ el8("am3d:preTrans", { dx: "0", dy: "0", dz: "0" }),
22371
+ el8("am3d:scale", {}, [
22372
+ el8("am3d:sx", { n: "1000000", d: "1000000" }),
22373
+ el8("am3d:sy", { n: "1000000", d: "1000000" }),
22374
+ el8("am3d:sz", { n: "1000000", d: "1000000" })
22375
+ ]),
22376
+ el8("am3d:rot", { ax: "0", ay: "0", az: "0" }),
22377
+ el8("am3d:postTrans", { dx: "0", dy: "0", dz: "0" })
22378
+ ]),
22379
+ el8("am3d:raster", { rName: "Office3DRenderer", rVer: "16.0" }, [
22380
+ el8("am3d:blip", { "r:embed": posterRelId })
22381
+ ]),
22382
+ el8("am3d:objViewport", { viewportSz: cx }),
22383
+ el8("am3d:ambientLight", {}, [
22384
+ el8("am3d:clr", {}, [el8("a:scrgbClr", { r: "50000", g: "50000", b: "50000" })]),
22385
+ el8("am3d:illuminance", { n: "500000", d: "1000000" })
22386
+ ]),
22387
+ el8("am3d:ptLight", { rad: "0" }, [
22388
+ el8("am3d:clr", {}, [el8("a:scrgbClr", { r: "100000", g: "100000", b: "100000" })]),
22389
+ el8("am3d:intensity", { n: "1000000", d: "1000000" }),
22390
+ el8("am3d:pos", { x: "30000000", y: "50000000", z: "50000000" })
22391
+ ])
22392
+ ])
22393
+ ])
22394
+ ]);
22395
+ const alt = input.alt ?? "3D model";
22396
+ const choice = inlineDrawing(id, `3D Model ${id}`, alt, cx, cy, modelGraphic);
22397
+ const fallback = inlineDrawing(id, `3D Model ${id}`, alt, cx, cy, pictureGraphic(posterRelId, id, cx, cy));
22398
+ const alternate = el8("mc:AlternateContent", { "xmlns:mc": NS_MC }, [
22399
+ el8("mc:Choice", { Requires: "am3d", "xmlns:am3d": NS_AM3D }, [choice]),
22400
+ el8("mc:Fallback", {}, [fallback])
22401
+ ]);
22402
+ return insertAfterCaretRun(doc, caretT, alternate);
22403
+ }
22404
+ function setModel3DRotation(doc, drawingEl, rotation) {
22405
+ let model;
22406
+ const visit = (node) => {
22407
+ if (model) return;
22408
+ if (localName(node.name) === "model3d") model = node;
22409
+ else for (const child4 of node.children) visit(child4);
22410
+ };
22411
+ visit(drawingEl);
22412
+ if (!model) return false;
22413
+ const trans = model.children.find((child4) => localName(child4.name) === "trans");
22414
+ if (!trans) return false;
22415
+ let rot = trans.children.find((child4) => localName(child4.name) === "rot");
22416
+ if (!rot) {
22417
+ rot = el8("am3d:rot");
22418
+ const post = trans.children.findIndex((child4) => localName(child4.name) === "postTrans");
22419
+ trans.children.splice(post === -1 ? trans.children.length : post, 0, rot);
22420
+ }
22421
+ const angle = (degrees) => {
22422
+ const normalized = (degrees % 360 + 360) % 360;
22423
+ return String(Math.round(normalized * 6e4));
22424
+ };
22425
+ rot.attrs.ax = angle(rotation.x);
22426
+ rot.attrs.ay = angle(rotation.y);
22427
+ rot.attrs.az = angle(rotation.z);
22428
+ doc.refresh();
22429
+ return true;
22430
+ }
22431
+ function normalizeWebVideoUrl(value) {
22432
+ try {
22433
+ const url = new URL(value.trim());
22434
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
22435
+ if (url.hostname === "youtu.be") return `https://www.youtube.com/embed/${url.pathname.slice(1)}`;
22436
+ if (url.hostname.endsWith("youtube.com") && url.pathname === "/watch") {
22437
+ const id = url.searchParams.get("v");
22438
+ if (id) return `https://www.youtube.com/embed/${id}`;
22439
+ }
22440
+ if (url.hostname.endsWith("vimeo.com") && /^\/\d+\/?$/.test(url.pathname)) {
22441
+ return `https://player.vimeo.com/video/${url.pathname.replace(/\//g, "")}`;
22442
+ }
22443
+ return url.href;
22444
+ } catch {
22445
+ return null;
22446
+ }
22447
+ }
22448
+ function insertWebVideoAt(doc, caretT, input) {
22449
+ const url = normalizeWebVideoUrl(input.url);
22450
+ if (!url) return false;
22451
+ const posterRelId = doc.addImageResource(input.poster, input.posterExt ?? "png");
22452
+ const width = input.width ?? 320;
22453
+ const height = input.height ?? 180;
22454
+ const cx = String(Math.round(width * EMU_PER_PX6));
22455
+ const cy = String(Math.round(height * EMU_PER_PX6));
22456
+ const id = String(doc.nextDrawingId());
22457
+ const embeddedHtml = `<iframe width="640" height="360" src="${url}" frameborder="0" allowfullscreen=""></iframe>`;
22458
+ return insertAfterCaretRun(
22459
+ doc,
22460
+ caretT,
22461
+ inlineDrawing(id, `Online Video ${id}`, url, cx, cy, pictureGraphic(posterRelId, id, cx, cy, embeddedHtml))
22462
+ );
22463
+ }
22464
+ function insertEmbeddedObjectAt(doc, caretT, input) {
22465
+ const posterRelId = doc.addImageResource(input.poster, input.posterExt ?? "png");
22466
+ const wordDocument = input.filename.toLowerCase().endsWith(".docx");
22467
+ const object = wordDocument ? doc.addEmbeddedWordDocumentResource(input.data) : doc.addEmbeddedObjectResource(buildOlePackage(input.data, input.filename));
22468
+ const id = String(doc.nextDrawingId());
22469
+ const vmlId = 1024 + Number(id);
22470
+ const shapeTypeId = `_x0000_t${vmlId}`;
22471
+ const shapeId = `_x0000_i${vmlId}`;
22472
+ const width = 320;
22473
+ const height = 180;
22474
+ const objectEl = el8("w:object", {
22475
+ "xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
22476
+ "xmlns:v": "urn:schemas-microsoft-com:vml",
22477
+ "xmlns:o": "urn:schemas-microsoft-com:office:office",
22478
+ "xmlns:r": NS_R3,
22479
+ "w:dxaOrig": String(width * 15),
22480
+ "w:dyaOrig": String(height * 15)
22481
+ }, [
22482
+ el8("v:shapetype", {
22483
+ id: shapeTypeId,
22484
+ coordsize: "21600,21600",
22485
+ "o:spt": "75",
22486
+ "o:preferrelative": "t",
22487
+ path: "m@4@5l@4@11@9@11@9@5xe",
22488
+ filled: "f",
22489
+ stroked: "f"
22490
+ }, [
22491
+ el8("v:stroke", { joinstyle: "miter" }),
22492
+ el8("v:formulas", {}, [
22493
+ el8("v:f", { eqn: "if lineDrawn pixelLineWidth 0" }),
22494
+ el8("v:f", { eqn: "sum @0 1 0" }),
22495
+ el8("v:f", { eqn: "sum 0 0 @1" }),
22496
+ el8("v:f", { eqn: "prod @2 1 2" }),
22497
+ el8("v:f", { eqn: "prod @3 21600 pixelWidth" }),
22498
+ el8("v:f", { eqn: "prod @3 21600 pixelHeight" }),
22499
+ el8("v:f", { eqn: "sum @0 0 1" }),
22500
+ el8("v:f", { eqn: "prod @6 1 2" }),
22501
+ el8("v:f", { eqn: "prod @7 21600 pixelWidth" }),
22502
+ el8("v:f", { eqn: "sum @8 21600 0" }),
22503
+ el8("v:f", { eqn: "prod @7 21600 pixelHeight" }),
22504
+ el8("v:f", { eqn: "sum @10 21600 0" })
22505
+ ]),
22506
+ el8("v:path", { "o:extrusionok": "f", gradientshapeok: "t", "o:connecttype": "rect" }),
22507
+ el8("o:lock", { "v:ext": "edit", aspectratio: "t" })
22508
+ ]),
22509
+ el8("v:shape", {
22510
+ id: shapeId,
22511
+ type: `#${shapeTypeId}`,
22512
+ style: `width:${width * 0.75}pt;height:${height * 0.75}pt`,
22513
+ "o:ole": ""
22514
+ }, [el8("v:imagedata", { "r:id": posterRelId, "o:title": input.filename })]),
22515
+ el8("o:OLEObject", {
22516
+ Type: "Embed",
22517
+ ProgID: wordDocument ? "Word.Document.12" : "Package",
22518
+ ShapeID: shapeId,
22519
+ DrawAspect: "Content",
22520
+ ObjectID: `_${1e9 + Number(id)}`,
22521
+ "r:id": object.relId
22522
+ }, wordDocument ? [el8("o:FieldCodes", {}, [], "\\s")] : [])
22523
+ ]);
22524
+ return insertAfterCaretRun(doc, caretT, objectEl);
22525
+ }
22526
+
21588
22527
  // ../core/src/edit/grapheme.ts
21589
22528
  var segmenter = null;
21590
22529
  var segmenterTried = false;
@@ -21626,8 +22565,8 @@ function graphemeStep(text, offset, delta) {
21626
22565
  }
21627
22566
 
21628
22567
  // ../core/src/edit/clipboard.ts
21629
- var el8 = (name, attrs = {}, children2 = [], text = "") => ({ name, attrs, children: children2, text });
21630
- var prefixOf9 = (node) => node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
22568
+ var el9 = (name, attrs = {}, children2 = [], text = "") => ({ name, attrs, children: children2, text });
22569
+ var prefixOf10 = (node) => node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
21631
22570
  function colorValue(value) {
21632
22571
  if (!value) return void 0;
21633
22572
  const hex = value.match(/^#([0-9a-f]{6})$/i);
@@ -21638,7 +22577,7 @@ function colorValue(value) {
21638
22577
  }
21639
22578
  function runPropsXml(w, props) {
21640
22579
  const children2 = [];
21641
- const add = (name, attrs = {}) => children2.push(el8(`${w}${name}`, attrs));
22580
+ const add = (name, attrs = {}) => children2.push(el9(`${w}${name}`, attrs));
21642
22581
  if (props.bold) add("b");
21643
22582
  if (props.italic) add("i");
21644
22583
  if (props.underline && props.underline !== "none") add("u", { [`${w}val`]: props.underline });
@@ -21659,10 +22598,10 @@ function runPropsXml(w, props) {
21659
22598
  if (props.verticalAlign && props.verticalAlign !== "baseline") {
21660
22599
  add("vertAlign", { [`${w}val`]: props.verticalAlign });
21661
22600
  }
21662
- return children2.length ? el8(`${w}rPr`, {}, children2) : null;
22601
+ return children2.length ? el9(`${w}rPr`, {}, children2) : null;
21663
22602
  }
21664
22603
  function paragraphFragment(paragraph, segments) {
21665
- const w = prefixOf9(paragraph);
22604
+ const w = prefixOf10(paragraph);
21666
22605
  const children2 = [];
21667
22606
  const pPr = child(paragraph, "pPr");
21668
22607
  if (pPr) {
@@ -21683,9 +22622,9 @@ function paragraphFragment(paragraph, segments) {
21683
22622
  const text = node.text.slice(segment.start, segment.end);
21684
22623
  if (!text) continue;
21685
22624
  const rPr = runPropsXml(w, segment.props);
21686
- children2.push(el8(`${w}r`, {}, [
22625
+ children2.push(el9(`${w}r`, {}, [
21687
22626
  ...rPr ? [rPr] : [],
21688
- el8(`${w}t`, { "xml:space": "preserve" }, [], text)
22627
+ el9(`${w}t`, { "xml:space": "preserve" }, [], text)
21689
22628
  ]));
21690
22629
  }
21691
22630
  return;
@@ -21693,7 +22632,7 @@ function paragraphFragment(paragraph, segments) {
21693
22632
  for (const childNode of node.children) visit(childNode);
21694
22633
  };
21695
22634
  visit(paragraph);
21696
- return el8(paragraph.name, { ...paragraph.attrs }, children2);
22635
+ return el9(paragraph.name, { ...paragraph.attrs }, children2);
21697
22636
  }
21698
22637
  function trimTable(source, copy, selected) {
21699
22638
  if (localName(source.name) === "t") {
@@ -21762,65 +22701,65 @@ function htmlStyle(node, inherited) {
21762
22701
  }
21763
22702
  function htmlRPr(w, style) {
21764
22703
  const children2 = [];
21765
- if (style.bold) children2.push(el8(`${w}b`));
21766
- if (style.italic) children2.push(el8(`${w}i`));
21767
- if (style.underline) children2.push(el8(`${w}u`, { [`${w}val`]: "single" }));
21768
- if (style.strike) children2.push(el8(`${w}strike`));
21769
- if (style.color) children2.push(el8(`${w}color`, { [`${w}val`]: style.color }));
21770
- if (style.font) children2.push(el8(`${w}rFonts`, { [`${w}ascii`]: style.font, [`${w}hAnsi`]: style.font }));
21771
- if (style.sizeHalfPoints) children2.push(el8(`${w}sz`, { [`${w}val`]: String(style.sizeHalfPoints) }));
21772
- return children2.length ? el8(`${w}rPr`, {}, children2) : null;
22704
+ if (style.bold) children2.push(el9(`${w}b`));
22705
+ if (style.italic) children2.push(el9(`${w}i`));
22706
+ if (style.underline) children2.push(el9(`${w}u`, { [`${w}val`]: "single" }));
22707
+ if (style.strike) children2.push(el9(`${w}strike`));
22708
+ if (style.color) children2.push(el9(`${w}color`, { [`${w}val`]: style.color }));
22709
+ if (style.font) children2.push(el9(`${w}rFonts`, { [`${w}ascii`]: style.font, [`${w}hAnsi`]: style.font }));
22710
+ if (style.sizeHalfPoints) children2.push(el9(`${w}sz`, { [`${w}val`]: String(style.sizeHalfPoints) }));
22711
+ return children2.length ? el9(`${w}rPr`, {}, children2) : null;
21773
22712
  }
21774
22713
  function inlineRuns(node, w, inherited = {}) {
21775
22714
  if (node.nodeType === Node.TEXT_NODE) {
21776
22715
  const text = node.textContent?.replace(/\s+/g, " ") ?? "";
21777
22716
  if (!text) return [];
21778
22717
  const rPr = htmlRPr(w, inherited);
21779
- return [el8(`${w}r`, {}, [...rPr ? [rPr] : [], el8(`${w}t`, { "xml:space": "preserve" }, [], text)])];
22718
+ return [el9(`${w}r`, {}, [...rPr ? [rPr] : [], el9(`${w}t`, { "xml:space": "preserve" }, [], text)])];
21780
22719
  }
21781
22720
  if (node.nodeType !== Node.ELEMENT_NODE) return [];
21782
22721
  const element = node;
21783
- if (element.tagName.toLowerCase() === "br") return [el8(`${w}r`, {}, [el8(`${w}br`)])];
22722
+ if (element.tagName.toLowerCase() === "br") return [el9(`${w}r`, {}, [el9(`${w}br`)])];
21784
22723
  const style = htmlStyle(element, inherited);
21785
22724
  return Array.from(element.childNodes).flatMap((childNode) => inlineRuns(childNode, w, style));
21786
22725
  }
21787
22726
  function htmlParagraph(node, w) {
21788
22727
  const tag = node.tagName.toLowerCase();
21789
22728
  const pPrChildren = [];
21790
- if (/^h[1-6]$/.test(tag)) pPrChildren.push(el8(`${w}pStyle`, { [`${w}val`]: `Heading${tag[1]}` }));
22729
+ if (/^h[1-6]$/.test(tag)) pPrChildren.push(el9(`${w}pStyle`, { [`${w}val`]: `Heading${tag[1]}` }));
21791
22730
  const align = node.style.textAlign;
21792
22731
  if (["left", "center", "right", "justify"].includes(align)) {
21793
- pPrChildren.push(el8(`${w}jc`, { [`${w}val`]: align === "justify" ? "both" : align }));
22732
+ pPrChildren.push(el9(`${w}jc`, { [`${w}val`]: align === "justify" ? "both" : align }));
21794
22733
  }
21795
22734
  const runs = inlineRuns(node, w);
21796
- return el8(`${w}p`, {}, [
21797
- ...pPrChildren.length ? [el8(`${w}pPr`, {}, pPrChildren)] : [],
21798
- ...runs.length ? runs : [el8(`${w}r`, {}, [el8(`${w}t`, { "xml:space": "preserve" })])]
22735
+ return el9(`${w}p`, {}, [
22736
+ ...pPrChildren.length ? [el9(`${w}pPr`, {}, pPrChildren)] : [],
22737
+ ...runs.length ? runs : [el9(`${w}r`, {}, [el9(`${w}t`, { "xml:space": "preserve" })])]
21799
22738
  ]);
21800
22739
  }
21801
22740
  function htmlTable(node, w, contentTwips) {
21802
22741
  const rowNodes = Array.from(node.querySelectorAll(":scope > thead > tr, :scope > tbody > tr, :scope > tfoot > tr, :scope > tr"));
21803
22742
  const cols = Math.max(1, ...rowNodes.map((row) => Array.from(row.children).reduce((n, cellNode) => n + Number(cellNode.getAttribute("colspan") || 1), 0)));
21804
22743
  const colWidth = Math.floor(contentTwips / cols);
21805
- const border = (name) => el8(`${w}${name}`, { [`${w}val`]: "single", [`${w}sz`]: "4", [`${w}color`]: "auto" });
21806
- const rows = rowNodes.map((row) => el8(`${w}tr`, {}, Array.from(row.children).map((cellNode) => {
22744
+ const border = (name) => el9(`${w}${name}`, { [`${w}val`]: "single", [`${w}sz`]: "4", [`${w}color`]: "auto" });
22745
+ const rows = rowNodes.map((row) => el9(`${w}tr`, {}, Array.from(row.children).map((cellNode) => {
21807
22746
  const span = Math.max(1, Number(cellNode.getAttribute("colspan") || 1));
21808
- const tcPr = [el8(`${w}tcW`, { [`${w}w`]: String(colWidth * span), [`${w}type`]: "dxa" })];
21809
- if (span > 1) tcPr.push(el8(`${w}gridSpan`, { [`${w}val`]: String(span) }));
22747
+ const tcPr = [el9(`${w}tcW`, { [`${w}w`]: String(colWidth * span), [`${w}type`]: "dxa" })];
22748
+ if (span > 1) tcPr.push(el9(`${w}gridSpan`, { [`${w}val`]: String(span) }));
21810
22749
  const fill = colorValue(cellNode.style.backgroundColor);
21811
- if (fill) tcPr.push(el8(`${w}shd`, { [`${w}val`]: "clear", [`${w}fill`]: fill }));
22750
+ if (fill) tcPr.push(el9(`${w}shd`, { [`${w}val`]: "clear", [`${w}fill`]: fill }));
21812
22751
  const paragraphs = Array.from(cellNode.children).filter((childNode) => /^(p|div|h[1-6]|li)$/i.test(childNode.tagName)).map((childNode) => htmlParagraph(childNode, w));
21813
- return el8(`${w}tc`, {}, [
21814
- el8(`${w}tcPr`, {}, tcPr),
22752
+ return el9(`${w}tc`, {}, [
22753
+ el9(`${w}tcPr`, {}, tcPr),
21815
22754
  ...paragraphs.length ? paragraphs : [htmlParagraph(cellNode, w)]
21816
22755
  ]);
21817
22756
  })));
21818
- return el8(`${w}tbl`, {}, [
21819
- el8(`${w}tblPr`, {}, [
21820
- el8(`${w}tblW`, { [`${w}w`]: "0", [`${w}type`]: "auto" }),
21821
- el8(`${w}tblBorders`, {}, ["top", "left", "bottom", "right", "insideH", "insideV"].map(border))
22757
+ return el9(`${w}tbl`, {}, [
22758
+ el9(`${w}tblPr`, {}, [
22759
+ el9(`${w}tblW`, { [`${w}w`]: "0", [`${w}type`]: "auto" }),
22760
+ el9(`${w}tblBorders`, {}, ["top", "left", "bottom", "right", "insideH", "insideV"].map(border))
21822
22761
  ]),
21823
- el8(`${w}tblGrid`, {}, Array.from({ length: cols }, () => el8(`${w}gridCol`, { [`${w}w`]: String(colWidth) }))),
22762
+ el9(`${w}tblGrid`, {}, Array.from({ length: cols }, () => el9(`${w}gridCol`, { [`${w}w`]: String(colWidth) }))),
21824
22763
  ...rows
21825
22764
  ]);
21826
22765
  }
@@ -21878,10 +22817,10 @@ function clipboardBlocksHtml(blocks) {
21878
22817
  }
21879
22818
 
21880
22819
  // ../core/src/edit/suggest.ts
21881
- function prefixOf10(e) {
22820
+ function prefixOf11(e) {
21882
22821
  return e.name.includes(":") ? e.name.slice(0, e.name.indexOf(":") + 1) : "";
21883
22822
  }
21884
- function el9(name, attrs = {}, children2 = [], text = "") {
22823
+ function el10(name, attrs = {}, children2 = [], text = "") {
21885
22824
  return { name, attrs, children: children2, text };
21886
22825
  }
21887
22826
  function attrByLocal(e, local) {
@@ -21925,14 +22864,14 @@ function insertSuggestedText(doc, t, offset, text, meta) {
21925
22864
  t.text = t.text.slice(0, offset) + text + t.text.slice(offset);
21926
22865
  return { t, offset: offset + text.length };
21927
22866
  }
21928
- const w = prefixOf10(rEl);
22867
+ const w = prefixOf11(rEl);
21929
22868
  const rPr = rEl.children.find((c) => localName(c.name) === "rPr");
21930
22869
  if (localName(parent.name) === "del") {
21931
22870
  const grand = doc.findParentOf(parent);
21932
22871
  if (!grand) return null;
21933
22872
  const delIdx = grand.children.indexOf(parent);
21934
22873
  const newT2 = textLike(t, t.name, text);
21935
- const ins2 = el9(`${w}ins`, revAttrs(w, meta), [runLike(rEl, rPr, [newT2])]);
22874
+ const ins2 = el10(`${w}ins`, revAttrs(w, meta), [runLike(rEl, rPr, [newT2])]);
21936
22875
  const at = offset <= 0 ? delIdx : delIdx + 1;
21937
22876
  grand.children.splice(at, 0, ins2);
21938
22877
  return { t: newT2, offset: text.length };
@@ -21947,7 +22886,7 @@ function insertSuggestedText(doc, t, offset, text, meta) {
21947
22886
  if (offset > 0) beforeChildren.push(textLike(t, t.name, t.text.slice(0, offset)));
21948
22887
  if (beforeChildren.length > 0) replacement.push(runLike(rEl, rPr, beforeChildren));
21949
22888
  const newT = textLike(t, t.name, text);
21950
- const ins = el9(`${w}ins`, revAttrs(w, meta), [runLike(rEl, rPr, [newT])]);
22889
+ const ins = el10(`${w}ins`, revAttrs(w, meta), [runLike(rEl, rPr, [newT])]);
21951
22890
  replacement.push(ins);
21952
22891
  const afterChildren = [];
21953
22892
  if (offset < t.text.length) afterChildren.push(textLike(t, t.name, t.text.slice(offset)));
@@ -21987,7 +22926,7 @@ function deleteOneRange(doc, t, start, end, meta) {
21987
22926
  t.text = t.text.slice(0, start) + t.text.slice(end);
21988
22927
  return { t, offset: start };
21989
22928
  }
21990
- const w = prefixOf10(rEl);
22929
+ const w = prefixOf11(rEl);
21991
22930
  const rPr = rEl.children.find((c) => localName(c.name) === "rPr");
21992
22931
  const tIdx = rEl.children.indexOf(t);
21993
22932
  const idx = parent.children.indexOf(rEl);
@@ -22004,7 +22943,7 @@ function deleteOneRange(doc, t, start, end, meta) {
22004
22943
  }
22005
22944
  if (beforeChildren.length > 0) replacement.push(runLike(rEl, rPr, beforeChildren));
22006
22945
  const deletedT = textLike(t, delTextName, t.text.slice(start, end));
22007
- const del = el9(`${w}del`, revAttrs(w, meta), [runLike(rEl, rPr, [deletedT])]);
22946
+ const del = el10(`${w}del`, revAttrs(w, meta), [runLike(rEl, rPr, [deletedT])]);
22008
22947
  replacement.push(del);
22009
22948
  const afterChildren = [];
22010
22949
  if (end < t.text.length) afterChildren.push(textLike(t, t.name, t.text.slice(end)));
@@ -22033,24 +22972,24 @@ function coalesceDeletions(parent, del, author) {
22033
22972
  }
22034
22973
  }
22035
22974
  function ensurePPrRPr(pEl) {
22036
- const w = prefixOf10(pEl);
22975
+ const w = prefixOf11(pEl);
22037
22976
  let pPr = pEl.children.find((c) => localName(c.name) === "pPr");
22038
22977
  if (!pPr) {
22039
- pPr = el9(`${w}pPr`);
22978
+ pPr = el10(`${w}pPr`);
22040
22979
  pEl.children.unshift(pPr);
22041
22980
  }
22042
22981
  let rPr = pPr.children.find((c) => localName(c.name) === "rPr");
22043
22982
  if (!rPr) {
22044
- rPr = el9(`${w}rPr`);
22983
+ rPr = el10(`${w}rPr`);
22045
22984
  pPr.children.push(rPr);
22046
22985
  }
22047
22986
  return rPr;
22048
22987
  }
22049
22988
  function markParagraphGlyph(pEl, kind, meta) {
22050
- const w = prefixOf10(pEl);
22989
+ const w = prefixOf11(pEl);
22051
22990
  const rPr = ensurePPrRPr(pEl);
22052
22991
  const existingIdx = rPr.children.findIndex((c) => localName(c.name) === kind);
22053
- const mark = el9(`${w}${kind}`, revAttrs(w, meta));
22992
+ const mark = el10(`${w}${kind}`, revAttrs(w, meta));
22054
22993
  if (existingIdx !== -1) rPr.children[existingIdx] = mark;
22055
22994
  else rPr.children.unshift(mark);
22056
22995
  return mark;
@@ -22534,6 +23473,30 @@ var _DocxEditor = class _DocxEditor {
22534
23473
  this.imageOverlay = null;
22535
23474
  this.imageToolbar = null;
22536
23475
  this.wordArtTextEditor = null;
23476
+ /** First press selects a model; subsequent drags belong to its 3D viewport. */
23477
+ this.onModel3DPointerDown = (event) => {
23478
+ const binding = this.model3DBinding(event.target);
23479
+ const src = binding?.item.src;
23480
+ if (!binding || !src || this.selectedImage?.src === src) return;
23481
+ if (this.regionOf(src) === "hf" !== this.inHeaderFooter) return;
23482
+ event.preventDefault();
23483
+ event.stopPropagation();
23484
+ this.selectImage(binding.el, src, binding.item);
23485
+ };
23486
+ this.onModel3DRotate = (event) => {
23487
+ const binding = this.model3DBinding(event.target);
23488
+ const src = binding?.item.src;
23489
+ const detail = event.detail;
23490
+ if (!binding || !src || !detail || ![detail.x, detail.y, detail.z].every(Number.isFinite)) return;
23491
+ event.stopPropagation();
23492
+ const rect = binding.el.getBoundingClientRect();
23493
+ const near = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
23494
+ this.host.history?.checkpoint();
23495
+ if (setModel3DRotation(this.host.doc, src, detail)) {
23496
+ this.host.rerender(void 0, "local");
23497
+ this.reselectImage(src, near);
23498
+ }
23499
+ };
22537
23500
  // ---------- watermarks / WordArt: select + edit ----------
22538
23501
  this.selectedWordArt = null;
22539
23502
  this.wordArtOverlay = null;
@@ -22557,6 +23520,7 @@ var _DocxEditor = class _DocxEditor {
22557
23520
  if (this.wordArtOverlay?.contains(e.target)) return;
22558
23521
  if (this.wordArtTextEditor?.input.contains(e.target)) return;
22559
23522
  if (this.selectedInkGroup?.overlay.contains(e.target)) return;
23523
+ if (e.target?.closest?.("[data-dxw-model3d-viewer]")) return;
22560
23524
  this.deselectInkGroup();
22561
23525
  this.deselectImage();
22562
23526
  this.deselectWordArt();
@@ -23583,7 +24547,9 @@ var _DocxEditor = class _DocxEditor {
23583
24547
  c.tabIndex = 0;
23584
24548
  c.style.outline = "none";
23585
24549
  c.addEventListener("mousedown", this.onGripMouseDown, true);
24550
+ c.addEventListener("pointerdown", this.onModel3DPointerDown, true);
23586
24551
  c.addEventListener("mouseup", this.onMouseUp);
24552
+ c.addEventListener("dxw-model3d-rotate", this.onModel3DRotate);
23587
24553
  c.addEventListener("keydown", this.onKeyDown);
23588
24554
  c.appendChild(this.imeEl);
23589
24555
  this.imeEl.addEventListener("compositionstart", this.onCompositionStart);
@@ -23602,7 +24568,9 @@ var _DocxEditor = class _DocxEditor {
23602
24568
  if (this.host.history) this.host.history.applyTextChanges = null;
23603
24569
  const c = this.host.container;
23604
24570
  c.removeEventListener("mousedown", this.onGripMouseDown, true);
24571
+ c.removeEventListener("pointerdown", this.onModel3DPointerDown, true);
23605
24572
  c.removeEventListener("mouseup", this.onMouseUp);
24573
+ c.removeEventListener("dxw-model3d-rotate", this.onModel3DRotate);
23606
24574
  c.removeEventListener("keydown", this.onKeyDown);
23607
24575
  this.imeEl.removeEventListener("compositionstart", this.onCompositionStart);
23608
24576
  this.imeEl.removeEventListener("compositionupdate", this.onCompositionUpdate);
@@ -24349,6 +25317,10 @@ var _DocxEditor = class _DocxEditor {
24349
25317
  document.addEventListener("mouseup", onUp);
24350
25318
  return true;
24351
25319
  }
25320
+ model3DBinding(target) {
25321
+ const viewer = target?.closest?.("[data-dxw-model3d-viewer]");
25322
+ return viewer ? this.host.getHandle()?.images.find((binding) => binding.el.contains(viewer)) : void 0;
25323
+ }
24352
25324
  /** First click selects a text box as an object; the second click edits only
24353
25325
  * its story, even when the source shape lives in a header part. */
24354
25326
  startTextboxTextInteraction(e, target) {
@@ -24444,9 +25416,11 @@ var _DocxEditor = class _DocxEditor {
24444
25416
  ];
24445
25417
  for (const [mode, label] of modes) {
24446
25418
  const b = document.createElement("button");
25419
+ b.type = "button";
24447
25420
  b.textContent = label;
24448
25421
  const active = mode === "inline" && !isFloating || isFloating && this.currentWrap(src) === mode;
24449
- b.style.cssText = `border:none;border-radius:3px;padding:3px 7px;cursor:pointer;color:#3c4043;background:${active ? "#dfe7f5" : "transparent"};`;
25422
+ b.setAttribute("aria-pressed", String(active));
25423
+ b.style.cssText = `border:1px solid ${active ? "#8ab4f8" : "transparent"};border-radius:4px;padding:3px 7px;cursor:pointer;color:${active ? "#174ea6" : "#3c4043"};font-weight:${active ? "600" : "400"};background:${active ? "#d2e3fc" : "transparent"};`;
24450
25424
  b.addEventListener("mousedown", (me) => {
24451
25425
  me.preventDefault();
24452
25426
  me.stopPropagation();
@@ -24552,6 +25526,13 @@ var _DocxEditor = class _DocxEditor {
24552
25526
  });
24553
25527
  });
24554
25528
  }
25529
+ const drawingBinding = kind === "drawing" ? this.host.getHandle()?.drawings.find((binding) => binding.item.src === src) : void 0;
25530
+ if (drawingBinding?.item.textboxStory && !isDrawingWordArt(src)) {
25531
+ extra("Edit text", "Edit shape text", () => {
25532
+ const rect = drawingBinding.el.getBoundingClientRect();
25533
+ this.enterTextboxStory(src, rect.left + rect.width / 2, rect.top + rect.height / 2);
25534
+ });
25535
+ }
24555
25536
  if (kind === "drawing" && isDrawingWordArt(src)) {
24556
25537
  extra("Edit text", "Edit WordArt text", () => this.editDrawingWordArt(src));
24557
25538
  }
@@ -24575,6 +25556,15 @@ var _DocxEditor = class _DocxEditor {
24575
25556
  this.deselectImage();
24576
25557
  });
24577
25558
  }
25559
+ if (el16.dataset.dxwModel3d) {
25560
+ extra("Reset 3D", "Reset 3D rotation", () => {
25561
+ this.host.history?.checkpoint();
25562
+ if (setModel3DRotation(this.host.doc, src, { x: 0, y: 0, z: 0 })) {
25563
+ this.host.rerender(void 0, "local");
25564
+ this.reselectImage(src);
25565
+ }
25566
+ });
25567
+ }
24578
25568
  const surface = el16.parentElement;
24579
25569
  surface.appendChild(overlay);
24580
25570
  const zoom = this.host.zoom ?? 1;
@@ -24784,6 +25774,7 @@ var _DocxEditor = class _DocxEditor {
24784
25774
  /** Handle mousedown on images / their resize handle. Returns true if consumed. */
24785
25775
  startImageInteraction(e, target) {
24786
25776
  const zoom = this.host.zoom ?? 1;
25777
+ if (target.closest?.("[data-dxw-model3d-viewer]")) return true;
24787
25778
  if (target.dataset.dxwImgHandle && this.selectedImage) {
24788
25779
  e.preventDefault();
24789
25780
  e.stopPropagation();
@@ -26677,7 +27668,7 @@ function isRelatedHistoryPart(name) {
26677
27668
  }
26678
27669
 
26679
27670
  // ../core/src/edit/comments.ts
26680
- function el10(name, attrs = {}, children2 = [], text = "") {
27671
+ function el11(name, attrs = {}, children2 = [], text = "") {
26681
27672
  return { name, attrs, children: children2, text };
26682
27673
  }
26683
27674
  function addComment(doc, segments, text, author, initials) {
@@ -26701,15 +27692,15 @@ function addComment(doc, segments, text, author, initials) {
26701
27692
  }
26702
27693
  const newId = String(idNum + 1);
26703
27694
  const startIdx = firstP.children.indexOf(firstR);
26704
- firstP.children.splice(startIdx, 0, el10(`${w}commentRangeStart`, { [`${w}id`]: newId }));
27695
+ firstP.children.splice(startIdx, 0, el11(`${w}commentRangeStart`, { [`${w}id`]: newId }));
26705
27696
  const endIdx = lastP.children.indexOf(lastR);
26706
27697
  lastP.children.splice(
26707
27698
  endIdx + 1,
26708
27699
  0,
26709
- el10(`${w}commentRangeEnd`, { [`${w}id`]: newId }),
26710
- el10(`${w}r`, {}, [
26711
- el10(`${w}rPr`, {}, [el10(`${w}rStyle`, { [`${w}val`]: "CommentReference" })]),
26712
- el10(`${w}commentReference`, { [`${w}id`]: newId })
27700
+ el11(`${w}commentRangeEnd`, { [`${w}id`]: newId }),
27701
+ el11(`${w}r`, {}, [
27702
+ el11(`${w}rPr`, {}, [el11(`${w}rStyle`, { [`${w}val`]: "CommentReference" })]),
27703
+ el11(`${w}commentReference`, { [`${w}id`]: newId })
26713
27704
  ])
26714
27705
  );
26715
27706
  const usedParaIds = new Set(doc.comments.map((c) => c.paraId).filter(Boolean));
@@ -26718,7 +27709,7 @@ function addComment(doc, segments, text, author, initials) {
26718
27709
  paraId2 = Math.floor(Math.random() * 4294967280 + 1).toString(16).toUpperCase().padStart(8, "0");
26719
27710
  } while (usedParaIds.has(paraId2));
26720
27711
  commentsRoot.children.push(
26721
- el10(
27712
+ el11(
26722
27713
  `${w}comment`,
26723
27714
  {
26724
27715
  [`${w}id`]: newId,
@@ -26727,13 +27718,13 @@ function addComment(doc, segments, text, author, initials) {
26727
27718
  [`${w}date`]: (/* @__PURE__ */ new Date()).toISOString()
26728
27719
  },
26729
27720
  [
26730
- el10(
27721
+ el11(
26731
27722
  `${w}p`,
26732
27723
  {
26733
27724
  "xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
26734
27725
  "w14:paraId": paraId2
26735
27726
  },
26736
- [el10(`${w}r`, {}, [el10(`${w}t`, { "xml:space": "preserve" }, [], text)])]
27727
+ [el11(`${w}r`, {}, [el11(`${w}t`, { "xml:space": "preserve" }, [], text)])]
26737
27728
  )
26738
27729
  ]
26739
27730
  )
@@ -26828,7 +27819,7 @@ function replyToComment(doc, parentId, text, author, initials) {
26828
27819
  }
26829
27820
  const replyParaId = freshParaId();
26830
27821
  commentsRoot.children.push(
26831
- el10(
27822
+ el11(
26832
27823
  `${w}comment`,
26833
27824
  {
26834
27825
  [`${w}id`]: newId,
@@ -26837,13 +27828,13 @@ function replyToComment(doc, parentId, text, author, initials) {
26837
27828
  [`${w}date`]: (/* @__PURE__ */ new Date()).toISOString()
26838
27829
  },
26839
27830
  [
26840
- el10(
27831
+ el11(
26841
27832
  `${w}p`,
26842
27833
  {
26843
27834
  "xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
26844
27835
  "w14:paraId": replyParaId
26845
27836
  },
26846
- [el10(`${w}r`, {}, [el10(`${w}t`, { "xml:space": "preserve" }, [], text)])]
27837
+ [el11(`${w}r`, {}, [el11(`${w}t`, { "xml:space": "preserve" }, [], text)])]
26847
27838
  )
26848
27839
  ]
26849
27840
  )
@@ -26859,11 +27850,11 @@ function replyToComment(doc, parentId, text, author, initials) {
26859
27850
  );
26860
27851
  if (!hasParentEx) {
26861
27852
  extRoot.children.push(
26862
- el10("w15:commentEx", { "w15:paraId": parentParaId, "w15:done": "0" })
27853
+ el11("w15:commentEx", { "w15:paraId": parentParaId, "w15:done": "0" })
26863
27854
  );
26864
27855
  }
26865
27856
  extRoot.children.push(
26866
- el10("w15:commentEx", {
27857
+ el11("w15:commentEx", {
26867
27858
  "w15:paraId": replyParaId,
26868
27859
  "w15:paraIdParent": parentParaId,
26869
27860
  "w15:done": "0"
@@ -26881,19 +27872,19 @@ function insertReplyMarkers(el0, parentId, newId, w) {
26881
27872
  const c = el0.children[i];
26882
27873
  const ln = localName(c.name);
26883
27874
  if (ln === "commentRangeStart" && attr(c, "id") === parentId) {
26884
- el0.children.splice(i + 1, 0, el10(`${w}commentRangeStart`, { [`${w}id`]: newId }));
27875
+ el0.children.splice(i + 1, 0, el11(`${w}commentRangeStart`, { [`${w}id`]: newId }));
26885
27876
  touched = true;
26886
27877
  i++;
26887
27878
  continue;
26888
27879
  }
26889
27880
  if (ln === "commentRangeEnd" && attr(c, "id") === parentId) {
26890
- el0.children.splice(i + 1, 0, el10(`${w}commentRangeEnd`, { [`${w}id`]: newId }));
27881
+ el0.children.splice(i + 1, 0, el11(`${w}commentRangeEnd`, { [`${w}id`]: newId }));
26891
27882
  touched = true;
26892
27883
  i++;
26893
27884
  continue;
26894
27885
  }
26895
27886
  if (ln === "r" && c.children.some((rc) => localName(rc.name) === "commentReference" && attr(rc, "id") === parentId)) {
26896
- el0.children.splice(i + 1, 0, el10(`${w}r`, {}, [el10(`${w}commentReference`, { [`${w}id`]: newId })]));
27887
+ el0.children.splice(i + 1, 0, el11(`${w}r`, {}, [el11(`${w}commentReference`, { [`${w}id`]: newId })]));
26897
27888
  touched = true;
26898
27889
  i++;
26899
27890
  continue;
@@ -26930,7 +27921,7 @@ function stripMarkers(el16, id) {
26930
27921
  }
26931
27922
 
26932
27923
  // ../core/src/edit/links.ts
26933
- function prefixOf11(e) {
27924
+ function prefixOf12(e) {
26934
27925
  return e.name.includes(":") ? e.name.slice(0, e.name.indexOf(":") + 1) : "";
26935
27926
  }
26936
27927
  function hyperlinkOf(doc, t) {
@@ -26975,7 +27966,7 @@ function setLink(doc, segments, url) {
26975
27966
  if (runsByPara.size === 0) return false;
26976
27967
  const relId = doc.addHyperlinkRel(url);
26977
27968
  for (const [pEl, runs] of runsByPara) {
26978
- const w = prefixOf11(pEl);
27969
+ const w = prefixOf12(pEl);
26979
27970
  const first = pEl.children.indexOf(runs[0]);
26980
27971
  for (const rEl of runs) {
26981
27972
  let rPr = rEl.children.find((c) => localName(c.name) === "rPr");
@@ -27022,13 +28013,13 @@ function removeLink(doc, t) {
27022
28013
 
27023
28014
  // ../core/src/edit/paragraph.ts
27024
28015
  var INDENT_STEP_TWIPS = 720;
27025
- function prefixOf12(e) {
28016
+ function prefixOf13(e) {
27026
28017
  return e.name.includes(":") ? e.name.slice(0, e.name.indexOf(":") + 1) : "";
27027
28018
  }
27028
28019
  function ensurePPr(pEl) {
27029
28020
  let pPr = pEl.children.find((c) => localName(c.name) === "pPr");
27030
28021
  if (!pPr) {
27031
- pPr = { name: `${prefixOf12(pEl)}pPr`, attrs: {}, children: [], text: "" };
28022
+ pPr = { name: `${prefixOf13(pEl)}pPr`, attrs: {}, children: [], text: "" };
27032
28023
  pEl.children.unshift(pPr);
27033
28024
  }
27034
28025
  return pPr;
@@ -27049,7 +28040,7 @@ function adjustIndent(doc, targets, direction) {
27049
28040
  if (paragraphs.size === 0) return false;
27050
28041
  let touched = false;
27051
28042
  for (const pEl of paragraphs) {
27052
- const w = prefixOf12(pEl);
28043
+ const w = prefixOf13(pEl);
27053
28044
  const pPr = ensurePPr(pEl);
27054
28045
  let ind = pPr.children.find((c) => localName(c.name) === "ind");
27055
28046
  if (!ind) {
@@ -27119,7 +28110,7 @@ function setDropCapAt(doc, target, mode, lines = 3) {
27119
28110
  }
27120
28111
  if (dropParagraph) {
27121
28112
  const frame = dropCapFrame(dropParagraph);
27122
- const w2 = prefixOf12(dropParagraph);
28113
+ const w2 = prefixOf13(dropParagraph);
27123
28114
  frame.attrs[attrKey(frame, "dropCap", w2)] = mode;
27124
28115
  frame.attrs[attrKey(frame, "lines", w2)] = String(lines);
27125
28116
  frame.attrs[attrKey(frame, "hSpace", w2)] = "144";
@@ -27145,7 +28136,7 @@ function setDropCapAt(doc, target, mode, lines = 3) {
27145
28136
  if (chars.length === 0) return false;
27146
28137
  const letter = chars.shift();
27147
28138
  sourceText.text = chars.join("");
27148
- const w = prefixOf12(paragraph);
28139
+ const w = prefixOf13(paragraph);
27149
28140
  const rPr = sourceRun.children.find((child4) => localName(child4.name) === "rPr");
27150
28141
  const capRun = {
27151
28142
  name: `${w}r`,
@@ -27189,7 +28180,7 @@ function setParagraphSpacing(doc, targets, patch) {
27189
28180
  const paragraphs = paragraphsOf(doc, targets);
27190
28181
  if (paragraphs.size === 0) return false;
27191
28182
  for (const pEl of paragraphs) {
27192
- const w = prefixOf12(pEl);
28183
+ const w = prefixOf13(pEl);
27193
28184
  const pPr = ensurePPr(pEl);
27194
28185
  let sp = pPr.children.find((c) => localName(c.name) === "spacing");
27195
28186
  if (!sp) {
@@ -27304,7 +28295,7 @@ function transformCase(doc, segments, mode) {
27304
28295
  }
27305
28296
 
27306
28297
  // ../core/src/edit/notes.ts
27307
- function el11(name, attrs = {}, children2 = [], text = "") {
28298
+ function el12(name, attrs = {}, children2 = [], text = "") {
27308
28299
  return { name, attrs, children: children2, text };
27309
28300
  }
27310
28301
  function insertFootnote(doc, t, offset, text) {
@@ -27324,9 +28315,9 @@ function insertFootnote(doc, t, offset, text) {
27324
28315
  const newId = maxId + 1;
27325
28316
  const rw = rEl.name.includes(":") ? rEl.name.slice(0, rEl.name.indexOf(":") + 1) : "";
27326
28317
  const rPr = rEl.children.find((c) => localName(c.name) === "rPr");
27327
- const refRun = el11(`${rw}r`, {}, [
27328
- el11(`${rw}rPr`, {}, [el11(`${rw}rStyle`, { [`${rw}val`]: "FootnoteReference" })]),
27329
- el11(`${rw}footnoteReference`, { [`${rw}id`]: String(newId) })
28318
+ const refRun = el12(`${rw}r`, {}, [
28319
+ el12(`${rw}rPr`, {}, [el12(`${rw}rStyle`, { [`${rw}val`]: "FootnoteReference" })]),
28320
+ el12(`${rw}footnoteReference`, { [`${rw}id`]: String(newId) })
27330
28321
  ]);
27331
28322
  const rIdx = pEl.children.indexOf(rEl);
27332
28323
  if (offset >= t.text.length) {
@@ -27334,20 +28325,20 @@ function insertFootnote(doc, t, offset, text) {
27334
28325
  } else if (offset <= 0) {
27335
28326
  pEl.children.splice(rIdx, 0, refRun);
27336
28327
  } else {
27337
- const tailT = el11(`${rw}t`, { "xml:space": "preserve" }, [], t.text.slice(offset));
28328
+ const tailT = el12(`${rw}t`, { "xml:space": "preserve" }, [], t.text.slice(offset));
27338
28329
  t.text = t.text.slice(0, offset);
27339
- const tail = el11(`${rw}r`, {}, [...rPr ? [cloneShallow(rPr)] : [], tailT]);
28330
+ const tail = el12(`${rw}r`, {}, [...rPr ? [cloneShallow(rPr)] : [], tailT]);
27340
28331
  pEl.children.splice(rIdx + 1, 0, refRun, tail);
27341
28332
  }
27342
28333
  notesRoot.children.push(
27343
- el11(`${w}footnote`, { [`${w}id`]: String(newId) }, [
27344
- el11(`${w}p`, {}, [
27345
- el11(`${w}pPr`, {}, [el11(`${w}pStyle`, { [`${w}val`]: "FootnoteText" })]),
27346
- el11(`${w}r`, {}, [
27347
- el11(`${w}rPr`, {}, [el11(`${w}rStyle`, { [`${w}val`]: "FootnoteReference" })]),
27348
- el11(`${w}footnoteRef`)
28334
+ el12(`${w}footnote`, { [`${w}id`]: String(newId) }, [
28335
+ el12(`${w}p`, {}, [
28336
+ el12(`${w}pPr`, {}, [el12(`${w}pStyle`, { [`${w}val`]: "FootnoteText" })]),
28337
+ el12(`${w}r`, {}, [
28338
+ el12(`${w}rPr`, {}, [el12(`${w}rStyle`, { [`${w}val`]: "FootnoteReference" })]),
28339
+ el12(`${w}footnoteRef`)
27349
28340
  ]),
27350
- el11(`${w}r`, {}, [el11(`${w}t`, { "xml:space": "preserve" }, [], " " + text.trim())])
28341
+ el12(`${w}r`, {}, [el12(`${w}t`, { "xml:space": "preserve" }, [], " " + text.trim())])
27351
28342
  ])
27352
28343
  ])
27353
28344
  );
@@ -27360,7 +28351,7 @@ function cloneShallow(e) {
27360
28351
  }
27361
28352
 
27362
28353
  // ../core/src/edit/fields.ts
27363
- function el12(name, attrs = {}, children2 = [], text = "") {
28354
+ function el13(name, attrs = {}, children2 = [], text = "") {
27364
28355
  return { name, attrs, children: children2, text };
27365
28356
  }
27366
28357
  function cloneDeep2(e) {
@@ -27376,8 +28367,8 @@ function insertElementsAt(doc, t, offset, inserted) {
27376
28367
  const tIdx = rEl.children.indexOf(t);
27377
28368
  if (rIdx < 0 || tIdx < 0) return false;
27378
28369
  const at = Math.max(0, Math.min(offset, t.text.length));
27379
- const makeText = (text) => el12(t.name, { ...t.attrs, "xml:space": "preserve" }, [], text);
27380
- const makeRun = (content) => el12(rEl.name, { ...rEl.attrs }, [...rPr ? [cloneDeep2(rPr)] : [], ...content]);
28370
+ const makeText = (text) => el13(t.name, { ...t.attrs, "xml:space": "preserve" }, [], text);
28371
+ const makeRun = (content) => el13(rEl.name, { ...rEl.attrs }, [...rPr ? [cloneDeep2(rPr)] : [], ...content]);
27381
28372
  const before = rEl.children.slice(0, tIdx).filter((child4) => localName(child4.name) !== "rPr");
27382
28373
  const after = rEl.children.slice(tIdx + 1).filter((child4) => localName(child4.name) !== "rPr");
27383
28374
  let beforeRun;
@@ -27410,11 +28401,11 @@ function insertField(doc, t, offset, instruction, cachedResult = "") {
27410
28401
  if (!rEl || localName(rEl.name) !== "r") return false;
27411
28402
  const w = rEl.name.includes(":") ? rEl.name.slice(0, rEl.name.indexOf(":") + 1) : "";
27412
28403
  const rPr = rEl.children.find((c) => localName(c.name) === "rPr");
27413
- const resultRun = el12(`${w}r`, {}, [
28404
+ const resultRun = el13(`${w}r`, {}, [
27414
28405
  ...rPr ? [cloneDeep2(rPr)] : [],
27415
- el12(`${w}t`, { "xml:space": "preserve" }, [], cachedResult)
28406
+ el13(`${w}t`, { "xml:space": "preserve" }, [], cachedResult)
27416
28407
  ]);
27417
- const field = el12(`${w}fldSimple`, { [`${w}instr`]: ` ${clean} ` }, [resultRun]);
28408
+ const field = el13(`${w}fldSimple`, { [`${w}instr`]: ` ${clean} ` }, [resultRun]);
27418
28409
  return insertElementsAt(doc, t, offset, [field]);
27419
28410
  }
27420
28411
  function insertPageField(doc, t, offset, kind = "page") {
@@ -27422,9 +28413,9 @@ function insertPageField(doc, t, offset, kind = "page") {
27422
28413
  if (!rEl || localName(rEl.name) !== "r") return false;
27423
28414
  const rw = rEl.name.includes(":") ? rEl.name.slice(0, rEl.name.indexOf(":") + 1) : "";
27424
28415
  const rPr = rEl.children.find((c) => localName(c.name) === "rPr");
27425
- const run = (content) => el12(`${rw}r`, {}, [...rPr ? [cloneDeep2(rPr)] : [], content]);
27426
- const textRun = (s) => run(el12(`${rw}t`, { "xml:space": "preserve" }, [], s));
27427
- const fld = (instr) => el12(`${rw}fldSimple`, { [`${rw}instr`]: ` ${instr} \\* MERGEFORMAT ` }, [textRun("1")]);
28416
+ const run = (content) => el13(`${rw}r`, {}, [...rPr ? [cloneDeep2(rPr)] : [], content]);
28417
+ const textRun = (s) => run(el13(`${rw}t`, { "xml:space": "preserve" }, [], s));
28418
+ const fld = (instr) => el13(`${rw}fldSimple`, { [`${rw}instr`]: ` ${instr} \\* MERGEFORMAT ` }, [textRun("1")]);
27428
28419
  const inserted = kind === "page" ? [fld("PAGE")] : [textRun("Page "), fld("PAGE"), textRun(" of "), fld("NUMPAGES")];
27429
28420
  return insertElementsAt(doc, t, offset, inserted);
27430
28421
  }
@@ -27435,15 +28426,15 @@ function insertDateTimeField(doc, t, offset, kind, picture) {
27435
28426
 
27436
28427
  // ../core/src/edit/charts.ts
27437
28428
  import { strToU8 as strToU83, zipSync as zipSync2 } from "fflate";
27438
- var EMU_PER_PX6 = 9525;
27439
- var NS_WP5 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
27440
- var NS_A4 = "http://schemas.openxmlformats.org/drawingml/2006/main";
28429
+ var EMU_PER_PX7 = 9525;
28430
+ var NS_WP6 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
28431
+ var NS_A5 = "http://schemas.openxmlformats.org/drawingml/2006/main";
27441
28432
  var NS_C = "http://schemas.openxmlformats.org/drawingml/2006/chart";
27442
- var NS_R3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
27443
- function el13(name, attrs = {}, children2 = [], text = "") {
28433
+ var NS_R4 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
28434
+ function el14(name, attrs = {}, children2 = [], text = "") {
27444
28435
  return { name, attrs, children: children2, text };
27445
28436
  }
27446
- function prefixOf13(node) {
28437
+ function prefixOf14(node) {
27447
28438
  return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
27448
28439
  }
27449
28440
  function descendant4(node, name) {
@@ -27510,7 +28501,7 @@ function buildChartWorkbook(input) {
27510
28501
  `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>`
27511
28502
  ),
27512
28503
  "xl/workbook.xml": strToU83(
27513
- `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="${NS_R3}"><bookViews><workbookView/></bookViews><sheets><sheet name="Data" sheetId="1" r:id="rId1"/></sheets><calcPr calcId="191029"/></workbook>`
28504
+ `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="${NS_R4}"><bookViews><workbookView/></bookViews><sheets><sheet name="Data" sheetId="1" r:id="rId1"/></sheets><calcPr calcId="191029"/></workbook>`
27514
28505
  ),
27515
28506
  "xl/_rels/workbook.xml.rels": strToU83(
27516
28507
  `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/></Relationships>`
@@ -27551,7 +28542,7 @@ function chartPlot(data) {
27551
28542
  }
27552
28543
  function buildChartXml(input, workbookRelId = "rId1") {
27553
28544
  const data = normalizeChartData(input);
27554
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><c:chartSpace xmlns:c="${NS_C}" xmlns:a="${NS_A4}" xmlns:r="${NS_R3}"><c:date1904 val="0"/><c:lang val="en-US"/><c:roundedCorners val="0"/><c:style val="2"/><c:chart>${chartTitle(data.title)}<c:autoTitleDeleted val="${data.title ? "0" : "1"}"/><c:plotArea><c:layout/>${chartPlot(data)}</c:plotArea><c:legend><c:legendPos val="r"/><c:layout/><c:overlay val="0"/></c:legend><c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/><c:showDLblsOverMax val="0"/></c:chart><c:externalData r:id="${escapeXml2(workbookRelId)}"><c:autoUpdate val="0"/></c:externalData></c:chartSpace>`;
28545
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><c:chartSpace xmlns:c="${NS_C}" xmlns:a="${NS_A5}" xmlns:r="${NS_R4}"><c:date1904 val="0"/><c:lang val="en-US"/><c:roundedCorners val="0"/><c:style val="2"/><c:chart>${chartTitle(data.title)}<c:autoTitleDeleted val="${data.title ? "0" : "1"}"/><c:plotArea><c:layout/>${chartPlot(data)}</c:plotArea><c:legend><c:legendPos val="r"/><c:layout/><c:overlay val="0"/></c:legend><c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/><c:showDLblsOverMax val="0"/></c:chart><c:externalData r:id="${escapeXml2(workbookRelId)}"><c:autoUpdate val="0"/></c:externalData></c:chartSpace>`;
27555
28546
  }
27556
28547
  function insertChartAt(doc, caretT, input) {
27557
28548
  const caretRun = doc.findParentOf(caretT);
@@ -27559,23 +28550,23 @@ function insertChartAt(doc, caretT, input) {
27559
28550
  if (!caretRun || !parent || localName(caretRun.name) !== "r") return null;
27560
28551
  const data = normalizeChartData(input);
27561
28552
  const { relId } = doc.addChartResource(buildChartXml(data), buildChartWorkbook(data));
27562
- const w = prefixOf13(caretRun);
28553
+ const w = prefixOf14(caretRun);
27563
28554
  const id = String(doc.nextDrawingId());
27564
- const cx = String(Math.round(480 * EMU_PER_PX6));
27565
- const cy = String(Math.round(288 * EMU_PER_PX6));
27566
- const drawing = el13(`${w}drawing`, {}, [
27567
- el13("wp:inline", { "xmlns:wp": NS_WP5, distT: "0", distB: "0", distL: "0", distR: "0" }, [
27568
- el13("wp:extent", { cx, cy }),
27569
- el13("wp:docPr", { id, name: `Chart ${id}` }),
27570
- el13("wp:cNvGraphicFramePr"),
27571
- el13("a:graphic", { "xmlns:a": NS_A4 }, [
27572
- el13("a:graphicData", { uri: NS_C }, [
27573
- el13("c:chart", { "xmlns:c": NS_C, "xmlns:r": NS_R3, "r:id": relId })
28555
+ const cx = String(Math.round(480 * EMU_PER_PX7));
28556
+ const cy = String(Math.round(288 * EMU_PER_PX7));
28557
+ const drawing = el14(`${w}drawing`, {}, [
28558
+ el14("wp:inline", { "xmlns:wp": NS_WP6, distT: "0", distB: "0", distL: "0", distR: "0" }, [
28559
+ el14("wp:extent", { cx, cy }),
28560
+ el14("wp:docPr", { id, name: `Chart ${id}` }),
28561
+ el14("wp:cNvGraphicFramePr"),
28562
+ el14("a:graphic", { "xmlns:a": NS_A5 }, [
28563
+ el14("a:graphicData", { uri: NS_C }, [
28564
+ el14("c:chart", { "xmlns:c": NS_C, "xmlns:r": NS_R4, "r:id": relId })
27574
28565
  ])
27575
28566
  ])
27576
28567
  ])
27577
28568
  ]);
27578
- parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el13(`${w}r`, {}, [drawing]));
28569
+ parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el14(`${w}r`, {}, [drawing]));
27579
28570
  doc.refresh();
27580
28571
  return drawing;
27581
28572
  }
@@ -27597,226 +28588,6 @@ function setChartData(doc, drawing, input) {
27597
28588
  return true;
27598
28589
  }
27599
28590
 
27600
- // ../core/src/edit/objects.ts
27601
- var EMU_PER_PX7 = 9525;
27602
- var NS_WP6 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
27603
- var NS_A5 = "http://schemas.openxmlformats.org/drawingml/2006/main";
27604
- var NS_PIC2 = "http://schemas.openxmlformats.org/drawingml/2006/picture";
27605
- var NS_R4 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
27606
- var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
27607
- var NS_AM3D = "http://schemas.microsoft.com/office/drawing/2017/model3d";
27608
- var NS_WP15 = "http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing";
27609
- function el14(name, attrs = {}, children2 = [], text = "") {
27610
- return { name, attrs, children: children2, text };
27611
- }
27612
- function prefixOf14(node) {
27613
- return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
27614
- }
27615
- function insertAfterCaretRun(doc, caretT, content) {
27616
- const caretRun = doc.findParentOf(caretT);
27617
- const parent = caretRun && doc.findParentOf(caretRun);
27618
- if (!caretRun || !parent || localName(caretRun.name) !== "r") return false;
27619
- const w = prefixOf14(caretRun);
27620
- parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el14(`${w}r`, {}, [content]));
27621
- doc.refresh();
27622
- return true;
27623
- }
27624
- function pictureGraphic(relId, id, cx, cy, webVideo) {
27625
- const blipChildren = webVideo ? [
27626
- el14("a:extLst", {}, [
27627
- el14("a:ext", { uri: "{9E29B28B-C9C2-4B96-BA92-6C9A3D8F4A6A}" }, [
27628
- el14("wp15:webVideoPr", {
27629
- "xmlns:wp15": NS_WP15,
27630
- embeddedHtml: webVideo,
27631
- w: "640",
27632
- h: "360"
27633
- })
27634
- ])
27635
- ])
27636
- ] : [];
27637
- return el14("a:graphic", { "xmlns:a": NS_A5 }, [
27638
- el14("a:graphicData", { uri: NS_PIC2 }, [
27639
- el14("pic:pic", { "xmlns:pic": NS_PIC2 }, [
27640
- el14("pic:nvPicPr", {}, [
27641
- el14("pic:cNvPr", { id, name: `Picture ${id}` }),
27642
- el14("pic:cNvPicPr", {}, [el14("a:picLocks", { noChangeAspect: "1" })])
27643
- ]),
27644
- el14("pic:blipFill", {}, [
27645
- el14("a:blip", { "xmlns:r": NS_R4, "r:embed": relId }, blipChildren),
27646
- el14("a:stretch", {}, [el14("a:fillRect")])
27647
- ]),
27648
- el14("pic:spPr", {}, [
27649
- el14("a:xfrm", {}, [el14("a:off", { x: "0", y: "0" }), el14("a:ext", { cx, cy })]),
27650
- el14("a:prstGeom", { prst: "rect" }, [el14("a:avLst")])
27651
- ])
27652
- ])
27653
- ])
27654
- ]);
27655
- }
27656
- function inlineDrawing(id, name, descr, cx, cy, graphic) {
27657
- return el14("w:drawing", {}, [
27658
- el14("wp:inline", { "xmlns:wp": NS_WP6, distT: "0", distB: "0", distL: "0", distR: "0" }, [
27659
- el14("wp:extent", { cx, cy }),
27660
- el14("wp:effectExtent", { l: "0", t: "0", r: "0", b: "0" }),
27661
- el14("wp:docPr", { id, name, descr }),
27662
- el14("wp:cNvGraphicFramePr", {}, [el14("a:graphicFrameLocks", { "xmlns:a": NS_A5, noChangeAspect: "1" })]),
27663
- graphic
27664
- ])
27665
- ]);
27666
- }
27667
- function insertModel3DAt(doc, caretT, input) {
27668
- const posterRelId = doc.addImageResource(input.poster, input.posterExt ?? "png");
27669
- const model = doc.addModel3DResource(input.data);
27670
- const id = String(doc.nextDrawingId());
27671
- const width = 320;
27672
- const height = 220;
27673
- const cx = String(width * EMU_PER_PX7);
27674
- const cy = String(height * EMU_PER_PX7);
27675
- const modelGraphic = el14("a:graphic", { "xmlns:a": NS_A5 }, [
27676
- el14("a:graphicData", { uri: NS_AM3D }, [
27677
- el14("am3d:model3d", { "xmlns:am3d": NS_AM3D, "xmlns:r": NS_R4, "r:embed": model.relId }, [
27678
- el14("am3d:spPr", {}, [
27679
- el14("a:xfrm", {}, [el14("a:off", { x: "0", y: "0" }), el14("a:ext", { cx, cy })]),
27680
- el14("a:prstGeom", { prst: "rect" }, [el14("a:avLst")])
27681
- ]),
27682
- el14("am3d:camera", {}, [
27683
- el14("am3d:pos", { x: "0", y: "0", z: "77741944" }),
27684
- el14("am3d:up", { dx: "0", dy: "36000000", dz: "0" }),
27685
- el14("am3d:lookAt", { x: "0", y: "0", z: "0" }),
27686
- el14("am3d:perspective", { fov: "2700000" })
27687
- ]),
27688
- el14("am3d:trans", {}, [
27689
- el14("am3d:meterPerModelUnit", { n: "1", d: "1" }),
27690
- el14("am3d:preTrans", { dx: "0", dy: "0", dz: "0" }),
27691
- el14("am3d:scale", {}, [
27692
- el14("am3d:sx", { n: "1000000", d: "1000000" }),
27693
- el14("am3d:sy", { n: "1000000", d: "1000000" }),
27694
- el14("am3d:sz", { n: "1000000", d: "1000000" })
27695
- ]),
27696
- el14("am3d:rot", { ax: "0", ay: "0", az: "0" }),
27697
- el14("am3d:postTrans", { dx: "0", dy: "0", dz: "0" })
27698
- ]),
27699
- el14("am3d:raster", { rName: "Office3DRenderer", rVer: "16.0" }, [
27700
- el14("am3d:blip", { "r:embed": posterRelId })
27701
- ]),
27702
- el14("am3d:objViewport", { viewportSz: cx }),
27703
- el14("am3d:ambientLight", {}, [
27704
- el14("am3d:clr", {}, [el14("a:scrgbClr", { r: "50000", g: "50000", b: "50000" })]),
27705
- el14("am3d:illuminance", { n: "500000", d: "1000000" })
27706
- ]),
27707
- el14("am3d:ptLight", { rad: "0" }, [
27708
- el14("am3d:clr", {}, [el14("a:scrgbClr", { r: "100000", g: "100000", b: "100000" })]),
27709
- el14("am3d:intensity", { n: "1000000", d: "1000000" }),
27710
- el14("am3d:pos", { x: "30000000", y: "50000000", z: "50000000" })
27711
- ])
27712
- ])
27713
- ])
27714
- ]);
27715
- const alt = input.alt ?? "3D model";
27716
- const choice = inlineDrawing(id, `3D Model ${id}`, alt, cx, cy, modelGraphic);
27717
- const fallback = inlineDrawing(id, `3D Model ${id}`, alt, cx, cy, pictureGraphic(posterRelId, id, cx, cy));
27718
- const alternate = el14("mc:AlternateContent", { "xmlns:mc": NS_MC }, [
27719
- el14("mc:Choice", { Requires: "am3d", "xmlns:am3d": NS_AM3D }, [choice]),
27720
- el14("mc:Fallback", {}, [fallback])
27721
- ]);
27722
- return insertAfterCaretRun(doc, caretT, alternate);
27723
- }
27724
- function normalizeWebVideoUrl(value) {
27725
- try {
27726
- const url = new URL(value.trim());
27727
- if (url.protocol !== "http:" && url.protocol !== "https:") return null;
27728
- if (url.hostname === "youtu.be") return `https://www.youtube.com/embed/${url.pathname.slice(1)}`;
27729
- if (url.hostname.endsWith("youtube.com") && url.pathname === "/watch") {
27730
- const id = url.searchParams.get("v");
27731
- if (id) return `https://www.youtube.com/embed/${id}`;
27732
- }
27733
- if (url.hostname.endsWith("vimeo.com") && /^\/\d+\/?$/.test(url.pathname)) {
27734
- return `https://player.vimeo.com/video/${url.pathname.replace(/\//g, "")}`;
27735
- }
27736
- return url.href;
27737
- } catch {
27738
- return null;
27739
- }
27740
- }
27741
- function insertWebVideoAt(doc, caretT, input) {
27742
- const url = normalizeWebVideoUrl(input.url);
27743
- if (!url) return false;
27744
- const posterRelId = doc.addImageResource(input.poster, input.posterExt ?? "png");
27745
- const width = input.width ?? 320;
27746
- const height = input.height ?? 180;
27747
- const cx = String(Math.round(width * EMU_PER_PX7));
27748
- const cy = String(Math.round(height * EMU_PER_PX7));
27749
- const id = String(doc.nextDrawingId());
27750
- const embeddedHtml = `<iframe width="640" height="360" src="${url}" frameborder="0" allowfullscreen=""></iframe>`;
27751
- return insertAfterCaretRun(
27752
- doc,
27753
- caretT,
27754
- inlineDrawing(id, `Online Video ${id}`, url, cx, cy, pictureGraphic(posterRelId, id, cx, cy, embeddedHtml))
27755
- );
27756
- }
27757
- function insertEmbeddedObjectAt(doc, caretT, input) {
27758
- const posterRelId = doc.addImageResource(input.poster, input.posterExt ?? "png");
27759
- const wordDocument = input.filename.toLowerCase().endsWith(".docx");
27760
- const object = wordDocument ? doc.addEmbeddedWordDocumentResource(input.data) : doc.addEmbeddedObjectResource(buildOlePackage(input.data, input.filename));
27761
- const id = String(doc.nextDrawingId());
27762
- const vmlId = 1024 + Number(id);
27763
- const shapeTypeId = `_x0000_t${vmlId}`;
27764
- const shapeId = `_x0000_i${vmlId}`;
27765
- const width = 320;
27766
- const height = 180;
27767
- const objectEl = el14("w:object", {
27768
- "xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
27769
- "xmlns:v": "urn:schemas-microsoft-com:vml",
27770
- "xmlns:o": "urn:schemas-microsoft-com:office:office",
27771
- "xmlns:r": NS_R4,
27772
- "w:dxaOrig": String(width * 15),
27773
- "w:dyaOrig": String(height * 15)
27774
- }, [
27775
- el14("v:shapetype", {
27776
- id: shapeTypeId,
27777
- coordsize: "21600,21600",
27778
- "o:spt": "75",
27779
- "o:preferrelative": "t",
27780
- path: "m@4@5l@4@11@9@11@9@5xe",
27781
- filled: "f",
27782
- stroked: "f"
27783
- }, [
27784
- el14("v:stroke", { joinstyle: "miter" }),
27785
- el14("v:formulas", {}, [
27786
- el14("v:f", { eqn: "if lineDrawn pixelLineWidth 0" }),
27787
- el14("v:f", { eqn: "sum @0 1 0" }),
27788
- el14("v:f", { eqn: "sum 0 0 @1" }),
27789
- el14("v:f", { eqn: "prod @2 1 2" }),
27790
- el14("v:f", { eqn: "prod @3 21600 pixelWidth" }),
27791
- el14("v:f", { eqn: "prod @3 21600 pixelHeight" }),
27792
- el14("v:f", { eqn: "sum @0 0 1" }),
27793
- el14("v:f", { eqn: "prod @6 1 2" }),
27794
- el14("v:f", { eqn: "prod @7 21600 pixelWidth" }),
27795
- el14("v:f", { eqn: "sum @8 21600 0" }),
27796
- el14("v:f", { eqn: "prod @7 21600 pixelHeight" }),
27797
- el14("v:f", { eqn: "sum @10 21600 0" })
27798
- ]),
27799
- el14("v:path", { "o:extrusionok": "f", gradientshapeok: "t", "o:connecttype": "rect" }),
27800
- el14("o:lock", { "v:ext": "edit", aspectratio: "t" })
27801
- ]),
27802
- el14("v:shape", {
27803
- id: shapeId,
27804
- type: `#${shapeTypeId}`,
27805
- style: `width:${width * 0.75}pt;height:${height * 0.75}pt`,
27806
- "o:ole": ""
27807
- }, [el14("v:imagedata", { "r:id": posterRelId, "o:title": input.filename })]),
27808
- el14("o:OLEObject", {
27809
- Type: "Embed",
27810
- ProgID: wordDocument ? "Word.Document.12" : "Package",
27811
- ShapeID: shapeId,
27812
- DrawAspect: "Content",
27813
- ObjectID: `_${1e9 + Number(id)}`,
27814
- "r:id": object.relId
27815
- }, wordDocument ? [el14("o:FieldCodes", {}, [], "\\s")] : [])
27816
- ]);
27817
- return insertAfterCaretRun(doc, caretT, objectEl);
27818
- }
27819
-
27820
28591
  // ../core/src/edit/references.ts
27821
28592
  function el15(name, attrs = {}) {
27822
28593
  return { name, attrs, children: [], text: "" };
@@ -29124,7 +29895,10 @@ function EquationMenu({ api }) {
29124
29895
  }
29125
29896
  };
29126
29897
  return /* @__PURE__ */ jsxs("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
29127
- /* @__PURE__ */ jsx("button", { title: "Insert equation", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: /* @__PURE__ */ jsx("span", { style: { fontFamily: "'Cambria Math', serif", fontSize: 18 }, children: "\u03C0" }) }),
29898
+ /* @__PURE__ */ jsxs("button", { title: "Insert equation", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: [
29899
+ /* @__PURE__ */ jsx("span", { style: { fontFamily: "'Cambria Math', serif", fontSize: 18 }, children: "\u03C0" }),
29900
+ /* @__PURE__ */ jsx("span", { style: { marginLeft: 5 }, children: "Equation" })
29901
+ ] }),
29128
29902
  open && /* @__PURE__ */ jsxs("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 340, padding: 10, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
29129
29903
  /* @__PURE__ */ jsx("div", { style: { font: "600 12px system-ui, sans-serif", marginBottom: 5, color: T.fg }, children: "Linear equation" }),
29130
29904
  /* @__PURE__ */ jsx(
@@ -31137,6 +31911,11 @@ function DocxView({
31137
31911
  const effZoomRef = useRef2(effectiveZoom);
31138
31912
  effZoomRef.current = effectiveZoom;
31139
31913
  const applyZoomRef = useRef2(null);
31914
+ useEffect2(() => {
31915
+ if (editable && typeof window !== "undefined" && !customElements.get("model-viewer")) {
31916
+ void import("@google/model-viewer");
31917
+ }
31918
+ }, [editable]);
31140
31919
  const recomputeFit = useCallback2(() => {
31141
31920
  const c = containerRef.current;
31142
31921
  if (!c) return;
@@ -31357,6 +32136,7 @@ function DocxView({
31357
32136
  }
31358
32137
  }
31359
32138
  loads.push(document.fonts.load('16px "Cambria Math"').catch(() => []));
32139
+ loads.push(document.fonts.load('16px "Segoe UI Emoji"', "\u{1F680}").catch(() => []));
31360
32140
  const cjk = [
31361
32141
  "MS Mincho",
31362
32142
  "MS Gothic",
@@ -31582,8 +32362,10 @@ function DocxView({
31582
32362
  const target = insertionTarget();
31583
32363
  if (!target) return false;
31584
32364
  history.checkpoint();
31585
- if (!insertShapeAt(doc, target.t, preset, text)) return false;
32365
+ const drawing = insertShapeAt(doc, target.t, preset, text);
32366
+ if (!drawing) return false;
31586
32367
  pages = rerender(doc, void 0, "global");
32368
+ editor?.reselectDrawing(drawing);
31587
32369
  return true;
31588
32370
  },
31589
32371
  insertWordArt: (text, preset = "plain") => {