wordinweb 0.1.16 → 0.1.18

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
@@ -2358,6 +2358,7 @@ var BORDER_STYLE_MAP = {
2358
2358
  dashed: "dashed",
2359
2359
  dotDash: "dotDash",
2360
2360
  dotDotDash: "dotDotDash",
2361
+ thinThickSmallGap: "thinThickSmallGap",
2361
2362
  triple: "triple",
2362
2363
  wave: "wave",
2363
2364
  none: "none",
@@ -4215,7 +4216,11 @@ function parseDrawing(drawing, ctx) {
4215
4216
  x2: emuToPx(x2),
4216
4217
  y2: emuToPx(y2),
4217
4218
  color,
4218
- weight: Math.max(weightEmu / EMU_PER_PT * (4 / 3), 0.75)
4219
+ weight: Math.max(weightEmu / EMU_PER_PT * (4 / 3), 0.75),
4220
+ style: (() => {
4221
+ const dash = attr(child(lnEl, "prstDash"), "val");
4222
+ return dash === "dot" || dash === "sysDot" ? "dotted" : dash && dash !== "solid" ? "dashed" : "single";
4223
+ })()
4219
4224
  });
4220
4225
  }
4221
4226
  const custGeom = child(spPr, "custGeom");
@@ -4772,6 +4777,7 @@ function resolveDiagramDrawing(relIds, ctx) {
4772
4777
  function collectDiagramShapes(dspRoot, ctx, out, dx, dy) {
4773
4778
  const spTree = findDescendant(dspRoot, "spTree");
4774
4779
  if (!spTree) return;
4780
+ let smartArtNodeIndex = 0;
4775
4781
  const emitShape = (sp, ox, oy, sx, sy) => {
4776
4782
  const spPr = child(sp, "spPr");
4777
4783
  if (!spPr) return;
@@ -4803,10 +4809,15 @@ function collectDiagramShapes(dspRoot, ctx, out, dx, dy) {
4803
4809
  x2: dx + emuToPx(x2),
4804
4810
  y2: dy + emuToPx(y2),
4805
4811
  color: stroke.color,
4806
- weight: Math.max(stroke.width, 0.75)
4812
+ weight: Math.max(stroke.width, 0.75),
4813
+ style: (() => {
4814
+ const dash = attr(child(lnEl, "prstDash"), "val");
4815
+ return dash === "dot" || dash === "sysDot" ? "dotted" : dash && dash !== "solid" ? "dashed" : "single";
4816
+ })()
4807
4817
  });
4808
4818
  }
4809
4819
  } else {
4820
+ const nodeIndex = smartArtNodeIndex++;
4810
4821
  const fill = child(spPr, "noFill") ? void 0 : solidFillColor(spPr, ctx.theme);
4811
4822
  if ((fill || stroke) && w > 0 && h > 0) {
4812
4823
  const d = presetPathD(prst, w, h, child(child(spPr, "prstGeom"), "avLst"));
@@ -4820,7 +4831,8 @@ function collectDiagramShapes(dspRoot, ctx, out, dx, dy) {
4820
4831
  viewW: w,
4821
4832
  viewH: h,
4822
4833
  fill,
4823
- stroke
4834
+ stroke,
4835
+ smartArtNodeIndex: nodeIndex
4824
4836
  });
4825
4837
  }
4826
4838
  }
@@ -5555,12 +5567,192 @@ function descendant2(node, name) {
5555
5567
  }
5556
5568
  return void 0;
5557
5569
  }
