wordinweb 0.1.17 → 0.1.19

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 {
@@ -20811,12 +21039,13 @@ function resizeDrawing(doc, drawingEl, widthPx, heightPx) {
20811
21039
  for (const childNode of node.children) findLineExtent(childNode);
20812
21040
  };
20813
21041
  findLineExtent(drawingEl);
21042
+ const keepVertical = lineExtent ? parseInt(lineExtent.attrs[Object.keys(lineExtent.attrs).find((key) => localName(key) === "cx") ?? "cx"] ?? "0", 10) === 0 : false;
20814
21043
  const keepHorizontal = lineExtent ? parseInt(lineExtent.attrs[Object.keys(lineExtent.attrs).find((key) => localName(key) === "cy") ?? "cy"] ?? "0", 10) === 0 : false;
20815
21044
  let touched = false;
20816
21045
  const setExt = (el16) => {
20817
21046
  const cxKey = Object.keys(el16.attrs).find((k) => localName(k) === "cx") ?? "cx";
20818
21047
  const cyKey = Object.keys(el16.attrs).find((k) => localName(k) === "cy") ?? "cy";
20819
- el16.attrs[cxKey] = cx;
21048
+ el16.attrs[cxKey] = el16 === lineExtent && keepVertical ? "0" : cx;
20820
21049
  el16.attrs[cyKey] = el16 === lineExtent && keepHorizontal ? "0" : cy;
20821
21050
  touched = true;
20822
21051
  };
@@ -21164,6 +21393,10 @@ function insertBlankPageAt(doc, t, offset) {
21164
21393
  if (ordinaryPPr) {
21165
21394
  ordinaryPPr.children = ordinaryPPr.children.filter((c) => localName(c.name) !== "sectPr");
21166
21395
  }
21396
+ const blankPPr = ordinaryPPr ? cloneDeep(ordinaryPPr) : null;
21397
+ if (blankPPr) {
21398
+ blankPPr.children = blankPPr.children.filter((c) => localName(c.name) !== "numPr");
21399
+ }
21167
21400
  const headBefore = pEl.children.slice(0, runIndex).filter((c) => localName(c.name) !== "pPr");
21168
21401
  const tailAfter = pEl.children.slice(runIndex + 1).filter((c) => localName(c.name) !== "pPr");
21169
21402
  pEl.children = [
@@ -21177,7 +21410,7 @@ function insertBlankPageAt(doc, t, offset) {
21177
21410
  el4(`${rw}t`, { "xml:space": "preserve" }, [], "")
21178
21411
  ]);
21179
21412
  const blank = el4(pEl.name, { ...pEl.attrs }, [
21180
- ...ordinaryPPr ? [cloneDeep(ordinaryPPr)] : [],
21413
+ ...blankPPr ? [blankPPr] : [],
21181
21414
  anchorRun,
21182
21415
  breakRun()
21183
21416
  ]);
@@ -21508,6 +21741,26 @@ function setMathLinear(doc, oMathEl, text) {
21508
21741
  doc.refresh();
21509
21742
  return true;
21510
21743
  }
21744
+ function deleteMath(doc, oMathEl) {
21745
+ const parent = doc.findParentOf(oMathEl);
21746
+ if (!parent) return false;
21747
+ let container = parent;
21748
+ let target = oMathEl;
21749
+ if (localName(parent.name) === "oMathPara") {
21750
+ const equations = parent.children.filter((child4) => localName(child4.name) === "oMath");
21751
+ if (equations.length === 1) {
21752
+ const grandparent = doc.findParentOf(parent);
21753
+ if (!grandparent) return false;
21754
+ container = grandparent;
21755
+ target = parent;
21756
+ }
21757
+ }
21758
+ const index = container.children.indexOf(target);
21759
+ if (index < 0) return false;
21760
+ container.children.splice(index, 1);
21761
+ doc.refresh();
21762
+ return true;
21763
+ }
21511
21764
  function insertMathAt(doc, t, offset, text) {
21512
21765
  const nodes = parseMathLinear(text.trim());
21513
21766
  if (nodes.length === 0) return null;
@@ -21812,19 +22065,21 @@ function insertShapeAt(doc, caretT, preset, text = "") {
21812
22065
  if (!caretRun || !parent || localName(caretRun.name) !== "r") return null;
21813
22066
  const w = prefixOf8(caretRun);
21814
22067
  const id = String(doc.nextDrawingId());
21815
- const isLine = preset === "line";
21816
- const width = isLine ? 240 : preset === "textBox" ? 240 : 192;
21817
- const height = isLine ? 2 : preset === "textBox" ? 72 : 96;
22068
+ const isLine = preset === "line" || preset === "verticalLine";
22069
+ const isVerticalLine = preset === "verticalLine";
22070
+ const width = isVerticalLine ? 2 : isLine ? 240 : preset === "textBox" ? 240 : 192;
22071
+ const height = isVerticalLine ? 240 : isLine ? 2 : preset === "textBox" ? 72 : 96;
21818
22072
  const cx = String(Math.round(width * EMU_PER_PX4));
21819
22073
  const cy = String(Math.round(height * EMU_PER_PX4));
21820
- const shapeCy = isLine ? "0" : cy;
21821
- const geometry = preset === "roundedRectangle" ? "roundRect" : preset === "rectangle" || preset === "textBox" ? "rect" : preset;
22074
+ const shapeCx = isVerticalLine ? "0" : cx;
22075
+ const shapeCy = isLine && !isVerticalLine ? "0" : cy;
22076
+ const geometry = isLine ? "line" : preset === "roundedRectangle" ? "roundRect" : preset === "rectangle" || preset === "textBox" ? "rect" : preset;
21822
22077
  const isTextBox = preset === "textBox";
21823
22078
  const shapeName = isLine ? `Line ${id}` : isTextBox ? `Text Box ${id}` : `Shape ${id}`;
21824
22079
  const spPr = [
21825
22080
  el6("a:xfrm", {}, [
21826
22081
  el6("a:off", { x: "0", y: "0" }),
21827
- el6("a:ext", { cx, cy: shapeCy })
22082
+ el6("a:ext", { cx: shapeCx, cy: shapeCy })
21828
22083
  ]),
21829
22084
  el6("a:prstGeom", { prst: geometry }, [el6("a:avLst")]),
21830
22085
  isTextBox || isLine ? el6("a:noFill") : el6("a:solidFill", {}, [el6("a:srgbClr", { val: "4472C4" })]),
@@ -21945,10 +22200,12 @@ function drawingLineStyle(drawing) {
21945
22200
  const spPr = descendant3(drawing, "spPr");
21946
22201
  if (!spPr) return null;
21947
22202
  const line2 = descendant3(drawing, "ln");
21948
- if (!line2) return { color: "#000000", width: 0.75 };
22203
+ if (!line2) return { color: "#000000", width: 0.75, dash: "solid" };
21949
22204
  const color = descendant3(line2, "srgbClr")?.attrs.val ?? "000000";
21950
22205
  const width = Math.max((parseInt(line2.attrs.w ?? "0", 10) || 0) / EMU_PER_PX4, 0.75);
21951
- return { color: `#${color.toUpperCase()}`, width };
22206
+ const dashValue = line2.children.find((child4) => localName(child4.name) === "prstDash")?.attrs.val;
22207
+ const dash = dashValue === "dot" || dashValue === "sysDot" ? "dotted" : dashValue && dashValue !== "solid" ? "dashed" : "solid";
22208
+ return { color: `#${color.toUpperCase()}`, width, dash };
21952
22209
  }
21953
22210
  function drawingFillColor(drawing) {
21954
22211
  const spPr = descendant3(drawing, "spPr");
@@ -21970,7 +22227,7 @@ function setDrawingFill(doc, drawing, color) {
21970
22227
  doc.refresh();
21971
22228
  return true;
21972
22229
  }
21973
- function setDrawingLineStyle(doc, drawing, color, widthPx) {
22230
+ function setDrawingLineStyle(doc, drawing, color, widthPx, dash = "solid") {
21974
22231
  const spPr = descendant3(drawing, "spPr");
21975
22232
  if (!spPr) return false;
21976
22233
  let line2 = spPr.children.find((child4) => localName(child4.name) === "ln");
@@ -21981,9 +22238,10 @@ function setDrawingLineStyle(doc, drawing, color, widthPx) {
21981
22238
  line2.attrs.w = String(Math.max(1, Math.round(widthPx * EMU_PER_PX4)));
21982
22239
  line2.children = line2.children.filter((child4) => {
21983
22240
  const name = localName(child4.name);
21984
- return name !== "solidFill" && name !== "noFill";
22241
+ return name !== "solidFill" && name !== "noFill" && name !== "prstDash";
21985
22242
  });
21986
22243
  line2.children.unshift(el6("a:solidFill", {}, [el6("a:srgbClr", { val: color.replace(/^#/, "").toUpperCase() })]));
22244
+ line2.children.splice(1, 0, el6("a:prstDash", { val: dash === "dotted" ? "dot" : dash === "dashed" ? "dash" : "solid" }));
21987
22245
  doc.refresh();
21988
22246
  return true;
21989
22247
  }
@@ -22444,6 +22702,12 @@ function requestTextInputDialog(anchor, options) {
22444
22702
  label.textContent = options.label ?? options.title;
22445
22703
  label.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
22446
22704
  const field = options.multiline ? doc.createElement("textarea") : doc.createElement("input");
22705
+ if (field instanceof HTMLInputElement) {
22706
+ field.type = options.inputType ?? "text";
22707
+ if (options.min !== void 0) field.min = String(options.min);
22708
+ if (options.max !== void 0) field.max = String(options.max);
22709
+ if (options.step !== void 0) field.step = String(options.step);
22710
+ }
22447
22711
  field.className = "dxw-input-dialog-field";
22448
22712
  field.value = options.value ?? "";
22449
22713
  field.placeholder = options.placeholder ?? "";
@@ -22499,55 +22763,459 @@ function requestTextInputDialog(anchor, options) {
22499
22763
  });
22500
22764
  });
22501
22765
  }
22502
-
22503
- // ../core/src/edit/objects.ts
22504
- var EMU_PER_PX6 = 9525;
22505
- var NS_WP5 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
22506
- var NS_A4 = "http://schemas.openxmlformats.org/drawingml/2006/main";
22507
- var NS_PIC2 = "http://schemas.openxmlformats.org/drawingml/2006/picture";
22508
- var NS_R3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
22509
- var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
22510
- var NS_AM3D = "http://schemas.microsoft.com/office/drawing/2017/model3d";
22511
- var NS_WP15 = "http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing";
22512
- function el8(name, attrs = {}, children2 = [], text = "") {
22513
- return { name, attrs, children: children2, text };
22514
- }
22515
- function prefixOf9(node) {
22516
- return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
22766
+ function requestNumberPairDialog(anchor, options) {
22767
+ const doc = anchor.ownerDocument;
22768
+ const win = doc.defaultView;
22769
+ return new Promise((resolve) => {
22770
+ const id = `dxw-number-pair-dialog-${++dialogSequence}`;
22771
+ const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
22772
+ const backdrop = doc.createElement("div");
22773
+ backdrop.className = "dxw-input-dialog-backdrop";
22774
+ backdrop.dataset.dxwNumberPairDialog = "";
22775
+ 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));";
22776
+ if (win) {
22777
+ const computed = win.getComputedStyle(anchor);
22778
+ for (const property of [
22779
+ "--dxw-toolbar-fg",
22780
+ "--dxw-toolbar-border",
22781
+ "--dxw-toolbar-muted",
22782
+ "--dxw-accent",
22783
+ "--dxw-accent-fg",
22784
+ "--dxw-popover-bg",
22785
+ "--dxw-popover-shadow",
22786
+ "--dxw-dialog-backdrop",
22787
+ "--dxw-dialog-z-index",
22788
+ "--dxw-dialog-width",
22789
+ "--dxw-dialog-radius",
22790
+ "--dxw-dialog-field-bg"
22791
+ ]) {
22792
+ const token = computed.getPropertyValue(property);
22793
+ if (token) backdrop.style.setProperty(property, token);
22794
+ }
22795
+ }
22796
+ const form = doc.createElement("form");
22797
+ form.className = "dxw-input-dialog dxw-number-pair-dialog";
22798
+ form.setAttribute("role", "dialog");
22799
+ form.setAttribute("aria-modal", "true");
22800
+ form.setAttribute("aria-labelledby", id);
22801
+ 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;";
22802
+ const title = doc.createElement("strong");
22803
+ title.id = id;
22804
+ title.textContent = options.title;
22805
+ title.style.cssText = "font-size:15px;line-height:1.35;";
22806
+ form.appendChild(title);
22807
+ const fields = doc.createElement("div");
22808
+ fields.style.cssText = "display:grid;grid-template-columns:1fr 1fr;gap:10px;";
22809
+ const makeField = (labelText, value) => {
22810
+ const label = doc.createElement("label");
22811
+ label.textContent = labelText;
22812
+ label.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
22813
+ const input = doc.createElement("input");
22814
+ input.type = "number";
22815
+ input.required = true;
22816
+ input.value = String(value);
22817
+ if (options.min !== void 0) input.min = String(options.min);
22818
+ if (options.step !== void 0) input.step = String(options.step);
22819
+ input.setAttribute("aria-label", labelText);
22820
+ 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;";
22821
+ label.appendChild(input);
22822
+ fields.appendChild(label);
22823
+ return input;
22824
+ };
22825
+ const first = makeField(options.firstLabel, options.value.first);
22826
+ const second = makeField(options.secondLabel, options.value.second);
22827
+ form.appendChild(fields);
22828
+ const actions = doc.createElement("div");
22829
+ actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
22830
+ const cancel = doc.createElement("button");
22831
+ cancel.type = "button";
22832
+ cancel.textContent = "Cancel";
22833
+ 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;";
22834
+ const submit = doc.createElement("button");
22835
+ submit.type = "submit";
22836
+ submit.textContent = "Apply";
22837
+ 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;";
22838
+ actions.append(cancel, submit);
22839
+ form.appendChild(actions);
22840
+ backdrop.appendChild(form);
22841
+ doc.body.appendChild(backdrop);
22842
+ let finished = false;
22843
+ const finish = (value) => {
22844
+ if (finished) return;
22845
+ finished = true;
22846
+ doc.removeEventListener("keydown", onKeyDown, true);
22847
+ backdrop.remove();
22848
+ previousFocus?.focus({ preventScroll: true });
22849
+ resolve(value);
22850
+ };
22851
+ const onKeyDown = (event) => {
22852
+ if (event.key === "Escape") {
22853
+ event.preventDefault();
22854
+ finish(null);
22855
+ }
22856
+ };
22857
+ doc.addEventListener("keydown", onKeyDown, true);
22858
+ backdrop.addEventListener("mousedown", (event) => {
22859
+ if (event.target === backdrop) finish(null);
22860
+ });
22861
+ cancel.addEventListener("click", () => finish(null));
22862
+ form.addEventListener("submit", (event) => {
22863
+ event.preventDefault();
22864
+ const firstValue = Number(first.value);
22865
+ const secondValue = Number(second.value);
22866
+ if (!Number.isFinite(firstValue) || !Number.isFinite(secondValue)) {
22867
+ form.reportValidity();
22868
+ return;
22869
+ }
22870
+ finish({ first: firstValue, second: secondValue });
22871
+ });
22872
+ requestAnimationFrame(() => {
22873
+ first.focus({ preventScroll: true });
22874
+ first.select();
22875
+ });
22876
+ });
22517
22877
  }
22518
- function insertAfterCaretRun(doc, caretT, content) {
22519
- const caretRun = doc.findParentOf(caretT);
22520
- const parent = caretRun && doc.findParentOf(caretRun);
22521
- if (!caretRun || !parent || localName(caretRun.name) !== "r") return false;
22522
- const w = prefixOf9(caretRun);
22523
- parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el8(`${w}r`, {}, [content]));
22524
- doc.refresh();
22525
- return true;
22878
+ function requestColorDialog(anchor, options) {
22879
+ const doc = anchor.ownerDocument;
22880
+ const win = doc.defaultView;
22881
+ return new Promise((resolve) => {
22882
+ const id = `dxw-color-dialog-${++dialogSequence}`;
22883
+ const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
22884
+ const backdrop = doc.createElement("div");
22885
+ backdrop.className = "dxw-input-dialog-backdrop";
22886
+ backdrop.dataset.dxwColorDialog = "";
22887
+ 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));";
22888
+ if (win) {
22889
+ const computed = win.getComputedStyle(anchor);
22890
+ for (const property of [
22891
+ "--dxw-toolbar-fg",
22892
+ "--dxw-toolbar-border",
22893
+ "--dxw-toolbar-muted",
22894
+ "--dxw-accent",
22895
+ "--dxw-accent-fg",
22896
+ "--dxw-popover-bg",
22897
+ "--dxw-popover-shadow",
22898
+ "--dxw-dialog-backdrop",
22899
+ "--dxw-dialog-z-index",
22900
+ "--dxw-dialog-width",
22901
+ "--dxw-dialog-radius",
22902
+ "--dxw-dialog-field-bg"
22903
+ ]) {
22904
+ const token = computed.getPropertyValue(property);
22905
+ if (token) backdrop.style.setProperty(property, token);
22906
+ }
22907
+ }
22908
+ const form = doc.createElement("form");
22909
+ form.className = "dxw-input-dialog dxw-color-dialog";
22910
+ form.setAttribute("role", "dialog");
22911
+ form.setAttribute("aria-modal", "true");
22912
+ form.setAttribute("aria-labelledby", id);
22913
+ 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;";
22914
+ const title = doc.createElement("strong");
22915
+ title.id = id;
22916
+ title.textContent = options.title;
22917
+ title.style.cssText = "font-size:15px;line-height:1.35;";
22918
+ form.appendChild(title);
22919
+ const initial = /^#?([0-9a-f]{6})$/i.exec(options.value ?? "")?.[1] ?? "4472C4";
22920
+ const colorLabel = doc.createElement("label");
22921
+ colorLabel.textContent = "Color";
22922
+ colorLabel.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
22923
+ const colorRow = doc.createElement("span");
22924
+ colorRow.style.cssText = "display:grid;grid-template-columns:42px 1fr;gap:7px;";
22925
+ const picker = doc.createElement("input");
22926
+ picker.type = "color";
22927
+ picker.value = `#${initial}`;
22928
+ picker.setAttribute("aria-label", `${options.title} color picker`);
22929
+ 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));";
22930
+ const field = doc.createElement("input");
22931
+ field.type = "text";
22932
+ field.value = `#${initial.toUpperCase()}`;
22933
+ field.required = true;
22934
+ field.pattern = "#?[0-9a-fA-F]{6}";
22935
+ field.setAttribute("aria-label", `${options.title} color`);
22936
+ 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;";
22937
+ let noFill = null;
22938
+ picker.addEventListener("input", () => {
22939
+ field.value = picker.value.toUpperCase();
22940
+ if (noFill) noFill.checked = false;
22941
+ });
22942
+ field.addEventListener("input", () => {
22943
+ if (noFill) noFill.checked = false;
22944
+ const match = /^#?([0-9a-f]{6})$/i.exec(field.value.trim());
22945
+ if (match) picker.value = `#${match[1]}`;
22946
+ });
22947
+ colorRow.append(picker, field);
22948
+ colorLabel.appendChild(colorRow);
22949
+ form.appendChild(colorLabel);
22950
+ if (options.allowNone) {
22951
+ const noneLabel = doc.createElement("label");
22952
+ noneLabel.style.cssText = "display:flex;align-items:center;gap:7px;color:var(--dxw-toolbar-fg,#3c4043);font-size:12px;";
22953
+ noFill = doc.createElement("input");
22954
+ noFill.type = "checkbox";
22955
+ noFill.checked = options.value === null;
22956
+ noFill.setAttribute("aria-label", "No fill");
22957
+ noneLabel.append(noFill, doc.createTextNode("No fill"));
22958
+ form.appendChild(noneLabel);
22959
+ }
22960
+ const actions = doc.createElement("div");
22961
+ actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
22962
+ const cancel = doc.createElement("button");
22963
+ cancel.type = "button";
22964
+ cancel.textContent = "Cancel";
22965
+ 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;";
22966
+ const submit = doc.createElement("button");
22967
+ submit.type = "submit";
22968
+ submit.textContent = "Apply";
22969
+ 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;";
22970
+ actions.append(cancel, submit);
22971
+ form.appendChild(actions);
22972
+ backdrop.appendChild(form);
22973
+ doc.body.appendChild(backdrop);
22974
+ let finished = false;
22975
+ const finish = (value) => {
22976
+ if (finished) return;
22977
+ finished = true;
22978
+ doc.removeEventListener("keydown", onKeyDown, true);
22979
+ backdrop.remove();
22980
+ previousFocus?.focus({ preventScroll: true });
22981
+ resolve(value);
22982
+ };
22983
+ const onKeyDown = (event) => {
22984
+ if (event.key === "Escape") {
22985
+ event.preventDefault();
22986
+ finish(void 0);
22987
+ }
22988
+ };
22989
+ doc.addEventListener("keydown", onKeyDown, true);
22990
+ backdrop.addEventListener("mousedown", (event) => {
22991
+ if (event.target === backdrop) finish(void 0);
22992
+ });
22993
+ cancel.addEventListener("click", () => finish(void 0));
22994
+ form.addEventListener("submit", (event) => {
22995
+ event.preventDefault();
22996
+ if (noFill?.checked) {
22997
+ finish(null);
22998
+ return;
22999
+ }
23000
+ const color = /^#?([0-9a-f]{6})$/i.exec(field.value.trim());
23001
+ if (!color) {
23002
+ form.reportValidity();
23003
+ return;
23004
+ }
23005
+ finish(`#${color[1].toUpperCase()}`);
23006
+ });
23007
+ requestAnimationFrame(() => {
23008
+ (noFill?.checked ? noFill : field).focus({ preventScroll: true });
23009
+ if (!noFill?.checked) field.select();
23010
+ });
23011
+ });
22526
23012
  }
22527
- function pictureGraphic(relId, id, cx, cy, webVideo) {
22528
- const blipChildren = webVideo ? [
22529
- el8("a:extLst", {}, [
22530
- el8("a:ext", { uri: "{9E29B28B-C9C2-4B96-BA92-6C9A3D8F4A6A}" }, [
22531
- el8("wp15:webVideoPr", {
22532
- "xmlns:wp15": NS_WP15,
22533
- embeddedHtml: webVideo,
22534
- w: "640",
22535
- h: "360"
22536
- })
22537
- ])
22538
- ])
22539
- ] : [];
22540
- return el8("a:graphic", { "xmlns:a": NS_A4 }, [
22541
- el8("a:graphicData", { uri: NS_PIC2 }, [
22542
- el8("pic:pic", { "xmlns:pic": NS_PIC2 }, [
22543
- el8("pic:nvPicPr", {}, [
22544
- el8("pic:cNvPr", { id, name: `Picture ${id}` }),
22545
- el8("pic:cNvPicPr", {}, [el8("a:picLocks", { noChangeAspect: "1" })])
22546
- ]),
22547
- el8("pic:blipFill", {}, [
22548
- el8("a:blip", { "xmlns:r": NS_R3, "r:embed": relId }, blipChildren),
22549
- el8("a:stretch", {}, [el8("a:fillRect")])
22550
- ]),
23013
+ function requestLineStyleDialog(anchor, value, titleText = "Line style") {
23014
+ const doc = anchor.ownerDocument;
23015
+ const win = doc.defaultView;
23016
+ return new Promise((resolve) => {
23017
+ const fieldName = titleText === "Outline" ? "Outline" : "Line";
23018
+ const id = `dxw-line-style-dialog-${++dialogSequence}`;
23019
+ const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
23020
+ const backdrop = doc.createElement("div");
23021
+ backdrop.className = "dxw-input-dialog-backdrop";
23022
+ backdrop.dataset.dxwLineStyleDialog = "";
23023
+ 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));";
23024
+ if (win) {
23025
+ const computed = win.getComputedStyle(anchor);
23026
+ for (const property of [
23027
+ "--dxw-toolbar-fg",
23028
+ "--dxw-toolbar-border",
23029
+ "--dxw-toolbar-muted",
23030
+ "--dxw-accent",
23031
+ "--dxw-accent-fg",
23032
+ "--dxw-popover-bg",
23033
+ "--dxw-popover-shadow",
23034
+ "--dxw-dialog-backdrop",
23035
+ "--dxw-dialog-z-index",
23036
+ "--dxw-dialog-width",
23037
+ "--dxw-dialog-radius",
23038
+ "--dxw-dialog-field-bg"
23039
+ ]) {
23040
+ const token = computed.getPropertyValue(property);
23041
+ if (token) backdrop.style.setProperty(property, token);
23042
+ }
23043
+ }
23044
+ const form = doc.createElement("form");
23045
+ form.className = "dxw-input-dialog dxw-line-style-dialog";
23046
+ form.setAttribute("role", "dialog");
23047
+ form.setAttribute("aria-modal", "true");
23048
+ form.setAttribute("aria-labelledby", id);
23049
+ 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;";
23050
+ const title = doc.createElement("strong");
23051
+ title.id = id;
23052
+ title.className = "dxw-input-dialog-title";
23053
+ title.textContent = titleText;
23054
+ title.style.cssText = "font-size:15px;line-height:1.35;";
23055
+ form.appendChild(title);
23056
+ 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;";
23057
+ const labelStyle = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
23058
+ const colorLabel = doc.createElement("label");
23059
+ colorLabel.textContent = "Color";
23060
+ colorLabel.style.cssText = labelStyle;
23061
+ const colorRow = doc.createElement("span");
23062
+ colorRow.style.cssText = "display:grid;grid-template-columns:42px 1fr;gap:7px;";
23063
+ const colorPicker = doc.createElement("input");
23064
+ colorPicker.type = "color";
23065
+ colorPicker.value = value.color;
23066
+ colorPicker.setAttribute("aria-label", `${fieldName} color picker`);
23067
+ 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));";
23068
+ const colorField = doc.createElement("input");
23069
+ colorField.type = "text";
23070
+ colorField.value = value.color.toUpperCase();
23071
+ colorField.required = true;
23072
+ colorField.pattern = "#?[0-9a-fA-F]{6}";
23073
+ colorField.setAttribute("aria-label", `${fieldName} color`);
23074
+ colorField.style.cssText = fieldStyle;
23075
+ colorPicker.addEventListener("input", () => {
23076
+ colorField.value = colorPicker.value.toUpperCase();
23077
+ });
23078
+ colorField.addEventListener("input", () => {
23079
+ const match = /^#?([0-9a-f]{6})$/i.exec(colorField.value.trim());
23080
+ if (match) colorPicker.value = `#${match[1]}`;
23081
+ });
23082
+ colorRow.append(colorPicker, colorField);
23083
+ colorLabel.appendChild(colorRow);
23084
+ form.appendChild(colorLabel);
23085
+ const widthLabel = doc.createElement("label");
23086
+ widthLabel.textContent = "Width (pixels)";
23087
+ widthLabel.style.cssText = labelStyle;
23088
+ const widthField = doc.createElement("input");
23089
+ widthField.type = "number";
23090
+ widthField.min = "0.25";
23091
+ widthField.step = "any";
23092
+ widthField.required = true;
23093
+ widthField.value = String(Number(value.width.toFixed(2)));
23094
+ widthField.setAttribute("aria-label", `${fieldName} width in pixels`);
23095
+ widthField.style.cssText = fieldStyle;
23096
+ widthLabel.appendChild(widthField);
23097
+ form.appendChild(widthLabel);
23098
+ const styleLabel = doc.createElement("label");
23099
+ styleLabel.textContent = "Style";
23100
+ styleLabel.style.cssText = labelStyle;
23101
+ const styleField = doc.createElement("select");
23102
+ styleField.setAttribute("aria-label", `${fieldName} style`);
23103
+ styleField.style.cssText = fieldStyle;
23104
+ for (const [style, label] of [["solid", "Solid"], ["dashed", "Dashed"], ["dotted", "Dotted"]]) {
23105
+ const option = doc.createElement("option");
23106
+ option.value = style;
23107
+ option.textContent = label;
23108
+ option.selected = value.style === style;
23109
+ styleField.appendChild(option);
23110
+ }
23111
+ styleLabel.appendChild(styleField);
23112
+ form.appendChild(styleLabel);
23113
+ const actions = doc.createElement("div");
23114
+ actions.className = "dxw-input-dialog-actions";
23115
+ actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
23116
+ const cancel = doc.createElement("button");
23117
+ cancel.type = "button";
23118
+ cancel.className = "dxw-input-dialog-cancel";
23119
+ cancel.textContent = "Cancel";
23120
+ 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;";
23121
+ const submit = doc.createElement("button");
23122
+ submit.type = "submit";
23123
+ submit.className = "dxw-input-dialog-submit";
23124
+ submit.textContent = "Apply";
23125
+ 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;";
23126
+ actions.append(cancel, submit);
23127
+ form.appendChild(actions);
23128
+ backdrop.appendChild(form);
23129
+ doc.body.appendChild(backdrop);
23130
+ let finished = false;
23131
+ const finish = (result) => {
23132
+ if (finished) return;
23133
+ finished = true;
23134
+ doc.removeEventListener("keydown", onKeyDown, true);
23135
+ backdrop.remove();
23136
+ previousFocus?.focus({ preventScroll: true });
23137
+ resolve(result);
23138
+ };
23139
+ const onKeyDown = (event) => {
23140
+ if (event.key === "Escape") {
23141
+ event.preventDefault();
23142
+ finish(null);
23143
+ }
23144
+ };
23145
+ doc.addEventListener("keydown", onKeyDown, true);
23146
+ backdrop.addEventListener("mousedown", (event) => {
23147
+ if (event.target === backdrop) finish(null);
23148
+ });
23149
+ cancel.addEventListener("click", () => finish(null));
23150
+ form.addEventListener("submit", (event) => {
23151
+ event.preventDefault();
23152
+ const color = /^#?([0-9a-f]{6})$/i.exec(colorField.value.trim());
23153
+ const width = Number(widthField.value);
23154
+ if (!color || !Number.isFinite(width) || width <= 0) {
23155
+ form.reportValidity();
23156
+ return;
23157
+ }
23158
+ finish({
23159
+ color: `#${color[1].toUpperCase()}`,
23160
+ width,
23161
+ style: styleField.value
23162
+ });
23163
+ });
23164
+ requestAnimationFrame(() => {
23165
+ colorField.focus({ preventScroll: true });
23166
+ colorField.select();
23167
+ });
23168
+ });
23169
+ }
23170
+
23171
+ // ../core/src/edit/objects.ts
23172
+ var EMU_PER_PX6 = 9525;
23173
+ var NS_WP5 = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
23174
+ var NS_A4 = "http://schemas.openxmlformats.org/drawingml/2006/main";
23175
+ var NS_PIC2 = "http://schemas.openxmlformats.org/drawingml/2006/picture";
23176
+ var NS_R3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
23177
+ var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
23178
+ var NS_AM3D = "http://schemas.microsoft.com/office/drawing/2017/model3d";
23179
+ var NS_WP15 = "http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing";
23180
+ function el8(name, attrs = {}, children2 = [], text = "") {
23181
+ return { name, attrs, children: children2, text };
23182
+ }
23183
+ function prefixOf9(node) {
23184
+ return node.name.includes(":") ? node.name.slice(0, node.name.indexOf(":") + 1) : "";
23185
+ }
23186
+ function insertAfterCaretRun(doc, caretT, content) {
23187
+ const caretRun = doc.findParentOf(caretT);
23188
+ const parent = caretRun && doc.findParentOf(caretRun);
23189
+ if (!caretRun || !parent || localName(caretRun.name) !== "r") return false;
23190
+ const w = prefixOf9(caretRun);
23191
+ parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el8(`${w}r`, {}, [content]));
23192
+ doc.refresh();
23193
+ return true;
23194
+ }
23195
+ function pictureGraphic(relId, id, cx, cy, webVideo) {
23196
+ const blipChildren = webVideo ? [
23197
+ el8("a:extLst", {}, [
23198
+ el8("a:ext", { uri: "{9E29B28B-C9C2-4B96-BA92-6C9A3D8F4A6A}" }, [
23199
+ el8("wp15:webVideoPr", {
23200
+ "xmlns:wp15": NS_WP15,
23201
+ embeddedHtml: webVideo,
23202
+ w: "640",
23203
+ h: "360"
23204
+ })
23205
+ ])
23206
+ ])
23207
+ ] : [];
23208
+ return el8("a:graphic", { "xmlns:a": NS_A4 }, [
23209
+ el8("a:graphicData", { uri: NS_PIC2 }, [
23210
+ el8("pic:pic", { "xmlns:pic": NS_PIC2 }, [
23211
+ el8("pic:nvPicPr", {}, [
23212
+ el8("pic:cNvPr", { id, name: `Picture ${id}` }),
23213
+ el8("pic:cNvPicPr", {}, [el8("a:picLocks", { noChangeAspect: "1" })])
23214
+ ]),
23215
+ el8("pic:blipFill", {}, [
23216
+ el8("a:blip", { "xmlns:r": NS_R3, "r:embed": relId }, blipChildren),
23217
+ el8("a:stretch", {}, [el8("a:fillRect")])
23218
+ ]),
22551
23219
  el8("pic:spPr", {}, [
22552
23220
  el8("a:xfrm", {}, [el8("a:off", { x: "0", y: "0" }), el8("a:ext", { cx, cy })]),
22553
23221
  el8("a:prstGeom", { prst: "rect" }, [el8("a:avLst")])
@@ -23398,6 +24066,19 @@ function textElements(el16) {
23398
24066
  walk2(el16);
23399
24067
  return out;
23400
24068
  }
24069
+ function clearListParagraphFormatting(doc, paragraph) {
24070
+ const pPr = paragraph.children.find((child4) => localName(child4.name) === "pPr");
24071
+ if (!pPr) return false;
24072
+ const style = pPr.children.find((child4) => localName(child4.name) === "pStyle");
24073
+ const styleHasNumbering = !!resolveParagraphStyleChain(doc.styles, attr(style, "val"), false).pPr.numbering;
24074
+ const hasDirectNumbering = pPr.children.some((child4) => localName(child4.name) === "numPr");
24075
+ if (!hasDirectNumbering && !styleHasNumbering) return false;
24076
+ pPr.children = pPr.children.filter((child4) => {
24077
+ const name = localName(child4.name);
24078
+ return name !== "numPr" && !(name === "pStyle" && styleHasNumbering);
24079
+ });
24080
+ return true;
24081
+ }
23401
24082
  function emptyParagraphLike(el16) {
23402
24083
  const prefix = el16.name.includes(":") ? el16.name.slice(0, el16.name.indexOf(":") + 1) : "";
23403
24084
  const text = {
@@ -23569,6 +24250,7 @@ var _DocxEditor = class _DocxEditor {
23569
24250
  this.onGripMouseDown = (e) => {
23570
24251
  const target = e.target;
23571
24252
  if (this.wordArtTextEditor?.input.contains(target)) return;
24253
+ if (this.smartArtTextEditor?.input.contains(target)) return;
23572
24254
  if (this.startInkGroupInteraction(e, target)) return;
23573
24255
  if (this.startInkInteraction(e, target)) return;
23574
24256
  if (this.startCheckboxInteraction(e, target)) return;
@@ -23767,9 +24449,11 @@ var _DocxEditor = class _DocxEditor {
23767
24449
  this.selectedInkGroup = null;
23768
24450
  // ---------- images: select, resize, drag-move ----------
23769
24451
  this.selectedImage = null;
24452
+ this.selectedSmartArtNodeIndex = null;
23770
24453
  this.imageOverlay = null;
23771
24454
  this.imageToolbar = null;
23772
24455
  this.wordArtTextEditor = null;
24456
+ this.smartArtTextEditor = null;
23773
24457
  /** First press selects a model; subsequent drags belong to its 3D viewport. */
23774
24458
  this.onModel3DPointerDown = (event) => {
23775
24459
  const binding = this.model3DBinding(event.target);
@@ -23816,6 +24500,7 @@ var _DocxEditor = class _DocxEditor {
23816
24500
  if (this.imageOverlay?.contains(e.target) || this.imageToolbar?.contains(e.target)) return;
23817
24501
  if (this.wordArtOverlay?.contains(e.target)) return;
23818
24502
  if (this.wordArtTextEditor?.input.contains(e.target)) return;
24503
+ if (this.smartArtTextEditor?.input.contains(e.target)) return;
23819
24504
  if (this.selectedInkGroup?.overlay.contains(e.target)) return;
23820
24505
  if (e.target?.closest?.("[data-dxw-model3d-viewer]")) return;
23821
24506
  this.deselectInkGroup();
@@ -24081,6 +24766,18 @@ var _DocxEditor = class _DocxEditor {
24081
24766
  this.exitHeaderFooter();
24082
24767
  return;
24083
24768
  }
24769
+ if (this.selectedImage && this.selectedSmartArtNodeIndex !== null && !e.metaKey && !e.ctrlKey && !e.altKey) {
24770
+ if (e.key === "Enter") {
24771
+ e.preventDefault();
24772
+ this.editSmartArtNodeText(this.selectedImage.src, this.selectedSmartArtNodeIndex);
24773
+ return;
24774
+ }
24775
+ if (e.key.length === 1) {
24776
+ e.preventDefault();
24777
+ this.editSmartArtNodeText(this.selectedImage.src, this.selectedSmartArtNodeIndex, e.key);
24778
+ return;
24779
+ }
24780
+ }
24084
24781
  if (this.caret && (e.key === "Backspace" || e.key === "Delete" || e.key.startsWith("Arrow"))) {
24085
24782
  this.positionCaret();
24086
24783
  }
@@ -24916,6 +25613,217 @@ var _DocxEditor = class _DocxEditor {
24916
25613
  getSelectedDrawingSource() {
24917
25614
  return this.selectedImage?.src ?? null;
24918
25615
  }
25616
+ getSelectedChartData() {
25617
+ const src = this.selectedImage?.src;
25618
+ if (!src) return null;
25619
+ return this.host.getHandle()?.drawings.find((binding) => binding.item.src === src)?.item.chartData ?? null;
25620
+ }
25621
+ getSelectedSmartArtData() {
25622
+ const src = this.selectedImage?.src;
25623
+ if (!src) return null;
25624
+ return this.host.getHandle()?.drawings.find((binding) => binding.item.src === src)?.item.smartArtData ?? null;
25625
+ }
25626
+ getSelectedSmartArtTextFormat() {
25627
+ const src = this.selectedImage?.src;
25628
+ if (!src || this.getSelectedObjectContext()?.kind !== "smartArt") return null;
25629
+ return smartArtTextFormat(this.host.doc, src, this.selectedSmartArtNodeIndex ?? 0);
25630
+ }
25631
+ setSelectedSmartArtTextFormat(patch) {
25632
+ const src = this.selectedImage?.src;
25633
+ if (!src || this.getSelectedObjectContext()?.kind !== "smartArt") return false;
25634
+ const current = smartArtTextFormat(this.host.doc, src, this.selectedSmartArtNodeIndex ?? 0);
25635
+ if (!current) return false;
25636
+ const nodeIndex = this.selectedSmartArtNodeIndex;
25637
+ this.host.history?.checkpoint();
25638
+ if (!setSmartArtTextFormat(this.host.doc, src, { ...current, ...patch }, nodeIndex ?? void 0)) return false;
25639
+ this.host.rerender();
25640
+ this.reselectImage(src, void 0, nodeIndex);
25641
+ return true;
25642
+ }
25643
+ getSelectedObjectContext() {
25644
+ const selected = this.selectedImage;
25645
+ if (!selected) return null;
25646
+ if (selected.kind === "image") {
25647
+ return { kind: selected.el.dataset.dxwModel3d ? "model3d" : "image", canEditText: false };
25648
+ }
25649
+ const binding = this.host.getHandle()?.drawings.find((item) => item.item.src === selected.src);
25650
+ if (binding?.item.smartArtData) {
25651
+ return {
25652
+ kind: "smartArt",
25653
+ canEditText: this.selectedSmartArtNodeIndex !== null,
25654
+ smartArtNodeSelected: this.selectedSmartArtNodeIndex !== null,
25655
+ smartArtNodeIndex: this.selectedSmartArtNodeIndex ?? void 0
25656
+ };
25657
+ }
25658
+ if (binding?.item.chartData) return { kind: "chart", canEditText: false };
25659
+ const kind = isDrawingLine(selected.src) ? "line" : "shape";
25660
+ return {
25661
+ kind,
25662
+ canEditText: kind === "shape" && !!binding?.item.textboxStory && !isDrawingWordArt(selected.src)
25663
+ };
25664
+ }
25665
+ runSelectedObjectCommand(command) {
25666
+ const selected = this.selectedImage;
25667
+ const context = this.getSelectedObjectContext();
25668
+ if (!selected || !context) return false;
25669
+ const { src, el: el16 } = selected;
25670
+ const selectedSmartArtNodeIndex = this.selectedSmartArtNodeIndex;
25671
+ const reselect = () => this.reselectImage(src, void 0, selectedSmartArtNodeIndex);
25672
+ if (command === "delete") {
25673
+ this.deleteSelectedImage();
25674
+ return true;
25675
+ }
25676
+ if (command === "bringForward" || command === "sendBackward") {
25677
+ return this.arrangeSelectedObject(command === "bringForward" ? "bringToFront" : "sendToBack");
25678
+ }
25679
+ if (command.startsWith("wrap")) {
25680
+ const mode = command === "wrapInline" ? "inline" : command === "wrapSquare" ? "square" : command === "wrapTopAndBottom" ? "topAndBottom" : command === "wrapBehind" ? "behind" : "none";
25681
+ this.host.history?.checkpoint();
25682
+ const handle = this.host.getHandle();
25683
+ const binding = selected.kind === "image" ? handle?.images.find((item) => item.item.src === src) : handle?.drawings.find((item) => item.item.src === src);
25684
+ const marginLeft = this.host.doc.sections[0]?.props.marginLeft ?? 96;
25685
+ const position = binding ? { x: binding.item.x - marginLeft, y: 0 } : void 0;
25686
+ if (!setImageWrap(this.host.doc, src, mode, position)) return false;
25687
+ this.host.rerender(void 0, "global");
25688
+ reselect();
25689
+ return true;
25690
+ }
25691
+ if (command === "size") {
25692
+ void requestNumberPairDialog(this.host.container, {
25693
+ title: "Exact size",
25694
+ firstLabel: "Width (pixels)",
25695
+ secondLabel: "Height (pixels)",
25696
+ value: {
25697
+ first: Math.round(parseFloat(el16.style.width) || 0),
25698
+ second: Math.round(parseFloat(el16.style.height) || 0)
25699
+ },
25700
+ min: 1,
25701
+ step: 1
25702
+ }).then((next) => {
25703
+ if (!next) return;
25704
+ this.host.history?.checkpoint();
25705
+ if (resizeDrawing(this.host.doc, src, next.first, next.second)) {
25706
+ this.host.rerender();
25707
+ reselect();
25708
+ }
25709
+ });
25710
+ return true;
25711
+ }
25712
+ if (command === "position") {
25713
+ void requestNumberPairDialog(this.host.container, {
25714
+ title: "Page position",
25715
+ firstLabel: "X (pixels)",
25716
+ secondLabel: "Y (pixels)",
25717
+ value: {
25718
+ first: Math.round(parseFloat(el16.style.left) || 0),
25719
+ second: Math.round(parseFloat(el16.style.top) || 0)
25720
+ },
25721
+ step: 1
25722
+ }).then((next) => {
25723
+ if (!next) return;
25724
+ this.host.history?.checkpoint();
25725
+ if (!isFloatingDrawing(src)) setImageWrap(this.host.doc, src, "square", { x: 0, y: 0 });
25726
+ if (setFloatingPagePosition(this.host.doc, src, next.first, next.second)) {
25727
+ this.host.rerender();
25728
+ reselect();
25729
+ }
25730
+ });
25731
+ return true;
25732
+ }
25733
+ if (command === "rotate") {
25734
+ if (!["shape", "line", "image", "model3d"].includes(context.kind)) return false;
25735
+ void requestTextInputDialog(this.host.container, {
25736
+ title: "Rotation",
25737
+ label: "Degrees clockwise",
25738
+ value: String(drawingRotation(src)),
25739
+ inputType: "number",
25740
+ step: 1
25741
+ }).then((next) => {
25742
+ if (next === null) return;
25743
+ const degrees = parseFloat(next);
25744
+ if (!Number.isFinite(degrees)) return;
25745
+ this.host.history?.checkpoint();
25746
+ if (setDrawingRotation(this.host.doc, src, degrees)) {
25747
+ this.host.rerender(void 0, "global");
25748
+ reselect();
25749
+ }
25750
+ });
25751
+ return true;
25752
+ }
25753
+ if (command === "altText") {
25754
+ if (context.kind !== "image" && context.kind !== "model3d") return false;
25755
+ void requestTextInputDialog(this.host.container, {
25756
+ title: "Alternative text",
25757
+ label: "Describe this object for screen readers",
25758
+ value: imageAltText(src)
25759
+ }).then((next) => {
25760
+ if (next === null) return;
25761
+ this.host.history?.checkpoint();
25762
+ if (setImageAltText(this.host.doc, src, next)) {
25763
+ this.host.rerender();
25764
+ reselect();
25765
+ }
25766
+ });
25767
+ return true;
25768
+ }
25769
+ if (command === "editText") {
25770
+ if (!context.canEditText) return false;
25771
+ if (context.kind === "smartArt" && selectedSmartArtNodeIndex !== null) {
25772
+ this.editSmartArtNodeText(src, selectedSmartArtNodeIndex);
25773
+ return true;
25774
+ }
25775
+ const binding = this.host.getHandle()?.drawings.find((item) => item.item.src === src);
25776
+ if (!binding) return false;
25777
+ const rect = binding.el.getBoundingClientRect();
25778
+ this.enterTextboxStory(src, rect.left + rect.width / 2, rect.top + rect.height / 2);
25779
+ return true;
25780
+ }
25781
+ if (command === "fill") {
25782
+ if (context.kind !== "shape" && context.kind !== "smartArt") return false;
25783
+ void requestColorDialog(this.host.container, {
25784
+ title: "Fill",
25785
+ value: context.kind === "smartArt" ? smartArtFillColor(this.host.doc, src, selectedSmartArtNodeIndex ?? 0) : drawingFillColor(src),
25786
+ allowNone: true
25787
+ }).then((next) => {
25788
+ if (next === void 0) return;
25789
+ this.host.history?.checkpoint();
25790
+ const changed = context.kind === "smartArt" ? setSmartArtFill(this.host.doc, src, next, selectedSmartArtNodeIndex ?? void 0) : setDrawingFill(this.host.doc, src, next);
25791
+ if (changed) {
25792
+ this.host.rerender();
25793
+ reselect();
25794
+ }
25795
+ });
25796
+ return true;
25797
+ }
25798
+ if (command === "outline" || command === "lineStyle") {
25799
+ if (command === "outline" && context.kind !== "shape" || command === "lineStyle" && context.kind !== "line") return false;
25800
+ const style = drawingLineStyle(src);
25801
+ if (!style) return false;
25802
+ const title = command === "lineStyle" ? "Line style" : "Outline";
25803
+ void requestLineStyleDialog(this.host.container, {
25804
+ color: style.color,
25805
+ width: style.width,
25806
+ style: style.dash
25807
+ }, title).then((next) => {
25808
+ if (!next) return;
25809
+ this.host.history?.checkpoint();
25810
+ if (setDrawingLineStyle(this.host.doc, src, next.color, next.width, next.style)) {
25811
+ this.host.rerender();
25812
+ reselect();
25813
+ }
25814
+ });
25815
+ return true;
25816
+ }
25817
+ if (command === "reset3d") {
25818
+ if (context.kind !== "model3d") return false;
25819
+ this.host.history?.checkpoint();
25820
+ if (!setModel3DRotation(this.host.doc, src, { x: 0, y: 0, z: 0 })) return false;
25821
+ this.host.rerender(void 0, "local");
25822
+ reselect();
25823
+ return true;
25824
+ }
25825
+ return false;
25826
+ }
24919
25827
  /** Whether Layout's contextual object commands currently have a target. */
24920
25828
  hasSelectedObject() {
24921
25829
  return this.selectedImage !== null || this.selectedInkGroup !== null;
@@ -25668,18 +26576,20 @@ var _DocxEditor = class _DocxEditor {
25668
26576
  deselectImage() {
25669
26577
  const changed = this.selectedImage !== null;
25670
26578
  this.wordArtTextEditor?.finish(true, false);
26579
+ this.smartArtTextEditor?.finish(true, false);
25671
26580
  this.imageOverlay?.remove();
25672
26581
  this.imageToolbar?.remove();
25673
26582
  this.imageOverlay = null;
25674
26583
  this.imageToolbar = null;
25675
26584
  this.selectedImage = null;
26585
+ this.selectedSmartArtNodeIndex = null;
25676
26586
  if (changed) this.notifyObjectSelection();
25677
26587
  }
25678
26588
  /** Re-select the same drawing after a re-render replaced its element.
25679
26589
  * A header/footer drawing paints one instance per page from the same src;
25680
26590
  * `near` (client px) picks the instance the user is actually working on
25681
26591
  * instead of the first page's copy. */
25682
- reselectImage(src, near) {
26592
+ reselectImage(src, near, smartArtNodeIndex = this.selectedSmartArtNodeIndex) {
25683
26593
  const handle = this.host.getHandle();
25684
26594
  if (!handle) return;
25685
26595
  const img = nearestInstance(handle.images.filter((b) => b.item.src === src), near);
@@ -25688,7 +26598,7 @@ var _DocxEditor = class _DocxEditor {
25688
26598
  return;
25689
26599
  }
25690
26600
  const drw = nearestInstance(handle.drawings.filter((b) => b.item.src === src), near);
25691
- if (drw) this.selectImage(drw.el, src, void 0, "drawing");
26601
+ if (drw) this.selectImage(drw.el, src, void 0, "drawing", smartArtNodeIndex);
25692
26602
  }
25693
26603
  static handleCursor(dir) {
25694
26604
  if (dir === "nw" || dir === "se") return "nwse-resize";
@@ -25696,11 +26606,12 @@ var _DocxEditor = class _DocxEditor {
25696
26606
  if (dir === "n" || dir === "s") return "ns-resize";
25697
26607
  return "ew-resize";
25698
26608
  }
25699
- selectImage(el16, src, item, kind = "image") {
26609
+ selectImage(el16, src, _item, kind = "image", smartArtNodeIndex = null) {
25700
26610
  this.deselectInkGroup();
25701
26611
  this.deselectImage();
25702
26612
  this.hideCaret();
25703
26613
  this.selectedImage = { el: el16, src, kind };
26614
+ this.selectedSmartArtNodeIndex = smartArtNodeIndex;
25704
26615
  const overlay = document.createElement("div");
25705
26616
  overlay.dataset.dxwObjectSelection = "1";
25706
26617
  overlay.style.position = "absolute";
@@ -25714,6 +26625,15 @@ var _DocxEditor = class _DocxEditor {
25714
26625
  overlay.style.boxSizing = "border-box";
25715
26626
  overlay.style.pointerEvents = "none";
25716
26627
  overlay.style.zIndex = "2147483647";
26628
+ if (smartArtNodeIndex !== null) {
26629
+ const node = this.host.getHandle()?.drawings.find((binding) => binding.item.src === src && binding.el === el16)?.item.smartArtNodes?.find((candidate) => candidate.index === smartArtNodeIndex);
26630
+ if (node) {
26631
+ const nodeOutline = document.createElement("div");
26632
+ nodeOutline.dataset.dxwSmartArtNodeSelection = String(node.index);
26633
+ 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);`;
26634
+ overlay.appendChild(nodeOutline);
26635
+ }
26636
+ }
25717
26637
  const line2 = kind === "drawing" && isDrawingLine(src);
25718
26638
  if (line2) {
25719
26639
  const move = document.createElement("div");
@@ -25763,15 +26683,8 @@ var _DocxEditor = class _DocxEditor {
25763
26683
  });
25764
26684
  b.addEventListener("click", (ce) => {
25765
26685
  ce.stopPropagation();
25766
- this.host.history?.checkpoint();
25767
- const sp = this.host.doc.sections[0]?.props;
25768
- const pos = item ? { x: item.x - (sp?.marginLeft ?? 96), y: 0 } : void 0;
25769
- if (setImageWrap(this.host.doc, src, mode, pos)) {
25770
- this.host.rerender();
25771
- this.reselectImage(src);
25772
- } else {
25773
- this.deselectImage();
25774
- }
26686
+ const command = mode === "inline" ? "wrapInline" : mode === "square" ? "wrapSquare" : mode === "topAndBottom" ? "wrapTopAndBottom" : mode === "behind" ? "wrapBehind" : "wrapFront";
26687
+ if (!this.runSelectedObjectCommand(command)) this.deselectImage();
25775
26688
  });
25776
26689
  bar.appendChild(b);
25777
26690
  }
@@ -25793,117 +26706,58 @@ var _DocxEditor = class _DocxEditor {
25793
26706
  });
25794
26707
  bar.appendChild(b);
25795
26708
  };
25796
- extra("Alt", "Alternative text", () => {
25797
- const cur = imageAltText(src);
25798
- void requestTextInputDialog(this.host.container, {
25799
- title: "Alternative text",
25800
- label: "Describe this object for screen readers",
25801
- value: cur
25802
- }).then((next) => {
25803
- if (next === null) return;
25804
- this.host.history?.checkpoint();
25805
- if (setImageAltText(this.host.doc, src, next)) this.host.rerender();
25806
- this.deselectImage();
26709
+ const context = this.getSelectedObjectContext();
26710
+ if (context?.kind === "image" || context?.kind === "model3d") {
26711
+ extra("Alt", "Alternative text", () => {
26712
+ this.runSelectedObjectCommand("altText");
25807
26713
  });
25808
- });
26714
+ }
25809
26715
  extra("Size", "Exact size (px)", () => {
25810
- const curW = parseFloat(el16.style.width) || 0;
25811
- const curH = parseFloat(el16.style.height) || 0;
25812
- const cur = `${Math.round(curW)}x${Math.round(curH)}`;
25813
- void requestTextInputDialog(this.host.container, {
25814
- title: "Exact size",
25815
- label: "Width \xD7 height in pixels",
25816
- value: cur,
25817
- placeholder: "640 \xD7 360"
25818
- }).then((next) => {
25819
- const match = next && /^\s*(\d+)\s*[x×]\s*(\d+)\s*$/i.exec(next);
25820
- if (!match) return;
25821
- this.host.history?.checkpoint();
25822
- if (resizeDrawing(this.host.doc, src, parseInt(match[1], 10), parseInt(match[2], 10))) this.host.rerender();
25823
- this.deselectImage();
25824
- });
26716
+ this.runSelectedObjectCommand("size");
25825
26717
  });
25826
26718
  extra("Position", "Exact page position (px)", () => {
25827
- const curX = parseFloat(el16.style.left) || 0;
25828
- const curY = parseFloat(el16.style.top) || 0;
25829
- void requestTextInputDialog(this.host.container, {
25830
- title: "Page position",
25831
- label: "X, Y in pixels",
25832
- value: `${Math.round(curX)}, ${Math.round(curY)}`,
25833
- placeholder: "120, 80"
25834
- }).then((next) => {
25835
- const match = next && /^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/.exec(next);
25836
- if (!match) return;
25837
- this.host.history?.checkpoint();
25838
- if (!isFloatingDrawing(src)) setImageWrap(this.host.doc, src, "square", { x: 0, y: 0 });
25839
- if (setFloatingPagePosition(this.host.doc, src, parseFloat(match[1]), parseFloat(match[2]))) {
25840
- this.host.rerender();
25841
- this.reselectImage(src);
25842
- }
25843
- });
26719
+ this.runSelectedObjectCommand("position");
25844
26720
  });
26721
+ const drawingBinding = kind === "drawing" ? this.host.getHandle()?.drawings.find((binding) => binding.item.src === src) : void 0;
25845
26722
  if (kind === "drawing") {
25846
- extra("Rotate", "Set rotation (degrees)", () => {
25847
- void requestTextInputDialog(this.host.container, {
25848
- title: "Rotation",
25849
- label: "Degrees clockwise",
25850
- value: String(drawingRotation(src)),
25851
- placeholder: "90"
25852
- }).then((next) => {
25853
- if (next === null) return;
25854
- const degrees = parseFloat(next);
25855
- if (!Number.isFinite(degrees)) return;
25856
- this.host.history?.checkpoint();
25857
- if (setDrawingRotation(this.host.doc, src, degrees)) {
25858
- this.host.rerender(void 0, "global");
25859
- this.reselectImage(src);
25860
- }
26723
+ const drawingIsLine = isDrawingLine(src);
26724
+ if (context?.kind === "shape" || context?.kind === "line") {
26725
+ extra("Rotate", "Set rotation (degrees)", () => {
26726
+ this.runSelectedObjectCommand("rotate");
25861
26727
  });
25862
- });
25863
- if (!isDrawingLine(src)) {
25864
- extra("Fill", "Shape fill color", () => {
25865
- void requestTextInputDialog(this.host.container, {
25866
- title: "Fill",
25867
- label: "Color or none",
25868
- value: drawingFillColor(src) ?? "none",
25869
- placeholder: "#4472C4 or none"
25870
- }).then((next) => {
25871
- if (next === null) return;
25872
- const color = /^\s*none\s*$/i.test(next) ? null : /^\s*#?([0-9a-f]{6})\s*$/i.exec(next)?.[1];
25873
- if (color === void 0) return;
25874
- this.host.history?.checkpoint();
25875
- if (setDrawingFill(this.host.doc, src, color ? `#${color}` : null)) {
25876
- this.host.rerender();
25877
- this.reselectImage(src);
26728
+ }
26729
+ if (!drawingIsLine) {
26730
+ if (context?.kind === "shape" || context?.kind === "smartArt") {
26731
+ extra(
26732
+ context.kind === "smartArt" ? context.smartArtNodeSelected ? "Node fill" : "Fill all" : "Fill",
26733
+ context.kind === "smartArt" ? context.smartArtNodeSelected ? "Selected SmartArt node fill" : "All SmartArt node fills" : "Shape fill color",
26734
+ () => {
26735
+ this.runSelectedObjectCommand("fill");
25878
26736
  }
25879
- });
25880
- });
26737
+ );
26738
+ }
25881
26739
  }
25882
- extra("Outline", "Outline color and weight", () => {
25883
- const style = drawingLineStyle(src);
25884
- if (!style) return;
25885
- void requestTextInputDialog(this.host.container, {
25886
- title: "Outline",
25887
- label: "Color and width in pixels",
25888
- value: `${style.color}, ${Number(style.width.toFixed(2))}`,
25889
- placeholder: "#1a73e8, 1.5"
25890
- }).then((next) => {
25891
- const match = next && /^\s*#?([0-9a-f]{6})\s*,\s*(\d+(?:\.\d+)?)\s*$/i.exec(next);
25892
- if (!match) return;
25893
- this.host.history?.checkpoint();
25894
- if (setDrawingLineStyle(this.host.doc, src, `#${match[1]}`, parseFloat(match[2]))) {
25895
- this.host.rerender();
25896
- this.reselectImage(src);
25897
- }
26740
+ if (context?.kind === "line") {
26741
+ extra("Line style", "Line color, weight, and style", () => {
26742
+ this.runSelectedObjectCommand("lineStyle");
25898
26743
  });
26744
+ } else if (context?.kind === "shape") {
26745
+ extra("Outline", "Outline color, weight, and style", () => {
26746
+ this.runSelectedObjectCommand("outline");
26747
+ });
26748
+ }
26749
+ extra("Delete", "Delete shape", () => {
26750
+ this.runSelectedObjectCommand("delete");
25899
26751
  });
25900
- extra("Delete", "Delete shape", () => this.deleteSelectedImage());
25901
26752
  }
25902
- const drawingBinding = kind === "drawing" ? this.host.getHandle()?.drawings.find((binding) => binding.item.src === src) : void 0;
25903
26753
  if (drawingBinding?.item.textboxStory && !isDrawingWordArt(src)) {
25904
26754
  extra("Edit text", "Edit shape text with the Home font controls", () => {
25905
- const rect = drawingBinding.el.getBoundingClientRect();
25906
- this.enterTextboxStory(src, rect.left + rect.width / 2, rect.top + rect.height / 2);
26755
+ this.runSelectedObjectCommand("editText");
26756
+ });
26757
+ }
26758
+ if (context?.kind === "smartArt" && this.selectedSmartArtNodeIndex !== null) {
26759
+ extra("Edit text", "Edit selected SmartArt node text", () => {
26760
+ this.runSelectedObjectCommand("editText");
25907
26761
  });
25908
26762
  }
25909
26763
  if (kind === "drawing" && isDrawingWordArt(src)) {
@@ -25931,11 +26785,7 @@ var _DocxEditor = class _DocxEditor {
25931
26785
  }
25932
26786
  if (el16.dataset.dxwModel3d) {
25933
26787
  extra("Reset 3D", "Reset 3D rotation", () => {
25934
- this.host.history?.checkpoint();
25935
- if (setModel3DRotation(this.host.doc, src, { x: 0, y: 0, z: 0 })) {
25936
- this.host.rerender(void 0, "local");
25937
- this.reselectImage(src);
25938
- }
26788
+ this.runSelectedObjectCommand("reset3d");
25939
26789
  });
25940
26790
  }
25941
26791
  const surface = el16.parentElement;
@@ -26094,7 +26944,9 @@ var _DocxEditor = class _DocxEditor {
26094
26944
  void requestTextInputDialog(this.host.container, {
26095
26945
  title: "Watermark rotation",
26096
26946
  label: "Degrees clockwise",
26097
- value: String(cur)
26947
+ value: String(cur),
26948
+ inputType: "number",
26949
+ step: 1
26098
26950
  }).then((next) => {
26099
26951
  if (next === null) return;
26100
26952
  const degrees = parseFloat(next);
@@ -26252,6 +27104,8 @@ var _DocxEditor = class _DocxEditor {
26252
27104
  const drawingTarget = objectMove && this.selectedImage?.kind === "drawing" ? this.selectedImage.el : target.closest?.("[data-dxw-drawing]");
26253
27105
  const handle = this.host.getHandle();
26254
27106
  let drawingBinding = drawingTarget ? handle?.drawings.find((b) => b.el === drawingTarget) : void 0;
27107
+ const smartArtNodeTarget = target.closest?.("[data-dxw-smart-art-node]");
27108
+ const smartArtNodeIndex = smartArtNodeTarget ? Number.parseInt(smartArtNodeTarget.dataset.dxwSmartArtNode ?? "", 10) : null;
26255
27109
  if (!drawingBinding && !target.closest("button")) {
26256
27110
  const pointCaret2 = this.caretFromPoint(e.clientX, e.clientY);
26257
27111
  if (!pointCaret2 || !this.inActiveRegion(pointCaret2.t)) {
@@ -26272,6 +27126,11 @@ var _DocxEditor = class _DocxEditor {
26272
27126
  e.stopPropagation();
26273
27127
  this.suppressNextMouseUp = true;
26274
27128
  if (e.detail >= 2) {
27129
+ if (binding.item.smartArtData && smartArtNodeIndex !== null && Number.isFinite(smartArtNodeIndex)) {
27130
+ this.selectImage(binding.el, binding.item.src, void 0, "drawing", smartArtNodeIndex);
27131
+ this.editSmartArtNodeText(binding.item.src, smartArtNodeIndex);
27132
+ return true;
27133
+ }
26275
27134
  if (textboxStory) {
26276
27135
  this.enterTextboxStory(binding.item.src, e.clientX, e.clientY);
26277
27136
  return true;
@@ -26295,7 +27154,7 @@ var _DocxEditor = class _DocxEditor {
26295
27154
  moved = true;
26296
27155
  if (binding.item.anchored) {
26297
27156
  if (this.selectedImage?.src !== binding.item.src) {
26298
- this.selectImage(el16, binding.item.src, void 0, "drawing");
27157
+ this.selectImage(el16, binding.item.src, void 0, "drawing", Number.isFinite(smartArtNodeIndex) ? smartArtNodeIndex : null);
26299
27158
  }
26300
27159
  toolbarLeft0 = parseFloat(this.imageToolbar?.style.left ?? "") || 0;
26301
27160
  toolbarTop0 = parseFloat(this.imageToolbar?.style.top ?? "") || 0;
@@ -26325,7 +27184,7 @@ var _DocxEditor = class _DocxEditor {
26325
27184
  this.hideDropIndicator();
26326
27185
  this.suppressNextMouseUp = false;
26327
27186
  if (!moved) {
26328
- this.selectImage(binding.el, binding.item.src, void 0, "drawing");
27187
+ this.selectImage(binding.el, binding.item.src, void 0, "drawing", Number.isFinite(smartArtNodeIndex) ? smartArtNodeIndex : null);
26329
27188
  return;
26330
27189
  }
26331
27190
  if (binding.item.anchored) {
@@ -26543,6 +27402,59 @@ var _DocxEditor = class _DocxEditor {
26543
27402
  }
26544
27403
  return false;
26545
27404
  }
27405
+ editSmartArtNodeText(src, nodeIndex, replacement) {
27406
+ if (this.smartArtTextEditor) {
27407
+ this.smartArtTextEditor.input.focus();
27408
+ this.smartArtTextEditor.input.select();
27409
+ return;
27410
+ }
27411
+ const binding = this.host.getHandle()?.drawings.find((item) => item.item.src === src);
27412
+ const node = binding?.item.smartArtNodes?.find((item) => item.index === nodeIndex);
27413
+ const surface = binding?.el.parentElement;
27414
+ const original = binding?.item.smartArtData?.items[nodeIndex];
27415
+ if (!binding || !node || !surface || original === void 0) return;
27416
+ const zoom = this.host.zoom ?? 1;
27417
+ const surfaceRect = surface.getBoundingClientRect();
27418
+ const drawingRect = binding.el.getBoundingClientRect();
27419
+ const input = document.createElement("input");
27420
+ input.dataset.dxwSmartArtNodeEditor = String(nodeIndex);
27421
+ input.value = replacement ?? original;
27422
+ input.setAttribute("aria-label", `Edit SmartArt node ${nodeIndex + 1}`);
27423
+ 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;`;
27424
+ const near = {
27425
+ x: drawingRect.left + (node.x + node.width / 2) * zoom,
27426
+ y: drawingRect.top + (node.y + node.height / 2) * zoom
27427
+ };
27428
+ const finish = (commit, reselect) => {
27429
+ if (this.smartArtTextEditor?.input !== input) return;
27430
+ this.smartArtTextEditor = null;
27431
+ const next = input.value;
27432
+ input.remove();
27433
+ if (commit && next !== original) {
27434
+ this.host.history?.checkpoint();
27435
+ if (setSmartArtNodeText(this.host.doc, src, nodeIndex, next)) this.host.rerender();
27436
+ }
27437
+ if (reselect) this.reselectImage(src, near, nodeIndex);
27438
+ this.focusText();
27439
+ };
27440
+ this.smartArtTextEditor = { input, finish };
27441
+ input.addEventListener("mousedown", (event) => event.stopPropagation());
27442
+ input.addEventListener("keydown", (event) => {
27443
+ event.stopPropagation();
27444
+ if (event.key === "Enter") {
27445
+ event.preventDefault();
27446
+ finish(true, true);
27447
+ } else if (event.key === "Escape") {
27448
+ event.preventDefault();
27449
+ finish(false, true);
27450
+ }
27451
+ });
27452
+ input.addEventListener("blur", () => finish(true, true));
27453
+ surface.appendChild(input);
27454
+ input.focus();
27455
+ if (replacement === void 0) input.select();
27456
+ else input.setSelectionRange(input.value.length, input.value.length);
27457
+ }
26546
27458
  editDrawingWordArt(src) {
26547
27459
  if (this.wordArtTextEditor) {
26548
27460
  this.wordArtTextEditor.input.focus();
@@ -26698,11 +27610,23 @@ var _DocxEditor = class _DocxEditor {
26698
27610
  box.appendChild(caption);
26699
27611
  document.body.appendChild(box);
26700
27612
  this.mathEditorEl = box;
27613
+ const deleteEquation = () => {
27614
+ this.host.history?.checkpoint();
27615
+ if (deleteMath(this.host.doc, oMathEl)) this.host.rerender();
27616
+ this.closeMathEditor();
27617
+ this.focusText();
27618
+ };
27619
+ const remove = document.createElement("button");
27620
+ remove.textContent = "Delete";
27621
+ remove.setAttribute("aria-label", "Delete equation");
27622
+ remove.style.cssText = "border:1px solid #f1a7a2;border-radius:14px;padding:3px 12px;cursor:pointer;background:#fff;color:#b3261e;";
27623
+ remove.addEventListener("click", deleteEquation);
26701
27624
  if (!editable) {
26702
27625
  input.readOnly = true;
26703
27626
  input.style.background = "#f1f3f4";
26704
27627
  input.style.color = "#5f6368";
26705
27628
  caption.textContent = "Structured equation \u2014 text editing is disabled to protect its formatting.";
27629
+ row.appendChild(remove);
26706
27630
  setTimeout(() => input.select(), 0);
26707
27631
  input.addEventListener("keydown", (ke) => {
26708
27632
  ke.stopPropagation();
@@ -26717,6 +27641,7 @@ var _DocxEditor = class _DocxEditor {
26717
27641
  apply.textContent = "Apply";
26718
27642
  apply.style.cssText = "border:1px solid #dadce0;border-radius:14px;padding:3px 12px;cursor:pointer;background:#1a73e8;color:#fff;";
26719
27643
  row.appendChild(apply);
27644
+ row.appendChild(remove);
26720
27645
  const reject = () => {
26721
27646
  input.style.borderColor = "#d93025";
26722
27647
  input.style.background = "#fce8e6";
@@ -26728,6 +27653,10 @@ var _DocxEditor = class _DocxEditor {
26728
27653
  };
26729
27654
  const commitMath = () => {
26730
27655
  const val = input.value.trim();
27656
+ if (!val) {
27657
+ deleteEquation();
27658
+ return;
27659
+ }
26731
27660
  if (val === original.trim()) {
26732
27661
  this.closeMathEditor();
26733
27662
  this.focusText();
@@ -27192,8 +28121,14 @@ var _DocxEditor = class _DocxEditor {
27192
28121
  offset: endText.text.length,
27193
28122
  bias: endText.text.length > 0 ? "end" : void 0
27194
28123
  };
28124
+ const splitWasList = (() => {
28125
+ const pPr = paragraph.children.find((child4) => localName(child4.name) === "pPr");
28126
+ const style = pPr?.children.find((child4) => localName(child4.name) === "pStyle");
28127
+ return !!pPr?.children.some((child4) => localName(child4.name) === "numPr") || !!resolveParagraphStyleChain(this.host.doc.styles, attr(style, "val"), false).pPr.numbering;
28128
+ })();
27195
28129
  const split = this.splitParagraphCore();
27196
28130
  if (!split) return null;
28131
+ if (splitWasList) clearListParagraphFormatting(this.host.doc, split.after);
27197
28132
  const hasPageBreak = (element) => localName(element.name) === "br" && attr(element, "type") === "page" || element.children.some(hasPageBreak);
27198
28133
  const insertBeforeTrailingBreak = hasPageBreak(split.after);
27199
28134
  const afterSources = insertBeforeTrailingBreak ? [] : [split.after];
@@ -27793,6 +28728,14 @@ var _DocxEditor = class _DocxEditor {
27793
28728
  this.splitParagraphNoHistory();
27794
28729
  }
27795
28730
  splitParagraphNoHistory() {
28731
+ if (this.caret) {
28732
+ const paragraph = paragraphOf(this.host.doc, this.caret.t);
28733
+ if (paragraph && textElements(paragraph).every((text) => text.text.length === 0) && clearListParagraphFormatting(this.host.doc, paragraph)) {
28734
+ this.commit();
28735
+ this.focusText();
28736
+ return;
28737
+ }
28738
+ }
27796
28739
  const split = this.splitParagraphCore();
27797
28740
  const reparsed = split ? this.host.doc.reparseDirectBodyParagraphSplit(split.before, split.after) : null;
27798
28741
  if (reparsed && split && this.caret) {
@@ -28672,6 +29615,84 @@ function adjustIndent(doc, targets, direction) {
28672
29615
  if (touched) doc.refresh();
28673
29616
  return touched;
28674
29617
  }
29618
+ var DIVIDER_STYLES = /* @__PURE__ */ new Set([
29619
+ "single",
29620
+ "double",
29621
+ "dotted",
29622
+ "dashed",
29623
+ "thinThickSmallGap"
29624
+ ]);
29625
+ function paragraphDividerAt(doc, target) {
29626
+ const paragraph = paragraphOf(doc, target);
29627
+ const pPr = paragraph?.children.find((child4) => localName(child4.name) === "pPr");
29628
+ const pBdr = pPr?.children.find((child4) => localName(child4.name) === "pBdr");
29629
+ const bottom = pBdr?.children.find((child4) => localName(child4.name) === "bottom");
29630
+ if (!bottom) return null;
29631
+ const value = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "val") ?? ""];
29632
+ if (value === "none" || value === "nil") return null;
29633
+ const style = DIVIDER_STYLES.has(value) ? value : "single";
29634
+ const colorValue2 = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "color") ?? ""];
29635
+ const sizeValue = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "sz") ?? ""];
29636
+ const spaceValue = bottom.attrs[Object.keys(bottom.attrs).find((key) => localName(key) === "space") ?? ""];
29637
+ return {
29638
+ style,
29639
+ color: colorValue2 && colorValue2 !== "auto" ? `#${colorValue2.toUpperCase()}` : "#000000",
29640
+ widthPt: (parseInt(sizeValue ?? "4", 10) || 4) / 8,
29641
+ spacePt: parseInt(spaceValue ?? "0", 10) || 0
29642
+ };
29643
+ }
29644
+ function setParagraphDivider(doc, targets, divider) {
29645
+ const paragraphs = paragraphsOf(doc, targets);
29646
+ if (paragraphs.size === 0) return false;
29647
+ for (const paragraph of paragraphs) {
29648
+ const w = prefixOf13(paragraph);
29649
+ const pPr = ensurePPr(paragraph);
29650
+ let pBdr = pPr.children.find((child4) => localName(child4.name) === "pBdr");
29651
+ if (!divider) {
29652
+ if (!pBdr) continue;
29653
+ pBdr.children = pBdr.children.filter((child4) => localName(child4.name) !== "bottom");
29654
+ if (pBdr.children.length === 0) pPr.children.splice(pPr.children.indexOf(pBdr), 1);
29655
+ continue;
29656
+ }
29657
+ if (!pBdr) {
29658
+ pBdr = { name: `${w}pBdr`, attrs: {}, children: [], text: "" };
29659
+ const later = /* @__PURE__ */ new Set([
29660
+ "shd",
29661
+ "tabs",
29662
+ "spacing",
29663
+ "ind",
29664
+ "contextualSpacing",
29665
+ "mirrorIndents",
29666
+ "suppressOverlap",
29667
+ "jc",
29668
+ "textDirection",
29669
+ "textAlignment",
29670
+ "textboxTightWrap",
29671
+ "outlineLvl",
29672
+ "divId",
29673
+ "cnfStyle",
29674
+ "rPr",
29675
+ "sectPr",
29676
+ "pPrChange"
29677
+ ]);
29678
+ const index = pPr.children.findIndex((child4) => later.has(localName(child4.name)));
29679
+ pPr.children.splice(index === -1 ? pPr.children.length : index, 0, pBdr);
29680
+ }
29681
+ let bottom = pBdr.children.find((child4) => localName(child4.name) === "bottom");
29682
+ if (!bottom) {
29683
+ bottom = { name: `${w}bottom`, attrs: {}, children: [], text: "" };
29684
+ pBdr.children.push(bottom);
29685
+ }
29686
+ bottom.attrs = {
29687
+ [`${w}val`]: divider.style,
29688
+ [`${w}sz`]: String(Math.max(1, Math.round(divider.widthPt * 8))),
29689
+ [`${w}space`]: String(Math.max(0, Math.round(divider.spacePt))),
29690
+ [`${w}color`]: divider.color.replace(/^#/, "").toUpperCase()
29691
+ };
29692
+ }
29693
+ doc.refresh();
29694
+ return true;
29695
+ }
28675
29696
  function firstText2(node) {
28676
29697
  if (localName(node.name) === "t") return node;
28677
29698
  for (const child4 of node.children) {
@@ -29410,7 +30431,7 @@ var GUIDE_GROUPS = [
29410
30431
  items: [
29411
30432
  {
29412
30433
  title: "Open or upload a document",
29413
- description: "Choose a sample from Try a template or use Upload .docx to edit a local Word file in the browser."
30434
+ description: "Choose File \u2192 Open .docx to edit a local Word file, or choose a starting document from the template menu."
29414
30435
  },
29415
30436
  {
29416
30437
  title: "Zoom, review, and author",
@@ -29472,7 +30493,7 @@ var GUIDE_GROUPS = [
29472
30493
  },
29473
30494
  {
29474
30495
  title: "Shapes and lines",
29475
- 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."
30496
+ 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."
29476
30497
  },
29477
30498
  {
29478
30499
  title: "Text boxes and WordArt",
@@ -29538,7 +30559,7 @@ var GUIDE_GROUPS = [
29538
30559
  },
29539
30560
  {
29540
30561
  title: "Page borders and line numbers",
29541
- description: "Apply a repeating page border and enable continuous, per-page, per-section, or interval-based line numbering."
30562
+ 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."
29542
30563
  },
29543
30564
  {
29544
30565
  title: "Arrange selected objects",
@@ -29559,7 +30580,7 @@ var GUIDE_GROUPS = [
29559
30580
  },
29560
30581
  {
29561
30582
  title: "Exact object properties",
29562
- 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."
30583
+ 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."
29563
30584
  }
29564
30585
  ]
29565
30586
  },
@@ -29573,7 +30594,7 @@ var GUIDE_GROUPS = [
29573
30594
  "Open Insert \u2192 Header, then insert a text box in the repeating header layer.",
29574
30595
  "Enter 1 through 28 as separate paragraphs and select all of those numbered paragraphs.",
29575
30596
  "Open Home \u2192 Line & paragraph spacing \u2192 Exactly 24 pt, then choose Remove space before and Remove space after.",
29576
- "Use Insert \u2192 Shape \u2192 Line for each vertical rule, rotate and position it in the same repeating header layer.",
30597
+ "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.",
29577
30598
  "Choose Close to return to body text."
29578
30599
  ]
29579
30600
  },
@@ -29588,11 +30609,11 @@ var GUIDE_GROUPS = [
29588
30609
  },
29589
30610
  {
29590
30611
  title: "Resume horizontal rule",
29591
- description: "Use a body line when the rule belongs to one location in the document.",
30612
+ description: "Use a native paragraph divider so the rule stays attached to the r\xE9sum\xE9 heading or contact line.",
29592
30613
  steps: [
29593
- "Place the caret near the intended rule and choose Insert \u2192 Shape \u2192 Line.",
29594
- "Drag to position and size it; use Position for exact placement.",
29595
- "Choose Inline, Wrap, In front, or Behind according to how nearby text should flow."
30614
+ "Place the caret in the paragraph that should carry the rule and choose Insert \u2192 Divider.",
30615
+ "Choose a single, double, dashed, dotted, or thin + thick style, then set its color, width, and gap.",
30616
+ "Choose Apply divider. Return to the same paragraph and reopen Divider whenever you want to edit or remove it."
29596
30617
  ]
29597
30618
  },
29598
30619
  {
@@ -29601,7 +30622,7 @@ var GUIDE_GROUPS = [
29601
30622
  },
29602
30623
  {
29603
30624
  title: "Border around every page",
29604
- description: "Choose Layout \u2192 Page border for a true page border. Use header shapes when the design needs custom partial rules or ornaments."
30625
+ 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."
29605
30626
  }
29606
30627
  ]
29607
30628
  }
@@ -29905,7 +30926,7 @@ function detectFonts() {
29905
30926
  };
29906
30927
  ctx.font = "16px monospace";
29907
30928
  const base = ctx.measureText(probe).width;
29908
- const always = /* @__PURE__ */ new Set(["Calibri", "Cambria"]);
30929
+ const always = /* @__PURE__ */ new Set(["Arial", "Calibri", "Cambria", "Courier New", "Times New Roman"]);
29909
30930
  availableFonts = FONT_CANDIDATES.filter((f) => always.has(f) || Math.abs(widthIn(f) - base) > 0.5);
29910
30931
  } catch {
29911
30932
  availableFonts = FONT_CANDIDATES;
@@ -30651,6 +31672,7 @@ function LinkMenu({ api }) {
30651
31672
  "input",
30652
31673
  {
30653
31674
  ref: inputRef,
31675
+ type: "url",
30654
31676
  value: url,
30655
31677
  placeholder: "Paste or type a link",
30656
31678
  onChange: (e) => setUrl(e.target.value),
@@ -30975,12 +31997,16 @@ function EquationMenu({ api }) {
30975
31997
  setError("Place the caret in editable text and enter a valid equation.");
30976
31998
  }
30977
31999
  };
32000
+ const anchor = open ? rootRef.current?.getBoundingClientRect() : null;
32001
+ const viewportWidth = typeof window === "undefined" ? 356 : window.innerWidth;
32002
+ const popoverWidth = Math.min(340, viewportWidth - 16);
32003
+ const popoverLeft = Math.max(8, Math.min(anchor?.left ?? 8, viewportWidth - popoverWidth - 8));
30978
32004
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
30979
32005
  /* @__PURE__ */ jsxs2("button", { title: "Insert equation", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: [
30980
32006
  /* @__PURE__ */ jsx2("span", { style: { fontFamily: "'Cambria Math', serif", fontSize: 18 }, children: "\u03C0" }),
30981
32007
  /* @__PURE__ */ jsx2("span", { style: { marginLeft: 5 }, children: "Equation" })
30982
32008
  ] }),
30983
- 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: [
32009
+ 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: [
30984
32010
  /* @__PURE__ */ jsx2("div", { style: { font: "600 12px system-ui, sans-serif", marginBottom: 5, color: T.fg }, children: "Linear equation" }),
30985
32011
  /* @__PURE__ */ jsx2(
30986
32012
  "input",
@@ -31055,15 +32081,88 @@ function SymbolMenu({ api }) {
31055
32081
  }
31056
32082
  var SHAPES = [
31057
32083
  ["line", "Line", "\u2015"],
32084
+ ["verticalLine", "Vertical line", "\u2502"],
31058
32085
  ["rectangle", "Rectangle", "\u25AD"],
31059
32086
  ["roundedRectangle", "Rounded rectangle", "\u25A2"],
31060
32087
  ["ellipse", "Ellipse", "\u25EF"],
31061
32088
  ["diamond", "Diamond", "\u25C7"],
31062
32089
  ["textBox", "Text box", "T"]
31063
32090
  ];
32091
+ function DividerMenu({ api }) {
32092
+ const [open, setOpen] = useState2(false);
32093
+ const [style, setStyle] = useState2("single");
32094
+ const [color, setColor] = useState2("#000000");
32095
+ const [widthPt, setWidthPt] = useState2(1);
32096
+ const [spacePt, setSpacePt] = useState2(1);
32097
+ const rootRef = useRef2(null);
32098
+ useEffect2(() => {
32099
+ if (!open) return;
32100
+ const close = (event) => {
32101
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
32102
+ };
32103
+ document.addEventListener("mousedown", close);
32104
+ return () => document.removeEventListener("mousedown", close);
32105
+ }, [open]);
32106
+ const toggle = () => {
32107
+ if (!open) {
32108
+ const current = api?.getParagraphDivider();
32109
+ if (current) {
32110
+ setStyle(current.style);
32111
+ setColor(current.color);
32112
+ setWidthPt(current.widthPt);
32113
+ setSpacePt(current.spacePt);
32114
+ }
32115
+ }
32116
+ setOpen(!open);
32117
+ };
32118
+ const apply = () => {
32119
+ if (api?.setParagraphDivider({ style, color, widthPt, spacePt })) setOpen(false);
32120
+ };
32121
+ const previewStyle = style === "double" || style === "thinThickSmallGap" ? "double" : style;
32122
+ return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
32123
+ /* @__PURE__ */ jsx2("button", { title: "Insert or edit divider", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: toggle, children: "Divider" }),
32124
+ 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: [
32125
+ /* @__PURE__ */ jsx2("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "Horizontal rule below the current paragraph" }),
32126
+ /* @__PURE__ */ jsx2("div", { "aria-hidden": "true", style: { height: 12, borderBottom: `${Math.max(widthPt, 1)}px ${previewStyle} ${color}` } }),
32127
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32128
+ "Style",
32129
+ /* @__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: [
32130
+ /* @__PURE__ */ jsx2("option", { value: "single", children: "Single" }),
32131
+ /* @__PURE__ */ jsx2("option", { value: "double", children: "Double" }),
32132
+ /* @__PURE__ */ jsx2("option", { value: "dashed", children: "Dashed" }),
32133
+ /* @__PURE__ */ jsx2("option", { value: "dotted", children: "Dotted" }),
32134
+ /* @__PURE__ */ jsx2("option", { value: "thinThickSmallGap", children: "Thin + thick" })
32135
+ ] })
32136
+ ] }),
32137
+ /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 7 }, children: [
32138
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32139
+ "Color",
32140
+ /* @__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 } })
32141
+ ] }),
32142
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32143
+ "Width (pt)",
32144
+ /* @__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 } })
32145
+ ] }),
32146
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: [
32147
+ "Gap (pt)",
32148
+ /* @__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 } })
32149
+ ] })
32150
+ ] }),
32151
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "space-between", gap: 8 }, children: [
32152
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => {
32153
+ if (api?.setParagraphDivider(null)) setOpen(false);
32154
+ }, style: { ...pillBtn, background: T.popoverBg, color: T.fg, border: `1px solid ${T.border}` }, children: "Remove" }),
32155
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: apply, style: pillBtn, children: "Apply divider" })
32156
+ ] })
32157
+ ] })
32158
+ ] });
32159
+ }
31064
32160
  function ShapeMenu({ api }) {
31065
32161
  const [open, setOpen] = useState2(false);
31066
32162
  const [text, setText] = useState2("");
32163
+ const [lineColor, setLineColor] = useState2("#404040");
32164
+ const [lineWidth, setLineWidth] = useState2("1.33");
32165
+ const [lineDash, setLineDash] = useState2("solid");
31067
32166
  const rootRef = useRef2(null);
31068
32167
  useEffect2(() => {
31069
32168
  if (!open) return;
@@ -31074,14 +32173,17 @@ function ShapeMenu({ api }) {
31074
32173
  return () => document.removeEventListener("mousedown", close);
31075
32174
  }, [open]);
31076
32175
  const insert = (preset) => {
31077
- if (api?.insertShape(preset, text)) {
32176
+ const isLine = preset === "line" || preset === "verticalLine";
32177
+ const width = Number(lineWidth);
32178
+ if (isLine && (!Number.isFinite(width) || width <= 0)) return;
32179
+ if (api?.insertShape(preset, text, isLine ? { color: lineColor, width, dash: lineDash } : void 0)) {
31078
32180
  setText("");
31079
32181
  setOpen(false);
31080
32182
  }
31081
32183
  };
31082
32184
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31083
32185
  /* @__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" }) }),
31084
- 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: [
32186
+ 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: [
31085
32187
  /* @__PURE__ */ jsx2(
31086
32188
  "input",
31087
32189
  {
@@ -31092,6 +32194,53 @@ function ShapeMenu({ api }) {
31092
32194
  style: { width: "100%", boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 6, padding: "5px 8px", font: "13px system-ui, sans-serif", outline: "none" }
31093
32195
  }
31094
32196
  ),
32197
+ /* @__PURE__ */ jsx2("div", { style: { marginTop: 9, color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "Line appearance" }),
32198
+ /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "auto 82px 88px", gap: 6, alignItems: "end", marginTop: 5 }, children: [
32199
+ /* @__PURE__ */ jsx2(
32200
+ ColorMenu,
32201
+ {
32202
+ current: lineColor,
32203
+ title: "Line color",
32204
+ trigger: /* @__PURE__ */ jsxs2(Fragment2, { children: [
32205
+ /* @__PURE__ */ jsx2("span", { style: { fontSize: 12 }, children: "Color" }),
32206
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", style: { width: 16, height: 16, borderRadius: 3, border: `1px solid ${T.border}`, background: lineColor } })
32207
+ ] }),
32208
+ onPick: setLineColor
32209
+ }
32210
+ ),
32211
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "10.5px system-ui, sans-serif" }, children: [
32212
+ "Weight (px)",
32213
+ /* @__PURE__ */ jsx2(
32214
+ "input",
32215
+ {
32216
+ "aria-label": "Line width in pixels",
32217
+ type: "number",
32218
+ min: "0.25",
32219
+ step: "0.25",
32220
+ value: lineWidth,
32221
+ onChange: (event) => setLineWidth(event.target.value),
32222
+ style: { width: "100%", height: 28, boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 5, padding: "3px 5px", color: T.fg, background: T.popoverBg }
32223
+ }
32224
+ )
32225
+ ] }),
32226
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 3, color: T.muted, font: "10.5px system-ui, sans-serif" }, children: [
32227
+ "Style",
32228
+ /* @__PURE__ */ jsxs2(
32229
+ "select",
32230
+ {
32231
+ "aria-label": "Line style",
32232
+ value: lineDash,
32233
+ onChange: (event) => setLineDash(event.target.value),
32234
+ style: { width: "100%", height: 28, border: `1px solid ${T.border}`, borderRadius: 5, padding: "3px 4px", color: T.fg, background: T.popoverBg },
32235
+ children: [
32236
+ /* @__PURE__ */ jsx2("option", { value: "solid", children: "Solid" }),
32237
+ /* @__PURE__ */ jsx2("option", { value: "dashed", children: "Dashed" }),
32238
+ /* @__PURE__ */ jsx2("option", { value: "dotted", children: "Dotted" })
32239
+ ]
32240
+ }
32241
+ )
32242
+ ] })
32243
+ ] }),
31095
32244
  /* @__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: [
31096
32245
  /* @__PURE__ */ jsx2("span", { style: { display: "block", fontSize: 20, lineHeight: 1 }, children: glyph }),
31097
32246
  /* @__PURE__ */ jsx2("span", { children: label })
@@ -31187,12 +32336,12 @@ function WordArtMenu({ api }) {
31187
32336
  ] })
31188
32337
  ] });
31189
32338
  }
31190
- function ChartMenu({ api }) {
32339
+ function ChartMenu({ api, label = "Chart" }) {
31191
32340
  const [open, setOpen] = useState2(false);
31192
32341
  const [type, setType] = useState2("column");
31193
- const [title, setTitle] = useState2("Quarterly sales");
31194
- const [categories, setCategories] = useState2("Q1, Q2, Q3, Q4");
31195
- const [series, setSeries] = useState2("Revenue: 12, 19, 15, 24\nCosts: 8, 11, 10, 14");
32342
+ const [title, setTitle] = useState2("");
32343
+ const [categories, setCategories] = useState2(["", ""]);
32344
+ const [series, setSeries] = useState2([{ name: "", values: ["", ""] }]);
31196
32345
  const [error, setError] = useState2("");
31197
32346
  const rootRef = useRef2(null);
31198
32347
  useEffect2(() => {
@@ -31204,28 +32353,52 @@ function ChartMenu({ api }) {
31204
32353
  return () => document.removeEventListener("mousedown", close);
31205
32354
  }, [open]);
31206
32355
  const submit = () => {
31207
- const categoryValues = categories.split(",").map((value) => value.trim()).filter(Boolean);
31208
- const seriesValues = series.split(/\r?\n/).map((line2) => {
31209
- const separator = line2.indexOf(":");
31210
- if (separator === -1) return null;
31211
- const name = line2.slice(0, separator).trim();
31212
- const values = line2.slice(separator + 1).split(",").map((value) => Number(value.trim()));
31213
- return name && values.length === categoryValues.length && values.every(Number.isFinite) ? { name, values } : null;
31214
- }).filter((value) => value !== null);
31215
- if (!categoryValues.length || !seriesValues.length || seriesValues.length !== series.split(/\r?\n/).filter((line2) => line2.trim()).length) {
31216
- setError("Use comma-separated categories and one \u201CName: 1, 2, 3\u201D series per line.");
32356
+ const categoryValues = categories.map((value) => value.trim());
32357
+ const rawSeries = series.map((entry) => ({
32358
+ name: entry.name.trim(),
32359
+ values: entry.values.map((value) => value.trim())
32360
+ }));
32361
+ if (categoryValues.some((value) => !value) || rawSeries.some((entry) => !entry.name || entry.values.some((value) => value === "" || !Number.isFinite(Number(value))))) {
32362
+ setError("Give every category and series a name, and enter a number in every data cell.");
31217
32363
  return;
31218
32364
  }
32365
+ const seriesValues = rawSeries.map((entry) => ({ name: entry.name, values: entry.values.map(Number) }));
31219
32366
  const data = { type, title, categories: categoryValues, series: seriesValues };
31220
32367
  if (api?.updateSelectedChart(data) || api?.insertChart(data)) {
31221
32368
  setError("");
31222
32369
  setOpen(false);
31223
32370
  }
31224
32371
  };
32372
+ const addCategory = () => {
32373
+ setCategories([...categories, ""]);
32374
+ setSeries(series.map((entry) => ({ ...entry, values: [...entry.values, ""] })));
32375
+ };
32376
+ const removeCategory = (index) => {
32377
+ if (categories.length === 1) return;
32378
+ setCategories(categories.filter((_, itemIndex) => itemIndex !== index));
32379
+ setSeries(series.map((entry) => ({ ...entry, values: entry.values.filter((_, itemIndex) => itemIndex !== index) })));
32380
+ };
32381
+ const anchor = open ? rootRef.current?.getBoundingClientRect() : null;
32382
+ const viewportWidth = typeof window === "undefined" ? 456 : window.innerWidth;
32383
+ const popoverWidth = Math.min(440, viewportWidth - 16);
32384
+ const popoverLeft = Math.max(8, Math.min(anchor?.left ?? 8, viewportWidth - popoverWidth - 8));
31225
32385
  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 };
32386
+ const toggle = () => {
32387
+ if (open) {
32388
+ setOpen(false);
32389
+ return;
32390
+ }
32391
+ const selected = api?.getSelectedChart();
32392
+ setType(selected?.type ?? "column");
32393
+ setTitle(selected?.title ?? "");
32394
+ setCategories(selected ? [...selected.categories] : ["", ""]);
32395
+ setSeries(selected ? selected.series.map((entry) => ({ name: entry.name, values: entry.values.map(String) })) : [{ name: "", values: ["", ""] }]);
32396
+ setError("");
32397
+ setOpen(true);
32398
+ };
31226
32399
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31227
- /* @__PURE__ */ jsx2("button", { title: "Insert or edit chart", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "Chart" }),
31228
- 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: [
32400
+ /* @__PURE__ */ jsx2("button", { title: "Insert or edit chart", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: toggle, children: label }),
32401
+ 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: [
31229
32402
  /* @__PURE__ */ jsx2(
31230
32403
  ToolbarMenuSelect,
31231
32404
  {
@@ -31244,58 +32417,145 @@ function ChartMenu({ api }) {
31244
32417
  }
31245
32418
  ),
31246
32419
  /* @__PURE__ */ jsx2("input", { "aria-label": "Chart title", value: title, onChange: (event) => setTitle(event.target.value), placeholder: "Chart title", style: fieldStyle }),
31247
- /* @__PURE__ */ jsx2("input", { "aria-label": "Chart categories", value: categories, onChange: (event) => setCategories(event.target.value), placeholder: "Q1, Q2, Q3, Q4", style: fieldStyle }),
31248
- /* @__PURE__ */ jsx2("textarea", { "aria-label": "Chart series", rows: 3, value: series, onChange: (event) => setSeries(event.target.value), style: { ...fieldStyle, resize: "vertical" } }),
31249
- /* @__PURE__ */ jsx2("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "Each series: Name: value, value, value" }),
32420
+ /* @__PURE__ */ jsxs2("div", { role: "group", "aria-label": "Chart data", style: { display: "grid", gap: 7 }, children: [
32421
+ /* @__PURE__ */ jsx2("strong", { style: { color: T.fg, font: "600 11.5px system-ui, sans-serif" }, children: "Data" }),
32422
+ /* @__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: [
32423
+ /* @__PURE__ */ jsx2("span", { style: { alignSelf: "center", color: T.muted, font: "11px system-ui, sans-serif" }, children: "Series" }),
32424
+ categories.map((category, index) => /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gridTemplateColumns: "1fr auto", gap: 3 }, children: [
32425
+ /* @__PURE__ */ jsx2(
32426
+ "input",
32427
+ {
32428
+ "aria-label": `Chart category ${index + 1}`,
32429
+ value: category,
32430
+ placeholder: "Category",
32431
+ onChange: (event) => setCategories(categories.map((value, itemIndex) => itemIndex === index ? event.target.value : value)),
32432
+ style: fieldStyle
32433
+ }
32434
+ ),
32435
+ 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" })
32436
+ ] }, index)),
32437
+ /* @__PURE__ */ jsx2("span", {}),
32438
+ series.map((entry, seriesIndex) => /* @__PURE__ */ jsxs2(Fragment, { children: [
32439
+ /* @__PURE__ */ jsx2(
32440
+ "input",
32441
+ {
32442
+ "aria-label": `Chart series ${seriesIndex + 1} name`,
32443
+ value: entry.name,
32444
+ placeholder: "Series",
32445
+ onChange: (event) => setSeries(series.map((value, itemIndex) => itemIndex === seriesIndex ? { ...value, name: event.target.value } : value)),
32446
+ style: fieldStyle
32447
+ }
32448
+ ),
32449
+ entry.values.map((value, valueIndex) => /* @__PURE__ */ jsx2(
32450
+ "input",
32451
+ {
32452
+ "aria-label": `Chart series ${seriesIndex + 1} value ${valueIndex + 1}`,
32453
+ type: "number",
32454
+ step: "any",
32455
+ value,
32456
+ placeholder: "0",
32457
+ onChange: (event) => setSeries(series.map((seriesValue, itemIndex) => itemIndex === seriesIndex ? { ...seriesValue, values: seriesValue.values.map((itemValue, itemValueIndex) => itemValueIndex === valueIndex ? event.target.value : itemValue) } : seriesValue)),
32458
+ style: fieldStyle
32459
+ },
32460
+ valueIndex
32461
+ )),
32462
+ /* @__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" })
32463
+ ] }, seriesIndex))
32464
+ ] }) }),
32465
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 6 }, children: [
32466
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setSeries([...series, { name: "", values: categories.map(() => "") }]), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Add series" }),
32467
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: addCategory, style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Add category" })
32468
+ ] })
32469
+ ] }),
31250
32470
  error && /* @__PURE__ */ jsx2("div", { role: "alert", style: { color: "#c5221f", font: "11.5px system-ui, sans-serif" }, children: error }),
31251
32471
  /* @__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" })
31252
32472
  ] })
31253
32473
  ] });
31254
32474
  }
31255
- function SmartArtMenu({ api }) {
32475
+ function SmartArtMenu({ api, label = "SmartArt" }) {
31256
32476
  const [open, setOpen] = useState2(false);
32477
+ const [step, setStep] = useState2("layout");
32478
+ const [editing, setEditing] = useState2(false);
31257
32479
  const [layout, setLayout] = useState2("process");
31258
- const [items, setItems] = useState2("Discover\nDesign\nDeliver");
32480
+ const [items, setItems] = useState2([""]);
31259
32481
  const rootRef = useRef2(null);
31260
- useEffect2(() => {
31261
- if (!open) return;
31262
- const close = (event) => {
31263
- if (!rootRef.current?.contains(event.target)) setOpen(false);
31264
- };
31265
- document.addEventListener("mousedown", close);
31266
- return () => document.removeEventListener("mousedown", close);
31267
- }, [open]);
31268
32482
  const submit = () => {
31269
- const values = items.split(/\r?\n/).map((value) => value.trim()).filter(Boolean);
32483
+ const values = items.map((value) => value.trim()).filter(Boolean);
31270
32484
  if (!values.length) return;
31271
32485
  const data = { layout, items: values };
31272
32486
  if (api?.updateSelectedSmartArt(data) || api?.insertSmartArt(data)) setOpen(false);
31273
32487
  };
31274
32488
  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 };
32489
+ const toggle = () => {
32490
+ if (open) {
32491
+ setOpen(false);
32492
+ return;
32493
+ }
32494
+ const selected = api?.getSelectedSmartArt();
32495
+ setEditing(!!selected);
32496
+ setLayout(selected?.layout ?? "process");
32497
+ setItems(selected ? [...selected.items] : [""]);
32498
+ setStep(selected ? "items" : "layout");
32499
+ setOpen(true);
32500
+ };
32501
+ const layouts = [
32502
+ { value: "process", label: "Process" },
32503
+ { value: "cycle", label: "Cycle" },
32504
+ { value: "hierarchy", label: "Hierarchy" },
32505
+ { value: "list", label: "List" }
32506
+ ];
32507
+ const preview = (value) => {
32508
+ const node = { width: 22, height: 13, borderRadius: 3, background: T.accent };
32509
+ 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)) });
32510
+ if (value === "hierarchy") return /* @__PURE__ */ jsxs2("div", { style: { display: "grid", justifyItems: "center", gap: 8 }, children: [
32511
+ /* @__PURE__ */ jsx2("span", { style: node }),
32512
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 12 }, children: [
32513
+ /* @__PURE__ */ jsx2("span", { style: node }),
32514
+ /* @__PURE__ */ jsx2("span", { style: node })
32515
+ ] })
32516
+ ] });
32517
+ 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)) });
32518
+ return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [
32519
+ /* @__PURE__ */ jsx2("span", { style: node }),
32520
+ /* @__PURE__ */ jsx2("span", { children: "\u2192" }),
32521
+ /* @__PURE__ */ jsx2("span", { style: node }),
32522
+ /* @__PURE__ */ jsx2("span", { children: "\u2192" }),
32523
+ /* @__PURE__ */ jsx2("span", { style: node })
32524
+ ] });
32525
+ };
31275
32526
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31276
- /* @__PURE__ */ jsx2("button", { title: "Insert or edit SmartArt", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "SmartArt" }),
31277
- 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: [
31278
- /* @__PURE__ */ jsx2(
31279
- ToolbarMenuSelect,
31280
- {
31281
- value: layout,
31282
- ariaLabel: "SmartArt layout",
31283
- width: "100%",
31284
- menuWidth: 260,
31285
- options: [
31286
- { value: "process", label: "Process" },
31287
- { value: "cycle", label: "Cycle" },
31288
- { value: "hierarchy", label: "Hierarchy" },
31289
- { value: "list", label: "List" }
31290
- ],
31291
- onChange: (value) => setLayout(value),
31292
- style: fieldStyle
31293
- }
31294
- ),
31295
- /* @__PURE__ */ jsx2("textarea", { "aria-label": "SmartArt items", rows: 5, value: items, onChange: (event) => setItems(event.target.value), style: { ...fieldStyle, resize: "vertical" } }),
31296
- /* @__PURE__ */ jsx2("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "One diagram item per line." }),
31297
- /* @__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" })
31298
- ] })
32527
+ /* @__PURE__ */ jsx2("button", { title: "Insert or edit SmartArt", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: toggle, children: label }),
32528
+ open && createPortal2(
32529
+ /* @__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: [
32530
+ /* @__PURE__ */ jsxs2("div", { children: [
32531
+ /* @__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" }),
32532
+ /* @__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 })
32533
+ ] }),
32534
+ 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: () => {
32535
+ setLayout(option.value);
32536
+ setStep("items");
32537
+ }, 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: [
32538
+ preview(option.value),
32539
+ /* @__PURE__ */ jsx2("span", { style: { font: "600 13px system-ui, sans-serif" }, children: option.label })
32540
+ ] }, option.value)) }) : /* @__PURE__ */ jsxs2("div", { role: "group", "aria-label": "SmartArt items", style: { display: "grid", gap: 7 }, children: [
32541
+ items.map((item, index) => /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr auto auto auto", gap: 5 }, children: [
32542
+ /* @__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 }),
32543
+ /* @__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" }),
32544
+ /* @__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" }),
32545
+ /* @__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" })
32546
+ ] }, index)),
32547
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setItems([...items, ""]), style: { ...pillBtn, justifySelf: "start", background: T.popoverBg, color: T.fg }, children: "Add item" })
32548
+ ] }),
32549
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "space-between", gap: 8 }, children: [
32550
+ /* @__PURE__ */ jsx2("div", { children: step === "items" && /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setStep("layout"), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Back" }) }),
32551
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 7 }, children: [
32552
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setOpen(false), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Cancel" }),
32553
+ 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" })
32554
+ ] })
32555
+ ] })
32556
+ ] }) }),
32557
+ document.body
32558
+ )
31299
32559
  ] });
31300
32560
  }
31301
32561
  function MediaMenu({ api }) {
@@ -31313,7 +32573,7 @@ function MediaMenu({ api }) {
31313
32573
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
31314
32574
  /* @__PURE__ */ jsx2("button", { title: "Insert online video", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "Media" }),
31315
32575
  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: [
31316
- /* @__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 } }),
32576
+ /* @__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 } }),
31317
32577
  /* @__PURE__ */ jsx2(
31318
32578
  "button",
31319
32579
  {
@@ -31583,6 +32843,65 @@ function TableMenu({ api }) {
31583
32843
  )
31584
32844
  ] });
31585
32845
  }
32846
+ function TableFormatTab({
32847
+ api,
32848
+ fill,
32849
+ onChanged
32850
+ }) {
32851
+ const run = (op) => {
32852
+ api?.tableOp(op);
32853
+ onChanged();
32854
+ };
32855
+ return /* @__PURE__ */ jsxs2("span", { "data-dxw-table-format": "", style: { display: "contents" }, children: [
32856
+ /* @__PURE__ */ jsx2(
32857
+ ColorMenu,
32858
+ {
32859
+ current: fill ?? "#FFFFFF",
32860
+ title: "Cell fill color",
32861
+ trigger: /* @__PURE__ */ jsxs2(Fragment2, { children: [
32862
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", style: { width: 14, height: 14, borderRadius: 3, border: `1px solid ${T.border}`, background: fill ?? "#FFFFFF" } }),
32863
+ "Cell fill"
32864
+ ] }),
32865
+ onPick: (color) => run({ kind: "cellShading", fill: color })
32866
+ }
32867
+ ),
32868
+ fill !== null && /* @__PURE__ */ jsx2(Btn, { label: "No fill", title: "Remove cell fill", onClick: () => run({ kind: "cellShading", fill: null }) }),
32869
+ /* @__PURE__ */ jsx2(
32870
+ ActionMenu,
32871
+ {
32872
+ label: "Cell alignment",
32873
+ title: "Align text inside the current cell",
32874
+ width: 132,
32875
+ groups: [{ items: [["top", "Top"], ["center", "Middle"], ["bottom", "Bottom"]] }],
32876
+ onPick: (value) => run({ kind: "cellVAlign", v: value })
32877
+ }
32878
+ ),
32879
+ /* @__PURE__ */ jsx2(
32880
+ ActionMenu,
32881
+ {
32882
+ label: "Rows & columns",
32883
+ title: "Edit rows and columns around the current cell",
32884
+ width: 144,
32885
+ groups: [
32886
+ { label: "Rows", items: [["rowAbove", "Insert row above"], ["rowBelow", "Insert row below"], ["deleteRow", "Delete row"]] },
32887
+ { label: "Columns", items: [["colLeft", "Insert column left"], ["colRight", "Insert column right"], ["deleteCol", "Delete column"]] }
32888
+ ],
32889
+ onPick: (value) => run(value)
32890
+ }
32891
+ ),
32892
+ /* @__PURE__ */ jsx2(
32893
+ ActionMenu,
32894
+ {
32895
+ label: "Merge",
32896
+ title: "Merge or split the current cell",
32897
+ width: 78,
32898
+ groups: [{ items: [["mergeRight", "Merge right"], ["mergeDown", "Merge down"], ["splitCell", "Split cell"]] }],
32899
+ onPick: (value) => run(value)
32900
+ }
32901
+ ),
32902
+ /* @__PURE__ */ jsx2(Btn, { label: "Delete table", title: "Delete the current table", onClick: () => run("deleteTable") })
32903
+ ] });
32904
+ }
31586
32905
  function PagePreview({
31587
32906
  kind,
31588
32907
  width = 8.5,
@@ -31592,6 +32911,7 @@ function PagePreview({
31592
32911
  columns,
31593
32912
  columnSeparator,
31594
32913
  border,
32914
+ borderColor,
31595
32915
  lineNumbers
31596
32916
  }) {
31597
32917
  const maxWidth = mirrored ? 21 : 34;
@@ -31602,7 +32922,7 @@ function PagePreview({
31602
32922
  const papers = mirrored ? 2 : 1;
31603
32923
  const inset = margins ?? [0.8, 0.8, 0.8, 0.8];
31604
32924
  const borderWidth = border === "thick" ? 2 : border === "none" ? 0 : 1;
31605
- const borderColor = border === "accent" ? T.accent : T.muted;
32925
+ const pageBorderColor = borderColor ?? (border === "accent" ? T.accent : T.muted);
31606
32926
  return /* @__PURE__ */ jsx2(
31607
32927
  "span",
31608
32928
  {
@@ -31621,7 +32941,7 @@ function PagePreview({
31621
32941
  width: paperWidth,
31622
32942
  height: paperHeight,
31623
32943
  background: "var(--dxw-layout-preview-bg, #fff)",
31624
- border: `${Math.max(1, borderWidth)}px solid ${borderWidth ? borderColor : T.border}`
32944
+ border: `${Math.max(1, borderWidth)}px solid ${borderWidth ? pageBorderColor : T.border}`
31625
32945
  },
31626
32946
  children: [
31627
32947
  kind === "margins" && /* @__PURE__ */ jsx2("span", { style: {
@@ -31950,8 +33270,9 @@ function MarginMenu({
31950
33270
  "input",
31951
33271
  {
31952
33272
  "aria-label": `${label} margin (inches)`,
31953
- type: "text",
31954
- inputMode: "decimal",
33273
+ type: "number",
33274
+ min: "0",
33275
+ step: "0.05",
31955
33276
  required: true,
31956
33277
  autoFocus: side === "top",
31957
33278
  value: values[side],
@@ -32076,8 +33397,9 @@ function PageSizeMenu({
32076
33397
  "input",
32077
33398
  {
32078
33399
  "aria-label": `Page ${side} (inches)`,
32079
- type: "text",
32080
- inputMode: "decimal",
33400
+ type: "number",
33401
+ min: "0.1",
33402
+ step: "0.05",
32081
33403
  required: true,
32082
33404
  autoFocus: side === "width",
32083
33405
  value: values[side],
@@ -32157,6 +33479,136 @@ function PageSizeMenu({
32157
33479
  )
32158
33480
  ] });
32159
33481
  }
33482
+ function PageBorderMenu({
33483
+ scope,
33484
+ onApply,
33485
+ open,
33486
+ onOpenChange
33487
+ }) {
33488
+ const [customOpen, setCustomOpen] = useState2(false);
33489
+ const [color, setColor] = useState2("#4472c4");
33490
+ const [widthPt, setWidthPt] = useState2("1");
33491
+ const rootRef = useRef2(null);
33492
+ const [dialogPosition, setDialogPosition] = useState2({ left: 8, top: 8 });
33493
+ useEffect2(() => {
33494
+ if (!customOpen) return;
33495
+ const positionDialog = () => {
33496
+ const trigger = rootRef.current?.querySelector("[data-dxw-layout-menu-trigger]");
33497
+ if (!trigger) return;
33498
+ const rect = trigger.getBoundingClientRect();
33499
+ const width2 = Math.min(244, window.innerWidth - 16);
33500
+ setDialogPosition({
33501
+ left: Math.max(8, Math.min(rect.left, window.innerWidth - width2 - 8)),
33502
+ top: Math.max(8, Math.min(rect.bottom + 4, window.innerHeight - 224))
33503
+ });
33504
+ };
33505
+ const close = (event) => {
33506
+ if (!rootRef.current?.contains(event.target)) setCustomOpen(false);
33507
+ };
33508
+ const keydown = (event) => {
33509
+ if (event.key === "Escape") setCustomOpen(false);
33510
+ };
33511
+ positionDialog();
33512
+ document.addEventListener("mousedown", close);
33513
+ document.addEventListener("keydown", keydown);
33514
+ window.addEventListener("resize", positionDialog);
33515
+ return () => {
33516
+ document.removeEventListener("mousedown", close);
33517
+ document.removeEventListener("keydown", keydown);
33518
+ window.removeEventListener("resize", positionDialog);
33519
+ };
33520
+ }, [customOpen]);
33521
+ const validColor = normalizedColor(color);
33522
+ const width = Number(widthPt);
33523
+ const valid = validColor !== null && Number.isFinite(width) && width >= 0.25 && width <= 12;
33524
+ const applyCustom = () => {
33525
+ if (!validColor || !valid) return;
33526
+ onApply({ pageBorders: { sz: Math.round(width * 8), color: validColor } });
33527
+ setCustomOpen(false);
33528
+ };
33529
+ const pick = (value) => {
33530
+ if (value === "custom") {
33531
+ setCustomOpen(true);
33532
+ return;
33533
+ }
33534
+ setCustomOpen(false);
33535
+ if (value === "none") onApply({ pageBorders: null });
33536
+ else if (value === "thin") onApply({ pageBorders: { sz: 4 } });
33537
+ else if (value === "thick") onApply({ pageBorders: { sz: 12 } });
33538
+ else onApply({ pageBorders: { sz: 8, color: "4472C4" } });
33539
+ };
33540
+ return /* @__PURE__ */ jsxs2("span", { ref: rootRef, style: { position: "relative", display: "inline-flex" }, children: [
33541
+ /* @__PURE__ */ jsx2(
33542
+ LayoutMenu,
33543
+ {
33544
+ name: "page-border",
33545
+ label: "Page border",
33546
+ open,
33547
+ onOpenChange,
33548
+ onPick: pick,
33549
+ options: [
33550
+ { value: "none", label: "None", description: "No page border", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "none" }) },
33551
+ { value: "thin", label: "Thin box", description: "\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thin" }) },
33552
+ { value: "thick", label: "Thick box", description: "1\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thick" }) },
33553
+ { value: "accent", label: "Accent box", description: "Blue 1 pt line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "accent" }) },
33554
+ { 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" }) }
33555
+ ]
33556
+ }
33557
+ ),
33558
+ customOpen && /* @__PURE__ */ jsxs2(
33559
+ "div",
33560
+ {
33561
+ role: "dialog",
33562
+ "aria-label": "Custom Page Border",
33563
+ onMouseDown: (event) => event.stopPropagation(),
33564
+ style: {
33565
+ position: "fixed",
33566
+ top: dialogPosition.top,
33567
+ left: dialogPosition.left,
33568
+ zIndex: 201,
33569
+ width: "min(224px, calc(100vw - 16px))",
33570
+ boxSizing: "border-box",
33571
+ background: T.popoverBg,
33572
+ border: `1px solid ${T.border}`,
33573
+ borderRadius: 8,
33574
+ boxShadow: T.popoverShadow,
33575
+ padding: 10,
33576
+ display: "grid",
33577
+ gap: 8
33578
+ },
33579
+ children: [
33580
+ /* @__PURE__ */ jsx2("strong", { style: { fontSize: 13 }, children: "Custom Page Border" }),
33581
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gridTemplateColumns: "54px 1fr", gap: 8, alignItems: "center", fontSize: 12 }, children: [
33582
+ /* @__PURE__ */ jsx2("span", { children: "Color" }),
33583
+ /* @__PURE__ */ jsxs2("span", { style: { display: "flex", gap: 6 }, children: [
33584
+ /* @__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 } }),
33585
+ /* @__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 } })
33586
+ ] })
33587
+ ] }),
33588
+ /* @__PURE__ */ jsxs2("label", { style: { display: "grid", gridTemplateColumns: "54px 1fr", gap: 8, alignItems: "center", fontSize: 12 }, children: [
33589
+ /* @__PURE__ */ jsx2("span", { children: "Weight" }),
33590
+ /* @__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: [
33591
+ /* @__PURE__ */ jsx2("option", { value: "0.5", children: "\xBD pt" }),
33592
+ /* @__PURE__ */ jsx2("option", { value: "1", children: "1 pt" }),
33593
+ /* @__PURE__ */ jsx2("option", { value: "1.5", children: "1\xBD pt" }),
33594
+ /* @__PURE__ */ jsx2("option", { value: "2.25", children: "2\xBC pt" }),
33595
+ /* @__PURE__ */ jsx2("option", { value: "3", children: "3 pt" })
33596
+ ] })
33597
+ ] }),
33598
+ /* @__PURE__ */ jsxs2("span", { style: { color: T.muted, fontSize: 11 }, children: [
33599
+ "Applies to ",
33600
+ scope === "section" ? "this section" : "the whole document",
33601
+ "."
33602
+ ] }),
33603
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "flex-end", gap: 6 }, children: [
33604
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setCustomOpen(false), style: { ...pillBtn, background: T.popoverBg, color: T.fg }, children: "Cancel" }),
33605
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: applyCustom, disabled: !valid, style: pillBtn, children: "Apply" })
33606
+ ] })
33607
+ ]
33608
+ }
33609
+ )
33610
+ ] });
33611
+ }
32160
33612
  function LayoutTab({ api, showArrange }) {
32161
33613
  const [scope, setScope] = useState2("document");
32162
33614
  const [section, setSection] = useState2(null);
@@ -32252,26 +33704,7 @@ function LayoutTab({ api, showArrange }) {
32252
33704
  onPick: (value) => set({ columns: parseInt(value, 10), columnSeparator: value === "2-divider" })
32253
33705
  }
32254
33706
  ),
32255
- /* @__PURE__ */ jsx2(
32256
- LayoutMenu,
32257
- {
32258
- name: "page-border",
32259
- label: "Page border",
32260
- ...menuState("page-border"),
32261
- options: [
32262
- { value: "none", label: "None", description: "No page border", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "none" }) },
32263
- { value: "thin", label: "Thin box", description: "\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thin" }) },
32264
- { value: "thick", label: "Thick box", description: "1\xBD pt solid line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "thick" }) },
32265
- { value: "accent", label: "Accent box", description: "Blue 1 pt line", preview: /* @__PURE__ */ jsx2(PagePreview, { kind: "page-border", border: "accent" }) }
32266
- ],
32267
- onPick: (value) => {
32268
- if (value === "none") set({ pageBorders: null });
32269
- else if (value === "thin") set({ pageBorders: { sz: 4 } });
32270
- else if (value === "thick") set({ pageBorders: { sz: 12 } });
32271
- else set({ pageBorders: { sz: 8, color: "4472C4" } });
32272
- }
32273
- }
32274
- ),
33707
+ /* @__PURE__ */ jsx2(PageBorderMenu, { scope, onApply: set, ...menuState("page-border") }),
32275
33708
  /* @__PURE__ */ jsx2(
32276
33709
  LayoutMenu,
32277
33710
  {
@@ -32336,6 +33769,125 @@ function LayoutTab({ api, showArrange }) {
32336
33769
  }
32337
33770
  );
32338
33771
  }
33772
+ function SmartArtTextControls({ api, nodeIndex }) {
33773
+ const nodeSelected = nodeIndex !== void 0;
33774
+ const [format, setFormat] = useState2(() => api?.getSelectedSmartArtTextFormat() ?? null);
33775
+ useEffect2(() => setFormat(api?.getSelectedSmartArtTextFormat() ?? null), [api, nodeIndex]);
33776
+ if (!format) return null;
33777
+ const apply = (patch) => {
33778
+ if (api?.setSelectedSmartArtTextFormat(patch)) setFormat(api.getSelectedSmartArtTextFormat());
33779
+ };
33780
+ const fonts = detectFonts();
33781
+ const sizes = SIZES.includes(format.fontSizePt) ? SIZES : [format.fontSizePt, ...SIZES];
33782
+ const scope = nodeSelected ? "selected node" : "all nodes";
33783
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
33784
+ /* @__PURE__ */ jsx2(Sep, {}),
33785
+ /* @__PURE__ */ jsx2(
33786
+ ToolbarMenuSelect,
33787
+ {
33788
+ title: `Font for ${scope}`,
33789
+ value: format.fontFamily,
33790
+ width: 126,
33791
+ menuWidth: 210,
33792
+ options: (fonts.includes(format.fontFamily) ? fonts : [format.fontFamily, ...fonts]).map((font) => ({
33793
+ value: font,
33794
+ label: font,
33795
+ fontFamily: font
33796
+ })),
33797
+ onChange: (fontFamily) => fontFamily && apply({ fontFamily })
33798
+ }
33799
+ ),
33800
+ /* @__PURE__ */ jsx2(
33801
+ ToolbarMenuSelect,
33802
+ {
33803
+ title: `Font size for ${scope}`,
33804
+ value: String(format.fontSizePt),
33805
+ width: 58,
33806
+ menuWidth: 92,
33807
+ options: sizes.map((size) => ({ value: String(size), label: String(size) })),
33808
+ onChange: (value) => value && apply({ fontSizePt: Number(value) })
33809
+ }
33810
+ ),
33811
+ /* @__PURE__ */ jsx2(Btn, { label: /* @__PURE__ */ jsx2("b", { children: "B" }), title: `Bold ${scope}`, active: format.bold, onClick: () => apply({ bold: !format.bold }) }),
33812
+ /* @__PURE__ */ jsx2(Btn, { label: /* @__PURE__ */ jsx2("i", { children: "I" }), title: `Italic ${scope}`, active: format.italic, onClick: () => apply({ italic: !format.italic }) }),
33813
+ /* @__PURE__ */ jsx2(
33814
+ ColorMenu,
33815
+ {
33816
+ current: format.color,
33817
+ title: `Text color for ${scope}`,
33818
+ trigger: /* @__PURE__ */ jsx2("span", { style: { fontSize: 13, borderBottom: `3px solid ${format.color}`, padding: "0 3px" }, children: "A" }),
33819
+ onPick: (color) => apply({ color })
33820
+ }
33821
+ ),
33822
+ /* @__PURE__ */ jsx2(
33823
+ ActionMenu,
33824
+ {
33825
+ label: format.alignment === "center" ? "Center" : format.alignment === "right" ? "Right" : "Left",
33826
+ title: `Text alignment for ${scope}`,
33827
+ width: 74,
33828
+ groups: [{ items: [["left", "Align left"], ["center", "Align center"], ["right", "Align right"]] }],
33829
+ onPick: (alignment) => apply({ alignment })
33830
+ }
33831
+ )
33832
+ ] });
33833
+ }
33834
+ function ObjectFormatTab({
33835
+ api,
33836
+ context,
33837
+ showArrange
33838
+ }) {
33839
+ const run = (command) => api?.runSelectedObjectCommand(command);
33840
+ const wrap = /* @__PURE__ */ jsx2(
33841
+ ActionMenu,
33842
+ {
33843
+ label: "Wrap",
33844
+ title: "Wrap",
33845
+ width: 72,
33846
+ groups: [{ items: [
33847
+ ["wrapInline", "Inline with text"],
33848
+ ["wrapSquare", "Square"],
33849
+ ["wrapTopAndBottom", "Top and bottom"],
33850
+ ["wrapFront", "In front of text"],
33851
+ ["wrapBehind", "Behind text"]
33852
+ ] }],
33853
+ onPick: (value) => run(value)
33854
+ }
33855
+ );
33856
+ return /* @__PURE__ */ jsxs2("span", { "data-dxw-object-format": "", style: { display: "contents" }, children: [
33857
+ context.kind === "chart" && /* @__PURE__ */ jsx2(ChartMenu, { api, label: "Edit data" }),
33858
+ context.kind === "smartArt" && /* @__PURE__ */ jsx2(SmartArtMenu, { api, label: "Edit SmartArt" }),
33859
+ context.kind === "smartArt" && /* @__PURE__ */ jsx2(SmartArtTextControls, { api, nodeIndex: context.smartArtNodeIndex }),
33860
+ context.canEditText && /* @__PURE__ */ jsx2(
33861
+ Btn,
33862
+ {
33863
+ label: "Edit text",
33864
+ title: context.kind === "smartArt" ? "Edit selected SmartArt node text" : "Edit shape text",
33865
+ onClick: () => run("editText")
33866
+ }
33867
+ ),
33868
+ (context.kind === "shape" || context.kind === "smartArt") && /* @__PURE__ */ jsx2(
33869
+ Btn,
33870
+ {
33871
+ label: context.kind === "smartArt" ? context.smartArtNodeSelected ? "Node fill" : "Fill all" : "Fill",
33872
+ title: context.kind === "smartArt" ? context.smartArtNodeSelected ? "Selected SmartArt node fill" : "All SmartArt node fills" : "Fill color",
33873
+ onClick: () => run("fill")
33874
+ }
33875
+ ),
33876
+ context.kind === "shape" && /* @__PURE__ */ jsx2(Btn, { label: "Outline", title: "Outline color, weight, and style", onClick: () => run("outline") }),
33877
+ context.kind === "line" && /* @__PURE__ */ jsx2(Btn, { label: "Line style", title: "Line color, weight, and style", onClick: () => run("lineStyle") }),
33878
+ (context.kind === "image" || context.kind === "model3d") && /* @__PURE__ */ jsx2(Btn, { label: "Alt text", title: "Alternative text", onClick: () => run("altText") }),
33879
+ wrap,
33880
+ /* @__PURE__ */ jsx2(Btn, { label: "Size", title: "Exact size", onClick: () => run("size") }),
33881
+ /* @__PURE__ */ jsx2(Btn, { label: "Position", title: "Exact page position", onClick: () => run("position") }),
33882
+ (context.kind === "shape" || context.kind === "line" || context.kind === "image" || context.kind === "model3d") && /* @__PURE__ */ jsx2(Btn, { label: "Rotate", title: "Set rotation", onClick: () => run("rotate") }),
33883
+ showArrange && /* @__PURE__ */ jsxs2(Fragment2, { children: [
33884
+ /* @__PURE__ */ jsx2(Btn, { label: "Bring forward", title: "Bring selected object forward", onClick: () => run("bringForward") }),
33885
+ /* @__PURE__ */ jsx2(Btn, { label: "Send backward", title: "Send selected object backward", onClick: () => run("sendBackward") })
33886
+ ] }),
33887
+ context.kind === "model3d" && /* @__PURE__ */ jsx2(Btn, { label: "Reset 3D", title: "Reset 3D rotation", onClick: () => run("reset3d") }),
33888
+ /* @__PURE__ */ jsx2(Btn, { label: "Delete", title: "Delete selected object", onClick: () => run("delete") })
33889
+ ] });
33890
+ }
32339
33891
  function DocxToolbar({
32340
33892
  api,
32341
33893
  onSave,
@@ -32346,6 +33898,14 @@ function DocxToolbar({
32346
33898
  }) {
32347
33899
  const on = (k) => features?.[k] !== false;
32348
33900
  const [tab, setTab] = useState2("home");
33901
+ const priorNormalTab = useRef2("home");
33902
+ const [objectContext, setObjectContext] = useState2(null);
33903
+ const [tableCellFill, setTableCellFill] = useState2(void 0);
33904
+ const tableContextRef = useRef2(void 0);
33905
+ const selectNormalTab = (next) => {
33906
+ priorNormalTab.current = next;
33907
+ setTab(next);
33908
+ };
32349
33909
  const [helpOpen, setHelpOpen] = useState2(false);
32350
33910
  const apple = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
32351
33911
  const shortcut = (key) => apple ? `\u2318${key}` : `Ctrl+${key}`;
@@ -32394,6 +33954,22 @@ function DocxToolbar({
32394
33954
  document.addEventListener("keydown", keydown);
32395
33955
  return () => document.removeEventListener("keydown", keydown);
32396
33956
  }, [features]);
33957
+ useEffect2(() => {
33958
+ const refreshObject = () => {
33959
+ const next = api?.getSelectedObjectContext() ?? null;
33960
+ setObjectContext(next);
33961
+ setTab((current) => {
33962
+ if (next) {
33963
+ if (["home", "insert", "draw", "layout"].includes(current)) priorNormalTab.current = current;
33964
+ return "format";
33965
+ }
33966
+ return current === "format" ? tableContextRef.current !== void 0 ? "tableFormat" : priorNormalTab.current : current;
33967
+ });
33968
+ };
33969
+ refreshObject();
33970
+ document.addEventListener("dxw-object-selection", refreshObject);
33971
+ return () => document.removeEventListener("dxw-object-selection", refreshObject);
33972
+ }, [api]);
32397
33973
  useEffect2(() => {
32398
33974
  const el16 = rootRef.current;
32399
33975
  if (!el16 || typeof ResizeObserver === "undefined") return;
@@ -32418,6 +33994,18 @@ function DocxToolbar({
32418
33994
  setFmt(api?.getSelectionFormat() ?? null);
32419
33995
  setCurStyle(api?.getParagraphStyleId?.() ?? null);
32420
33996
  setListKind(api?.getListType?.() ?? null);
33997
+ const nextTableFill = api?.getTableCellFill();
33998
+ const wasInTable = tableContextRef.current !== void 0;
33999
+ tableContextRef.current = nextTableFill;
34000
+ setTableCellFill(nextTableFill);
34001
+ setTab((current) => {
34002
+ if (nextTableFill !== void 0 && !wasInTable && current !== "format") {
34003
+ if (["home", "insert", "draw", "layout"].includes(current)) priorNormalTab.current = current;
34004
+ return "tableFormat";
34005
+ }
34006
+ if (nextTableFill === void 0 && current === "tableFormat") return priorNormalTab.current;
34007
+ return current;
34008
+ });
32421
34009
  }, [api]);
32422
34010
  useEffect2(() => {
32423
34011
  document.addEventListener("selectionchange", refresh);
@@ -32633,8 +34221,10 @@ function DocxToolbar({
32633
34221
  title: "Exact line height",
32634
34222
  label: "Line height (points)",
32635
34223
  value: "24",
32636
- placeholder: "24",
32637
- submitLabel: "Apply"
34224
+ submitLabel: "Apply",
34225
+ inputType: "number",
34226
+ min: 1,
34227
+ step: 0.5
32638
34228
  }).then((next) => {
32639
34229
  if (next === null) return;
32640
34230
  const points = Number(next.trim());
@@ -32742,8 +34332,9 @@ function DocxToolbar({
32742
34332
  "button",
32743
34333
  {
32744
34334
  "data-tab": t,
34335
+ "aria-pressed": tab === t,
32745
34336
  onMouseDown: (e) => e.preventDefault(),
32746
- onClick: () => setTab(t),
34337
+ onClick: () => selectNormalTab(t),
32747
34338
  style: {
32748
34339
  border: "none",
32749
34340
  background: tab === t ? T.tabActiveBg : "transparent",
@@ -32758,6 +34349,51 @@ function DocxToolbar({
32758
34349
  },
32759
34350
  t
32760
34351
  )),
34352
+ objectContext && /* @__PURE__ */ jsx2(
34353
+ "button",
34354
+ {
34355
+ "data-tab": "format",
34356
+ "aria-pressed": tab === "format",
34357
+ onMouseDown: (event) => event.preventDefault(),
34358
+ onClick: () => setTab("format"),
34359
+ style: {
34360
+ border: "none",
34361
+ background: tab === "format" ? T.tabActiveBg : "transparent",
34362
+ color: tab === "format" ? T.accent : T.fg,
34363
+ font: "600 12.5px system-ui, sans-serif",
34364
+ padding: "5px 10px",
34365
+ borderRadius: 6,
34366
+ cursor: "pointer"
34367
+ },
34368
+ children: {
34369
+ shape: "Shape Format",
34370
+ line: "Line Format",
34371
+ smartArt: "SmartArt Format",
34372
+ chart: "Chart Format",
34373
+ image: "Picture Format",
34374
+ model3d: "3D Format"
34375
+ }[objectContext.kind]
34376
+ }
34377
+ ),
34378
+ !objectContext && tableCellFill !== void 0 && /* @__PURE__ */ jsx2(
34379
+ "button",
34380
+ {
34381
+ "data-tab": "tableFormat",
34382
+ "aria-pressed": tab === "tableFormat",
34383
+ onMouseDown: (event) => event.preventDefault(),
34384
+ onClick: () => setTab("tableFormat"),
34385
+ style: {
34386
+ border: "none",
34387
+ background: tab === "tableFormat" ? T.tabActiveBg : "transparent",
34388
+ color: tab === "tableFormat" ? T.accent : T.fg,
34389
+ font: "600 12.5px system-ui, sans-serif",
34390
+ padding: "5px 10px",
34391
+ borderRadius: 6,
34392
+ cursor: "pointer"
34393
+ },
34394
+ children: "Table Format"
34395
+ }
34396
+ ),
32761
34397
  on("help") && /* @__PURE__ */ jsx2(
32762
34398
  "button",
32763
34399
  {
@@ -32797,6 +34433,7 @@ function DocxToolbar({
32797
34433
  on("chart") && /* @__PURE__ */ jsx2(ChartMenu, { api }),
32798
34434
  on("media") && /* @__PURE__ */ jsx2(MediaMenu, { api }),
32799
34435
  on("shape") && /* @__PURE__ */ jsx2(ShapeMenu, { api }),
34436
+ on("divider") && /* @__PURE__ */ jsx2(DividerMenu, { api }),
32800
34437
  on("textBox") && /* @__PURE__ */ jsx2(TextBoxMenu, { api }),
32801
34438
  on("wordArt") && /* @__PURE__ */ jsx2(WordArtMenu, { api }),
32802
34439
  on("link") && /* @__PURE__ */ jsx2(LinkMenu, { api }),
@@ -32804,10 +34441,16 @@ function DocxToolbar({
32804
34441
  on("footnote") && /* @__PURE__ */ jsx2(FootnoteMenu, { api }),
32805
34442
  on("bookmark") && /* @__PURE__ */ jsx2(BookmarkMenu, { api }),
32806
34443
  on("crossReference") && /* @__PURE__ */ jsx2(CrossReferenceMenu, { api }),
32807
- on("headerFooter") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
32808
- /* @__PURE__ */ jsx2(Btn, { label: "Header", title: "Edit header", onClick: () => api?.openHeaderFooter("header") }),
32809
- /* @__PURE__ */ jsx2(Btn, { label: "Footer", title: "Edit footer", onClick: () => api?.openHeaderFooter("footer") })
32810
- ] }),
34444
+ on("headerFooter") && /* @__PURE__ */ jsx2(
34445
+ ActionMenu,
34446
+ {
34447
+ label: "Header & footer",
34448
+ title: "Edit the repeating header or footer",
34449
+ width: 118,
34450
+ groups: [{ items: [["header", "Header"], ["footer", "Footer"]] }],
34451
+ onPick: (value) => api?.openHeaderFooter(value)
34452
+ }
34453
+ ),
32811
34454
  /* @__PURE__ */ jsx2(Sep, {}),
32812
34455
  on("pageNumber") && /* @__PURE__ */ jsx2(
32813
34456
  ActionMenu,
@@ -32891,6 +34534,7 @@ function DocxToolbar({
32891
34534
  on("chart") && /* @__PURE__ */ jsx2(ChartMenu, { api }),
32892
34535
  on("media") && /* @__PURE__ */ jsx2(MediaMenu, { api }),
32893
34536
  on("shape") && /* @__PURE__ */ jsx2(ShapeMenu, { api }),
34537
+ on("divider") && /* @__PURE__ */ jsx2(DividerMenu, { api }),
32894
34538
  on("textBox") && /* @__PURE__ */ jsx2(TextBoxMenu, { api }),
32895
34539
  on("wordArt") && /* @__PURE__ */ jsx2(WordArtMenu, { api }),
32896
34540
  on("link") && /* @__PURE__ */ jsx2(LinkMenu, { api }),
@@ -32898,10 +34542,16 @@ function DocxToolbar({
32898
34542
  on("footnote") && /* @__PURE__ */ jsx2(FootnoteMenu, { api }),
32899
34543
  on("bookmark") && /* @__PURE__ */ jsx2(BookmarkMenu, { api }),
32900
34544
  on("crossReference") && /* @__PURE__ */ jsx2(CrossReferenceMenu, { api }),
32901
- on("headerFooter") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
32902
- /* @__PURE__ */ jsx2(Btn, { label: "Header", title: "Edit header", onClick: () => api?.openHeaderFooter("header") }),
32903
- /* @__PURE__ */ jsx2(Btn, { label: "Footer", title: "Edit footer", onClick: () => api?.openHeaderFooter("footer") })
32904
- ] }),
34545
+ on("headerFooter") && /* @__PURE__ */ jsx2(
34546
+ ActionMenu,
34547
+ {
34548
+ label: "Header & footer",
34549
+ title: "Edit the repeating header or footer",
34550
+ width: 118,
34551
+ groups: [{ items: [["header", "Header"], ["footer", "Footer"]] }],
34552
+ onPick: (value) => api?.openHeaderFooter(value)
34553
+ }
34554
+ ),
32905
34555
  on("pageNumber") && /* @__PURE__ */ jsx2(
32906
34556
  ActionMenu,
32907
34557
  {
@@ -32963,6 +34613,8 @@ function DocxToolbar({
32963
34613
  ] })
32964
34614
  ] }),
32965
34615
  mode === "advanced" && tab === "draw" && on("drawing") && /* @__PURE__ */ jsx2(DrawTab, { api }),
34616
+ mode === "advanced" && tab === "format" && objectContext && /* @__PURE__ */ jsx2(ObjectFormatTab, { api, context: objectContext, showArrange: on("arrange") }),
34617
+ mode === "advanced" && tab === "tableFormat" && tableCellFill !== void 0 && /* @__PURE__ */ jsx2(TableFormatTab, { api, fill: tableCellFill, onChanged: refresh }),
32966
34618
  /* @__PURE__ */ jsx2(
32967
34619
  "input",
32968
34620
  {
@@ -33395,7 +35047,8 @@ function DocxView({
33395
35047
  void requestTextInputDialog(anchor, {
33396
35048
  title: "Link address",
33397
35049
  label: "URL",
33398
- value: current.getLinkAt() ?? "https://"
35050
+ value: current.getLinkAt() ?? "https://",
35051
+ inputType: "url"
33399
35052
  }).then((next) => {
33400
35053
  if (next !== null) current.setLink(next.trim() || null);
33401
35054
  });
@@ -33545,12 +35198,13 @@ function DocxView({
33545
35198
  return true;
33546
35199
  },
33547
35200
  insertSymbol: (symbol) => editor?.insertText(symbol) ?? false,
33548
- insertShape: (preset, text) => {
35201
+ insertShape: (preset, text, lineStyle) => {
33549
35202
  const target = insertionTarget();
33550
35203
  if (!target) return false;
33551
35204
  history.checkpoint();
33552
35205
  const drawing = insertShapeAt(doc, target.t, preset, text);
33553
35206
  if (!drawing) return false;
35207
+ if (lineStyle) setDrawingLineStyle(doc, drawing, lineStyle.color, lineStyle.width, lineStyle.dash);
33554
35208
  pages = rerender(doc, void 0, "global");
33555
35209
  editor?.reselectDrawing(drawing);
33556
35210
  return true;
@@ -33580,6 +35234,7 @@ function DocxView({
33580
35234
  editor?.reselectDrawing(source2);
33581
35235
  return true;
33582
35236
  },
35237
+ getSelectedChart: () => editor?.getSelectedChartData() ?? null,
33583
35238
  insertSmartArt: (data) => {
33584
35239
  const target = insertionTarget();
33585
35240
  if (!target) return false;
@@ -33597,6 +35252,7 @@ function DocxView({
33597
35252
  editor?.reselectDrawing(source2);
33598
35253
  return true;
33599
35254
  },
35255
+ getSelectedSmartArt: () => editor?.getSelectedSmartArtData() ?? null,
33600
35256
  insertModel3D: async (file, poster) => {
33601
35257
  const target = insertionTarget();
33602
35258
  if (!target) return false;
@@ -33634,6 +35290,10 @@ function DocxView({
33634
35290
  getDrawingTool: () => editor?.getDrawingTool() ?? null,
33635
35291
  arrangeObject: (action) => editor?.arrangeSelectedObject(action) ?? false,
33636
35292
  hasSelectedObject: () => editor?.hasSelectedObject() ?? false,
35293
+ getSelectedObjectContext: () => editor?.getSelectedObjectContext() ?? null,
35294
+ runSelectedObjectCommand: (command) => editor?.runSelectedObjectCommand(command) ?? false,
35295
+ getSelectedSmartArtTextFormat: () => editor?.getSelectedSmartArtTextFormat() ?? null,
35296
+ setSelectedSmartArtTextFormat: (patch) => editor?.setSelectedSmartArtTextFormat(patch) ?? false,
33637
35297
  addComment: (text) => {
33638
35298
  const segs = editor?.getSelectionSegments() ?? [];
33639
35299
  const segments = segs.length > 0 ? segs : handle ? selectionToSegments(handle.bindings) : [];
@@ -33662,6 +35322,10 @@ function DocxView({
33662
35322
  history.checkpoint();
33663
35323
  if (applyTableOp(doc, caret.t, op)) pages = rerender(doc);
33664
35324
  },
35325
+ getTableCellFill: () => {
35326
+ const caret = editor?.getCaretTarget();
35327
+ return caret ? cellShadingAt(doc, caret.t) : void 0;
35328
+ },
33665
35329
  insertImage: async (file) => {
33666
35330
  const caret = editor?.getCaretTarget();
33667
35331
  if (!caret) return;
@@ -33817,6 +35481,20 @@ function DocxView({
33817
35481
  history.checkpoint();
33818
35482
  if (setParagraphSpacing(doc, targets, patch)) pages = rerender(doc);
33819
35483
  },
35484
+ setParagraphDivider: (divider) => {
35485
+ const segs = editor?.getSelectionSegments() ?? [];
35486
+ const caret = editor?.getCaretTarget();
35487
+ const targets = segs.length > 0 ? segs.map((segment) => segment.t).filter((target) => !!target) : caret ? [caret.t] : [];
35488
+ if (targets.length === 0) return false;
35489
+ history.checkpoint();
35490
+ if (!setParagraphDivider(doc, targets, divider)) return false;
35491
+ pages = rerender(doc);
35492
+ return true;
35493
+ },
35494
+ getParagraphDivider: () => {
35495
+ const target = editor?.getSelectionSegments()?.find((segment) => segment.t)?.t ?? editor?.getCaretTarget()?.t;
35496
+ return target ? paragraphDividerAt(doc, target) : null;
35497
+ },
33820
35498
  setDropCap: (mode, lines = 3) => {
33821
35499
  const target = insertionTarget();
33822
35500
  if (!target) return false;