5570
+ function descendants3(node, name, out = []) {
5571
+ if (localName(node.name) === name) out.push(node);
5572
+ for (const child4 of node.children) descendants3(child4, name, out);
5573
+ return out;
5574
+ }
5575
+ function smartArtDrawingPart(doc, drawing) {
5576
+ const relIds = descendant2(drawing, "relIds");
5577
+ const dataRel = relIds ? doc.documentRels.get(attr(relIds, "dm") ?? "") : void 0;
5578
+ if (!dataRel || dataRel.external) return null;
5579
+ const dataXml = doc.pkg.text(dataRel.target);
5580
+ if (!dataXml) return null;
5581
+ const drawingRelId = attr(descendant2(parseXml(dataXml), "dataModelExt"), "relId");
5582
+ if (drawingRelId) {
5583
+ const hostRel = doc.documentRels.get(drawingRelId);
5584
+ if (hostRel && !hostRel.external) return hostRel.target;
5585
+ const relsXml = doc.pkg.text(relsPathFor(dataRel.target));
5586
+ if (relsXml) {
5587
+ const dataRelEntry = parseRelationships(parseXml(relsXml), dataRel.target).get(drawingRelId);
5588
+ if (dataRelEntry && !dataRelEntry.external) return dataRelEntry.target;
5589
+ }
5590
+ }
5591
+ for (const rel of doc.documentRels.values()) {
5592
+ if (!rel.external && rel.type.endsWith("/diagramDrawing")) return rel.target;
5593
+ }
5594
+ return null;
5595
+ }
5596
+ function smartArtNodeShapes(root) {
5597
+ return descendants3(root, "sp").filter((shape) => {
5598
+ const spPr = shape.children.find((child4) => localName(child4.name) === "spPr");
5599
+ if (!spPr) return false;
5600
+ const name = attr(descendant2(shape, "cNvPr"), "name") ?? "";
5601
+ const geometry = (attr(descendant2(spPr, "prstGeom"), "prst") ?? "").toLowerCase();
5602
+ return !/^connector\b/i.test(name) && geometry !== "line" && !geometry.includes("connector");
5603
+ });
5604
+ }
5605
+ function smartArtNodeShapeProperties(root) {
5606
+ return smartArtNodeShapes(root).flatMap((shape) => {
5607
+ const spPr = shape.children.find((child4) => localName(child4.name) === "spPr");
5608
+ return spPr ? [spPr] : [];
5609
+ });
5610
+ }
5611
+ function replaceTextLeaves(root, value) {
5612
+ const leaves = descendants3(root, "t").filter((node) => node.children.length === 0);
5613
+ if (!leaves.length) return false;
5614
+ leaves[0].text = value;
5615
+ for (const leaf of leaves.slice(1)) leaf.text = "";
5616
+ return true;
5617
+ }
5618
+ function directChild(node, name) {
5619
+ return node.children.find((child4) => localName(child4.name) === name);
5620
+ }
5621
+ function textColor(rPr) {
5622
+ const color = attr(descendant2(directChild(rPr ?? el("a:rPr"), "solidFill"), "srgbClr"), "val") ?? attr(descendant2(directChild(rPr ?? el("a:rPr"), "solidFill"), "sysClr"), "lastClr");
5623
+ return `#${(color ?? "000000").toUpperCase()}`;
5624
+ }
5625
+ function applyTextFormat(root, format) {
5626
+ for (const run of descendants3(root, "r")) {
5627
+ let rPr = directChild(run, "rPr");
5628
+ if (!rPr) {
5629
+ rPr = el("a:rPr");
5630
+ run.children.unshift(rPr);
5631
+ }
5632
+ rPr.attrs.sz = String(Math.round(format.fontSizePt * 100));
5633
+ rPr.attrs.b = format.bold ? "1" : "0";
5634
+ rPr.attrs.i = format.italic ? "1" : "0";
5635
+ for (const name of ["latin", "ea", "cs"]) {
5636
+ let font = directChild(rPr, name);
5637
+ if (!font) {
5638
+ font = el(`a:${name}`);
5639
+ rPr.children.push(font);
5640
+ }
5641
+ font.attrs.typeface = format.fontFamily;
5642
+ }
5643
+ rPr.children = rPr.children.filter((child4) => {
5644
+ const name = localName(child4.name);
5645
+ return !["solidFill", "noFill", "gradFill", "pattFill"].includes(name);
5646
+ });
5647
+ rPr.children.unshift(el("a:solidFill", {}, [el("a:srgbClr", { val: format.color.replace(/^#/, "").toUpperCase() })]));
5648
+ }
5649
+ for (const paragraph of descendants3(root, "p")) {
5650
+ let pPr = directChild(paragraph, "pPr");
5651
+ if (!pPr) {
5652
+ pPr = el("a:pPr");
5653
+ paragraph.children.unshift(pPr);
5654
+ }
5655
+ pPr.attrs.algn = format.alignment === "center" ? "ctr" : format.alignment === "right" ? "r" : "l";
5656
+ }
5657
+ }
5658
+ function smartArtFillColor(doc, drawing, nodeIndex = 0) {
5659
+ const part = smartArtDrawingPart(doc, drawing);
5660
+ const xml = part ? doc.pkg.text(part) : void 0;
5661
+ if (!xml) return null;
5662
+ const spPr = smartArtNodeShapeProperties(parseXml(xml))[nodeIndex];
5663
+ if (!spPr || spPr.children.some((child4) => localName(child4.name) === "noFill")) return null;
5664
+ const solidFill = spPr.children.find((child4) => localName(child4.name) === "solidFill");
5665
+ if (!solidFill) return null;
5666
+ const color = attr(descendant2(solidFill, "srgbClr"), "val") ?? attr(descendant2(solidFill, "sysClr"), "lastClr");
5667
+ return `#${(color ?? COLORS[0]).toUpperCase()}`;
5668
+ }
5669
+ function setSmartArtFill(doc, drawing, color, nodeIndex) {
5670
+ const part = smartArtDrawingPart(doc, drawing);
5671
+ const xml = part ? doc.pkg.text(part) : void 0;
5672
+ if (!part || !xml) return false;
5673
+ const root = parseXml(xml);
5674
+ const allNodes = smartArtNodeShapeProperties(root);
5675
+ const nodes = nodeIndex === void 0 ? allNodes : allNodes.slice(nodeIndex, nodeIndex + 1);
5676
+ if (!nodes.length) return false;
5677
+ for (const spPr of nodes) {
5678
+ spPr.children = spPr.children.filter((child4) => {
5679
+ const name = localName(child4.name);
5680
+ return !["solidFill", "noFill", "gradFill", "pattFill", "blipFill", "grpFill"].includes(name);
5681
+ });
5682
+ const fill = color ? el("a:solidFill", {}, [el("a:srgbClr", { val: color.replace(/^#/, "").toUpperCase() })]) : el("a:noFill");
5683
+ const lineIndex = spPr.children.findIndex((child4) => localName(child4.name) === "ln");
5684
+ spPr.children.splice(lineIndex === -1 ? spPr.children.length : lineIndex, 0, fill);
5685
+ }
5686
+ doc.pkg.raw()[part] = strToU8(serializeXml(root, true));
5687
+ doc.markPackageResourceChanged();
5688
+ doc.refresh();
5689
+ return true;
5690
+ }
5691
+ function setSmartArtNodeText(doc, drawing, nodeIndex, value) {
5692
+ const relIds = descendant2(drawing, "relIds");
5693
+ const dataRel = relIds ? doc.documentRels.get(attr(relIds, "dm") ?? "") : void 0;
5694
+ const drawingPart = smartArtDrawingPart(doc, drawing);
5695
+ const dataXml = dataRel && !dataRel.external ? doc.pkg.text(dataRel.target) : void 0;
5696
+ const drawingXml = drawingPart ? doc.pkg.text(drawingPart) : void 0;
5697
+ if (!dataRel || dataRel.external || !drawingPart || !dataXml || !drawingXml) return false;
5698
+ const drawingRoot = parseXml(drawingXml);
5699
+ const shape = smartArtNodeShapes(drawingRoot)[nodeIndex];
5700
+ const modelId = shape ? attr(shape, "modelId") : void 0;
5701
+ if (!shape || !modelId) return false;
5702
+ const dataRoot = parseXml(dataXml);
5703
+ const point = descendants3(dataRoot, "pt").find((candidate) => attr(candidate, "modelId") === modelId);
5704
+ if (!point || !replaceTextLeaves(shape, value) || !replaceTextLeaves(point, value)) return false;
5705
+ doc.pkg.raw()[drawingPart] = strToU8(serializeXml(drawingRoot, true));
5706
+ doc.pkg.raw()[dataRel.target] = strToU8(serializeXml(dataRoot, true));
5707
+ doc.markPackageResourceChanged();
5708
+ doc.refresh();
5709
+ return true;
5710
+ }
5711
+ function smartArtTextFormat(doc, drawing, nodeIndex = 0) {
5712
+ const part = smartArtDrawingPart(doc, drawing);
5713
+ const xml = part ? doc.pkg.text(part) : void 0;
5714
+ if (!xml) return null;
5715
+ const shape = smartArtNodeShapes(parseXml(xml))[nodeIndex];
5716
+ const rPr = shape ? descendant2(shape, "rPr") : void 0;
5717
+ if (!shape || !rPr) return null;
5718
+ const alignment = attr(descendant2(shape, "pPr"), "algn");
5719
+ return {
5720
+ fontFamily: attr(descendant2(rPr, "latin"), "typeface") ?? "Calibri",
5721
+ fontSizePt: Number(attr(rPr, "sz") ?? "1200") / 100,
5722
+ color: textColor(rPr),
5723
+ bold: attr(rPr, "b") === "1",
5724
+ italic: attr(rPr, "i") === "1",
5725
+ alignment: alignment === "r" ? "right" : alignment === "ctr" ? "center" : "left"
5726
+ };
5727
+ }
5728
+ function setSmartArtTextFormat(doc, drawing, format, nodeIndex) {
5729
+ const relIds = descendant2(drawing, "relIds");
5730
+ const dataRel = relIds ? doc.documentRels.get(attr(relIds, "dm") ?? "") : void 0;
5731
+ const drawingPart = smartArtDrawingPart(doc, drawing);
5732
+ const dataXml = dataRel && !dataRel.external ? doc.pkg.text(dataRel.target) : void 0;
5733
+ const drawingXml = drawingPart ? doc.pkg.text(drawingPart) : void 0;
5734
+ if (!dataRel || dataRel.external || !drawingPart || !dataXml || !drawingXml) return false;
5735
+ const drawingRoot = parseXml(drawingXml);
5736
+ const allShapes = smartArtNodeShapes(drawingRoot);
5737
+ const shapes = nodeIndex === void 0 ? allShapes : allShapes.slice(nodeIndex, nodeIndex + 1);
5738
+ if (!shapes.length) return false;
5739
+ const modelIds = new Set(shapes.map((shape) => attr(shape, "modelId")).filter((value) => !!value));
5740
+ const dataRoot = parseXml(dataXml);
5741
+ const points = descendants3(dataRoot, "pt").filter((point) => modelIds.has(attr(point, "modelId") ?? ""));
5742
+ for (const shape of shapes) applyTextFormat(shape, format);
5743
+ for (const point of points) applyTextFormat(point, format);
5744
+ doc.pkg.raw()[drawingPart] = strToU8(serializeXml(drawingRoot, true));
5745
+ doc.pkg.raw()[dataRel.target] = strToU8(serializeXml(dataRoot, true));
5746
+ doc.markPackageResourceChanged();
5747
+ doc.refresh();
5748
+ return true;
5749
+ }
5558
5750
  function escapeXml(value) {
5559
5751
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5560
5752
  }
5561
5753
  function normalizeSmartArtData(data) {
5562
5754
  const items = data.items.map((item) => item.trim()).filter(Boolean);
5563
- return { layout: data.layout, items: items.length ? items : ["First idea", "Second idea", "Third idea"] };
5755
+ return { layout: data.layout, items: items.length ? items : [""] };
5564
5756
  }
5565
5757
  function line(modelId, x1, y1, x2, y2) {
5566
5758
  return { modelId, x: x1, y: y1, width: x2 - x1, height: y2 - y1, geometry: "line" };
@@ -5651,13 +5843,13 @@ function buildSmartArtDataXml(input, drawingRelId) {
5651
5843
  (text, index) => `<dgm:pt modelId="${index + 1}"><dgm:prSet/><dgm:spPr/><dgm:t><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US"/><a:t>${escapeXml(text)}</a:t></a:r></a:p></dgm:t></dgm:pt>`
5652
5844
  ).join("");
5653
5845
  const connections = data.items.map(
5654
- (_, index) => `<dgm:cxn modelId="${data.items.length + index + 1}" srcId="0" destId="${index + 1}" srcOrd="${index}" destOrd="0"/>`
5846
+ (_, index) => `<dgm:cxn modelId="${data.items.length + index + 1}" type="parOf" srcId="0" destId="${index + 1}" srcOrd="${index}" destOrd="0" presId=""/>`
5655
5847
  ).join("");
5656
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dgm:dataModel xmlns:dgm="${NS_DGM}" xmlns:a="${NS_A}"><dgm:ptLst><dgm:pt modelId="0" type="doc"><dgm:prSet loTypeId="urn:wordinweb:smartart:${data.layout}" loCatId="${data.layout}"/><dgm:spPr/><dgm:t><a:bodyPr/><a:lstStyle/><a:p/></dgm:t></dgm:pt>${points}</dgm:ptLst><dgm:cxnLst>${connections}</dgm:cxnLst><dgm:bg/><dgm:whole/><dgm:extLst><a:ext uri="http://schemas.microsoft.com/office/drawing/2008/diagram"><dsp:dataModelExt xmlns:dsp="${NS_DSP}" relId="${escapeXml(drawingRelId)}" minVer="${NS_DGM}"/></a:ext></dgm:extLst></dgm:dataModel>`;
5848
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dgm:dataModel xmlns:dgm="${NS_DGM}" xmlns:a="${NS_A}"><dgm:ptLst><dgm:pt modelId="0" type="doc"><dgm:prSet loTypeId="urn:wordinweb:smartart:${data.layout}" loCatId="${data.layout}" qsTypeId="urn:wordinweb:smartart:style" qsCatId="simple" csTypeId="urn:wordinweb:smartart:colors" csCatId="accent1"/><dgm:spPr/><dgm:t><a:bodyPr/><a:lstStyle/><a:p/></dgm:t></dgm:pt>${points}</dgm:ptLst><dgm:cxnLst>${connections}</dgm:cxnLst><dgm:bg/><dgm:whole/><dgm:extLst><a:ext uri="http://schemas.microsoft.com/office/drawing/2008/diagram"><dsp:dataModelExt xmlns:dsp="${NS_DSP}" relId="${escapeXml(drawingRelId)}" minVer="${NS_DGM}"/></a:ext></dgm:extLst></dgm:dataModel>`;
5657
5849
  }
5658
5850
  function buildSmartArtLayoutXml(input) {
5659
5851
  const data = normalizeSmartArtData(input);
5660
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dgm:layoutDef xmlns:dgm="${NS_DGM}" xmlns:a="${NS_A}" uniqueId="urn:wordinweb:smartart:${data.layout}"><dgm:title val="${data.layout}"/><dgm:desc val="WordInWeb ${data.layout} diagram"/><dgm:catLst><dgm:cat type="${data.layout}" pri="1000"/></dgm:catLst><dgm:layoutNode name="root"><dgm:alg type="composite"/></dgm:layoutNode></dgm:layoutDef>`;
5852
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dgm:layoutDef xmlns:dgm="${NS_DGM}" xmlns:a="${NS_A}" uniqueId="urn:wordinweb:smartart:${data.layout}"><dgm:title val="${data.layout}"/><dgm:desc val="WordInWeb ${data.layout} diagram"/><dgm:catLst><dgm:cat type="${data.layout}" pri="1000"/></dgm:catLst><dgm:layoutNode name="diagram"><dgm:alg type="lin"/><dgm:shape/><dgm:presOf/><dgm:constrLst><dgm:constr type="w" for="ch" forName="node" refType="w"/><dgm:constr op="equ" type="h" for="ch" forName="node"/><dgm:constr op="equ" type="primFontSz" for="ch" forName="node" val="65"/></dgm:constrLst><dgm:ruleLst/><dgm:forEach axis="ch" ptType="node"><dgm:layoutNode name="node" styleLbl="node0"><dgm:varLst><dgm:bulletEnabled val="true"/></dgm:varLst><dgm:alg type="tx"/><dgm:shape type="roundRect"/><dgm:presOf axis="desOrSelf" ptType="node"/><dgm:constrLst><dgm:constr type="tMarg" refType="primFontSz" fact="0.3"/><dgm:constr type="bMarg" refType="primFontSz" fact="0.3"/><dgm:constr type="lMarg" refType="primFontSz" fact="0.3"/><dgm:constr type="rMarg" refType="primFontSz" fact="0.3"/></dgm:constrLst><dgm:ruleLst><dgm:rule type="primFontSz" val="5"/></dgm:ruleLst></dgm:layoutNode></dgm:forEach></dgm:layoutNode></dgm:layoutDef>`;
5661
5853
  }
5662
5854
  function buildSmartArtStyleXml() {
5663
5855
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dgm:styleDef xmlns:dgm="${NS_DGM}" xmlns:a="${NS_A}" uniqueId="urn:wordinweb:smartart:style"><dgm:title val="WordInWeb"/><dgm:desc val="WordInWeb diagram style"/><dgm:catLst><dgm:cat type="simple" pri="1000"/></dgm:catLst><dgm:scene3d><a:camera prst="orthographicFront"/><a:lightRig rig="threePt" dir="t"/></dgm:scene3d><dgm:styleLbl name="node0"><dgm:scene3d><a:camera prst="orthographicFront"/><a:lightRig rig="threePt" dir="t"/></dgm:scene3d><dgm:sp3d/><dgm:txPr/><dgm:style><a:lnRef idx="2"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="1"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="0"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></dgm:style></dgm:styleLbl></dgm:styleDef>`;
@@ -5712,12 +5904,12 @@ function setSmartArtData(doc, drawing, input) {
5712
5904
  const dataRootXml = doc.pkg.text(dataRel.target);
5713
5905
  if (!dataRootXml) return false;
5714
5906
  const drawingRelId = attr(descendant2(parseXml(dataRootXml), "dataModelExt"), "relId");
5715
- const drawingRel = drawingRelId ? doc.documentRels.get(drawingRelId) : void 0;
5716
- if (!drawingRel || drawingRel.external) return false;
5907
+ const drawingPart = smartArtDrawingPart(doc, drawing);
5908
+ if (!drawingRelId || !drawingPart) return false;
5717
5909
  const data = normalizeSmartArtData(input);
5718
- doc.pkg.raw()[dataRel.target] = strToU8(buildSmartArtDataXml(data, drawingRel.id));
5910
+ doc.pkg.raw()[dataRel.target] = strToU8(buildSmartArtDataXml(data, drawingRelId));
5719
5911
  doc.pkg.raw()[layoutRel.target] = strToU8(buildSmartArtLayoutXml(data));
5720
- doc.pkg.raw()[drawingRel.target] = strToU8(buildSmartArtDrawingXml(data));
5912
+ doc.pkg.raw()[drawingPart] = strToU8(buildSmartArtDrawingXml(data));
5721
5913
  doc.markPackageResourceChanged();
5722
5914
  doc.refresh();
5723
5915
  return true;
@@ -14558,7 +14750,7 @@ var Engine = class {
14558
14750
  y1: by + l.y1,
14559
14751
  x2: bx + l.x2,
14560
14752
  y2: by + l.y2,
14561
- border: { style: "single", width: l.weight, color: l.color, space: 0 }
14753
+ border: { style: l.style ?? "single", width: l.weight, color: l.color, space: 0 }
14562
14754
  });
14563
14755
  }
14564
14756
  for (const pth of span.drawing.paths ?? []) {
@@ -14585,7 +14777,16 @@ var Engine = class {
14585
14777
  src: span.drawing.srcDrawing,
14586
14778
  anchored: false,
14587
14779
  belowText: true,
14588
- smartArt: !!span.drawing.smartArt
14780
+ smartArt: !!span.drawing.smartArt,
14781
+ smartArtNodes: span.drawing.smartArt ? (span.drawing.paths ?? []).flatMap((path2) => path2.smartArtNodeIndex === void 0 ? [] : [{
14782
+ index: path2.smartArtNodeIndex,
14783
+ x: path2.x,
14784
+ y: path2.y,
14785
+ width: path2.width,
14786
+ height: path2.height
14787
+ }]) : void 0,
14788
+ chartData: span.drawing.chart,
14789
+ smartArtData: span.drawing.smartArt
14589
14790
  });
14590
14791
  }
14591
14792
  for (const ts of span.drawing.texts ?? []) {
@@ -15061,7 +15262,7 @@ var Engine = class {
15061
15262
  const y1 = oy + l.y1 - fy;
15062
15263
  const x2 = ox + l.x2 - fx;
15063
15264
  const y2 = oy + l.y2 - fy;
15064
- page.items.push({ kind: "edge", x1, y1, x2, y2, border: { style: "single", width: l.weight, color: l.color, space: 0 }, ...rotate ? { rotate: rotate(Math.min(x1, x2), Math.min(y1, y2)) } : {}, ...shape.behind ? { behind: true } : { front: true }, z: shape.z });
15265
+ page.items.push({ kind: "edge", x1, y1, x2, y2, border: { style: l.style ?? "single", width: l.weight, color: l.color, space: 0 }, ...rotate ? { rotate: rotate(Math.min(x1, x2), Math.min(y1, y2)) } : {}, ...shape.behind ? { behind: true } : { front: true }, z: shape.z });
15065
15266
  }
15066
15267
  for (const img of shape.images) {
15067
15268
  const x = ox + img.x - fx;
@@ -18101,6 +18302,10 @@ function printPages(root, pageWidthPx, pageHeightPx) {
18101
18302
  @page { size: ${pageWidthPx / 96}in ${pageHeightPx / 96}in; margin: 0; }
18102
18303
  html, body { margin: 0; padding: 0; }
18103
18304
  .dxw-pages { display: block !important; padding: 0 !important; gap: 0 !important; }
18305
+ .dxw-pages, .dxw-pages * {
18306
+ -webkit-print-color-adjust: exact !important;
18307
+ print-color-adjust: exact !important;
18308
+ }
18104
18309
  .dxw-page { box-shadow: none !important; margin: 0 !important; break-after: page; }
18105
18310
  .dxw-comment-card, .dxw-hf-marker { display: none !important; }
18106
18311
  `;
@@ -18762,9 +18967,17 @@ function renderItem(doc, item, urls, interactive) {
18762
18967
  hit.dataset.dxwDrawing = "1";
18763
18968
  if (item.ink) hit.dataset.dxwInk = "1";
18764
18969
  if (item.smartArt) hit.dataset.dxwSmartArt = "1";
18765
- if (item.height < 12) {
18970
+ for (const node of item.smartArtNodes ?? []) {
18971
+ const nodeHit = document.createElement("div");
18972
+ nodeHit.dataset.dxwSmartArtNode = String(node.index);
18973
+ nodeHit.style.cssText = `position:absolute;left:${node.x}px;top:${node.y}px;width:${node.width}px;height:${node.height}px;cursor:move;`;
18974
+ hit.appendChild(nodeHit);
18975
+ }
18976
+ if (item.width < 12 || item.height < 12) {
18766
18977
  const target = document.createElement("div");
18767
- target.style.cssText = `position:absolute;left:0;top:${-(12 - item.height) / 2}px;width:100%;height:12px;cursor:move;`;
18978
+ const targetWidth = Math.max(item.width, 12);
18979
+ const targetHeight = Math.max(item.height, 12);
18980
+ target.style.cssText = `position:absolute;left:${-(targetWidth - item.width) / 2}px;top:${-(targetHeight - item.height) / 2}px;width:${targetWidth}px;height:${targetHeight}px;cursor:move;`;
18768
18981
  hit.appendChild(target);
18769
18982
  }
18770
18983
  return hit;
@@ -19481,6 +19694,8 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
19481
19694
  stroke.style.transformOrigin = "0 50%";
19482
19695
  if (border.style === "double") {
19483
19696
  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)`;
19697
+ } else if (border.style === "thinThickSmallGap") {
19698
+ stroke.style.background = `linear-gradient(180deg, ${border.color} 0 25%, transparent 25% 50%, ${border.color} 50% 100%)`;
19484
19699
  } else if (dashPattern) {
19485
19700
  const on = Math.max(dashPattern[0] * border.width, 2);
19486
19701
  const period = on + Math.max(dashPattern[1] * border.width, 1);
@@ -19505,6 +19720,9 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
19505
19720
  if (border.style === "double") {
19506
19721
  el16.style.height = `${w * 3}px`;
19507
19722
  el16.style.background = `linear-gradient(180deg, ${border.color} 0 ${w}px, transparent ${w}px ${w * 2}px, ${border.color} ${w * 2}px ${w * 3}px)`;
19723
+ } else if (border.style === "thinThickSmallGap") {
19724
+ el16.style.height = `${w}px`;
19725
+ el16.style.background = `linear-gradient(180deg, ${border.color} 0 25%, transparent 25% 50%, ${border.color} 50% 100%)`;
19508
19726
  } else if (dashPattern) {
19509
19727
  const on = Math.max(dashPattern[0] * border.width, 2);
19510
19728
  const period = on + Math.max(dashPattern[1] * border.width, 1);
@@ -19533,6 +19751,9 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
19533
19751
  if (border.style === "double") {
19534
19752
  el16.style.width = `${w * 3}px`;
19535
19753
  el16.style.background = `linear-gradient(90deg, ${border.color} 0 ${w}px, transparent ${w}px ${w * 2}px, ${border.color} ${w * 2}px ${w * 3}px)`;
19754
+ } else if (border.style === "thinThickSmallGap") {
19755
+ el16.style.width = `${w}px`;
19756
+ el16.style.background = `linear-gradient(90deg, ${border.color} 0 25%, transparent 25% 50%, ${border.color} 50% 100%)`;
19536
19757
  } else if (dashPattern) {
19537
19758
  const on = Math.max(dashPattern[0] * border.width, 2);
19538
19759
  const period = on + Math.max(dashPattern[1] * border.width, 1);
@@ -20318,6 +20539,13 @@ function cellContextOf(doc, target) {
20318
20539
  }
20319
20540
  return null;
20320
20541
  }
20542
+ function cellShadingAt(doc, target) {
20543
+ const ctx = cellContextOf(doc, target);
20544
+ if (!ctx) return void 0;
20545
+ const shd = child(child(ctx.tc, "tcPr"), "shd");
20546
+ const fill = shd ? attr(shd, "fill") : void 0;
20547
+ return fill && fill.toLowerCase() !== "auto" ? `#${fill.replace(/^#/, "").toUpperCase()}` : null;
20548
+ }
20321
20549
  function emptyCellLike(tc, w) {
20322
20550
  const tcPr = tc.children.find((c) => localName(c.name) === "tcPr");
20323
20551
  return {
@@ -20716,7 +20944,7 @@ function resizeTableRow(doc, tblEl, rowIdx, newHeightPx) {
20716
20944
  doc.refresh();
20717
20945
  return true;
20718
20946
  }
20719
- function moveTableTo(doc, tblEl, xPx, yPx, preservePageStart = false) {
20947
+ function moveTableTo(doc, tblEl, xPx, yPx, preservePageStart = false, pageDelta = 0) {
20720
20948
  if (localName(tblEl.name) !== "tbl") return false;
20721
20949
  const w = prefixOf5(tblEl);
20722
20950
  let tblPr = child(tblEl, "tblPr");
@@ -20725,31 +20953,54 @@ function moveTableTo(doc, tblEl, xPx, yPx, preservePageStart = false) {
20725
20953
  tblEl.children.unshift(tblPr);
20726
20954
  }
20727
20955
  let position = child(tblPr, "tblpPr");
20956
+ const wasInline = !position;
20728
20957
  if (!position) {
20729
- if (preservePageStart) {
20730
- const parent = doc.findParentOf(tblEl);
20731
- const tableIndex = parent?.children.indexOf(tblEl) ?? -1;
20732
- const previous = parent && tableIndex > 0 ? parent.children[tableIndex - 1] : void 0;
20733
- const breakRun = {
20958
+ position = { name: `${w}tblpPr`, attrs: {}, children: [], text: "" };
20959
+ const styleIdx = tblPr.children.findIndex((c) => localName(c.name) === "tblStyle");
20960
+ tblPr.children.splice(styleIdx + 1, 0, position);
20961
+ }
20962
+ let pageBreakAdjustment = pageDelta + (wasInline && preservePageStart ? 1 : 0);
20963
+ const parent = doc.findParentOf(tblEl);
20964
+ if (parent && pageBreakAdjustment > 0) {
20965
+ const tableIndex = parent.children.indexOf(tblEl);
20966
+ let previous = tableIndex > 0 ? parent.children[tableIndex - 1] : void 0;
20967
+ if (!previous || localName(previous.name) !== "p") {
20968
+ previous = { name: `${w}p`, attrs: {}, children: [], text: "" };
20969
+ parent.children.splice(tableIndex, 0, previous);
20970
+ }
20971
+ while (pageBreakAdjustment-- > 0) {
20972
+ previous.children.push({
20734
20973
  name: `${w}r`,
20735
20974
  attrs: {},
20736
20975
  children: [{ name: `${w}br`, attrs: { [`${w}type`]: "page" }, children: [], text: "" }],
20737
20976
  text: ""
20738
- };
20739
- if (previous && localName(previous.name) === "p") {
20740
- previous.children.push(breakRun);
20741
- } else if (parent && tableIndex >= 0) {
20742
- parent.children.splice(tableIndex, 0, {
20743
- name: `${w}p`,
20744
- attrs: {},
20745
- children: [breakRun],
20746
- text: ""
20747
- });
20977
+ });
20978
+ }
20979
+ } else if (parent && pageBreakAdjustment < 0) {
20980
+ while (pageBreakAdjustment++ < 0) {
20981
+ const tableIndex = parent.children.indexOf(tblEl);
20982
+ const previous = tableIndex > 0 ? parent.children[tableIndex - 1] : void 0;
20983
+ if (!previous || localName(previous.name) !== "p") break;
20984
+ let removed = false;
20985
+ for (let runIndex = previous.children.length - 1; runIndex >= 0 && !removed; runIndex--) {
20986
+ const run = previous.children[runIndex];
20987
+ if (localName(run.name) !== "r") continue;
20988
+ for (let childIndex = run.children.length - 1; childIndex >= 0; childIndex--) {
20989
+ const runChild = run.children[childIndex];
20990
+ if (localName(runChild.name) !== "br" || attr(runChild, "type") !== "page") continue;
20991
+ run.children.splice(childIndex, 1);
20992
+ if (!run.children.some((childEl) => localName(childEl.name) !== "rPr")) {
20993
+ previous.children.splice(runIndex, 1);
20994
+ }
20995
+ removed = true;
20996
+ break;
20997
+ }
20998
+ }
20999
+ if (!removed) break;
21000
+ if (!previous.children.some((childEl) => localName(childEl.name) !== "pPr")) {
21001
+ parent.children.splice(parent.children.indexOf(previous), 1);
20748
21002
  }
20749
21003
  }
20750
- position = { name: `${w}tblpPr`, attrs: {}, children: [], text: "" };
20751
- const styleIdx = tblPr.children.findIndex((c) => localName(c.name) === "tblStyle");
20752
- tblPr.children.splice(styleIdx + 1, 0, position);
20753
21004
  }
20754
21005
  const keyOf = (name) => Object.keys(position.attrs).find((key) => localName(key) === name);
20755
21006
  const set = (name, value) => {
@@ -20788,12 +21039,13 @@ function resizeDrawing(doc, drawingEl, widthPx, heightPx) {
20788
21039
  for (const childNode of node.children) findLineExtent(childNode);
20789
21040
  };
20790
21041
  findLineExtent(drawingEl);
21042
+ const keepVertical = lineExtent ? parseInt(lineExtent.attrs[Object.keys(lineExtent.attrs).find((key) => localName(key) === "cx") ?? "cx"] ?? "0", 10) === 0 : false;
20791
21043
  const keepHorizontal = lineExtent ? parseInt(lineExtent.attrs[Object.keys(lineExtent.attrs).find((key) => localName(key) === "cy") ?? "cy"] ?? "0", 10) === 0 : false;
20792
21044
  let touched = false;
20793
21045
  const setExt = (el16) => {
20794
21046
  const cxKey = Object.keys(el16.attrs).find((k) => localName(k) === "cx") ?? "cx";
20795
21047
  const cyKey = Object.keys(el16.attrs).find((k) => localName(k) === "cy") ?? "cy";
20796
- el16.attrs[cxKey] = cx;
21048
+ el16.attrs[cxKey] = el16 === lineExtent && keepVertical ? "0" : cx;
20797
21049
  el16.attrs[cyKey] = el16 === lineExtent && keepHorizontal ? "0" : cy;
20798
21050
  touched = true;
20799
21051
  };
@@ -21141,6 +21393,10 @@ function insertBlankPageAt(doc, t, offset) {
21141
21393
  if (ordinaryPPr) {
21142
21394
  ordinaryPPr.children = ordinaryPPr.children.filter((c) => localName(c.name) !== "sectPr");
21143
21395
  }
21396
+ const blankPPr = ordinaryPPr ? cloneDeep(ordinaryPPr) : null;
21397
+ if (blankPPr) {
21398
+ blankPPr.children = blankPPr.children.filter((c) => localName(c.name) !== "numPr");
21399
+ }
21144
21400
  const headBefore = pEl.children.slice(0, runIndex).filter((c) => localName(c.name) !== "pPr");
21145
21401
  const tailAfter = pEl.children.slice(runIndex + 1).filter((c) => localName(c.name) !== "pPr");
21146
21402
  pEl.children = [
@@ -21154,7 +21410,7 @@ function insertBlankPageAt(doc, t, offset) {
21154
21410
  el4(`${rw}t`, { "xml:space": "preserve" }, [], "")
21155
21411
  ]);
21156
21412
  const blank = el4(pEl.name, { ...pEl.attrs }, [
21157
- ...ordinaryPPr ? [cloneDeep(ordinaryPPr)] : [],
21413
+ ...blankPPr ? [blankPPr] : [],
21158
21414
  anchorRun,
21159
21415
  breakRun()
21160
21416
  ]);
@@ -21789,19 +22045,21 @@ function insertShapeAt(doc, caretT, preset, text = "") {
21789
22045
  if (!caretRun || !parent || localName(caretRun.name) !== "r") return null;
21790
22046
  const w = prefixOf8(caretRun);
21791
22047
  const id = String(doc.nextDrawingId());
21792
- const isLine = preset === "line";
21793
- const width = isLine ? 240 : preset === "textBox" ? 240 : 192;
21794
- const height = isLine ? 2 : preset === "textBox" ? 72 : 96;
22048
+ const isLine = preset === "line" || preset === "verticalLine";
22049
+ const isVerticalLine = preset === "verticalLine";
22050
+ const width = isVerticalLine ? 2 : isLine ? 240 : preset === "textBox" ? 240 : 192;
22051
+ const height = isVerticalLine ? 240 : isLine ? 2 : preset === "textBox" ? 72 : 96;
21795
22052
  const cx = String(Math.round(width * EMU_PER_PX4));
21796
22053
  const cy = String(Math.round(height * EMU_PER_PX4));
21797
- const shapeCy = isLine ? "0" : cy;
21798
- const geometry = preset === "roundedRectangle" ? "roundRect" : preset === "rectangle" || preset === "textBox" ? "rect" : preset;
22054
+ const shapeCx = isVerticalLine ? "0" : cx;
22055
+ const shapeCy = isLine && !isVerticalLine ? "0" : cy;
22056
+ const geometry = isLine ? "line" : preset === "roundedRectangle" ? "roundRect" : preset === "rectangle" || preset === "textBox" ? "rect" : preset;
21799
22057
  const isTextBox = preset === "textBox";
21800
22058
  const shapeName = isLine ? `Line ${id}` : isTextBox ? `Text Box ${id}` : `Shape ${id}`;
21801
22059
  const spPr = [
21802
22060
  el6("a:xfrm", {}, [
21803
22061
  el6("a:off", { x: "0", y: "0" }),
21804
- el6("a:ext", { cx, cy: shapeCy })
22062
+ el6("a:ext", { cx: shapeCx, cy: shapeCy })
21805
22063
  ]),
21806
22064
  el6("a:prstGeom", { prst: geometry }, [el6("a:avLst")]),
21807
22065
  isTextBox || isLine ? el6("a:noFill") : el6("a:solidFill", {}, [el6("a:srgbClr", { val: "4472C4" })]),
@@ -21922,10 +22180,12 @@ function drawingLineStyle(drawing) {
21922
22180
  const spPr = descendant3(drawing, "spPr");
21923
22181
  if (!spPr) return null;
21924
22182
  const line2 = descendant3(drawing, "ln");
21925
- if (!line2) return { color: "#000000", width: 0.75 };
22183
+ if (!line2) return { color: "#000000", width: 0.75, dash: "solid" };
21926
22184
  const color = descendant3(line2, "srgbClr")?.attrs.val ?? "000000";
21927
22185
  const width = Math.max((parseInt(line2.attrs.w ?? "0", 10) || 0) / EMU_PER_PX4, 0.75);
21928
- return { color: `#${color.toUpperCase()}`, width };
22186
+ const dashValue = line2.children.find((child4) => localName(child4.name) === "prstDash")?.attrs.val;
22187
+ const dash = dashValue === "dot" || dashValue === "sysDot" ? "dotted" : dashValue && dashValue !== "solid" ? "dashed" : "solid";
22188
+ return { color: `#${color.toUpperCase()}`, width, dash };
21929
22189
  }
21930
22190
  function drawingFillColor(drawing) {
21931
22191
  const spPr = descendant3(drawing, "spPr");
@@ -21947,7 +22207,7 @@ function setDrawingFill(doc, drawing, color) {
21947
22207
  doc.refresh();
21948
22208
  return true;
21949
22209
  }
21950
- function setDrawingLineStyle(doc, drawing, color, widthPx) {
22210
+ function setDrawingLineStyle(doc, drawing, color, widthPx, dash = "solid") {
21951
22211
  const spPr = descendant3(drawing, "spPr");
21952
22212
  if (!spPr) return false;
21953
22213
  let line2 = spPr.children.find((child4) => localName(child4.name) === "ln");
@@ -21958,9 +22218,10 @@ function setDrawingLineStyle(doc, drawing, color, widthPx) {
21958
22218
  line2.attrs.w = String(Math.max(1, Math.round(widthPx * EMU_PER_PX4)));
21959
22219
  line2.children = line2.children.filter((child4) => {
21960
22220
  const name = localName(child4.name);
21961
- return name !== "solidFill" && name !== "noFill";
22221
+ return name !== "solidFill" && name !== "noFill" && name !== "prstDash";
21962
22222
  });
21963
22223
  line2.children.unshift(el6("a:solidFill", {}, [el6("a:srgbClr", { val: color.replace(/^#/, "").toUpperCase() })]));
22224
+ line2.children.splice(1, 0, el6("a:prstDash", { val: dash === "dotted" ? "dot" : dash === "dashed" ? "dash" : "solid" }));
21964
22225
  doc.refresh();
21965
22226
  return true;
21966
22227
  }
@@ -22421,6 +22682,12 @@ function requestTextInputDialog(anchor, options) {
22421
22682
  label.textContent = options.label ?? options.title;
22422
22683
  label.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
22423
22684
  const field = options.multiline ? doc.createElement("textarea") : doc.createElement("input");
22685
+ if (field instanceof HTMLInputElement) {
22686
+ field.type = options.inputType ?? "text";
22687
+ if (options.min !== void 0) field.min = String(options.min);
22688
+ if (options.max !== void 0) field.max = String(options.max);
22689
+ if (options.step !== void 0) field.step = String(options.step);
22690
+ }
22424
22691
  field.className = "dxw-input-dialog-field";
22425
22692
  field.value = options.value ?? "";
22426
22693
  field.placeholder = options.placeholder ?? "";
@@ -22476,42 +22743,446 @@ function requestTextInputDialog(anchor, options) {
22476
22743
  });
22477
22744
  });
22478
22745
  }
22479
-
22480
- // ../core/src/edit/objects.ts
22481
- var EMU_PER_PX6 = 9525;
22482
- var NS_WP5 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
22483
- var NS_A4 = "http://schemas.openxmlformats.org/drawingml/2006/main";
22484
- var NS_PIC2 = "http://schemas.openxmlformats.org/drawingml/2006/picture";
22485
- var NS_R3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
22486
- var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
22487
- var NS_AM3D = "http://schemas.microsoft.com/office/drawing/2017/model3d";
22488
- var NS_WP15 = "http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing";
22489
- function el8(name, attrs = {}, children2 = [], text = "") {
22490
- return { name, attrs, children: children2, text };
22491
- }
22492
- function prefixOf9(node) {
22493
- return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
22746
+ function requestNumberPairDialog(anchor, options) {
22747
+ const doc = anchor.ownerDocument;
22748
+ const win = doc.defaultView;
22749
+ return new Promise((resolve) => {
22750
+ const id = `dxw-number-pair-dialog-${++dialogSequence}`;
22751
+ const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
22752
+ const backdrop = doc.createElement("div");
22753
+ backdrop.className = "dxw-input-dialog-backdrop";
22754
+ backdrop.dataset.dxwNumberPairDialog = "";
22755
+ backdrop.style.cssText = "position:fixed;inset:0;z-index:var(--dxw-dialog-z-index,1000);display:grid;place-items:center;padding:16px;box-sizing:border-box;background:var(--dxw-dialog-backdrop,rgba(32,33,36,.38));";
22756
+ if (win) {
22757
+ const computed = win.getComputedStyle(anchor);
22758
+ for (const property of [
22759
+ "--dxw-toolbar-fg",
22760
+ "--dxw-toolbar-border",
22761
+ "--dxw-toolbar-muted",
22762
+ "--dxw-accent",
22763
+ "--dxw-accent-fg",
22764
+ "--dxw-popover-bg",
22765
+ "--dxw-popover-shadow",
22766
+ "--dxw-dialog-backdrop",
22767
+ "--dxw-dialog-z-index",
22768
+ "--dxw-dialog-width",
22769
+ "--dxw-dialog-radius",
22770
+ "--dxw-dialog-field-bg"
22771
+ ]) {
22772
+ const token = computed.getPropertyValue(property);
22773
+ if (token) backdrop.style.setProperty(property, token);
22774
+ }
22775
+ }
22776
+ const form = doc.createElement("form");
22777
+ form.className = "dxw-input-dialog dxw-number-pair-dialog";
22778
+ form.setAttribute("role", "dialog");
22779
+ form.setAttribute("aria-modal", "true");
22780
+ form.setAttribute("aria-labelledby", id);
22781
+ form.style.cssText = "width:min(var(--dxw-dialog-width,420px),calc(100vw - 32px));box-sizing:border-box;display:grid;gap:12px;padding:16px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:var(--dxw-dialog-radius,10px);color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);box-shadow:var(--dxw-popover-shadow,0 8px 28px rgba(0,0,0,.24));font:13px system-ui,sans-serif;";
22782
+ const title = doc.createElement("strong");
22783
+ title.id = id;
22784
+ title.textContent = options.title;
22785
+ title.style.cssText = "font-size:15px;line-height:1.35;";
22786
+ form.appendChild(title);
22787
+ const fields = doc.createElement("div");
22788
+ fields.style.cssText = "display:grid;grid-template-columns:1fr 1fr;gap:10px;";
22789
+ const makeField = (labelText, value) => {
22790
+ const label = doc.createElement("label");
22791
+ label.textContent = labelText;
22792
+ label.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
22793
+ const input = doc.createElement("input");
22794
+ input.type = "number";
22795
+ input.required = true;
22796
+ input.value = String(value);
22797
+ if (options.min !== void 0) input.min = String(options.min);
22798
+ if (options.step !== void 0) input.step = String(options.step);
22799
+ input.setAttribute("aria-label", labelText);
22800
+ input.style.cssText = "width:100%;min-height:34px;box-sizing:border-box;padding:7px 9px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:6px;outline:none;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-dialog-field-bg,var(--dxw-popover-bg,#fff));font:13px system-ui,sans-serif;";
22801
+ label.appendChild(input);
22802
+ fields.appendChild(label);
22803
+ return input;
22804
+ };
22805
+ const first = makeField(options.firstLabel, options.value.first);
22806
+ const second = makeField(options.secondLabel, options.value.second);
22807
+ form.appendChild(fields);
22808
+ const actions = doc.createElement("div");
22809
+ actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
22810
+ const cancel = doc.createElement("button");
22811
+ cancel.type = "button";
22812
+ cancel.textContent = "Cancel";
22813
+ cancel.style.cssText = "min-height:32px;padding:0 12px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:7px;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);cursor:pointer;font:600 12px system-ui,sans-serif;";
22814
+ const submit = doc.createElement("button");
22815
+ submit.type = "submit";
22816
+ submit.textContent = "Apply";
22817
+ submit.style.cssText = "min-height:32px;padding:0 14px;border:1px solid transparent;border-radius:7px;color:var(--dxw-accent-fg,#fff);background:var(--dxw-accent,#1a73e8);cursor:pointer;font:600 12px system-ui,sans-serif;";
22818
+ actions.append(cancel, submit);
22819
+ form.appendChild(actions);
22820
+ backdrop.appendChild(form);
22821
+ doc.body.appendChild(backdrop);
22822
+ let finished = false;
22823
+ const finish = (value) => {
22824
+ if (finished) return;
22825
+ finished = true;
22826
+ doc.removeEventListener("keydown", onKeyDown, true);
22827
+ backdrop.remove();
22828
+ previousFocus?.focus({ preventScroll: true });
22829
+ resolve(value);
22830
+ };
22831
+ const onKeyDown = (event) => {
22832
+ if (event.key === "Escape") {
22833
+ event.preventDefault();
22834
+ finish(null);
22835
+ }
22836
+ };
22837
+ doc.addEventListener("keydown", onKeyDown, true);
22838
+ backdrop.addEventListener("mousedown", (event) => {
22839
+ if (event.target === backdrop) finish(null);
22840
+ });
22841
+ cancel.addEventListener("click", () => finish(null));
22842
+ form.addEventListener("submit", (event) => {
22843
+ event.preventDefault();
22844
+ const firstValue = Number(first.value);
22845
+ const secondValue = Number(second.value);
22846
+ if (!Number.isFinite(firstValue) || !Number.isFinite(secondValue)) {
22847
+ form.reportValidity();
22848
+ return;
22849
+ }
22850
+ finish({ first: firstValue, second: secondValue });
22851
+ });
22852
+ requestAnimationFrame(() => {
22853
+ first.focus({ preventScroll: true });
22854
+ first.select();
22855
+ });
22856
+ });
22494
22857
  }
22495
- function insertAfterCaretRun(doc, caretT, content) {
22496
- const caretRun = doc.findParentOf(caretT);
22497
- const parent = caretRun && doc.findParentOf(caretRun);
22498
- if (!caretRun || !parent || localName(caretRun.name) !== "r") return false;
22499
- const w = prefixOf9(caretRun);
22500
- parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el8(`${w}r`, {}, [content]));
22501
- doc.refresh();
22502
- return true;
22858
+ function requestColorDialog(anchor, options) {
22859
+ const doc = anchor.ownerDocument;
22860
+ const win = doc.defaultView;
22861
+ return new Promise((resolve) => {
22862
+ const id = `dxw-color-dialog-${++dialogSequence}`;
22863
+ const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
22864
+ const backdrop = doc.createElement("div");
22865
+ backdrop.className = "dxw-input-dialog-backdrop";
22866
+ backdrop.dataset.dxwColorDialog = "";
22867
+ backdrop.style.cssText = "position:fixed;inset:0;z-index:var(--dxw-dialog-z-index,1000);display:grid;place-items:center;padding:16px;box-sizing:border-box;background:var(--dxw-dialog-backdrop,rgba(32,33,36,.38));";
22868
+ if (win) {
22869
+ const computed = win.getComputedStyle(anchor);
22870
+ for (const property of [
22871
+ "--dxw-toolbar-fg",
22872
+ "--dxw-toolbar-border",
22873
+ "--dxw-toolbar-muted",
22874
+ "--dxw-accent",
22875
+ "--dxw-accent-fg",
22876
+ "--dxw-popover-bg",
22877
+ "--dxw-popover-shadow",
22878
+ "--dxw-dialog-backdrop",
22879
+ "--dxw-dialog-z-index",
22880
+ "--dxw-dialog-width",
22881
+ "--dxw-dialog-radius",
22882
+ "--dxw-dialog-field-bg"
22883
+ ]) {
22884
+ const token = computed.getPropertyValue(property);
22885
+ if (token) backdrop.style.setProperty(property, token);
22886
+ }
22887
+ }
22888
+ const form = doc.createElement("form");
22889
+ form.className = "dxw-input-dialog dxw-color-dialog";
22890
+ form.setAttribute("role", "dialog");
22891
+ form.setAttribute("aria-modal", "true");
22892
+ form.setAttribute("aria-labelledby", id);
22893
+ form.style.cssText = "width:min(var(--dxw-dialog-width,420px),calc(100vw - 32px));box-sizing:border-box;display:grid;gap:12px;padding:16px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:var(--dxw-dialog-radius,10px);color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);box-shadow:var(--dxw-popover-shadow,0 8px 28px rgba(0,0,0,.24));font:13px system-ui,sans-serif;";
22894
+ const title = doc.createElement("strong");
22895
+ title.id = id;
22896
+ title.textContent = options.title;
22897
+ title.style.cssText = "font-size:15px;line-height:1.35;";
22898
+ form.appendChild(title);
22899
+ const initial = /^#?([0-9a-f]{6})$/i.exec(options.value ?? "")?.[1] ?? "4472C4";
22900
+ const colorLabel = doc.createElement("label");
22901
+ colorLabel.textContent = "Color";
22902
+ colorLabel.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
22903
+ const colorRow = doc.createElement("span");
22904
+ colorRow.style.cssText = "display:grid;grid-template-columns:42px 1fr;gap:7px;";
22905
+ const picker = doc.createElement("input");
22906
+ picker.type = "color";
22907
+ picker.value = `#${initial}`;
22908
+ picker.setAttribute("aria-label", `${options.title} color picker`);
22909
+ picker.style.cssText = "width:42px;height:34px;box-sizing:border-box;padding:2px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:6px;background:var(--dxw-dialog-field-bg,var(--dxw-popover-bg,#fff));";
22910
+ const field = doc.createElement("input");
22911
+ field.type = "text";
22912
+ field.value = `#${initial.toUpperCase()}`;
22913
+ field.required = true;
22914
+ field.pattern = "#?[0-9a-fA-F]{6}";
22915
+ field.setAttribute("aria-label", `${options.title} color`);
22916
+ field.style.cssText = "width:100%;min-height:34px;box-sizing:border-box;padding:7px 9px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:6px;outline:none;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-dialog-field-bg,var(--dxw-popover-bg,#fff));font:13px system-ui,sans-serif;";
22917
+ let noFill = null;
22918
+ picker.addEventListener("input", () => {
22919
+ field.value = picker.value.toUpperCase();
22920
+ if (noFill) noFill.checked = false;
22921
+ });
22922
+ field.addEventListener("input", () => {
22923
+ if (noFill) noFill.checked = false;
22924
+ const match = /^#?([0-9a-f]{6})$/i.exec(field.value.trim());
22925
+ if (match) picker.value = `#${match[1]}`;
22926
+ });
22927
+ colorRow.append(picker, field);
22928
+ colorLabel.appendChild(colorRow);
22929
+ form.appendChild(colorLabel);
22930
+ if (options.allowNone) {
22931
+ const noneLabel = doc.createElement("label");
22932
+ noneLabel.style.cssText = "display:flex;align-items:center;gap:7px;color:var(--dxw-toolbar-fg,#3c4043);font-size:12px;";
22933
+ noFill = doc.createElement("input");
22934
+ noFill.type = "checkbox";
22935
+ noFill.checked = options.value === null;
22936
+ noFill.setAttribute("aria-label", "No fill");
22937
+ noneLabel.append(noFill, doc.createTextNode("No fill"));
22938
+ form.appendChild(noneLabel);
22939
+ }
22940
+ const actions = doc.createElement("div");
22941
+ actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
22942
+ const cancel = doc.createElement("button");
22943
+ cancel.type = "button";
22944
+ cancel.textContent = "Cancel";
22945
+ cancel.style.cssText = "min-height:32px;padding:0 12px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:7px;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);cursor:pointer;font:600 12px system-ui,sans-serif;";
22946
+ const submit = doc.createElement("button");
22947
+ submit.type = "submit";
22948
+ submit.textContent = "Apply";
22949
+ submit.style.cssText = "min-height:32px;padding:0 14px;border:1px solid transparent;border-radius:7px;color:var(--dxw-accent-fg,#fff);background:var(--dxw-accent,#1a73e8);cursor:pointer;font:600 12px system-ui,sans-serif;";
22950
+ actions.append(cancel, submit);
22951
+ form.appendChild(actions);
22952
+ backdrop.appendChild(form);
22953
+ doc.body.appendChild(backdrop);
22954
+ let finished = false;
22955
+ const finish = (value) => {
22956
+ if (finished) return;
22957
+ finished = true;
22958
+ doc.removeEventListener("keydown", onKeyDown, true);
22959
+ backdrop.remove();
22960
+ previousFocus?.focus({ preventScroll: true });
22961
+ resolve(value);
22962
+ };
22963
+ const onKeyDown = (event) => {
22964
+ if (event.key === "Escape") {
22965
+ event.preventDefault();
22966
+ finish(void 0);
22967
+ }
22968
+ };
22969
+ doc.addEventListener("keydown", onKeyDown, true);
22970
+ backdrop.addEventListener("mousedown", (event) => {
22971
+ if (event.target === backdrop) finish(void 0);
22972
+ });
22973
+ cancel.addEventListener("click", () => finish(void 0));
22974
+ form.addEventListener("submit", (event) => {
22975
+ event.preventDefault();
22976
+ if (noFill?.checked) {
22977
+ finish(null);
22978
+ return;
22979
+ }
22980
+ const color = /^#?([0-9a-f]{6})$/i.exec(field.value.trim());
22981
+ if (!color) {
22982
+ form.reportValidity();
22983
+ return;
22984
+ }
22985
+ finish(`#${color[1].toUpperCase()}`);
22986
+ });
22987
+ requestAnimationFrame(() => {
22988
+ (noFill?.checked ? noFill : field).focus({ preventScroll: true });
22989
+ if (!noFill?.checked) field.select();
22990
+ });
22991
+ });
22503
22992
  }
22504
- function pictureGraphic(relId, id, cx, cy, webVideo) {
22505
- const blipChildren = webVideo ? [
22506
- el8("a:extLst", {}, [
22507
- el8("a:ext", { uri: "{9E29B28B-C9C2-4B96-BA92-6C9A3D8F4A6A}" }, [
22508
- el8("wp15:webVideoPr", {
22509
- "xmlns:wp15": NS_WP15,
22510
- embeddedHtml: webVideo,
22511
- w: "640",
22512
- h: "360"
22513
- })
22514
- ])
22993
+ function requestLineStyleDialog(anchor, value, titleText = "Line style") {
22994
+ const doc = anchor.ownerDocument;
22995
+ const win = doc.defaultView;
22996
+ return new Promise((resolve) => {
22997
+ const fieldName = titleText === "Outline" ? "Outline" : "Line";
22998
+ const id = `dxw-line-style-dialog-${++dialogSequence}`;
22999
+ const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
23000
+ const backdrop = doc.createElement("div");
23001
+ backdrop.className = "dxw-input-dialog-backdrop";
23002
+ backdrop.dataset.dxwLineStyleDialog = "";
23003
+ backdrop.style.cssText = "position:fixed;inset:0;z-index:var(--dxw-dialog-z-index,1000);display:grid;place-items:center;padding:16px;box-sizing:border-box;background:var(--dxw-dialog-backdrop,rgba(32,33,36,.38));";
23004
+ if (win) {
23005
+ const computed = win.getComputedStyle(anchor);
23006
+ for (const property of [
23007
+ "--dxw-toolbar-fg",
23008
+ "--dxw-toolbar-border",
23009
+ "--dxw-toolbar-muted",
23010
+ "--dxw-accent",
23011
+ "--dxw-accent-fg",
23012
+ "--dxw-popover-bg",
23013
+ "--dxw-popover-shadow",
23014
+ "--dxw-dialog-backdrop",
23015
+ "--dxw-dialog-z-index",
23016
+ "--dxw-dialog-width",
23017
+ "--dxw-dialog-radius",
23018
+ "--dxw-dialog-field-bg"
23019
+ ]) {
23020
+ const token = computed.getPropertyValue(property);
23021
+ if (token) backdrop.style.setProperty(property, token);
23022
+ }
23023
+ }
23024
+ const form = doc.createElement("form");
23025
+ form.className = "dxw-input-dialog dxw-line-style-dialog";
23026
+ form.setAttribute("role", "dialog");
23027
+ form.setAttribute("aria-modal", "true");
23028
+ form.setAttribute("aria-labelledby", id);
23029
+ form.style.cssText = "width:min(var(--dxw-dialog-width,420px),calc(100vw - 32px));box-sizing:border-box;display:grid;gap:12px;padding:16px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:var(--dxw-dialog-radius,10px);color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);box-shadow:var(--dxw-popover-shadow,0 8px 28px rgba(0,0,0,.24));font:13px system-ui,sans-serif;";
23030
+ const title = doc.createElement("strong");
23031
+ title.id = id;
23032
+ title.className = "dxw-input-dialog-title";
23033
+ title.textContent = titleText;
23034
+ title.style.cssText = "font-size:15px;line-height:1.35;";
23035
+ form.appendChild(title);
23036
+ const fieldStyle = "width:100%;min-height:34px;box-sizing:border-box;padding:7px 9px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:6px;outline:none;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-dialog-field-bg,var(--dxw-popover-bg,#fff));font:13px system-ui,sans-serif;";
23037
+ const labelStyle = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
23038
+ const colorLabel = doc.createElement("label");
23039
+ colorLabel.textContent = "Color";
23040
+ colorLabel.style.cssText = labelStyle;
23041
+ const colorRow = doc.createElement("span");
23042
+ colorRow.style.cssText = "display:grid;grid-template-columns:42px 1fr;gap:7px;";
23043
+ const colorPicker = doc.createElement("input");
23044
+ colorPicker.type = "color";
23045
+ colorPicker.value = value.color;
23046
+ colorPicker.setAttribute("aria-label", `${fieldName} color picker`);
23047
+ colorPicker.style.cssText = "width:42px;height:34px;box-sizing:border-box;padding:2px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:6px;background:var(--dxw-dialog-field-bg,var(--dxw-popover-bg,#fff));";
23048
+ const colorField = doc.createElement("input");
23049
+ colorField.type = "text";
23050
+ colorField.value = value.color.toUpperCase();
23051
+ colorField.required = true;
23052
+ colorField.pattern = "#?[0-9a-fA-F]{6}";
23053
+ colorField.setAttribute("aria-label", `${fieldName} color`);
23054
+ colorField.style.cssText = fieldStyle;
23055
+ colorPicker.addEventListener("input", () => {
23056
+ colorField.value = colorPicker.value.toUpperCase();
23057
+ });
23058
+ colorField.addEventListener("input", () => {
23059
+ const match = /^#?([0-9a-f]{6})$/i.exec(colorField.value.trim());
23060
+ if (match) colorPicker.value = `#${match[1]}`;
23061
+ });
23062
+ colorRow.append(colorPicker, colorField);
23063
+ colorLabel.appendChild(colorRow);
23064
+ form.appendChild(colorLabel);
23065
+ const widthLabel = doc.createElement("label");
23066
+ widthLabel.textContent = "Width (pixels)";
23067
+ widthLabel.style.cssText = labelStyle;
23068
+ const widthField = doc.createElement("input");
23069
+ widthField.type = "number";
23070
+ widthField.min = "0.25";
23071
+ widthField.step = "any";
23072
+ widthField.required = true;
23073
+ widthField.value = String(Number(value.width.toFixed(2)));
23074
+ widthField.setAttribute("aria-label", `${fieldName} width in pixels`);
23075
+ widthField.style.cssText = fieldStyle;
23076
+ widthLabel.appendChild(widthField);
23077
+ form.appendChild(widthLabel);
23078
+ const styleLabel = doc.createElement("label");
23079
+ styleLabel.textContent = "Style";
23080
+ styleLabel.style.cssText = labelStyle;
23081
+ const styleField = doc.createElement("select");
23082
+ styleField.setAttribute("aria-label", `${fieldName} style`);
23083
+ styleField.style.cssText = fieldStyle;
23084
+ for (const [style, label] of [["solid", "Solid"], ["dashed", "Dashed"], ["dotted", "Dotted"]]) {
23085
+ const option = doc.createElement("option");
23086
+ option.value = style;
23087
+ option.textContent = label;
23088
+ option.selected = value.style === style;
23089
+ styleField.appendChild(option);
23090
+ }
23091
+ styleLabel.appendChild(styleField);
23092
+ form.appendChild(styleLabel);
23093
+ const actions = doc.createElement("div");
23094
+ actions.className = "dxw-input-dialog-actions";
23095
+ actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
23096
+ const cancel = doc.createElement("button");
23097
+ cancel.type = "button";
23098
+ cancel.className = "dxw-input-dialog-cancel";
23099
+ cancel.textContent = "Cancel";
23100
+ cancel.style.cssText = "min-height:32px;padding:0 12px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:7px;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);cursor:pointer;font:600 12px system-ui,sans-serif;";
23101
+ const submit = doc.createElement("button");
23102
+ submit.type = "submit";
23103
+ submit.className = "dxw-input-dialog-submit";
23104
+ submit.textContent = "Apply";
23105
+ submit.style.cssText = "min-height:32px;padding:0 14px;border:1px solid transparent;border-radius:7px;color:var(--dxw-accent-fg,#fff);background:var(--dxw-accent,#1a73e8);cursor:pointer;font:600 12px system-ui,sans-serif;";
23106
+ actions.append(cancel, submit);
23107
+ form.appendChild(actions);
23108
+ backdrop.appendChild(form);
23109
+ doc.body.appendChild(backdrop);
23110
+ let finished = false;
23111
+ const finish = (result) => {
23112
+ if (finished) return;
23113
+ finished = true;
23114
+ doc.removeEventListener("keydown", onKeyDown, true);
23115
+ backdrop.remove();
23116
+ previousFocus?.focus({ preventScroll: true });
23117
+ resolve(result);
23118
+ };
23119
+ const onKeyDown = (event) => {
23120
+ if (event.key === "Escape") {
23121
+ event.preventDefault();
23122
+ finish(null);
23123
+ }
23124
+ };
23125
+ doc.addEventListener("keydown", onKeyDown, true);
23126
+ backdrop.addEventListener("mousedown", (event) => {
23127
+ if (event.target === backdrop) finish(null);
23128
+ });
23129
+ cancel.addEventListener("click", () => finish(null));
23130
+ form.addEventListener("submit", (event) => {
23131
+ event.preventDefault();
23132
+ const color = /^#?([0-9a-f]{6})$/i.exec(colorField.value.trim());
23133
+ const width = Number(widthField.value);
23134
+ if (!color || !Number.isFinite(width) || width <= 0) {
23135
+ form.reportValidity();
23136
+ return;
23137
+ }
23138
+ finish({
23139
+ color: `#${color[1].toUpperCase()}`,
23140
+ width,
23141
+ style: styleField.value
23142
+ });
23143
+ });
23144
+ requestAnimationFrame(() => {
23145
+ colorField.focus({ preventScroll: true });
23146
+ colorField.select();
23147
+ });
23148
+ });
23149
+ }
23150
+
23151
+ // ../core/src/edit/objects.ts
23152
+ var EMU_PER_PX6 = 9525;
23153
+ var NS_WP5 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
23154
+ var NS_A4 = "http://schemas.openxmlformats.org/drawingml/2006/main";
23155
+ var NS_PIC2 = "http://schemas.openxmlformats.org/drawingml/2006/picture";
23156
+ var NS_R3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
23157
+ var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
23158
+ var NS_AM3D = "http://schemas.microsoft.com/office/drawing/2017/model3d";
23159
+ var NS_WP15 = "http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing";
23160
+ function el8(name, attrs = {}, children2 = [], text = "") {
23161
+ return { name, attrs, children: children2, text };
23162
+ }
23163
+ function prefixOf9(node) {
23164
+ return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
23165
+ }
23166
+ function insertAfterCaretRun(doc, caretT, content) {
23167
+ const caretRun = doc.findParentOf(caretT);
23168
+ const parent = caretRun && doc.findParentOf(caretRun);
23169
+ if (!caretRun || !parent || localName(caretRun.name) !== "r") return false;
23170
+ const w = prefixOf9(caretRun);
23171
+ parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el8(`${w}r`, {}, [content]));
23172
+ doc.refresh();
23173
+ return true;
23174
+ }
23175
+ function pictureGraphic(relId, id, cx, cy, webVideo) {
23176
+ const blipChildren = webVideo ? [
23177
+ el8("a:extLst", {}, [
23178
+ el8("a:ext", { uri: "{9E29B28B-C9C2-4B96-BA92-6C9A3D8F4A6A}" }, [
23179
+ el8("wp15:webVideoPr", {
23180
+ "xmlns:wp15": NS_WP15,
23181
+ embeddedHtml: webVideo,
23182
+ w: "640",
23183
+ h: "360"
23184
+ })
23185
+ ])
22515
23186
  ])
22516
23187
  ] : [];
22517
23188
  return el8("a:graphic", { "xmlns:a": NS_A4 }, [
@@ -23375,6 +24046,19 @@ function textElements(el16) {
23375
24046
  walk2(el16);
23376
24047
  return out;
23377
24048
  }
24049
+ function clearListParagraphFormatting(doc, paragraph) {
24050
+ const pPr = paragraph.children.find((child4) => localName(child4.name) === "pPr");
24051
+ if (!pPr) return false;
24052
+ const style = pPr.children.find((child4) => localName(child4.name) === "pStyle");
24053
+ const styleHasNumbering = !!resolveParagraphStyleChain(doc.styles, attr(style, "val"), false).pPr.numbering;
24054
+ const hasDirectNumbering = pPr.children.some((child4) => localName(child4.name) === "numPr");
24055
+ if (!hasDirectNumbering && !styleHasNumbering) return false;
24056
+ pPr.children = pPr.children.filter((child4) => {
24057
+ const name = localName(child4.name);
24058
+ return name !== "numPr" && !(name === "pStyle" && styleHasNumbering);
24059
+ });
24060
+ return true;
24061
+ }
23378
24062
  function emptyParagraphLike(el16) {
23379
24063
  const prefix = el16.name.includes(":") ? el16.name.slice(0, el16.name.indexOf(":") + 1) : "";
23380
24064
  const text = {
@@ -23546,6 +24230,7 @@ var _DocxEditor = class _DocxEditor {
23546
24230
  this.onGripMouseDown = (e) => {
23547
24231
  const target = e.target;
23548
24232
  if (this.wordArtTextEditor?.input.contains(target)) return;
24233
+ if (this.smartArtTextEditor?.input.contains(target)) return;
23549
24234
  if (this.startInkGroupInteraction(e, target)) return;
23550
24235
  if (this.startInkInteraction(e, target)) return;
23551
24236
  if (this.startCheckboxInteraction(e, target)) return;
@@ -23595,39 +24280,102 @@ var _DocxEditor = class _DocxEditor {
23595
24280
  const zoom = this.host.zoom ?? 1;
23596
24281
  const startX = e.clientX;
23597
24282
  const startY = e.clientY;
24283
+ const pages = Array.from(handle?.root.querySelectorAll(".dxw-page") ?? []);
24284
+ const sourcePage = surface.parentElement;
24285
+ const sourcePageIndex = sourcePage ? pages.indexOf(sourcePage) : -1;
24286
+ const sourceRect = surface.getBoundingClientRect();
24287
+ const pointerOffsetX = (startX - sourceRect.left) / zoom - grip.item.x;
24288
+ const pointerOffsetY = (startY - sourceRect.top) / zoom - grip.item.y1;
23598
24289
  let dx = 0;
23599
24290
  let dy = 0;
23600
- const onMove = (me) => {
23601
- dx = (me.clientX - startX) / zoom;
23602
- dy = (me.clientY - startY) / zoom;
24291
+ let targetPageIndex = sourcePageIndex;
24292
+ let targetX = grip.item.x;
24293
+ let targetY = grip.item.y1;
24294
+ let pointerX = startX;
24295
+ let pointerY = startY;
24296
+ let scrollParent = surface.parentElement;
24297
+ while (scrollParent) {
24298
+ const style = getComputedStyle(scrollParent);
24299
+ if (/(auto|scroll)/.test(style.overflowY) && scrollParent.scrollHeight > scrollParent.clientHeight) break;
24300
+ scrollParent = scrollParent.parentElement;
24301
+ }
24302
+ scrollParent ?? (scrollParent = document.scrollingElement);
24303
+ const updateMove = (clientX, clientY) => {
24304
+ dx = (clientX - startX) / zoom;
24305
+ dy = (clientY - startY) / zoom;
23603
24306
  if (isMove) {
23604
24307
  const width = (grip.item.x2 ?? grip.item.x) - grip.item.x;
23605
24308
  const height = grip.item.y2 - grip.item.y1;
23606
- const maxX = Math.max(0, parseFloat(surface.style.width) - width);
23607
- const maxY = Math.max(0, parseFloat(surface.style.height) - height);
23608
- dx = Math.max(-grip.item.x, Math.min(dx, maxX - grip.item.x));
23609
- dy = Math.max(-grip.item.y1, Math.min(dy, maxY - grip.item.y1));
23610
- guide.style.left = `${grip.item.x + dx}px`;
23611
- guide.style.top = `${grip.item.y1 + dy}px`;
24309
+ let targetSurface = surface;
24310
+ let bestDistance = Infinity;
24311
+ for (let pageIndex = 0; pageIndex < pages.length; pageIndex++) {
24312
+ const candidate = pages[pageIndex].firstElementChild;
24313
+ if (!candidate) continue;
24314
+ const rect = candidate.getBoundingClientRect();
24315
+ const distX = clientX < rect.left ? rect.left - clientX : clientX > rect.right ? clientX - rect.right : 0;
24316
+ const distY = clientY < rect.top ? rect.top - clientY : clientY > rect.bottom ? clientY - rect.bottom : 0;
24317
+ const distance = distX * distX + distY * distY;
24318
+ if (distance >= bestDistance) continue;
24319
+ bestDistance = distance;
24320
+ targetSurface = candidate;
24321
+ targetPageIndex = pageIndex;
24322
+ }
24323
+ const targetRect = targetSurface.getBoundingClientRect();
24324
+ const maxX = Math.max(0, targetRect.width / zoom - width);
24325
+ const maxY = Math.max(0, targetRect.height / zoom - height);
24326
+ targetX = Math.max(0, Math.min((clientX - targetRect.left) / zoom - pointerOffsetX, maxX));
24327
+ targetY = Math.max(0, Math.min((clientY - targetRect.top) / zoom - pointerOffsetY, maxY));
24328
+ dx = targetX - grip.item.x;
24329
+ dy = targetY - grip.item.y1;
24330
+ if (guide.parentElement !== targetSurface) targetSurface.appendChild(guide);
24331
+ guide.style.left = `${targetX}px`;
24332
+ guide.style.top = `${targetY}px`;
23612
24333
  } else if (isCol) {
23613
24334
  guide.style.left = `${grip.item.x + dx}px`;
23614
24335
  } else {
23615
24336
  guide.style.top = `${grip.item.y1 + dy}px`;
23616
24337
  }
23617
24338
  };
24339
+ const onMove = (me) => {
24340
+ pointerX = me.clientX;
24341
+ pointerY = me.clientY;
24342
+ updateMove(pointerX, pointerY);
24343
+ };
24344
+ let autoScrollFrame;
24345
+ const autoScroll = () => {
24346
+ if (isMove && scrollParent) {
24347
+ const isDocumentScroll = scrollParent === document.documentElement || scrollParent === document.body;
24348
+ const rect = isDocumentScroll ? { top: 0, bottom: window.innerHeight } : scrollParent.getBoundingClientRect();
24349
+ const margin = 48;
24350
+ const amount = pointerY < rect.top + margin ? -Math.min(28, Math.ceil(rect.top + margin - pointerY)) : pointerY > rect.bottom - margin ? Math.min(28, Math.ceil(pointerY - (rect.bottom - margin))) : 0;
24351
+ if (amount !== 0) {
24352
+ const before = scrollParent.scrollTop;
24353
+ scrollParent.scrollTop += amount;
24354
+ if (scrollParent.scrollTop !== before) updateMove(pointerX, pointerY);
24355
+ }
24356
+ }
24357
+ autoScrollFrame = requestAnimationFrame(autoScroll);
24358
+ };
24359
+ autoScrollFrame = requestAnimationFrame(autoScroll);
23618
24360
  const onUp = () => {
23619
24361
  document.removeEventListener("mousemove", onMove);
23620
24362
  document.removeEventListener("mouseup", onUp);
24363
+ if (autoScrollFrame !== void 0) cancelAnimationFrame(autoScrollFrame);
23621
24364
  guide.remove();
23622
24365
  this.suppressNextMouseUp = false;
23623
24366
  const delta = isCol ? dx : dy;
23624
- if ((isMove ? Math.hypot(dx, dy) : Math.abs(delta)) >= 1) {
24367
+ if (isMove ? targetPageIndex !== sourcePageIndex || Math.hypot(dx, dy) >= 1 : Math.abs(delta) >= 1) {
23625
24368
  this.host.history?.checkpoint();
23626
- const page = surface.parentElement;
23627
- const pages = Array.from(this.host.getHandle()?.root.querySelectorAll(".dxw-page") ?? []);
23628
- const bodyTop = parseFloat(page?.dataset.bodyTop ?? "");
23629
- const preservePageStart = isMove && page !== null && pages.indexOf(page) > 0 && Number.isFinite(bodyTop) && Math.abs(grip.item.y1 - bodyTop) <= 1;
23630
- const ok = isMove ? moveTableTo(this.host.doc, grip.item.tbl, grip.item.x + dx, grip.item.y1 + dy, preservePageStart) : isCol ? resizeTableColumn(this.host.doc, grip.item.tbl, grip.item.boundary, dx, grip.item.renderedWidths) : resizeTableRow(this.host.doc, grip.item.tbl, grip.item.boundary, (grip.item.rowHeightPx ?? 0) + dy);
24369
+ const bodyTop = parseFloat(sourcePage?.dataset.bodyTop ?? "");
24370
+ const preservePageStart = isMove && sourcePage !== null && sourcePageIndex > 0 && Number.isFinite(bodyTop) && Math.abs(grip.item.y1 - bodyTop) <= 1;
24371
+ const ok = isMove ? moveTableTo(
24372
+ this.host.doc,
24373
+ grip.item.tbl,
24374
+ targetX,
24375
+ targetY,
24376
+ preservePageStart,
24377
+ targetPageIndex - sourcePageIndex
24378
+ ) : isCol ? resizeTableColumn(this.host.doc, grip.item.tbl, grip.item.boundary, dx, grip.item.renderedWidths) : resizeTableRow(this.host.doc, grip.item.tbl, grip.item.boundary, (grip.item.rowHeightPx ?? 0) + dy);
23631
24379
  if (ok) {
23632
24380
  this.host.rerender(void 0, isMove ? "global" : "local");
23633
24381
  this.positionCaret();
@@ -23681,9 +24429,11 @@ var _DocxEditor = class _DocxEditor {
23681
24429
  this.selectedInkGroup = null;
23682
24430
  // ---------- images: select, resize, drag-move ----------
23683
24431
  this.selectedImage = null;
24432
+ this.selectedSmartArtNodeIndex = null;
23684
24433
  this.imageOverlay = null;
23685
24434
  this.imageToolbar = null;
23686
24435
  this.wordArtTextEditor = null;
24436
+ this.smartArtTextEditor = null;
23687
24437
  /** First press selects a model; subsequent drags belong to its 3D viewport. */
23688
24438
  this.onModel3DPointerDown = (event) => {
23689
24439
  const binding = this.model3DBinding(event.target);
@@ -23730,6 +24480,7 @@ var _DocxEditor = class _DocxEditor {
23730
24480
  if (this.imageOverlay?.contains(e.target) || this.imageToolbar?.contains(e.target)) return;
23731
24481
  if (this.wordArtOverlay?.contains(e.target)) return;
23732
24482
  if (this.wordArtTextEditor?.input.contains(e.target)) return;
24483
+ if (this.smartArtTextEditor?.input.contains(e.target)) return;
23733
24484
  if (this.selectedInkGroup?.overlay.contains(e.target)) return;
23734
24485
  if (e.target?.closest?.("[data-dxw-model3d-viewer]")) return;
23735
24486
  this.deselectInkGroup();
@@ -23995,6 +24746,18 @@ var _DocxEditor = class _DocxEditor {
23995
24746
  this.exitHeaderFooter();
23996
24747
  return;
23997
24748
  }
24749
+ if (this.selectedImage && this.selectedSmartArtNodeIndex !== null && !e.metaKey && !e.ctrlKey && !e.altKey) {
24750
+ if (e.key === "Enter") {
24751
+ e.preventDefault();
24752
+ this.editSmartArtNodeText(this.selectedImage.src, this.selectedSmartArtNodeIndex);
24753
+ return;
24754
+ }
24755
+ if (e.key.length === 1) {
24756
+ e.preventDefault();
24757
+ this.editSmartArtNodeText(this.selectedImage.src, this.selectedSmartArtNodeIndex, e.key);
24758
+ return;
24759
+ }
24760
+ }
23998
24761
  if (this.caret && (e.key === "Backspace" || e.key === "Delete" || e.key.startsWith("Arrow"))) {
23999
24762
  this.positionCaret();
24000
24763
  }
@@ -24830,6 +25593,217 @@ var _DocxEditor = class _DocxEditor {
24830
25593
  getSelectedDrawingSource() {
24831
25594
  return this.selectedImage?.src ?? null;
24832
25595
  }
25596
+ getSelectedChartData() {
25597
+ const src = this.selectedImage?.src;
25598
+ if (!src) return null;
25599
+ return this.host.getHandle()?.drawings.find((binding) => binding.item.src === src)?.item.chartData ?? null;
25600
+ }
25601
+ getSelectedSmartArtData() {
25602
+ const src = this.selectedImage?.src;
25603
+ if (!src) return null;
25604
+ return this.host.getHandle()?.drawings.find((binding) => binding.item.src === src)?.item.smartArtData ?? null;
25605
+ }
25606
+ getSelectedSmartArtTextFormat() {
25607
+ const src = this.selectedImage?.src;
25608
+ if (!src || this.getSelectedObjectContext()?.kind !== "smartArt") return null;
25609
+ return smartArtTextFormat(this.host.doc, src, this.selectedSmartArtNodeIndex ?? 0);
25610
+ }
25611
+ setSelectedSmartArtTextFormat(patch) {
25612
+ const src = this.selectedImage?.src;
25613
+ if (!src || this.getSelectedObjectContext()?.kind !== "smartArt") return false;
25614
+ const current = smartArtTextFormat(this.host.doc, src, this.selectedSmartArtNodeIndex ?? 0);
25615
+ if (!current) return false;
25616
+ const nodeIndex = this.selectedSmartArtNodeIndex;
25617
+ this.host.history?.checkpoint();
25618
+ if (!setSmartArtTextFormat(this.host.doc, src, { ...current, ...patch }, nodeIndex ?? void 0)) return false;
25619
+ this.host.rerender();
25620
+ this.reselectImage(src, void 0, nodeIndex);
25621
+ return true;
25622
+ }
25623
+ getSelectedObjectContext() {
25624
+ const selected = this.selectedImage;
25625
+ if (!selected) return null;
25626
+ if (selected.kind === "image") {
25627
+ return { kind: selected.el.dataset.dxwModel3d ? "model3d" : "image", canEditText: false };
25628
+ }
25629
+ const binding = this.host.getHandle()?.drawings.find((item) => item.item.src === selected.src);
25630
+ if (binding?.item.smartArtData) {
25631
+ return {
25632
+ kind: "smartArt",
25633
+ canEditText: this.selectedSmartArtNodeIndex !== null,
25634
+ smartArtNodeSelected: this.selectedSmartArtNodeIndex !== null,
25635
+ smartArtNodeIndex: this.selectedSmartArtNodeIndex ?? void 0
25636
+ };
25637
+ }
25638
+ if (binding?.item.chartData) return { kind: "chart", canEditText: false };
25639
+ const kind = isDrawingLine(selected.src) ? "line" : "shape";
25640
+ return {
25641
+ kind,
25642
+ canEditText: kind === "shape" && !!binding?.item.textboxStory && !isDrawingWordArt(selected.src)
25643
+ };
25644
+ }
25645
+ runSelectedObjectCommand(command) {
25646
+ const selected = this.selectedImage;
25647
+ const context = this.getSelectedObjectContext();
25648
+ if (!selected || !context) return false;
25649
+ const { src, el: el16 } = selected;
25650
+ const selectedSmartArtNodeIndex = this.selectedSmartArtNodeIndex;
25651
+ const reselect = () => this.reselectImage(src, void 0, selectedSmartArtNodeIndex);
25652
+ if (command === "delete") {
25653
+ this.deleteSelectedImage();
25654
+ return true;
25655
+ }
25656
+ if (command === "bringForward" || command === "sendBackward") {
25657
+ return this.arrangeSelectedObject(command === "bringForward" ? "bringToFront" : "sendToBack");
25658
+ }
25659
+ if (command.startsWith("wrap")) {
25660
+ const mode = command === "wrapInline" ? "inline" : command === "wrapSquare" ? "square" : command === "wrapTopAndBottom" ? "topAndBottom" : command === "wrapBehind" ? "behind" : "none";
25661
+ this.host.history?.checkpoint();
25662
+ const handle = this.host.getHandle();
25663
+ const binding = selected.kind === "image" ? handle?.images.find((item) => item.item.src === src) : handle?.drawings.find((item) => item.item.src === src);
25664
+ const marginLeft = this.host.doc.sections[0]?.props.marginLeft ?? 96;
25665
+ const position = binding ? { x: binding.item.x - marginLeft, y: 0 } : void 0;
25666
+ if (!setImageWrap(this.host.doc, src, mode, position)) return false;
25667
+ this.host.rerender(void 0, "global");
25668
+ reselect();
25669
+ return true;
25670
+ }
25671
+ if (command === "size") {
25672
+ void requestNumberPairDialog(this.host.container, {
25673
+ title: "Exact size",
25674
+ firstLabel: "Width (pixels)",
25675
+ secondLabel: "Height (pixels)",
25676
+ value: {
25677
+ first: Math.round(parseFloat(el16.style.width) || 0),
25678
+ second: Math.round(parseFloat(el16.style.height) || 0)
25679
+ },
25680
+ min: 1,
25681
+ step: 1
25682
+ }).then((next) => {
25683
+ if (!next) return;
25684
+ this.host.history?.checkpoint();
25685
+ if (resizeDrawing(this.host.doc, src, next.first, next.second)) {
25686
+ this.host.rerender();
25687
+ reselect();
25688
+ }
25689
+ });
25690
+ return true;
25691
+ }
25692
+ if (command === "position") {
25693
+ void requestNumberPairDialog(this.host.container, {
25694
+ title: "Page position",
25695
+ firstLabel: "X (pixels)",
25696
+ secondLabel: "Y (pixels)",
25697
+ value: {
25698
+ first: Math.round(parseFloat(el16.style.left) || 0),
25699
+ second: Math.round(parseFloat(el16.style.top) || 0)
25700
+ },
25701
+ step: 1
25702
+ }).then((next) => {
25703
+ if (!next) return;
25704
+ this.host.history?.checkpoint();
25705
+ if (!isFloatingDrawing(src)) setImageWrap(this.host.doc, src, "square", { x: 0, y: 0 });
25706
+ if (setFloatingPagePosition(this.host.doc, src, next.first, next.second)) {
25707
+ this.host.rerender();
25708
+ reselect();
25709
+ }
25710
+ });
25711
+ return true;
25712
+ }
25713
+ if (command === "rotate") {
25714
+ if (!["shape", "line", "image", "model3d"].includes(context.kind)) return false;
25715
+ void requestTextInputDialog(this.host.container, {
25716
+ title: "Rotation",
25717
+ label: "Degrees clockwise",
25718
+ value: String(drawingRotation(src)),
25719
+ inputType: "number",
25720
+ step: 1
25721
+ }).then((next) => {
25722
+ if (next === null) return;
25723
+ const degrees = parseFloat(next);
25724
+ if (!Number.isFinite(degrees)) return;
25725
+ this.host.history?.checkpoint();
25726
+ if (setDrawingRotation(this.host.doc, src, degrees)) {
25727
+ this.host.rerender(void 0, "global");
25728
+ reselect();
25729
+ }
25730
+ });
25731
+ return true;
25732
+ }
25733
+ if (command === "altText") {
25734
+ if (context.kind !== "image" && context.kind !== "model3d") return false;
25735
+ void requestTextInputDialog(this.host.container, {
25736
+ title: "Alternative text",
25737
+ label: "Describe this object for screen readers",
25738
+ value: imageAltText(src)
25739
+ }).then((next) => {
25740
+ if (next === null) return;
25741
+ this.host.history?.checkpoint();
25742
+ if (setImageAltText(this.host.doc, src, next)) {
25743
+ this.host.rerender();
25744
+ reselect();
25745
+ }
25746
+ });
25747
+ return true;
25748
+ }
25749
+ if (command === "editText") {
25750
+ if (!context.canEditText) return false;
25751
+ if (context.kind === "smartArt" && selectedSmartArtNodeIndex !== null) {
25752
+ this.editSmartArtNodeText(src, selectedSmartArtNodeIndex);
25753
+ return true;
25754
+ }
25755
+ const binding = this.host.getHandle()?.drawings.find((item) => item.item.src === src);
25756
+ if (!binding) return false;
25757
+ const rect = binding.el.getBoundingClientRect();
25758
+ this.enterTextboxStory(src, rect.left + rect.width / 2, rect.top + rect.height / 2);
25759
+ return true;
25760
+ }
25761
+ if (command === "fill") {
25762
+ if (context.kind !== "shape" && context.kind !== "smartArt") return false;
25763
+ void requestColorDialog(this.host.container, {
25764
+ title: "Fill",
25765
+ value: context.kind === "smartArt" ? smartArtFillColor(this.host.doc, src, selectedSmartArtNodeIndex ?? 0) : drawingFillColor(src),
25766
+ allowNone: true
25767
+ }).then((next) => {
25768
+ if (next === void 0) return;
25769
+ this.host.history?.checkpoint();
25770
+ const changed = context.kind === "smartArt" ? setSmartArtFill(this.host.doc, src, next, selectedSmartArtNodeIndex ?? void 0) : setDrawingFill(this.host.doc, src, next);
25771
+ if (changed) {
25772
+ this.host.rerender();
25773
+ reselect();
25774
+ }
25775
+ });
25776
+ return true;
25777
+ }
25778
+ if (command === "outline" || command === "lineStyle") {
25779
+ if (command === "outline" && context.kind !== "shape" || command === "lineStyle" && context.kind !== "line") return false;
25780
+ const style = drawingLineStyle(src);
25781
+ if (!style) return false;
25782
+ const title = command === "lineStyle" ? "Line style" : "Outline";
25783
+ void requestLineStyleDialog(this.host.container, {
25784
+ color: style.color,
25785
+ width: style.width,
25786
+ style: style.dash
25787
+ }, title).then((next) => {
25788
+ if (!next) return;
25789
+ this.host.history?.checkpoint();
25790
+ if (setDrawingLineStyle(this.host.doc, src, next.color, next.width, next.style)) {
25791
+ this.host.rerender();
25792
+ reselect();
25793
+ }
25794
+ });
25795
+ return true;
25796
+ }
25797
+ if (command === "reset3d") {
25798
+ if (context.kind !== "model3d") return false;
25799
+ this.host.history?.checkpoint();
25800
+ if (!setModel3DRotation(this.host.doc, src, { x: 0, y: 0, z: 0 })) return false;
25801
+ this.host.rerender(void 0, "local");
25802
+ reselect();
25803
+ return true;
25804
+ }
25805
+ return false;
25806
+ }
24833
25807
  /** Whether Layout's contextual object commands currently have a target. */
24834
25808
  hasSelectedObject() {
24835
25809
  return this.selectedImage !== null || this.selectedInkGroup !== null;
@@ -25582,18 +26556,20 @@ var _DocxEditor = class _DocxEditor {
25582
26556
  deselectImage() {
25583
26557
  const changed = this.selectedImage !== null;
25584
26558
  this.wordArtTextEditor?.finish(true, false);
26559
+ this.smartArtTextEditor?.finish(true, false);
25585
26560
  this.imageOverlay?.remove();
25586
26561
  this.imageToolbar?.remove();
25587
26562
  this.imageOverlay = null;
25588
26563
  this.imageToolbar = null;
25589
26564
  this.selectedImage = null;
26565
+ this.selectedSmartArtNodeIndex = null;
25590
26566
  if (changed) this.notifyObjectSelection();
25591
26567
  }
25592
26568
  /** Re-select the same drawing after a re-render replaced its element.
25593
26569
  * A header/footer drawing paints one instance per page from the same src;
25594
26570
  * `near` (client px) picks the instance the user is actually working on
25595
26571
  * instead of the first page's copy. */
25596
- reselectImage(src, near) {
26572
+ reselectImage(src, near, smartArtNodeIndex = this.selectedSmartArtNodeIndex) {
25597
26573
  const handle = this.host.getHandle();
25598
26574
  if (!handle) return;
25599
26575
  const img = nearestInstance(handle.images.filter((b) => b.item.src === src), near);
@@ -25602,7 +26578,7 @@ var _DocxEditor = class _DocxEditor {
25602
26578
  return;
25603
26579
  }
25604
26580
  const drw = nearestInstance(handle.drawings.filter((b) => b.item.src === src), near);
25605
- if (drw) this.selectImage(drw.el, src, void 0, "drawing");
26581
+ if (drw) this.selectImage(drw.el, src, void 0, "drawing", smartArtNodeIndex);
25606
26582
  }
25607
26583
  static handleCursor(dir) {
25608
26584
  if (dir === "nw" || dir === "se") return "nwse-resize";
@@ -25610,11 +26586,12 @@ var _DocxEditor = class _DocxEditor {
25610
26586
  if (dir === "n" || dir === "s") return "ns-resize";
25611
26587
  return "ew-resize";
25612
26588
  }
25613
- selectImage(el16, src, item, kind = "image") {
26589
+ selectImage(el16, src, _item, kind = "image", smartArtNodeIndex = null) {
25614
26590
  this.deselectInkGroup();
25615
26591
  this.deselectImage();
25616
26592
  this.hideCaret();
25617
26593
  this.selectedImage = { el: el16, src, kind };
26594
+ this.selectedSmartArtNodeIndex = smartArtNodeIndex;
25618
26595
  const overlay = document.createElement("div");
25619
26596
  overlay.dataset.dxwObjectSelection = "1";
25620
26597
  overlay.style.position = "absolute";
@@ -25628,6 +26605,15 @@ var _DocxEditor = class _DocxEditor {
25628
26605
  overlay.style.boxSizing = "border-box";
25629
26606
  overlay.style.pointerEvents = "none";
25630
26607
  overlay.style.zIndex = "2147483647";
26608
+ if (smartArtNodeIndex !== null) {
26609
+ const node = this.host.getHandle()?.drawings.find((binding) => binding.item.src === src && binding.el === el16)?.item.smartArtNodes?.find((candidate) => candidate.index === smartArtNodeIndex);
26610
+ if (node) {
26611
+ const nodeOutline = document.createElement("div");
26612
+ nodeOutline.dataset.dxwSmartArtNodeSelection = String(node.index);
26613
+ nodeOutline.style.cssText = `position:absolute;left:${node.x}px;top:${node.y}px;width:${node.width}px;height:${node.height}px;box-sizing:border-box;border:2px solid #1a73e8;border-radius:3px;background:rgba(26,115,232,.08);`;
26614
+ overlay.appendChild(nodeOutline);
26615
+ }
26616
+ }
25631
26617
  const line2 = kind === "drawing" && isDrawingLine(src);
25632
26618
  if (line2) {
25633
26619
  const move = document.createElement("div");
@@ -25677,15 +26663,8 @@ var _DocxEditor = class _DocxEditor {
25677
26663
  });
25678
26664
  b.addEventListener("click", (ce) => {
25679
26665
  ce.stopPropagation();
25680
- this.host.history?.checkpoint();
25681
- const sp = this.host.doc.sections[0]?.props;
25682
- const pos = item ? { x: item.x - (sp?.marginLeft ?? 96), y: 0 } : void 0;
25683
- if (setImageWrap(this.host.doc, src, mode, pos)) {
25684
- this.host.rerender();
25685
- this.reselectImage(src);
25686
- } else {
25687
- this.deselectImage();
25688
- }
26666
+ const command = mode === "inline" ? "wrapInline" : mode === "square" ? "wrapSquare" : mode === "topAndBottom" ? "wrapTopAndBottom" : mode === "behind" ? "wrapBehind" : "wrapFront";
26667
+ if (!this.runSelectedObjectCommand(command)) this.deselectImage();
25689
26668
  });
25690
26669
  bar.appendChild(b);
25691
26670
  }
@@ -25707,117 +26686,58 @@ var _DocxEditor = class _DocxEditor {
25707
26686
  });
25708
26687
  bar.appendChild(b);
25709
26688
  };
25710
- extra("Alt", "Alternative text", () => {
25711
- const cur = imageAltText(src);
25712
- void requestTextInputDialog(this.host.container, {
25713
- title: "Alternative text",
25714
- label: "Describe this object for screen readers",
25715
- value: cur
25716
- }).then((next) => {
25717
- if (next === null) return;
25718
- this.host.history?.checkpoint();
25719
- if (setImageAltText(this.host.doc, src, next)) this.host.rerender();
25720
- this.deselectImage();
26689
+ const context = this.getSelectedObjectContext();
26690
+ if (context?.kind === "image" || context?.kind === "model3d") {
26691
+ extra("Alt", "Alternative text", () => {
26692
+ this.runSelectedObjectCommand("altText");
25721
26693
  });
25722
- });
26694
+ }
25723
26695
  extra("Size", "Exact size (px)", () => {
25724
- const curW = parseFloat(el16.style.width) || 0;
25725
- const curH = parseFloat(el16.style.height) || 0;
25726
- const cur = `${Math.round(curW)}x${Math.round(curH)}`;
25727
- void requestTextInputDialog(this.host.container, {
25728
- title: "Exact size",
25729
- label: "Width \xD7 height in pixels",
25730
- value: cur,
25731
- placeholder: "640 \xD7 360"
25732
- }).then((next) => {
25733
- const match = next && /^\s*(\d+)\s*[x×]\s*(\d+)\s*$/i.exec(next);
25734
- if (!match) return;
25735
- this.host.history?.checkpoint();
25736
- if (resizeDrawing(this.host.doc, src, parseInt(match[1], 10), parseInt(match[2], 10))) this.host.rerender();
25737
- this.deselectImage();
25738
- });
26696
+ this.runSelectedObjectCommand("size");
25739
26697
  });
25740
26698
  extra("Position", "Exact page position (px)", () => {
25741
- const curX = parseFloat(el16.style.left) || 0;
25742
- const curY = parseFloat(el16.style.top) || 0;
25743
- void requestTextInputDialog(this.host.container, {
25744
- title: "Page position",
25745
- label: "X, Y in pixels",
25746
- value: `${Math.round(curX)}, ${Math.round(curY)}`,
25747
- placeholder: "120, 80"
25748
- }).then((next) => {
25749
- const match = next && /^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/.exec(next);
25750
- if (!match) return;
25751
- this.host.history?.checkpoint();
25752
- if (!isFloatingDrawing(src)) setImageWrap(this.host.doc, src, "square", { x: 0, y: 0 });
25753
- if (setFloatingPagePosition(this.host.doc, src, parseFloat(match[1]), parseFloat(match[2]))) {
25754
- this.host.rerender();
25755
- this.reselectImage(src);
25756
- }
25757
- });
26699
+ this.runSelectedObjectCommand("position");
25758
26700
  });
26701
+ const drawingBinding = kind === "drawing" ? this.host.getHandle()?.drawings.find((binding) => binding.item.src === src) : void 0;
25759
26702
  if (kind === "drawing") {
25760
- extra("Rotate", "Set rotation (degrees)", () => {
25761
- void requestTextInputDialog(this.host.container, {
25762
- title: "Rotation",
25763
- label: "Degrees clockwise",
25764
- value: String(drawingRotation(src)),
25765
- placeholder: "90"
25766
- }).then((next) => {
25767
- if (next === null) return;
25768
- const degrees = parseFloat(next);
25769
- if (!Number.isFinite(degrees)) return;
25770
- this.host.history?.checkpoint();
25771
- if (setDrawingRotation(this.host.doc, src, degrees)) {
25772
- this.host.rerender(void 0, "global");
25773
- this.reselectImage(src);
25774
- }
26703
+ const drawingIsLine = isDrawingLine(src);
26704
+ if (context?.kind === "shape" || context?.kind === "line") {
26705
+ extra("Rotate", "Set rotation (degrees)", () => {
26706
+ this.runSelectedObjectCommand("rotate");
25775
26707
  });
25776
- });
25777
- if (!isDrawingLine(src)) {
25778
- extra("Fill", "Shape fill color", () => {
25779
- void requestTextInputDialog(this.host.container, {
25780
- title: "Fill",
25781
- label: "Color or none",
25782
- value: drawingFillColor(src) ?? "none",
25783
- placeholder: "#4472C4 or none"
25784
- }).then((next) => {
25785
- if (next === null) return;
25786
- const color = /^\s*none\s*$/i.test(next) ? null : /^\s*#?([0-9a-f]{6})\s*$/i.exec(next)?.[1];
25787
- if (color === void 0) return;
25788
- this.host.history?.checkpoint();
25789
- if (setDrawingFill(this.host.doc, src, color ? `#${color}` : null)) {
25790
- this.host.rerender();
25791
- this.reselectImage(src);
26708
+ }
26709
+ if (!drawingIsLine) {
26710
+ if (context?.kind === "shape" || context?.kind === "smartArt") {
26711
+ extra(
26712
+ context.kind === "smartArt" ? context.smartArtNodeSelected ? "Node fill" : "Fill all" : "Fill",
26713
+ context.kind === "smartArt" ? context.smartArtNodeSelected ? "Selected SmartArt node fill" : "All SmartArt node fills" : "Shape fill color",
26714
+ () => {
26715
+ this.runSelectedObjectCommand("fill");
25792
26716
  }
25793
- });
25794
- });
26717
+ );
26718
+ }
25795
26719
  }
25796
- extra("Outline", "Outline color and weight", () => {
25797
- const style = drawingLineStyle(src);
25798
- if (!style) return;
25799
- void requestTextInputDialog(this.host.container, {
25800
- title: "Outline",
25801
- label: "Color and width in pixels",
25802
- value: `${style.color}, ${Number(style.width.toFixed(2))}`,
25803
- placeholder: "#1a73e8, 1.5"
25804
- }).then((next) => {
25805
- const match = next && /^\s*#?([0-9a-f]{6})\s*,\s*(\d+(?:\.\d+)?)\s*$/i.exec(next);
25806
- if (!match) return;
25807
- this.host.history?.checkpoint();
25808
- if (setDrawingLineStyle(this.host.doc, src, `#${match[1]}`, parseFloat(match[2]))) {
25809
- this.host.rerender();
25810
- this.reselectImage(src);
25811
- }
26720
+ if (context?.kind === "line") {
26721
+ extra("Line style", "Line color, weight, and style", () => {
26722
+ this.runSelectedObjectCommand("lineStyle");
26723
+ });
26724
+ } else if (context?.kind === "shape") {
26725
+ extra("Outline", "Outline color, weight, and style", () => {
26726
+ this.runSelectedObjectCommand("outline");
25812
26727
  });
26728
+ }
26729
+ extra("Delete", "Delete shape", () => {
26730
+ this.runSelectedObjectCommand("delete");
25813
26731
  });
25814
- extra("Delete", "Delete shape", () => this.deleteSelectedImage());
25815
26732
  }
25816
- const drawingBinding = kind === "drawing" ? this.host.getHandle()?.drawings.find((binding) => binding.item.src === src) : void 0;
25817
26733
  if (drawingBinding?.item.textboxStory && !isDrawingWordArt(src)) {
25818
26734
  extra("Edit text", "Edit shape text with the Home font controls", () => {
25819
- const rect = drawingBinding.el.getBoundingClientRect();
25820
- this.enterTextboxStory(src, rect.left + rect.width / 2, rect.top + rect.height / 2);
26735
+ this.runSelectedObjectCommand("editText");
26736
+ });
26737
+ }
26738
+ if (context?.kind === "smartArt" && this.selectedSmartArtNodeIndex !== null) {
26739
+ extra("Edit text", "Edit selected SmartArt node text", () => {
26740
+ this.runSelectedObjectCommand("editText");
25821
26741
  });
25822
26742
  }
25823
26743
  if (kind === "drawing" && isDrawingWordArt(src)) {
@@ -25845,11 +26765,7 @@ var _DocxEditor = class _DocxEditor {
25845
26765
  }
25846
26766
  if (el16.dataset.dxwModel3d) {
25847
26767
  extra("Reset 3D", "Reset 3D rotation", () => {
25848
- this.host.history?.checkpoint();
25849
- if (setModel3DRotation(this.host.doc, src, { x: 0, y: 0, z: 0 })) {
25850
- this.host.rerender(void 0, "local");
25851
- this.reselectImage(src);
25852
- }
26768
+ this.runSelectedObjectCommand("reset3d");
25853
26769
  });
25854
26770
  }
25855
26771
  const surface = el16.parentElement;
@@ -26008,7 +26924,9 @@ var _DocxEditor = class _DocxEditor {
26008
26924
  void requestTextInputDialog(this.host.container, {
26009
26925
  title: "Watermark rotation",
26010
26926
  label: "Degrees clockwise",
26011
- value: String(cur)
26927
+ value: String(cur),
26928
+ inputType: "number",
26929
+ step: 1
26012
26930
  }).then((next) => {
26013
26931
  if (next === null) return;
26014
26932
  const degrees = parseFloat(next);
@@ -26166,6 +27084,8 @@ var _DocxEditor = class _DocxEditor {
26166
27084
  const drawingTarget = objectMove && this.selectedImage?.kind === "drawing" ? this.selectedImage.el : target.closest?.("[data-dxw-drawing]");
26167
27085
  const handle = this.host.getHandle();
26168
27086
  let drawingBinding = drawingTarget ? handle?.drawings.find((b) => b.el === drawingTarget) : void 0;
27087
+ const smartArtNodeTarget = target.closest?.("[data-dxw-smart-art-node]");
27088
+ const smartArtNodeIndex = smartArtNodeTarget ? Number.parseInt(smartArtNodeTarget.dataset.dxwSmartArtNode ?? "", 10) : null;
26169
27089
  if (!drawingBinding && !target.closest("button")) {
26170
27090
  const pointCaret2 = this.caretFromPoint(e.clientX, e.clientY);
26171
27091
  if (!pointCaret2 || !this.inActiveRegion(pointCaret2.t)) {
@@ -26186,6 +27106,11 @@ var _DocxEditor = class _DocxEditor {
26186
27106
  e.stopPropagation();
26187
27107
  this.suppressNextMouseUp = true;
26188
27108
  if (e.detail >= 2) {
27109
+ if (binding.item.smartArtData && smartArtNodeIndex !== null && Number.isFinite(smartArtNodeIndex)) {
27110
+ this.selectImage(binding.el, binding.item.src, void 0, "drawing", smartArtNodeIndex);
27111
+ this.editSmartArtNodeText(binding.item.src, smartArtNodeIndex);
27112
+ return true;
27113
+ }
26189
27114
  if (textboxStory) {
26190
27115
  this.enterTextboxStory(binding.item.src, e.clientX, e.clientY);
26191
27116
  return true;
@@ -26209,7 +27134,7 @@ var _DocxEditor = class _DocxEditor {
26209
27134
  moved = true;
26210
27135
  if (binding.item.anchored) {
26211
27136
  if (this.selectedImage?.src !== binding.item.src) {
26212
- this.selectImage(el16, binding.item.src, void 0, "drawing");
27137
+ this.selectImage(el16, binding.item.src, void 0, "drawing", Number.isFinite(smartArtNodeIndex) ? smartArtNodeIndex : null);
26213
27138
  }
26214
27139
  toolbarLeft0 = parseFloat(this.imageToolbar?.style.left ?? "") || 0;
26215
27140
  toolbarTop0 = parseFloat(this.imageToolbar?.style.top ?? "") || 0;
@@ -26239,7 +27164,7 @@ var _DocxEditor = class _DocxEditor {
26239
27164
  this.hideDropIndicator();
26240
27165
  this.suppressNextMouseUp = false;
26241
27166
  if (!moved) {
26242
- this.selectImage(binding.el, binding.item.src, void 0, "drawing");
27167
+ this.selectImage(binding.el, binding.item.src, void 0, "drawing", Number.isFinite(smartArtNodeIndex) ? smartArtNodeIndex : null);
26243
27168
  return;
26244
27169
  }
26245
27170
  if (binding.item.anchored) {
@@ -26457,6 +27382,59 @@ var _DocxEditor = class _DocxEditor {
26457
27382
  }
26458
27383
  return false;
26459
27384
  }
27385
+ editSmartArtNodeText(src, nodeIndex, replacement) {
27386
+ if (this.smartArtTextEditor) {
27387
+ this.smartArtTextEditor.input.focus();
27388
+ this.smartArtTextEditor.input.select();
27389
+ return;
27390
+ }
27391
+ const binding = this.host.getHandle()?.drawings.find((item) => item.item.src === src);
27392
+ const node = binding?.item.smartArtNodes?.find((item) => item.index === nodeIndex);
27393
+ const surface = binding?.el.parentElement;
27394
+ const original = binding?.item.smartArtData?.items[nodeIndex];
27395
+ if (!binding || !node || !surface || original === void 0) return;
27396
+ const zoom = this.host.zoom ?? 1;
27397
+ const surfaceRect = surface.getBoundingClientRect();
27398
+ const drawingRect = binding.el.getBoundingClientRect();
27399
+ const input = document.createElement("input");
27400
+ input.dataset.dxwSmartArtNodeEditor = String(nodeIndex);
27401
+ input.value = replacement ?? original;
27402
+ input.setAttribute("aria-label", `Edit SmartArt node ${nodeIndex + 1}`);
27403
+ input.style.cssText = `position:absolute;left:${(drawingRect.left - surfaceRect.left) / zoom + node.x}px;top:${(drawingRect.top - surfaceRect.top) / zoom + node.y}px;width:${node.width}px;height:${node.height}px;box-sizing:border-box;border:2px solid #1a73e8;border-radius:4px;background:rgba(255,255,255,.96);color:#202124;font:600 14px/1.2 system-ui,sans-serif;text-align:center;padding:4px 8px;z-index:2147483647;outline:none;`;
27404
+ const near = {
27405
+ x: drawingRect.left + (node.x + node.width / 2) * zoom,
27406
+ y: drawingRect.top + (node.y + node.height / 2) * zoom
27407
+ };
27408
+ const finish = (commit, reselect) => {
27409
+ if (this.smartArtTextEditor?.input !== input) return;
27410
+ this.smartArtTextEditor = null;
27411
+ const next = input.value;
27412
+ input.remove();
27413
+ if (commit && next !== original) {
27414
+ this.host.history?.checkpoint();
27415
+ if (setSmartArtNodeText(this.host.doc, src, nodeIndex, next)) this.host.rerender();
27416
+ }
27417
+ if (reselect) this.reselectImage(src, near, nodeIndex);
27418
+ this.focusText();
27419
+ };
27420
+ this.smartArtTextEditor = { input, finish };
27421
+ input.addEventListener("mousedown", (event) => event.stopPropagation());
27422
+ input.addEventListener("keydown", (event) => {
27423
+ event.stopPropagation();
27424
+ if (event.key === "Enter") {
27425
+ event.preventDefault();
27426
+ finish(true, true);
27427
+ } else if (event.key === "Escape") {
27428
+ event.preventDefault();
27429
+ finish(false, true);
27430
+ }
27431
+ });
27432
+ input.addEventListener("blur", () => finish(true, true));
27433
+ surface.appendChild(input);
27434
+ input.focus();
27435
+ if (replacement === void 0) input.select();
27436
+ else input.setSelectionRange(input.value.length, input.value.length);
27437
+ }
26460
27438
  editDrawingWordArt(src) {
26461
27439
  if (this.wordArtTextEditor) {
26462
27440
  this.wordArtTextEditor.input.focus();
@@ -27106,8 +28084,14 @@ var _DocxEditor = class _DocxEditor {
27106
28084
  offset: endText.text.length,
27107
28085
  bias: endText.text.length > 0 ? "end" : void 0
27108
28086
  };
28087
+ const splitWasList = (() => {
28088
+ const pPr = paragraph.children.find((child4) => localName(child4.name) === "pPr");
28089
+ const style = pPr?.children.find((child4) => localName(child4.name) === "pStyle");
28090
+ return !!pPr?.children.some((child4) => localName(child4.name) === "numPr") || !!resolveParagraphStyleChain(this.host.doc.styles, attr(style, "val"), false).pPr.numbering;
28091
+ })();
27109
28092
  const split = this.splitParagraphCore();
27110
28093
  if (!split) return null;
28094
+ if (splitWasList) clearListParagraphFormatting(this.host.doc, split.after);
27111
28095
  const hasPageBreak = (element) => localName(element.name) === "br" && attr(element, "type") === "page" || element.children.some(hasPageBreak);
27112
28096
  const insertBeforeTrailingBreak = hasPageBreak(split.after);
27113
28097
  const afterSources = insertBeforeTrailingBreak ? [] : [split.after];
@@ -27707,6 +28691,14 @@ var _DocxEditor = class _DocxEditor {
27707
28691
  this.splitParagraphNoHistory();
27708
28692
  }
27709
28693
  splitParagraphNoHistory() {
28694
+ if (this.caret) {
28695
+ const paragraph = paragraphOf(this.host.doc, this.caret.t);
28696
+ if (paragraph && textElements(paragraph).every((text) => text.text.length === 0) && clearListParagraphFormatting(this.host.doc, paragraph)) {
28697
+ this.commit();
28698
+ this.focusText();
28699
+ return;
28700
+ }
28701
+ }
27710
28702
  const split = this.splitParagraphCore();
27711
28703
  const reparsed = split ? this.host.doc.reparseDirectBodyParagraphSplit(split.before, split.after) : null;
27712
28704
  if (reparsed && split && this.caret) {
@@ -28586,6 +29578,84 @@ function adjustIndent(doc, targets, direction) {
28586
29578
  if (touched) doc.refresh();
28587
29579
  return touched;
28588
29580
  }
29581
+ var DIVIDER_STYLES = /* @__PURE__ */ new Set([
29582
+ "single",
29583
+ "double",
29584
+ "dotted",
29585
+ "dashed",
29586
+ "thinThickSmallGap"
29587
+ ]);
29588
+ function paragraphDividerAt(doc, target) {
29589
+ const paragraph = paragraphOf(doc, target);
29590
+ const pPr = paragraph?.children.find((child4) => localName(child4.name) === "pPr");
29591
+ const pBdr = pPr?.children.find((child4) => localName(child4.name) === "pBdr");
29592
+ const bottom = pBdr?.children.find((child4) => localName(child4.name) === "bottom");
29593
+ if (!bottom) return null;
29594
+ const value = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "val") ?? ""];
29595
+ if (value === "none" || value === "nil") return null;
29596
+ const style = DIVIDER_STYLES.has(value) ? value : "single";
29597
+ const colorValue2 = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "color") ?? ""];
29598
+ const sizeValue = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "sz") ?? ""];
29599
+ const spaceValue = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "space") ?? ""];
29600
+ return {
29601
+ style,
29602
+ color: colorValue2 && colorValue2 !== "auto" ? `#${colorValue2.toUpperCase()}` : "#000000",
29603
+ widthPt: (parseInt(sizeValue ?? "4", 10) || 4) / 8,
29604
+ spacePt: parseInt(spaceValue ?? "0", 10) || 0
29605
+ };
29606
+ }
29607
+ function setParagraphDivider(doc, targets, divider) {
29608
+ const paragraphs = paragraphsOf(doc, targets);
29609
+ if (paragraphs.size === 0) return false;
29610
+ for (const paragraph of paragraphs) {
29611
+ const w = prefixOf13(paragraph);
29612
+ const pPr = ensurePPr(paragraph);
29613
+ let pBdr = pPr.children.find((child4) => localName(child4.name) === "pBdr");
29614
+ if (!divider) {
29615
+ if (!pBdr) continue;
29616
+ pBdr.children = pBdr.children.filter((child4) => localName(child4.name) !== "bottom");
29617
+ if (pBdr.children.length === 0) pPr.children.splice(pPr.children.indexOf(pBdr), 1);
29618
+ continue;
29619
+ }
29620
+ if (!pBdr) {
29621
+ pBdr = { name: `${w}pBdr`, attrs: {}, children: [], text: "" };
29622
+ const later = /* @__PURE__ */ new Set([
29623
+ "shd",
29624
+ "tabs",
29625
+ "spacing",
29626
+ "ind",
29627
+ "contextualSpacing",
29628
+ "mirrorIndents",
29629
+ "suppressOverlap",
29630
+ "jc",
29631
+ "textDirection",
29632
+ "textAlignment",
29633
+ "textboxTightWrap",
29634
+ "outlineLvl",
29635
+ "divId",
29636
+ "cnfStyle",
29637
+ "rPr",
29638
+ "sectPr",
29639
+ "pPrChange"
29640
+ ]);
29641
+ const index = pPr.children.findIndex((child4) => later.has(localName(child4.name)));
29642
+ pPr.children.splice(index === -1 ? pPr.children.length : index, 0, pBdr);
29643
+ }
29644
+ let bottom = pBdr.children.find((child4) => localName(child4.name) === "bottom");
29645
+ if (!bottom) {
29646
+ bottom = { name: `${w}bottom`, attrs: {}, children: [], text: "" };
29647
+ pBdr.children.push(bottom);
29648
+ }
29649
+ bottom.attrs = {
29650
+ [`${w}val`]: divider.style,
29651
+ [`${w}sz`]: String(Math.max(1, Math.round(divider.widthPt * 8))),
29652
+ [`${w}space`]: String(Math.max(0, Math.round(divider.spacePt))),
29653
+ [`${w}color`]: divider.color.replace(/^#/, "").toUpperCase()
29654
+ };
29655
+ }
29656
+ doc.refresh();
29657
+ return true;
29658
+ }
28589
29659
  function firstText2(node) {
28590
29660
  if (localName(node.name) === "t") return node;
28591
29661
  for (const child4 of node.children) {
@@ -29324,7 +30394,7 @@ var GUIDE_GROUPS = [
29324
30394
  items: [
29325
30395
  {
29326
30396
  title: "Open or upload a document",
29327
- description: "Choose a sample from Try a template or use Upload .docx to edit a local Word file in the browser."
30397
+ description: "Choose File \u2192 Open .docx to edit a local Word file, or choose a starting document from the template menu."
29328
30398
  },
29329
30399
  {
29330
30400
  title: "Zoom, review, and author",
@@ -29386,7 +30456,7 @@ var GUIDE_GROUPS = [
29386
30456
  },
29387
30457
  {
29388
30458
  title: "Shapes and lines",
29389
- description: "Insert a line, rectangle, rounded rectangle, ellipse, arrow, or callout. Select it to move, resize, rotate, change wrapping and layering, or edit fill and outline."
30459
+ description: "Insert a horizontal or vertical line, rectangle, rounded rectangle, ellipse, arrow, or callout. Select it to move, resize, rotate, change wrapping and layering, or edit its color, thickness, and solid, dashed, or dotted outline."
29390
30460
  },
29391
30461
  {
29392
30462
  title: "Text boxes and WordArt",
@@ -29452,7 +30522,7 @@ var GUIDE_GROUPS = [
29452
30522
  },
29453
30523
  {
29454
30524
  title: "Page borders and line numbers",
29455
- description: "Apply a repeating page border and enable continuous, per-page, per-section, or interval-based line numbering."
30525
+ description: "Apply a repeating page border with a preset or custom color and line weight, and enable continuous, per-page, per-section, or interval-based line numbering."
29456
30526
  },
29457
30527
  {
29458
30528
  title: "Arrange selected objects",
@@ -29473,7 +30543,7 @@ var GUIDE_GROUPS = [
29473
30543
  },
29474
30544
  {
29475
30545
  title: "Exact object properties",
29476
- description: "Use Size to set the object's width \xD7 height, Position for exact page coordinates, Fill for a shape's interior color, and Outline for its border or line color and thickness."
30546
+ description: "Set a line's color, weight, and solid, dashed, or dotted style directly in Insert \u2192 Shapes. After insertion, select it and choose Line style to revise those settings; Size and Position provide exact geometry."
29477
30547
  }
29478
30548
  ]
29479
30549
  },
@@ -29487,7 +30557,7 @@ var GUIDE_GROUPS = [
29487
30557
  "Open Insert \u2192 Header, then insert a text box in the repeating header layer.",
29488
30558
  "Enter 1 through 28 as separate paragraphs and select all of those numbered paragraphs.",
29489
30559
  "Open Home \u2192 Line & paragraph spacing \u2192 Exactly 24 pt, then choose Remove space before and Remove space after.",
29490
- "Use Insert \u2192 Shape \u2192 Line for each vertical rule, rotate and position it in the same repeating header layer.",
30560
+ "Open Insert \u2192 Shapes, set the line color, weight, and style, then insert a Vertical line for each rule and set its exact Size and Position in the repeating header layer.",
29491
30561
  "Choose Close to return to body text."
29492
30562
  ]
29493
30563
  },
@@ -29502,11 +30572,11 @@ var GUIDE_GROUPS = [
29502
30572
  },
29503
30573
  {
29504
30574
  title: "Resume horizontal rule",
29505
- description: "Use a body line when the rule belongs to one location in the document.",
30575
+ description: "Use a native paragraph divider so the rule stays attached to the r\xE9sum\xE9 heading or contact line.",
29506
30576
  steps: [
29507
- "Place the caret near the intended rule and choose Insert \u2192 Shape \u2192 Line.",
29508
- "Drag to position and size it; use Position for exact placement.",
29509
- "Choose Inline, Wrap, In front, or Behind according to how nearby text should flow."
30577
+ "Place the caret in the paragraph that should carry the rule and choose Insert \u2192 Divider.",
30578
+ "Choose a single, double, dashed, dotted, or thin + thick style, then set its color, width, and gap.",
30579
+ "Choose Apply divider. Return to the same paragraph and reopen Divider whenever you want to edit or remove it."
29510
30580
  ]
29511
30581
  },
29512
30582
  {
@@ -29515,7 +30585,7 @@ var GUIDE_GROUPS = [
29515
30585
  },
29516
30586
  {
29517
30587
  title: "Border around every page",
29518
- description: "Choose Layout \u2192 Page border for a true page border. Use header shapes when the design needs custom partial rules or ornaments."
30588
+ description: "Choose Layout \u2192 Page border \u2192 Custom border, set the color and line weight, then apply it to the whole document or current section."
29519
30589
  }
29520
30590
  ]
29521
30591
  }
@@ -29819,7 +30889,7 @@ function detectFonts() {
29819
30889
  };
29820
30890
  ctx.font = "16px monospace";
29821
30891
  const base = ctx.measureText(probe).width;
29822
- const always = /* @__PURE__ */ new Set(["Calibri", "Cambria"]);
30892
+ const always = /* @__PURE__ */ new Set(["Arial", "Calibri", "Cambria", "Courier New", "Times New Roman"]);
29823
30893
  availableFonts = FONT_CANDIDATES.filter((f) => always.has(f) || Math.abs(widthIn(f) - base) > 0.5);
29824
30894
  } catch {
29825
30895
  availableFonts = FONT_CANDIDATES;
@@ -30565,6 +31635,7 @@ function LinkMenu({ api }) {
30565
31635
  "input",
30566
31636
  {
30567
31637
  ref: inputRef,
31638
+ type: "url",
30568
31639
  value: url,
30569
31640
  placeholder: "Paste or type a link",
30570
31641
  onChange: (e) => setUrl(e.target.value),
@@ -30889,12 +31960,16 @@ function EquationMenu({ api }) {
30889
31960
  setError("Place the caret in editable text and enter a valid equation.");
30890
31961
  }
30891
31962
  };
31963
+ const anchor = open ? rootRef.current?.getBoundingClientRect() : null;
31964
+ const viewportWidth = typeof window === "undefined" ? 356 : window.innerWidth;
31965
+ const popoverWidth = Math.min(340, viewportWidth - 16);
31966
+ const popoverLeft = Math.max(8, Math.min(anchor?.left ?? 8, viewportWidth - popoverWidth - 8));
30892
31967
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
30893
31968
  /* @__PURE__ */ jsxs2("button", { title: "Insert equation", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: [
30894
31969
  /* @__PURE__ */ jsx2("span", { style: { fontFamily: "'Cambria Math', serif", fontSize: 18 }, children: "\u03C0" }),
30895
31970
  /* @__PURE__ */ jsx2("span", { style: { marginLeft: 5 }, children: "Equation" })
30896
31971
  ] }),
30897
- open && /* @__PURE__ */ jsxs2("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: [
31972
+ open && /* @__PURE__ */ jsxs2("div", { "data-dxw-equation-menu": "", style: { position: "fixed", top: anchor?.bottom ?? 28, left: popoverLeft, zIndex: 100, width: popoverWidth, boxSizing: "border-box", padding: 10, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
30898
31973
  /* @__PURE__ */ jsx2("div", { style: { font: "600 12px system-ui, sans-serif", marginBottom: 5, color: T.fg }, children: "Linear equation" }),
30899
31974
  /* @__PURE__ */ jsx2(
30900
31975
  "input",
@@ -30969,15 +32044,88 @@ function SymbolMenu({ api }) {
30969
32044
  }
30970
32045
  var SHAPES = [
30971
32046
  ["line", "Line", "\u2015"],
32047
+ ["verticalLine", "Vertical line", "\u2502"],
30972
32048
  ["rectangle", "Rectangle", "\u25AD"],
30973
32049
  ["roundedRectangle", "Rounded rectangle", "\u25A2"],
30974
32050
  ["ellipse", "Ellipse", "\u25EF"],
30975
32051
  ["diamond", "Diamond", "\u25C7"],
30976
32052
  ["textBox", "Text box", "T"]
30977
32053
  ];
32054
+ function DividerMenu({ api }) {
32055
+ const [open, setOpen] = useState2(false);
32056
+ const [style, setStyle] = useState2("single");
32057
+ const [color, setColor] = useState2("#000000");
32058
+ const [widthPt, setWidthPt] = useState2(1);
32059
+ const [spacePt, setSpacePt] = useState2(1);
32060
+ const rootRef = useRef2(null);
32061
+ useEffect2(() => {
32062
+ if (!open) return;
32063
+ const close = (event) => {
32064
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
32065
+ };
32066
+ document.addEventListener("mousedown", close);
32067
+ return () => document.removeEventListener("mousedown", close);
32068
+ }, [open]);
32069
+ const toggle = () => {
32070
+ if (!open) {
32071
+ const current = api?.getParagraphDivider();
32072
+ if (current) {
32073
+ setStyle(current.style);
32074
+ setColor(current.color);
32075
+ setWidthPt(current.widthPt);
32076
+ setSpacePt(current.spacePt);
32077
+ }
32078
+ }
32079
+ setOpen(!open);
32080
+ };
32081
+ const apply = () => {
32082
+ if (api?.setParagraphDivider({ style, color, widthPt, spacePt })) setOpen(false);
32083
+ };
32084
+ const previewStyle = style === "double" || style === "thinThickSmallGap" ? "double" : style;
32085
+ return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
32086
+ /* @__PURE__ */ jsx2("button", { title: "Insert or edit divider", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: toggle, children: "Divider" }),
32087
+ open && /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 270, padding: 10, display: "grid", gap: 8, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
32088
+ /* @__PURE__ */ jsx2("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "Horizontal rule below the current paragraph" }),
32089
+ /* @__PURE__ */ jsx2("div", { "aria-hidden": "true", style: { height: 12, borderBottom: `${Math.max(widthPt, 1)}px ${previewStyle} ${color}` } }),
32090
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32091
+ "Style",
32092
+ /* @__PURE__ */ jsxs2("select", { "aria-label": "Divider style", value: style, onChange: (event) => setStyle(event.target.value), style: { border: `1px solid ${T.border}`, borderRadius: 5, padding: "5px 7px", background: T.popoverBg, color: T.fg }, children: [
32093
+ /* @__PURE__ */ jsx2("option", { value: "single", children: "Single" }),
32094
+ /* @__PURE__ */ jsx2("option", { value: "double", children: "Double" }),
32095
+ /* @__PURE__ */ jsx2("option", { value: "dashed", children: "Dashed" }),
32096
+ /* @__PURE__ */ jsx2("option", { value: "dotted", children: "Dotted" }),
32097
+ /* @__PURE__ */ jsx2("option", { value: "thinThickSmallGap", children: "Thin + thick" })
32098
+ ] })
32099
+ ] }),
32100
+ /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 7 }, children: [
32101
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32102
+ "Color",
32103
+ /* @__PURE__ */ jsx2("input", { "aria-label": "Divider color", type: "color", value: color, onChange: (event) => setColor(event.target.value), style: { width: "100%", height: 30, border: `1px solid ${T.border}`, borderRadius: 5, background: T.popoverBg } })
32104
+ ] }),
32105
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32106
+ "Width (pt)",
32107
+ /* @__PURE__ */ jsx2("input", { "aria-label": "Divider width in points", type: "number", min: "0.25", step: "0.25", value: widthPt, onChange: (event) => setWidthPt(Number(event.target.value)), style: { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 5, padding: "5px 6px", color: T.fg, background: T.popoverBg } })
32108
+ ] }),
32109
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32110
+ "Gap (pt)",
32111
+ /* @__PURE__ */ jsx2("input", { "aria-label": "Divider gap in points", type: "number", min: "0", step: "1", value: spacePt, onChange: (event) => setSpacePt(Number(event.target.value)), style: { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 5, padding: "5px 6px", color: T.fg, background: T.popoverBg } })
32112
+ ] })
32113
+ ] }),
32114
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "space-between", gap: 8 }, children: [
32115
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => {
32116
+ if (api?.setParagraphDivider(null)) setOpen(false);
32117
+ }, style: { ...pillBtn, background: T.popoverBg, color: T.fg, border: `1px solid ${T.border}` }, children: "Remove" }),
32118
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: apply, style: pillBtn, children: "Apply divider" })
32119
+ ] })
32120
+ ] })
32121
+ ] });
32122
+ }
30978
32123
  function ShapeMenu({ api }) {
30979
32124
  const [open, setOpen] = useState2(false);
30980
32125
  const [text, setText] = useState2("");
32126
+ const [lineColor, setLineColor] = useState2("#404040");
32127
+ const [lineWidth, setLineWidth] = useState2("1.33");
32128
+ const [lineDash, setLineDash] = useState2("solid");
30981
32129
  const rootRef = useRef2(null);
30982
32130
  useEffect2(() => {
30983
32131
  if (!open) return;
@@ -30988,14 +32136,17 @@ function ShapeMenu({ api }) {
30988
32136
  return () => document.removeEventListener("mousedown", close);
30989
32137
  }, [open]);
30990
32138
  const insert = (preset) => {
30991
- if (api?.insertShape(preset, text)) {
32139
+ const isLine = preset === "line" || preset === "verticalLine";
32140
+ const width = Number(lineWidth);
32141
+ if (isLine && (!Number.isFinite(width) || width <= 0)) return;
32142
+ if (api?.insertShape(preset, text, isLine ? { color: lineColor, width, dash: lineDash } : void 0)) {
30992
32143
  setText("");
30993
32144
  setOpen(false);
30994
32145
  }
30995
32146
  };
30996
32147
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
30997
32148
  /* @__PURE__ */ jsx2("button", { title: "Insert shape", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: /* @__PURE__ */ jsx2("span", { style: { fontSize: 17 }, children: "\u25C7" }) }),
30998
- open && /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 250, padding: 10, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
32149
+ open && /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 290, padding: 10, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
30999
32150
  /* @__PURE__ */ jsx2(
31000
32151
  "input",
31001
32152
  {
@@ -31006,6 +32157,53 @@ function ShapeMenu({ api }) {
31006
32157
  style: { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 6, padding: "5px 8px", font: "13px system-ui, sans-serif", outline: "none" }
31007
32158
  }
31008
32159
  ),
32160
+ /* @__PURE__ */ jsx2("div", { style: { marginTop: 9, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "Line appearance" }),
32161
+ /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "auto 82px 88px", gap: 6, alignItems: "end", marginTop: 5 }, children: [
32162
+ /* @__PURE__ */ jsx2(
32163
+ ColorMenu,
32164
+ {
32165
+ current: lineColor,
32166
+ title: "Line color",
32167
+ trigger: /* @__PURE__ */ jsxs2(Fragment2, { children: [
32168
+ /* @__PURE__ */ jsx2("span", { style: { fontSize: 12 }, children: "Color" }),
32169
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", style: { width: 16, height: 16, borderRadius: 3, border: `1px solid ${T.border}`, background: lineColor } })
32170
+ ] }),
32171
+ onPick: setLineColor
32172
+ }
32173
+ ),
32174
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "10.5px system-ui, sans-serif" }, children: [
32175
+ "Weight (px)",
32176
+ /* @__PURE__ */ jsx2(
32177
+ "input",
32178
+ {
32179
+ "aria-label": "Line width in pixels",
32180
+ type: "number",
32181
+ min: "0.25",
32182
+ step: "0.25",
32183
+ value: lineWidth,
32184
+ onChange: (event) => setLineWidth(event.target.value),
32185
+ style: { width: "100%", height: 28, boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 5, padding: "3px 5px", color: T.fg, background: T.popoverBg }
32186
+ }
32187
+ )
32188
+ ] }),
32189
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "10.5px system-ui, sans-serif" }, children: [
32190
+ "Style",
32191
+ /* @__PURE__ */ jsxs2(
32192
+ "select",
32193
+ {
32194
+ "aria-label": "Line style",
32195
+ value: lineDash,
32196
+ onChange: (event) => setLineDash(event.target.value),
32197
+ style: { width: "100%", height: 28, border: `1px solid ${T.border}`, borderRadius: 5, padding: "3px 4px", color: T.fg, background: T.popoverBg },
32198
+ children: [
32199
+ /* @__PURE__ */ jsx2("option", { value: "solid", children: "Solid" }),
32200
+ /* @__PURE__ */ jsx2("option", { value: "dashed", children: "Dashed" }),
32201
+ /* @__PURE__ */ jsx2("option", { value: "dotted", children: "Dotted" })
32202
+ ]
32203
+ }
32204
+ )
32205
+ ] })
32206
+ ] }),
31009
32207
  /* @__PURE__ */ jsx2("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 6, marginTop: 8 }, children: SHAPES.map(([preset, label, glyph]) => /* @__PURE__ */ jsxs2("button", { title: `Insert ${label}`, onClick: () => insert(preset), style: { minHeight: 48, border: `1px solid ${T.border}`, borderRadius: 6, background: T.popoverBg, color: T.fg, cursor: "pointer", font: "12px system-ui, sans-serif" }, children: [
31010
32208
  /* @__PURE__ */ jsx2("span", { style: { display: "block", fontSize: 20, lineHeight: 1 }, children: glyph }),
31011
32209
  /* @__PURE__ */ jsx2("span", { children: label })
@@ -31101,12 +32299,12 @@ function WordArtMenu({ api }) {
31101
32299
  ] })
31102
32300
  ] });
31103
32301
  }
31104
- function ChartMenu({ api }) {
32302
+ function ChartMenu({ api, label = "Chart" }) {
31105
32303
  const [open, setOpen] = useState2(false);
31106
32304
  const [type, setType] = useState2("column");
31107
- const [title, setTitle] = useState2("Quarterly sales");
31108
- const [categories, setCategories] = useState2("Q1, Q2, Q3, Q4");
31109
- const [series, setSeries] = useState2("Revenue: 12, 19, 15, 24\nCosts: 8, 11, 10, 14");
32305
+ const [title, setTitle] = useState2("");
32306
+ const [categories, setCategories] = useState2(["", ""]);
32307
+ const [series, setSeries] = useState2([{ name: "", values: ["", ""] }]);
31110
32308
  const [error, setError] = useState2("");
31111
32309
  const rootRef = useRef2(null);
31112
32310
  useEffect2(() => {
@@ -31118,28 +32316,52 @@ function ChartMenu({ api }) {
31118
32316
  return () => document.removeEventListener("mousedown", close);
31119
32317
  }, [open]);
31120
32318
  const submit = () => {
31121
- const categoryValues = categories.split(",").map((value) => value.trim()).filter(Boolean);
31122
- const seriesValues = series.split(/\r?\n/).map((line2) => {
31123
- const separator = line2.indexOf(":");
31124
- if (separator === -1) return null;
31125
- const name = line2.slice(0, separator).trim();
31126
- const values = line2.slice(separator + 1).split(",").map((value) => Number(value.trim()));
31127
- return name && values.length === categoryValues.length && values.every(Number.isFinite) ? { name, values } : null;
31128
- }).filter((value) => value !== null);
31129
- if (!categoryValues.length || !seriesValues.length || seriesValues.length !== series.split(/\r?\n/).filter((line2) => line2.trim()).length) {
31130
- setError("Use comma-separated categories and one \u201CName: 1, 2, 3\u201D series per line.");
32319
+ const categoryValues = categories.map((value) => value.trim());
32320
+ const rawSeries = series.map((entry) => ({
32321
+ name: entry.name.trim(),
32322
+ values: entry.values.map((value) => value.trim())
32323
+ }));
32324
+ if (categoryValues.some((value) => !value) || rawSeries.some((entry) => !entry.name || entry.values.some((value) => value === "" || !Number.isFinite(Number(value))))) {
32325
+ setError("Give every category and series a name, and enter a number in every data cell.");
31131
32326
  return;
31132
32327
  }
32328
+ const seriesValues = rawSeries.map((entry) => ({ name: entry.name, values: entry.values.map(Number) }));
31133
32329
  const data = { type, title, categories: categoryValues, series: seriesValues };
31134
32330
  if (api?.updateSelectedChart(data) || api?.insertChart(data)) {
31135
32331
  setError("");
31136
32332
  setOpen(false);
31137
32333
  }
31138
32334
  };
32335
+ const addCategory = () => {
32336
+ setCategories([...categories, ""]);
32337
+ setSeries(series.map((entry) => ({ ...entry, values: [...entry.values, ""] })));
32338
+ };
32339
+ const removeCategory = (index) => {
32340
+ if (categories.length === 1) return;
32341
+ setCategories(categories.filter((_, itemIndex) => itemIndex !== index));
32342
+ setSeries(series.map((entry) => ({ ...entry, values: entry.values.filter((_, itemIndex) => itemIndex !== index) })));
32343
+ };
32344
+ const anchor = open ? rootRef.current?.getBoundingClientRect() : null;
32345
+ const viewportWidth = typeof window === "undefined" ? 456 : window.innerWidth;
32346
+ const popoverWidth = Math.min(440, viewportWidth - 16);
32347
+ const popoverLeft = Math.max(8, Math.min(anchor?.left ?? 8, viewportWidth - popoverWidth - 8));
31139
32348
  const fieldStyle = { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 6, padding: "6px 8px", font: "13px system-ui, sans-serif", color: T.fg, background: T.popoverBg };
32349
+ const toggle = () => {
32350
+ if (open) {
32351
+ setOpen(false);
32352
+ return;
32353
+ }
32354
+ const selected = api?.getSelectedChart();
32355
+ setType(selected?.type ?? "column");
32356
+ setTitle(selected?.title ?? "");
32357
+ setCategories(selected ? [...selected.categories] : ["", ""]);
32358
+ setSeries(selected ? selected.series.map((entry) => ({ name: entry.name, values: entry.values.map(String) })) : [{ name: "", values: ["", ""] }]);
32359
+ setError("");
32360
+ setOpen(true);
32361
+ };
31140
32362
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31141
- /* @__PURE__ */ jsx2("button", { title: "Insert or edit chart", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "Chart" }),
31142
- open && /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 320, padding: 10, display: "grid", gap: 7, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
32363
+ /* @__PURE__ */ jsx2("button", { title: "Insert or edit chart", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: toggle, children: label }),
32364
+ open && /* @__PURE__ */ jsxs2("div", { style: { position: "fixed", top: anchor?.bottom ?? 28, left: popoverLeft, zIndex: 100, width: popoverWidth, maxHeight: "calc(100vh - 48px)", overflow: "auto", boxSizing: "border-box", padding: 10, display: "grid", gap: 8, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
31143
32365
  /* @__PURE__ */ jsx2(
31144
32366
  ToolbarMenuSelect,
31145
32367
  {
@@ -31158,58 +32380,145 @@ function ChartMenu({ api }) {
31158
32380
  }
31159
32381
  ),
31160
32382
  /* @__PURE__ */ jsx2("input", { "aria-label": "Chart title", value: title, onChange: (event) => setTitle(event.target.value), placeholder: "Chart title", style: fieldStyle }),
31161
- /* @__PURE__ */ jsx2("input", { "aria-label": "Chart categories", value: categories, onChange: (event) => setCategories(event.target.value), placeholder: "Q1, Q2, Q3, Q4", style: fieldStyle }),
31162
- /* @__PURE__ */ jsx2("textarea", { "aria-label": "Chart series", rows: 3, value: series, onChange: (event) => setSeries(event.target.value), style: { ...fieldStyle, resize: "vertical" } }),
31163
- /* @__PURE__ */ jsx2("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "Each series: Name: value, value, value" }),
32383
+ /* @__PURE__ */ jsxs2("div", { role: "group", "aria-label": "Chart data", style: { display: "grid", gap: 7 }, children: [
32384
+ /* @__PURE__ */ jsx2("strong", { style: { color: T.fg, font: "600 11.5px system-ui, sans-serif" }, children: "Data" }),
32385
+ /* @__PURE__ */ jsx2("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: `minmax(110px,1.2fr) repeat(${categories.length},minmax(72px,1fr)) 62px`, gap: 5, minWidth: categories.length > 3 ? 430 : void 0 }, children: [
32386
+ /* @__PURE__ */ jsx2("span", { style: { alignSelf: "center", color: T.muted, font: "11px system-ui, sans-serif" }, children: "Series" }),
32387
+ categories.map((category, index) => /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gridTemplateColumns: "1fr auto", gap: 3 }, children: [
32388
+ /* @__PURE__ */ jsx2(
32389
+ "input",
32390
+ {
32391
+ "aria-label": `Chart category ${index + 1}`,
32392
+ value: category,
32393
+ placeholder: "Category",
32394
+ onChange: (event) => setCategories(categories.map((value, itemIndex) => itemIndex === index ? event.target.value : value)),
32395
+ style: fieldStyle
32396
+ }
32397
+ ),
32398
+ categories.length > 1 && /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove chart category ${index + 1}`, onClick: () => removeCategory(index), style: { ...pillBtn, padding: "0 6px" }, children: "\xD7" })
32399
+ ] }, index)),
32400
+ /* @__PURE__ */ jsx2("span", {}),
32401
+ series.map((entry, seriesIndex) => /* @__PURE__ */ jsxs2(Fragment, { children: [
32402
+ /* @__PURE__ */ jsx2(
32403
+ "input",
32404
+ {
32405
+ "aria-label": `Chart series ${seriesIndex + 1} name`,
32406
+ value: entry.name,
32407
+ placeholder: "Series",
32408
+ onChange: (event) => setSeries(series.map((value, itemIndex) => itemIndex === seriesIndex ? { ...value, name: event.target.value } : value)),
32409
+ style: fieldStyle
32410
+ }
32411
+ ),
32412
+ entry.values.map((value, valueIndex) => /* @__PURE__ */ jsx2(
32413
+ "input",
32414
+ {
32415
+ "aria-label": `Chart series ${seriesIndex + 1} value ${valueIndex + 1}`,
32416
+ type: "number",
32417
+ step: "any",
32418
+ value,
32419
+ placeholder: "0",
32420
+ onChange: (event) => setSeries(series.map((seriesValue, itemIndex) => itemIndex === seriesIndex ? { ...seriesValue, values: seriesValue.values.map((itemValue, itemValueIndex) => itemValueIndex === valueIndex ? event.target.value : itemValue) } : seriesValue)),
32421
+ style: fieldStyle
32422
+ },
32423
+ valueIndex
32424
+ )),
32425
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove chart series ${seriesIndex + 1}`, disabled: series.length === 1, onClick: () => setSeries(series.filter((_, itemIndex) => itemIndex !== seriesIndex)), style: { ...pillBtn, padding: "0 7px" }, children: "Remove" })
32426
+ ] }, seriesIndex))
32427
+ ] }) }),
32428
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 6 }, children: [
32429
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setSeries([...series, { name: "", values: categories.map(() => "") }]), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Add series" }),
32430
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: addCategory, style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Add category" })
32431
+ ] })
32432
+ ] }),
31164
32433
  error && /* @__PURE__ */ jsx2("div", { role: "alert", style: { color: "#c5221f", font: "11.5px system-ui, sans-serif" }, children: error }),
31165
32434
  /* @__PURE__ */ jsx2("button", { onClick: submit, style: { border: 0, borderRadius: 6, padding: "7px 10px", background: T.accent, color: T.accentFg, cursor: "pointer", font: "600 12px system-ui, sans-serif" }, children: "Insert or update chart" })
31166
32435
  ] })
31167
32436
  ] });
31168
32437
  }
31169
- function SmartArtMenu({ api }) {
32438
+ function SmartArtMenu({ api, label = "SmartArt" }) {
31170
32439
  const [open, setOpen] = useState2(false);
32440
+ const [step, setStep] = useState2("layout");
32441
+ const [editing, setEditing] = useState2(false);
31171
32442
  const [layout, setLayout] = useState2("process");
31172
- const [items, setItems] = useState2("Discover\nDesign\nDeliver");
32443
+ const [items, setItems] = useState2([""]);
31173
32444
  const rootRef = useRef2(null);
31174
- useEffect2(() => {
31175
- if (!open) return;
31176
- const close = (event) => {
31177
- if (!rootRef.current?.contains(event.target)) setOpen(false);
31178
- };
31179
- document.addEventListener("mousedown", close);
31180
- return () => document.removeEventListener("mousedown", close);
31181
- }, [open]);
31182
32445
  const submit = () => {
31183
- const values = items.split(/\r?\n/).map((value) => value.trim()).filter(Boolean);
32446
+ const values = items.map((value) => value.trim()).filter(Boolean);
31184
32447
  if (!values.length) return;
31185
32448
  const data = { layout, items: values };
31186
32449
  if (api?.updateSelectedSmartArt(data) || api?.insertSmartArt(data)) setOpen(false);
31187
32450
  };
31188
32451
  const fieldStyle = { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 6, padding: "6px 8px", font: "13px system-ui, sans-serif", color: T.fg, background: T.popoverBg };
32452
+ const toggle = () => {
32453
+ if (open) {
32454
+ setOpen(false);
32455
+ return;
32456
+ }
32457
+ const selected = api?.getSelectedSmartArt();
32458
+ setEditing(!!selected);
32459
+ setLayout(selected?.layout ?? "process");
32460
+ setItems(selected ? [...selected.items] : [""]);
32461
+ setStep(selected ? "items" : "layout");
32462
+ setOpen(true);
32463
+ };
32464
+ const layouts = [
32465
+ { value: "process", label: "Process" },
32466
+ { value: "cycle", label: "Cycle" },
32467
+ { value: "hierarchy", label: "Hierarchy" },
32468
+ { value: "list", label: "List" }
32469
+ ];
32470
+ const preview = (value) => {
32471
+ const node = { width: 22, height: 13, borderRadius: 3, background: T.accent };
32472
+ if (value === "list") return /* @__PURE__ */ jsx2("div", { style: { display: "grid", gap: 4 }, children: [0, 1, 2].map((key) => /* @__PURE__ */ jsx2("span", { style: { ...node, width: 72 } }, key)) });
32473
+ if (value === "hierarchy") return /* @__PURE__ */ jsxs2("div", { style: { display: "grid", justifyItems: "center", gap: 8 }, children: [
32474
+ /* @__PURE__ */ jsx2("span", { style: node }),
32475
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 12 }, children: [
32476
+ /* @__PURE__ */ jsx2("span", { style: node }),
32477
+ /* @__PURE__ */ jsx2("span", { style: node })
32478
+ ] })
32479
+ ] });
32480
+ if (value === "cycle") return /* @__PURE__ */ jsx2("div", { style: { position: "relative", width: 76, height: 48 }, children: [[27, 0], [53, 18], [27, 35], [1, 18]].map(([left, top], key) => /* @__PURE__ */ jsx2("span", { style: { ...node, position: "absolute", left, top } }, key)) });
32481
+ return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [
32482
+ /* @__PURE__ */ jsx2("span", { style: node }),
32483
+ /* @__PURE__ */ jsx2("span", { children: "\u2192" }),
32484
+ /* @__PURE__ */ jsx2("span", { style: node }),
32485
+ /* @__PURE__ */ jsx2("span", { children: "\u2192" }),
32486
+ /* @__PURE__ */ jsx2("span", { style: node })
32487
+ ] });
32488
+ };
31189
32489
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31190
- /* @__PURE__ */ jsx2("button", { title: "Insert or edit SmartArt", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "SmartArt" }),
31191
- open && /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 280, padding: 10, display: "grid", gap: 7, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
31192
- /* @__PURE__ */ jsx2(
31193
- ToolbarMenuSelect,
31194
- {
31195
- value: layout,
31196
- ariaLabel: "SmartArt layout",
31197
- width: "100%",
31198
- menuWidth: 260,
31199
- options: [
31200
- { value: "process", label: "Process" },
31201
- { value: "cycle", label: "Cycle" },
31202
- { value: "hierarchy", label: "Hierarchy" },
31203
- { value: "list", label: "List" }
31204
- ],
31205
- onChange: (value) => setLayout(value),
31206
- style: fieldStyle
31207
- }
31208
- ),
31209
- /* @__PURE__ */ jsx2("textarea", { "aria-label": "SmartArt items", rows: 5, value: items, onChange: (event) => setItems(event.target.value), style: { ...fieldStyle, resize: "vertical" } }),
31210
- /* @__PURE__ */ jsx2("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "One diagram item per line." }),
31211
- /* @__PURE__ */ jsx2("button", { disabled: !items.trim(), onClick: submit, style: { border: 0, borderRadius: 6, padding: "7px 10px", background: items.trim() ? T.accent : T.border, color: T.accentFg, cursor: items.trim() ? "pointer" : "default", font: "600 12px system-ui, sans-serif" }, children: "Insert or update SmartArt" })
31212
- ] })
32490
+ /* @__PURE__ */ jsx2("button", { title: "Insert or edit SmartArt", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: toggle, children: label }),
32491
+ open && createPortal2(
32492
+ /* @__PURE__ */ jsx2("div", { style: { position: "fixed", inset: 0, zIndex: 1e3, display: "grid", placeItems: "center", padding: 16, background: "rgba(0,0,0,.34)" }, onMouseDown: (event) => event.target === event.currentTarget && setOpen(false), children: /* @__PURE__ */ jsxs2("div", { role: "dialog", "aria-modal": "true", "aria-label": editing ? "Edit SmartArt" : "Insert SmartArt", style: { width: "min(560px,calc(100vw - 32px))", maxHeight: "calc(100vh - 32px)", overflow: "auto", boxSizing: "border-box", padding: 18, display: "grid", gap: 14, color: T.fg, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 12, boxShadow: T.popoverShadow }, children: [
32493
+ /* @__PURE__ */ jsxs2("div", { children: [
32494
+ /* @__PURE__ */ jsx2("strong", { style: { display: "block", font: "600 18px system-ui, sans-serif" }, children: step === "layout" ? "Choose a SmartArt layout" : editing ? "Edit SmartArt" : "Add SmartArt text" }),
32495
+ /* @__PURE__ */ jsx2("span", { style: { color: T.muted, font: "12px system-ui, sans-serif" }, children: step === "layout" ? "Choose one of the supported layout families." : layouts.find((item) => item.value === layout)?.label })
32496
+ ] }),
32497
+ step === "layout" ? /* @__PURE__ */ jsx2("div", { role: "group", "aria-label": "SmartArt layouts", style: { display: "grid", gridTemplateColumns: "repeat(2,minmax(0,1fr))", gap: 10 }, children: layouts.map((option) => /* @__PURE__ */ jsxs2("button", { type: "button", "aria-label": `${option.label} SmartArt`, onClick: () => {
32498
+ setLayout(option.value);
32499
+ setStep("items");
32500
+ }, style: { minHeight: 118, display: "grid", placeItems: "center", gap: 9, padding: 12, border: `1px solid ${layout === option.value ? T.accent : T.border}`, borderRadius: 9, background: layout === option.value ? T.activeBg : T.popoverBg, color: T.fg, cursor: "pointer" }, children: [
32501
+ preview(option.value),
32502
+ /* @__PURE__ */ jsx2("span", { style: { font: "600 13px system-ui, sans-serif" }, children: option.label })
32503
+ ] }, option.value)) }) : /* @__PURE__ */ jsxs2("div", { role: "group", "aria-label": "SmartArt items", style: { display: "grid", gap: 7 }, children: [
32504
+ items.map((item, index) => /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr auto auto auto", gap: 5 }, children: [
32505
+ /* @__PURE__ */ jsx2("input", { "aria-label": `SmartArt item ${index + 1}`, value: item, placeholder: "Item", onChange: (event) => setItems(items.map((value, itemIndex) => itemIndex === index ? event.target.value : value)), style: fieldStyle }),
32506
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Move SmartArt item ${index + 1} up`, disabled: index === 0, onClick: () => setItems(items.map((value, itemIndex) => itemIndex === index - 1 ? items[index] : itemIndex === index ? items[index - 1] : value)), style: { ...pillBtn, padding: "0 8px" }, children: "\u2191" }),
32507
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Move SmartArt item ${index + 1} down`, disabled: index === items.length - 1, onClick: () => setItems(items.map((value, itemIndex) => itemIndex === index ? items[index + 1] : itemIndex === index + 1 ? items[index] : value)), style: { ...pillBtn, padding: "0 8px" }, children: "\u2193" }),
32508
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove SmartArt item ${index + 1}`, disabled: items.length === 1, onClick: () => setItems(items.filter((_, itemIndex) => itemIndex !== index)), style: { ...pillBtn, padding: "0 8px" }, children: "\xD7" })
32509
+ ] }, index)),
32510
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setItems([...items, ""]), style: { ...pillBtn, justifySelf: "start", background: T.popoverBg, color: T.fg }, children: "Add item" })
32511
+ ] }),
32512
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "space-between", gap: 8 }, children: [
32513
+ /* @__PURE__ */ jsx2("div", { children: step === "items" && /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setStep("layout"), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Back" }) }),
32514
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 7 }, children: [
32515
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setOpen(false), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Cancel" }),
32516
+ step === "items" && /* @__PURE__ */ jsx2("button", { type: "button", disabled: !items.some((item) => item.trim()), onClick: submit, style: { border: 0, borderRadius: 6, padding: "7px 12px", background: items.some((item) => item.trim()) ? T.accent : T.border, color: T.accentFg, cursor: items.some((item) => item.trim()) ? "pointer" : "default", font: "600 12px system-ui, sans-serif" }, children: editing ? "Update" : "Insert" })
32517
+ ] })
32518
+ ] })
32519
+ ] }) }),
32520
+ document.body
32521
+ )
31213
32522
  ] });
31214
32523
  }
31215
32524
  function MediaMenu({ api }) {
@@ -31227,7 +32536,7 @@ function MediaMenu({ api }) {
31227
32536
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31228
32537
  /* @__PURE__ */ jsx2("button", { title: "Insert online video", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "Media" }),
31229
32538
  open && /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 300, padding: 10, display: "grid", gap: 7, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
31230
- /* @__PURE__ */ jsx2("input", { "aria-label": "Online video URL", value: url, onChange: (event) => setUrl(event.target.value), placeholder: "https://www.youtube.com/watch?v=\u2026", style: { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 6, padding: "6px 8px", font: "13px system-ui, sans-serif", color: T.fg, background: T.popoverBg } }),
32539
+ /* @__PURE__ */ jsx2("input", { "aria-label": "Online video URL", type: "url", value: url, onChange: (event) => setUrl(event.target.value), placeholder: "https://www.youtube.com/watch?v=\u2026", style: { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 6, padding: "6px 8px", font: "13px system-ui, sans-serif", color: T.fg, background: T.popoverBg } }),
31231
32540
  /* @__PURE__ */ jsx2(
31232
32541
  "button",
31233
32542
  {
@@ -31497,6 +32806,65 @@ function TableMenu({ api }) {
31497
32806
  )
31498
32807
  ] });
31499
32808
  }
32809
+ function TableFormatTab({
32810
+ api,
32811
+ fill,
32812
+ onChanged
32813
+ }) {
32814
+ const run = (op) => {
32815
+ api?.tableOp(op);
32816
+ onChanged();
32817
+ };
32818
+ return /* @__PURE__ */ jsxs2("span", { "data-dxw-table-format": "", style: { display: "contents" }, children: [
32819
+ /* @__PURE__ */ jsx2(
32820
+ ColorMenu,
32821
+ {
32822
+ current: fill ?? "#FFFFFF",
32823
+ title: "Cell fill color",
32824
+ trigger: /* @__PURE__ */ jsxs2(Fragment2, { children: [
32825
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", style: { width: 14, height: 14, borderRadius: 3, border: `1px solid ${T.border}`, background: fill ?? "#FFFFFF" } }),
32826
+ "Cell fill"
32827
+ ] }),
32828
+ onPick: (color) => run({ kind: "cellShading", fill: color })
32829
+ }
32830
+ ),
32831
+ fill !== null && /* @__PURE__ */ jsx2(Btn, { label: "No fill", title: "Remove cell fill", onClick: () => run({ kind: "cellShading", fill: null }) }),
32832
+ /* @__PURE__ */ jsx2(
32833
+ ActionMenu,
32834
+ {
32835
+ label: "Cell alignment",
32836
+ title: "Align text inside the current cell",
32837
+ width: 132,
32838
+ groups: [{ items: [["top", "Top"], ["center", "Middle"], ["bottom", "Bottom"]] }],
32839
+ onPick: (value) => run({ kind: "cellVAlign", v: value })
32840
+ }
32841
+ ),
32842
+ /* @__PURE__ */ jsx2(
32843
+ ActionMenu,
32844
+ {
32845
+ label: "Rows & columns",
32846
+ title: "Edit rows and columns around the current cell",
32847
+ width: 144,
32848
+ groups: [
32849
+ { label: "Rows", items: [["rowAbove", "Insert row above"], ["rowBelow", "Insert row below"], ["deleteRow", "Delete row"]] },
32850
+ { label: "Columns", items: [["colLeft", "Insert column left"], ["colRight", "Insert column right"], ["deleteCol", "Delete column"]] }
32851
+ ],
32852
+ onPick: (value) => run(value)
32853
+ }
32854
+ ),
32855
+ /* @__PURE__ */ jsx2(
32856
+ ActionMenu,
32857
+ {
32858
+ label: "Merge",
32859
+ title: "Merge or split the current cell",
32860
+ width: 78,
32861
+ groups: [{ items: [["mergeRight", "Merge right"], ["mergeDown", "Merge down"], ["splitCell", "Split cell"]] }],
32862
+ onPick: (value) => run(value)
32863
+ }
32864
+ ),
32865
+ /* @__PURE__ */ jsx2(Btn, { label: "Delete table", title: "Delete the current table", onClick: () => run("deleteTable") })
32866
+ ] });
32867
+ }
31500
32868
  function PagePreview({
31501
32869
  kind,
31502
32870
  width = 8.5,
@@ -31506,6 +32874,7 @@ function PagePreview({
31506
32874
  columns,
31507
32875
  columnSeparator,
31508
32876
  border,
32877
+ borderColor,
31509
32878
  lineNumbers
31510
32879
  }) {
31511
32880
  const maxWidth = mirrored ? 21 : 34;
@@ -31516,7 +32885,7 @@ function PagePreview({
31516
32885
  const papers = mirrored ? 2 : 1;
31517
32886
  const inset = margins ?? [0.8, 0.8, 0.8, 0.8];
31518
32887
  const borderWidth = border === "thick" ? 2 : border === "none" ? 0 : 1;
31519
- const borderColor = border === "accent" ? T.accent : T.muted;
32888
+ const pageBorderColor = borderColor ?? (border === "accent" ? T.accent : T.muted);
31520
32889
  return /* @__PURE__ */ jsx2(
31521
32890
  "span",
31522
32891
  {
@@ -31535,7 +32904,7 @@ function PagePreview({
31535
32904
  width: paperWidth,
31536
32905
  height: paperHeight,
31537
32906
  background: "var(--dxw-layout-preview-bg, #fff)",
31538
- border: `${Math.max(1, borderWidth)}px solid ${borderWidth ? borderColor : T.border}`
32907
+ border: `${Math.max(1, borderWidth)}px solid ${borderWidth ? pageBorderColor : T.border}`
31539
32908
  },
31540
32909
  children: [
31541
32910
  kind === "margins" && /* @__PURE__ */ jsx2("span", { style: {
@@ -31864,8 +33233,9 @@ function MarginMenu({
31864
33233
  "input",
31865
33234
  {
31866
33235
  "aria-label": `${label} margin (inches)`,
31867
- type: "text",
31868
- inputMode: "decimal",
33236
+ type: "number",
33237
+ min: "0",
33238
+ step: "0.05",
31869
33239
  required: true,
31870
33240
  autoFocus: side === "top",
31871
33241
  value: values[side],
@@ -31990,8 +33360,9 @@ function PageSizeMenu({
31990
33360
  "input",
31991
33361
  {
31992
33362
  "aria-label": `Page ${side} (inches)`,
31993
- type: "text",
31994
- inputMode: "decimal",
33363
+ type: "number",
33364
+ min: "0.1",
33365
+ step: "0.05",
31995
33366
  required: true,
31996
33367
  autoFocus: side === "width",
31997
33368
  value: values[side],
@@ -32071,6 +33442,136 @@ function PageSizeMenu({
32071
33442
  )
32072
33443
  ] });
32073
33444
  }
33445
+ function PageBorderMenu({
33446
+ scope,
33447
+ onApply,
33448
+ open,
33449
+ onOpenChange
33450
+ }) {
33451
+ const [customOpen, setCustomOpen] = useState2(false);
33452
+ const [color, setColor] = useState2("#4472c4");
33453
+ const [widthPt, setWidthPt] = useState2("1");
33454
+ const rootRef = useRef2(null);
33455
+ const [dialogPosition, setDialogPosition] = useState2({ left: 8, top: 8 });
33456
+ useEffect2(() => {
33457
+ if (!customOpen) return;
33458
+ const positionDialog = () => {
33459
+ const trigger = rootRef.current?.querySelector("[data-dxw-layout-menu-trigger]");
33460
+ if (!trigger) return;
33461
+ const rect = trigger.getBoundingClientRect();
33462
+ const width2 = Math.min(244, window.innerWidth - 16);
33463
+ setDialogPosition({
33464
+ left: Math.max(8, Math.min(rect.left, window.innerWidth - width2 - 8)),
33465
+ top: Math.max(8, Math.min(rect.bottom + 4, window.innerHeight - 224))
33466
+ });
33467
+ };
33468
+ const close = (event) => {
33469
+ if (!rootRef.current?.contains(event.target)) setCustomOpen(false);
33470
+ };
33471
+ const keydown = (event) => {
33472
+ if (event.key === "Escape") setCustomOpen(false);
33473
+ };
33474
+ positionDialog();
33475
+ document.addEventListener("mousedown", close);
33476
+ document.addEventListener("keydown", keydown);
33477
+ window.addEventListener("resize", positionDialog);
33478
+ return () => {
33479
+ document.removeEventListener("mousedown", close);
33480
+ document.removeEventListener("keydown", keydown);
33481
+ window.removeEventListener("resize", positionDialog);
33482
+ };
33483
+ }, [customOpen]);
33484
+ const validColor = normalizedColor(color);
33485
+ const width = Number(widthPt);
33486
+ const valid = validColor !== null && Number.isFinite(width) && width >= 0.25 && width <= 12;
33487
+ const applyCustom = () => {
33488
+ if (!validColor || !valid) return;
33489
+ onApply({ pageBorders: { sz: Math.round(width * 8), color: validColor } });
33490
+ setCustomOpen(false);
33491
+ };
33492
+ const pick = (value) => {
33493
+ if (value === "custom") {
33494
+ setCustomOpen(true);
33495
+ return;
33496
+ }
33497
+ setCustomOpen(false);
33498
+ if (value === "none") onApply({ pageBorders: null });
33499
+ else if (value === "thin") onApply({ pageBorders: { sz: 4 } });
33500
+ else if (value === "thick") onApply({ pageBorders: { sz: 12 } });
33501
+ else onApply({ pageBorders: { sz: 8, color: "4472C4" } });
33502
+ };
33503
+ return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-flex" }, children: [
33504
+ /* @__PURE__ */ jsx2(
33505
+ LayoutMenu,
33506
+ {
33507
+ name: "page-border",
33508
+ label: "Page border",
33509
+ open,
33510
+ onOpenChange,
33511
+ onPick: pick,
33512
+ options: [
33513
+ { value: "none", label: "None", description: "No page border", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "none" }) },
33514
+ { value: "thin", label: "Thin box", description: "\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thin" }) },
33515
+ { value: "thick", label: "Thick box", description: "1\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thick" }) },
33516
+ { value: "accent", label: "Accent box", description: "Blue 1 pt line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "accent" }) },
33517
+ { value: "custom", label: "Custom border\u2026", description: "Choose a color and line weight", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "accent", borderColor: validColor ?? "#4472c4" }) }
33518
+ ]
33519
+ }
33520
+ ),
33521
+ customOpen && /* @__PURE__ */ jsxs2(
33522
+ "div",
33523
+ {
33524
+ role: "dialog",
33525
+ "aria-label": "Custom Page Border",
33526
+ onMouseDown: (event) => event.stopPropagation(),
33527
+ style: {
33528
+ position: "fixed",
33529
+ top: dialogPosition.top,
33530
+ left: dialogPosition.left,
33531
+ zIndex: 201,
33532
+ width: "min(224px, calc(100vw - 16px))",
33533
+ boxSizing: "border-box",
33534
+ background: T.popoverBg,
33535
+ border: `1px solid ${T.border}`,
33536
+ borderRadius: 8,
33537
+ boxShadow: T.popoverShadow,
33538
+ padding: 10,
33539
+ display: "grid",
33540
+ gap: 8
33541
+ },
33542
+ children: [
33543
+ /* @__PURE__ */ jsx2("strong", { style: { fontSize: 13 }, children: "Custom Page Border" }),
33544
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gridTemplateColumns: "54px 1fr", gap: 8, alignItems: "center", fontSize: 12 }, children: [
33545
+ /* @__PURE__ */ jsx2("span", { children: "Color" }),
33546
+ /* @__PURE__ */ jsxs2("span", { style: { display: "flex", gap: 6 }, children: [
33547
+ /* @__PURE__ */ jsx2("input", { "aria-label": "Page border color picker", type: "color", value: validColor ?? "#4472c4", onChange: (event) => setColor(event.target.value), style: { width: 34, height: 28, padding: 1, border: `1px solid ${T.border}`, borderRadius: 5, background: T.popoverBg } }),
33548
+ /* @__PURE__ */ jsx2("input", { "aria-label": "Page border color", autoFocus: true, value: color, onChange: (event) => setColor(event.target.value), onKeyDown: (event) => event.key === "Enter" && applyCustom(), spellCheck: false, style: { width: 92, boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 5, padding: "4px 6px", color: T.fg, background: T.popoverBg } })
33549
+ ] })
33550
+ ] }),
33551
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gridTemplateColumns: "54px 1fr", gap: 8, alignItems: "center", fontSize: 12 }, children: [
33552
+ /* @__PURE__ */ jsx2("span", { children: "Weight" }),
33553
+ /* @__PURE__ */ jsxs2("select", { "aria-label": "Page border width", value: widthPt, onChange: (event) => setWidthPt(event.target.value), style: { width: 132, border: `1px solid ${T.border}`, borderRadius: 5, padding: "4px 6px", color: T.fg, background: T.popoverBg }, children: [
33554
+ /* @__PURE__ */ jsx2("option", { value: "0.5", children: "\xBD pt" }),
33555
+ /* @__PURE__ */ jsx2("option", { value: "1", children: "1 pt" }),
33556
+ /* @__PURE__ */ jsx2("option", { value: "1.5", children: "1\xBD pt" }),
33557
+ /* @__PURE__ */ jsx2("option", { value: "2.25", children: "2\xBC pt" }),
33558
+ /* @__PURE__ */ jsx2("option", { value: "3", children: "3 pt" })
33559
+ ] })
33560
+ ] }),
33561
+ /* @__PURE__ */ jsxs2("span", { style: { color: T.muted, fontSize: 11 }, children: [
33562
+ "Applies to ",
33563
+ scope === "section" ? "this section" : "the whole document",
33564
+ "."
33565
+ ] }),
33566
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "flex-end", gap: 6 }, children: [
33567
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setCustomOpen(false), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Cancel" }),
33568
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: applyCustom, disabled: !valid, style: pillBtn, children: "Apply" })
33569
+ ] })
33570
+ ]
33571
+ }
33572
+ )
33573
+ ] });
33574
+ }
32074
33575
  function LayoutTab({ api, showArrange }) {
32075
33576
  const [scope, setScope] = useState2("document");
32076
33577
  const [section, setSection] = useState2(null);
@@ -32166,26 +33667,7 @@ function LayoutTab({ api, showArrange }) {
32166
33667
  onPick: (value) => set({ columns: parseInt(value, 10), columnSeparator: value === "2-divider" })
32167
33668
  }
32168
33669
  ),
32169
- /* @__PURE__ */ jsx2(
32170
- LayoutMenu,
32171
- {
32172
- name: "page-border",
32173
- label: "Page border",
32174
- ...menuState("page-border"),
32175
- options: [
32176
- { value: "none", label: "None", description: "No page border", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "none" }) },
32177
- { value: "thin", label: "Thin box", description: "\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thin" }) },
32178
- { value: "thick", label: "Thick box", description: "1\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thick" }) },
32179
- { value: "accent", label: "Accent box", description: "Blue 1 pt line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "accent" }) }
32180
- ],
32181
- onPick: (value) => {
32182
- if (value === "none") set({ pageBorders: null });
32183
- else if (value === "thin") set({ pageBorders: { sz: 4 } });
32184
- else if (value === "thick") set({ pageBorders: { sz: 12 } });
32185
- else set({ pageBorders: { sz: 8, color: "4472C4" } });
32186
- }
32187
- }
32188
- ),
33670
+ /* @__PURE__ */ jsx2(PageBorderMenu, { scope, onApply: set, ...menuState("page-border") }),
32189
33671
  /* @__PURE__ */ jsx2(
32190
33672
  LayoutMenu,
32191
33673
  {
@@ -32250,6 +33732,125 @@ function LayoutTab({ api, showArrange }) {
32250
33732
  }
32251
33733
  );
32252
33734
  }
33735
+ function SmartArtTextControls({ api, nodeIndex }) {
33736
+ const nodeSelected = nodeIndex !== void 0;
33737
+ const [format, setFormat] = useState2(() => api?.getSelectedSmartArtTextFormat() ?? null);
33738
+ useEffect2(() => setFormat(api?.getSelectedSmartArtTextFormat() ?? null), [api, nodeIndex]);
33739
+ if (!format) return null;
33740
+ const apply = (patch) => {
33741
+ if (api?.setSelectedSmartArtTextFormat(patch)) setFormat(api.getSelectedSmartArtTextFormat());
33742
+ };
33743
+ const fonts = detectFonts();
33744
+ const sizes = SIZES.includes(format.fontSizePt) ? SIZES : [format.fontSizePt, ...SIZES];
33745
+ const scope = nodeSelected ? "selected node" : "all nodes";
33746
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
33747
+ /* @__PURE__ */ jsx2(Sep, {}),
33748
+ /* @__PURE__ */ jsx2(
33749
+ ToolbarMenuSelect,
33750
+ {
33751
+ title: `Font for ${scope}`,
33752
+ value: format.fontFamily,
33753
+ width: 126,
33754
+ menuWidth: 210,
33755
+ options: (fonts.includes(format.fontFamily) ? fonts : [format.fontFamily, ...fonts]).map((font) => ({
33756
+ value: font,
33757
+ label: font,
33758
+ fontFamily: font
33759
+ })),
33760
+ onChange: (fontFamily) => fontFamily && apply({ fontFamily })
33761
+ }
33762
+ ),
33763
+ /* @__PURE__ */ jsx2(
33764
+ ToolbarMenuSelect,
33765
+ {
33766
+ title: `Font size for ${scope}`,
33767
+ value: String(format.fontSizePt),
33768
+ width: 58,
33769
+ menuWidth: 92,
33770
+ options: sizes.map((size) => ({ value: String(size), label: String(size) })),
33771
+ onChange: (value) => value && apply({ fontSizePt: Number(value) })
33772
+ }
33773
+ ),
33774
+ /* @__PURE__ */ jsx2(Btn, { label: /* @__PURE__ */ jsx2("b", { children: "B" }), title: `Bold ${scope}`, active: format.bold, onClick: () => apply({ bold: !format.bold }) }),
33775
+ /* @__PURE__ */ jsx2(Btn, { label: /* @__PURE__ */ jsx2("i", { children: "I" }), title: `Italic ${scope}`, active: format.italic, onClick: () => apply({ italic: !format.italic }) }),
33776
+ /* @__PURE__ */ jsx2(
33777
+ ColorMenu,
33778
+ {
33779
+ current: format.color,
33780
+ title: `Text color for ${scope}`,
33781
+ trigger: /* @__PURE__ */ jsx2("span", { style: { fontSize: 13, borderBottom: `3px solid ${format.color}`, padding: "0 3px" }, children: "A" }),
33782
+ onPick: (color) => apply({ color })
33783
+ }
33784
+ ),
33785
+ /* @__PURE__ */ jsx2(
33786
+ ActionMenu,
33787
+ {
33788
+ label: format.alignment === "center" ? "Center" : format.alignment === "right" ? "Right" : "Left",
33789
+ title: `Text alignment for ${scope}`,
33790
+ width: 74,
33791
+ groups: [{ items: [["left", "Align left"], ["center", "Align center"], ["right", "Align right"]] }],
33792
+ onPick: (alignment) => apply({ alignment })
33793
+ }
33794
+ )
33795
+ ] });
33796
+ }
33797
+ function ObjectFormatTab({
33798
+ api,
33799
+ context,
33800
+ showArrange
33801
+ }) {
33802
+ const run = (command) => api?.runSelectedObjectCommand(command);
33803
+ const wrap = /* @__PURE__ */ jsx2(
33804
+ ActionMenu,
33805
+ {
33806
+ label: "Wrap",
33807
+ title: "Wrap",
33808
+ width: 72,
33809
+ groups: [{ items: [
33810
+ ["wrapInline", "Inline with text"],
33811
+ ["wrapSquare", "Square"],
33812
+ ["wrapTopAndBottom", "Top and bottom"],
33813
+ ["wrapFront", "In front of text"],
33814
+ ["wrapBehind", "Behind text"]
33815
+ ] }],
33816
+ onPick: (value) => run(value)
33817
+ }
33818
+ );
33819
+ return /* @__PURE__ */ jsxs2("span", { "data-dxw-object-format": "", style: { display: "contents" }, children: [
33820
+ context.kind === "chart" && /* @__PURE__ */ jsx2(ChartMenu, { api, label: "Edit data" }),
33821
+ context.kind === "smartArt" && /* @__PURE__ */ jsx2(SmartArtMenu, { api, label: "Edit SmartArt" }),
33822
+ context.kind === "smartArt" && /* @__PURE__ */ jsx2(SmartArtTextControls, { api, nodeIndex: context.smartArtNodeIndex }),
33823
+ context.canEditText && /* @__PURE__ */ jsx2(
33824
+ Btn,
33825
+ {
33826
+ label: "Edit text",
33827
+ title: context.kind === "smartArt" ? "Edit selected SmartArt node text" : "Edit shape text",
33828
+ onClick: () => run("editText")
33829
+ }
33830
+ ),
33831
+ (context.kind === "shape" || context.kind === "smartArt") && /* @__PURE__ */ jsx2(
33832
+ Btn,
33833
+ {
33834
+ label: context.kind === "smartArt" ? context.smartArtNodeSelected ? "Node fill" : "Fill all" : "Fill",
33835
+ title: context.kind === "smartArt" ? context.smartArtNodeSelected ? "Selected SmartArt node fill" : "All SmartArt node fills" : "Fill color",
33836
+ onClick: () => run("fill")
33837
+ }
33838
+ ),
33839
+ context.kind === "shape" && /* @__PURE__ */ jsx2(Btn, { label: "Outline", title: "Outline color, weight, and style", onClick: () => run("outline") }),
33840
+ context.kind === "line" && /* @__PURE__ */ jsx2(Btn, { label: "Line style", title: "Line color, weight, and style", onClick: () => run("lineStyle") }),
33841
+ (context.kind === "image" || context.kind === "model3d") && /* @__PURE__ */ jsx2(Btn, { label: "Alt text", title: "Alternative text", onClick: () => run("altText") }),
33842
+ wrap,
33843
+ /* @__PURE__ */ jsx2(Btn, { label: "Size", title: "Exact size", onClick: () => run("size") }),
33844
+ /* @__PURE__ */ jsx2(Btn, { label: "Position", title: "Exact page position", onClick: () => run("position") }),
33845
+ (context.kind === "shape" || context.kind === "line" || context.kind === "image" || context.kind === "model3d") && /* @__PURE__ */ jsx2(Btn, { label: "Rotate", title: "Set rotation", onClick: () => run("rotate") }),
33846
+ showArrange && /* @__PURE__ */ jsxs2(Fragment2, { children: [
33847
+ /* @__PURE__ */ jsx2(Btn, { label: "Bring forward", title: "Bring selected object forward", onClick: () => run("bringForward") }),
33848
+ /* @__PURE__ */ jsx2(Btn, { label: "Send backward", title: "Send selected object backward", onClick: () => run("sendBackward") })
33849
+ ] }),
33850
+ context.kind === "model3d" && /* @__PURE__ */ jsx2(Btn, { label: "Reset 3D", title: "Reset 3D rotation", onClick: () => run("reset3d") }),
33851
+ /* @__PURE__ */ jsx2(Btn, { label: "Delete", title: "Delete selected object", onClick: () => run("delete") })
33852
+ ] });
33853
+ }
32253
33854
  function DocxToolbar({
32254
33855
  api,
32255
33856
  onSave,
@@ -32260,6 +33861,14 @@ function DocxToolbar({
32260
33861
  }) {
32261
33862
  const on = (k) => features?.[k] !== false;
32262
33863
  const [tab, setTab] = useState2("home");
33864
+ const priorNormalTab = useRef2("home");
33865
+ const [objectContext, setObjectContext] = useState2(null);
33866
+ const [tableCellFill, setTableCellFill] = useState2(void 0);
33867
+ const tableContextRef = useRef2(void 0);
33868
+ const selectNormalTab = (next) => {
33869
+ priorNormalTab.current = next;
33870
+ setTab(next);
33871
+ };
32263
33872
  const [helpOpen, setHelpOpen] = useState2(false);
32264
33873
  const apple = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
32265
33874
  const shortcut = (key) => apple ? `\u2318${key}` : `Ctrl+${key}`;
@@ -32308,6 +33917,22 @@ function DocxToolbar({
32308
33917
  document.addEventListener("keydown", keydown);
32309
33918
  return () => document.removeEventListener("keydown", keydown);
32310
33919
  }, [features]);
33920
+ useEffect2(() => {
33921
+ const refreshObject = () => {
33922
+ const next = api?.getSelectedObjectContext() ?? null;
33923
+ setObjectContext(next);
33924
+ setTab((current) => {
33925
+ if (next) {
33926
+ if (["home", "insert", "draw", "layout"].includes(current)) priorNormalTab.current = current;
33927
+ return "format";
33928
+ }
33929
+ return current === "format" ? tableContextRef.current !== void 0 ? "tableFormat" : priorNormalTab.current : current;
33930
+ });
33931
+ };
33932
+ refreshObject();
33933
+ document.addEventListener("dxw-object-selection", refreshObject);
33934
+ return () => document.removeEventListener("dxw-object-selection", refreshObject);
33935
+ }, [api]);
32311
33936
  useEffect2(() => {
32312
33937
  const el16 = rootRef.current;
32313
33938
  if (!el16 || typeof ResizeObserver === "undefined") return;
@@ -32332,6 +33957,18 @@ function DocxToolbar({
32332
33957
  setFmt(api?.getSelectionFormat() ?? null);
32333
33958
  setCurStyle(api?.getParagraphStyleId?.() ?? null);
32334
33959
  setListKind(api?.getListType?.() ?? null);
33960
+ const nextTableFill = api?.getTableCellFill();
33961
+ const wasInTable = tableContextRef.current !== void 0;
33962
+ tableContextRef.current = nextTableFill;
33963
+ setTableCellFill(nextTableFill);
33964
+ setTab((current) => {
33965
+ if (nextTableFill !== void 0 && !wasInTable && current !== "format") {
33966
+ if (["home", "insert", "draw", "layout"].includes(current)) priorNormalTab.current = current;
33967
+ return "tableFormat";
33968
+ }
33969
+ if (nextTableFill === void 0 && current === "tableFormat") return priorNormalTab.current;
33970
+ return current;
33971
+ });
32335
33972
  }, [api]);
32336
33973
  useEffect2(() => {
32337
33974
  document.addEventListener("selectionchange", refresh);
@@ -32547,8 +34184,10 @@ function DocxToolbar({
32547
34184
  title: "Exact line height",
32548
34185
  label: "Line height (points)",
32549
34186
  value: "24",
32550
- placeholder: "24",
32551
- submitLabel: "Apply"
34187
+ submitLabel: "Apply",
34188
+ inputType: "number",
34189
+ min: 1,
34190
+ step: 0.5
32552
34191
  }).then((next) => {
32553
34192
  if (next === null) return;
32554
34193
  const points = Number(next.trim());
@@ -32656,8 +34295,9 @@ function DocxToolbar({
32656
34295
  "button",
32657
34296
  {
32658
34297
  "data-tab": t,
34298
+ "aria-pressed": tab === t,
32659
34299
  onMouseDown: (e) => e.preventDefault(),
32660
- onClick: () => setTab(t),
34300
+ onClick: () => selectNormalTab(t),
32661
34301
  style: {
32662
34302
  border: "none",
32663
34303
  background: tab === t ? T.tabActiveBg : "transparent",
@@ -32672,6 +34312,51 @@ function DocxToolbar({
32672
34312
  },
32673
34313
  t
32674
34314
  )),
34315
+ objectContext && /* @__PURE__ */ jsx2(
34316
+ "button",
34317
+ {
34318
+ "data-tab": "format",
34319
+ "aria-pressed": tab === "format",
34320
+ onMouseDown: (event) => event.preventDefault(),
34321
+ onClick: () => setTab("format"),
34322
+ style: {
34323
+ border: "none",
34324
+ background: tab === "format" ? T.tabActiveBg : "transparent",
34325
+ color: tab === "format" ? T.accent : T.fg,
34326
+ font: "600 12.5px system-ui, sans-serif",
34327
+ padding: "5px 10px",
34328
+ borderRadius: 6,
34329
+ cursor: "pointer"
34330
+ },
34331
+ children: {
34332
+ shape: "Shape Format",
34333
+ line: "Line Format",
34334
+ smartArt: "SmartArt Format",
34335
+ chart: "Chart Format",
34336
+ image: "Picture Format",
34337
+ model3d: "3D Format"
34338
+ }[objectContext.kind]
34339
+ }
34340
+ ),
34341
+ !objectContext && tableCellFill !== void 0 && /* @__PURE__ */ jsx2(
34342
+ "button",
34343
+ {
34344
+ "data-tab": "tableFormat",
34345
+ "aria-pressed": tab === "tableFormat",
34346
+ onMouseDown: (event) => event.preventDefault(),
34347
+ onClick: () => setTab("tableFormat"),
34348
+ style: {
34349
+ border: "none",
34350
+ background: tab === "tableFormat" ? T.tabActiveBg : "transparent",
34351
+ color: tab === "tableFormat" ? T.accent : T.fg,
34352
+ font: "600 12.5px system-ui, sans-serif",
34353
+ padding: "5px 10px",
34354
+ borderRadius: 6,
34355
+ cursor: "pointer"
34356
+ },
34357
+ children: "Table Format"
34358
+ }
34359
+ ),
32675
34360
  on("help") && /* @__PURE__ */ jsx2(
32676
34361
  "button",
32677
34362
  {
@@ -32711,6 +34396,7 @@ function DocxToolbar({
32711
34396
  on("chart") && /* @__PURE__ */ jsx2(ChartMenu, { api }),
32712
34397
  on("media") && /* @__PURE__ */ jsx2(MediaMenu, { api }),
32713
34398
  on("shape") && /* @__PURE__ */ jsx2(ShapeMenu, { api }),
34399
+ on("divider") && /* @__PURE__ */ jsx2(DividerMenu, { api }),
32714
34400
  on("textBox") && /* @__PURE__ */ jsx2(TextBoxMenu, { api }),
32715
34401
  on("wordArt") && /* @__PURE__ */ jsx2(WordArtMenu, { api }),
32716
34402
  on("link") && /* @__PURE__ */ jsx2(LinkMenu, { api }),
@@ -32718,10 +34404,16 @@ function DocxToolbar({
32718
34404
  on("footnote") && /* @__PURE__ */ jsx2(FootnoteMenu, { api }),
32719
34405
  on("bookmark") && /* @__PURE__ */ jsx2(BookmarkMenu, { api }),
32720
34406
  on("crossReference") && /* @__PURE__ */ jsx2(CrossReferenceMenu, { api }),
32721
- on("headerFooter") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
32722
- /* @__PURE__ */ jsx2(Btn, { label: "Header", title: "Edit header", onClick: () => api?.openHeaderFooter("header") }),
32723
- /* @__PURE__ */ jsx2(Btn, { label: "Footer", title: "Edit footer", onClick: () => api?.openHeaderFooter("footer") })
32724
- ] }),
34407
+ on("headerFooter") && /* @__PURE__ */ jsx2(
34408
+ ActionMenu,
34409
+ {
34410
+ label: "Header & footer",
34411
+ title: "Edit the repeating header or footer",
34412
+ width: 118,
34413
+ groups: [{ items: [["header", "Header"], ["footer", "Footer"]] }],
34414
+ onPick: (value) => api?.openHeaderFooter(value)
34415
+ }
34416
+ ),
32725
34417
  /* @__PURE__ */ jsx2(Sep, {}),
32726
34418
  on("pageNumber") && /* @__PURE__ */ jsx2(
32727
34419
  ActionMenu,
@@ -32805,6 +34497,7 @@ function DocxToolbar({
32805
34497
  on("chart") && /* @__PURE__ */ jsx2(ChartMenu, { api }),
32806
34498
  on("media") && /* @__PURE__ */ jsx2(MediaMenu, { api }),
32807
34499
  on("shape") && /* @__PURE__ */ jsx2(ShapeMenu, { api }),
34500
+ on("divider") && /* @__PURE__ */ jsx2(DividerMenu, { api }),
32808
34501
  on("textBox") && /* @__PURE__ */ jsx2(TextBoxMenu, { api }),
32809
34502
  on("wordArt") && /* @__PURE__ */ jsx2(WordArtMenu, { api }),
32810
34503
  on("link") && /* @__PURE__ */ jsx2(LinkMenu, { api }),
@@ -32812,10 +34505,16 @@ function DocxToolbar({
32812
34505
  on("footnote") && /* @__PURE__ */ jsx2(FootnoteMenu, { api }),
32813
34506
  on("bookmark") && /* @__PURE__ */ jsx2(BookmarkMenu, { api }),
32814
34507
  on("crossReference") && /* @__PURE__ */ jsx2(CrossReferenceMenu, { api }),
32815
- on("headerFooter") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
32816
- /* @__PURE__ */ jsx2(Btn, { label: "Header", title: "Edit header", onClick: () => api?.openHeaderFooter("header") }),
32817
- /* @__PURE__ */ jsx2(Btn, { label: "Footer", title: "Edit footer", onClick: () => api?.openHeaderFooter("footer") })
32818
- ] }),
34508
+ on("headerFooter") && /* @__PURE__ */ jsx2(
34509
+ ActionMenu,
34510
+ {
34511
+ label: "Header & footer",
34512
+ title: "Edit the repeating header or footer",
34513
+ width: 118,
34514
+ groups: [{ items: [["header", "Header"], ["footer", "Footer"]] }],
34515
+ onPick: (value) => api?.openHeaderFooter(value)
34516
+ }
34517
+ ),
32819
34518
  on("pageNumber") && /* @__PURE__ */ jsx2(
32820
34519
  ActionMenu,
32821
34520
  {
@@ -32877,6 +34576,8 @@ function DocxToolbar({
32877
34576
  ] })
32878
34577
  ] }),
32879
34578
  mode === "advanced" && tab === "draw" && on("drawing") && /* @__PURE__ */ jsx2(DrawTab, { api }),
34579
+ mode === "advanced" && tab === "format" && objectContext && /* @__PURE__ */ jsx2(ObjectFormatTab, { api, context: objectContext, showArrange: on("arrange") }),
34580
+ mode === "advanced" && tab === "tableFormat" && tableCellFill !== void 0 && /* @__PURE__ */ jsx2(TableFormatTab, { api, fill: tableCellFill, onChanged: refresh }),
32880
34581
  /* @__PURE__ */ jsx2(
32881
34582
  "input",
32882
34583
  {
@@ -33309,7 +35010,8 @@ function DocxView({
33309
35010
  void requestTextInputDialog(anchor, {
33310
35011
  title: "Link address",
33311
35012
  label: "URL",
33312
- value: current.getLinkAt() ?? "https://"
35013
+ value: current.getLinkAt() ?? "https://",
35014
+ inputType: "url"
33313
35015
  }).then((next) => {
33314
35016
  if (next !== null) current.setLink(next.trim() || null);
33315
35017
  });
@@ -33459,12 +35161,13 @@ function DocxView({
33459
35161
  return true;
33460
35162
  },
33461
35163
  insertSymbol: (symbol) => editor?.insertText(symbol) ?? false,
33462
- insertShape: (preset, text) => {
35164
+ insertShape: (preset, text, lineStyle) => {
33463
35165
  const target = insertionTarget();
33464
35166
  if (!target) return false;
33465
35167
  history.checkpoint();
33466
35168
  const drawing = insertShapeAt(doc, target.t, preset, text);
33467
35169
  if (!drawing) return false;
35170
+ if (lineStyle) setDrawingLineStyle(doc, drawing, lineStyle.color, lineStyle.width, lineStyle.dash);
33468
35171
  pages = rerender(doc, void 0, "global");
33469
35172
  editor?.reselectDrawing(drawing);
33470
35173
  return true;
@@ -33494,6 +35197,7 @@ function DocxView({
33494
35197
  editor?.reselectDrawing(source2);
33495
35198
  return true;
33496
35199
  },
35200
+ getSelectedChart: () => editor?.getSelectedChartData() ?? null,
33497
35201
  insertSmartArt: (data) => {
33498
35202
  const target = insertionTarget();
33499
35203
  if (!target) return false;
@@ -33511,6 +35215,7 @@ function DocxView({
33511
35215
  editor?.reselectDrawing(source2);
33512
35216
  return true;
33513
35217
  },
35218
+ getSelectedSmartArt: () => editor?.getSelectedSmartArtData() ?? null,
33514
35219
  insertModel3D: async (file, poster) => {
33515
35220
  const target = insertionTarget();
33516
35221
  if (!target) return false;
@@ -33548,6 +35253,10 @@ function DocxView({
33548
35253
  getDrawingTool: () => editor?.getDrawingTool() ?? null,
33549
35254
  arrangeObject: (action) => editor?.arrangeSelectedObject(action) ?? false,
33550
35255
  hasSelectedObject: () => editor?.hasSelectedObject() ?? false,
35256
+ getSelectedObjectContext: () => editor?.getSelectedObjectContext() ?? null,
35257
+ runSelectedObjectCommand: (command) => editor?.runSelectedObjectCommand(command) ?? false,
35258
+ getSelectedSmartArtTextFormat: () => editor?.getSelectedSmartArtTextFormat() ?? null,
35259
+ setSelectedSmartArtTextFormat: (patch) => editor?.setSelectedSmartArtTextFormat(patch) ?? false,
33551
35260
  addComment: (text) => {
33552
35261
  const segs = editor?.getSelectionSegments() ?? [];
33553
35262
  const segments = segs.length > 0 ? segs : handle ? selectionToSegments(handle.bindings) : [];
@@ -33576,6 +35285,10 @@ function DocxView({
33576
35285
  history.checkpoint();
33577
35286
  if (applyTableOp(doc, caret.t, op)) pages = rerender(doc);
33578
35287
  },
35288
+ getTableCellFill: () => {
35289
+ const caret = editor?.getCaretTarget();
35290
+ return caret ? cellShadingAt(doc, caret.t) : void 0;
35291
+ },
33579
35292
  insertImage: async (file) => {
33580
35293
  const caret = editor?.getCaretTarget();
33581
35294
  if (!caret) return;
@@ -33731,6 +35444,20 @@ function DocxView({
33731
35444
  history.checkpoint();
33732
35445
  if (setParagraphSpacing(doc, targets, patch)) pages = rerender(doc);
33733
35446
  },
35447
+ setParagraphDivider: (divider) => {
35448
+ const segs = editor?.getSelectionSegments() ?? [];
35449
+ const caret = editor?.getCaretTarget();
35450
+ const targets = segs.length > 0 ? segs.map((segment) => segment.t).filter((target) => !!target) : caret ? [caret.t] : [];
35451
+ if (targets.length === 0) return false;
35452
+ history.checkpoint();
35453
+ if (!setParagraphDivider(doc, targets, divider)) return false;
35454
+ pages = rerender(doc);
35455
+ return true;
35456
+ },
35457
+ getParagraphDivider: () => {
35458
+ const target = editor?.getSelectionSegments()?.find((segment) => segment.t)?.t ?? editor?.getCaretTarget()?.t;
35459
+ return target ? paragraphDividerAt(doc, target) : null;
35460
+ },
33734
35461
  setDropCap: (mode, lines = 3) => {
33735
35462
  const target = insertionTarget();
33736
35463
  if (!target) return false;