@pixldocs/canvas-renderer 0.5.205 → 0.5.206

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.
@@ -3631,17 +3631,14 @@ async function normalizeSvgImageDimensions(fabricImage, imageUrl, sourceFormat)
3631
3631
  const el = ((_a = fabricImage.getElement) == null ? void 0 : _a.call(fabricImage)) ?? fabricImage._element;
3632
3632
  let w = 0;
3633
3633
  let h = 0;
3634
- if (el && typeof el.naturalWidth === "number" && typeof el.naturalHeight === "number" && el.naturalWidth > 0 && el.naturalHeight > 0) {
3634
+ const dims = await loadSvgDimensions(imageUrl);
3635
+ if (dims && dims.width > 0 && dims.height > 0) {
3636
+ w = dims.width;
3637
+ h = dims.height;
3638
+ } else if (el && typeof el.naturalWidth === "number" && typeof el.naturalHeight === "number" && el.naturalWidth > 0 && el.naturalHeight > 0) {
3635
3639
  w = el.naturalWidth;
3636
3640
  h = el.naturalHeight;
3637
3641
  }
3638
- if (w <= 0 || h <= 0) {
3639
- const dims = await loadSvgDimensions(imageUrl);
3640
- if (dims && dims.width > 0 && dims.height > 0) {
3641
- w = dims.width;
3642
- h = dims.height;
3643
- }
3644
- }
3645
3642
  if (w > 0 && h > 0) {
3646
3643
  fabricImage.set({ width: w, height: h });
3647
3644
  fabricImage.setCoords();
@@ -5695,6 +5692,134 @@ function calculateScaleSnapGuides(scalingObj, corner, canvas, canvasWidth, canva
5695
5692
  return true;
5696
5693
  });
5697
5694
  }
5695
+ const clamp01$1 = (v) => Math.max(0, Math.min(1, Number.isFinite(v) ? v : 0));
5696
+ function arcPath(w, sag, up) {
5697
+ if (sag <= 0.5) return `M 0 0 L ${w} 0`;
5698
+ const r = (sag * sag + w / 2 * (w / 2)) / (2 * sag);
5699
+ const sweep = 1;
5700
+ const y0 = sag;
5701
+ const y1 = sag;
5702
+ return `M 0 ${y0} A ${r.toFixed(2)} ${r.toFixed(2)} 0 0 ${sweep} ${w} ${y1}`;
5703
+ }
5704
+ function sampledPath(fn, steps = 60) {
5705
+ const parts = [];
5706
+ for (let i = 0; i <= steps; i++) {
5707
+ const [x, y] = fn(i / steps);
5708
+ parts.push(i === 0 ? `M ${x.toFixed(2)} ${y.toFixed(2)}` : `L ${x.toFixed(2)} ${y.toFixed(2)}`);
5709
+ }
5710
+ return parts.join(" ");
5711
+ }
5712
+ function resolveTextPath(cfg, width, fontSize) {
5713
+ if (!cfg || !cfg.preset || cfg.preset === "none") return null;
5714
+ const w = Math.max(1, width);
5715
+ const fs = Math.max(4, fontSize);
5716
+ const t = clamp01$1(cfg.intensity ?? 0.5);
5717
+ if (cfg.bezier && cfg.preset !== "circle" && cfg.preset !== "rise" && cfg.preset !== "angle") {
5718
+ const { p0, c0, c1, p1 } = cfg.bezier;
5719
+ const minX = Math.min(p0[0], c0[0], c1[0], p1[0]);
5720
+ const maxX = Math.max(p0[0], c0[0], c1[0], p1[0]);
5721
+ const minY = Math.min(p0[1], c0[1], c1[1], p1[1]);
5722
+ const maxY = Math.max(p0[1], c0[1], c1[1], p1[1]);
5723
+ return {
5724
+ d: `M ${p0[0]} ${p0[1]} C ${c0[0]} ${c0[1]}, ${c1[0]} ${c1[1]}, ${p1[0]} ${p1[1]}`,
5725
+ bbox: { width: maxX - minX, height: maxY - minY + fs * 1.4 }
5726
+ };
5727
+ }
5728
+ if (cfg.preset === "custom") {
5729
+ if (!cfg.path) return null;
5730
+ return { d: cfg.path, bbox: cfg.bbox ?? { width: w, height: fs * 2 } };
5731
+ }
5732
+ switch (cfg.preset) {
5733
+ case "arch": {
5734
+ const sag = t * w * 0.45;
5735
+ return { d: arcPath(w, sag), bbox: { width: w, height: sag + fs * 1.4 } };
5736
+ }
5737
+ case "rise":
5738
+ case "angle": {
5739
+ const ep = cfg.endpoints;
5740
+ const defaultDy = t * fs * 3;
5741
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultDy;
5742
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : 0;
5743
+ const lineMid = (leftY + rightY) / 2;
5744
+ const hasCenterHandle = ep && Number.isFinite(ep.centerY);
5745
+ const rawCurve = Number.isFinite(cfg.curve) ? cfg.curve : 0;
5746
+ const curveAmt = Math.max(-1, Math.min(1, rawCurve));
5747
+ const curveAmp = Math.min(w * 0.18, fs * 4);
5748
+ const centerY = hasCenterHandle ? ep.centerY : lineMid - curveAmt * curveAmp;
5749
+ if (Math.abs(centerY - lineMid) < 0.5) {
5750
+ const minY2 = Math.min(leftY, rightY);
5751
+ const maxY2 = Math.max(leftY, rightY);
5752
+ return {
5753
+ d: `M 0 ${leftY.toFixed(2)} L ${w} ${rightY.toFixed(2)}`,
5754
+ bbox: { width: w, height: maxY2 - minY2 + fs * 1.4 }
5755
+ };
5756
+ }
5757
+ const controlY = 2 * centerY - lineMid;
5758
+ const minY = Math.min(leftY, rightY, centerY);
5759
+ const maxY = Math.max(leftY, rightY, centerY);
5760
+ return {
5761
+ d: `M 0 ${leftY.toFixed(2)} Q ${(w / 2).toFixed(2)} ${controlY.toFixed(2)} ${w} ${rightY.toFixed(2)}`,
5762
+ bbox: { width: w, height: maxY - minY + fs * 1.4 }
5763
+ };
5764
+ }
5765
+ case "wave": {
5766
+ const rawCurve = Number.isFinite(cfg.curve) ? cfg.curve : t;
5767
+ const c = Math.max(-1, Math.min(1, rawCurve));
5768
+ const amp = c * fs * 3;
5769
+ const absAmp = Math.abs(amp);
5770
+ const d = sampledPath((u) => [u * w, absAmp - amp * Math.sin(u * Math.PI)]);
5771
+ return { d, bbox: { width: w, height: absAmp * 2 + fs * 1.4 } };
5772
+ }
5773
+ case "flag": {
5774
+ const rawCurve = Number.isFinite(cfg.curve) ? cfg.curve : t;
5775
+ const c = Math.max(-1, Math.min(1, rawCurve));
5776
+ const amp = c * fs * 2.5;
5777
+ const absAmp = Math.abs(amp);
5778
+ const d = sampledPath((u) => [u * w, absAmp + amp * Math.sin(u * Math.PI * 2)]);
5779
+ return { d, bbox: { width: w, height: absAmp * 2 + fs * 1.4 } };
5780
+ }
5781
+ case "circle": {
5782
+ const auto = Math.max(fs * 1.5, w / Math.PI);
5783
+ const r = Math.max(fs * 0.75, Number.isFinite(cfg.radius) && cfg.radius > 0 ? cfg.radius : auto);
5784
+ return {
5785
+ d: `M ${r} ${2 * r} A ${r} ${r} 0 1 1 ${r} 0 A ${r} ${r} 0 1 1 ${r} ${2 * r}`,
5786
+ bbox: { width: 2 * r, height: 2 * r + fs * 1.4 }
5787
+ };
5788
+ }
5789
+ default:
5790
+ return null;
5791
+ }
5792
+ }
5793
+ function measurePath(d) {
5794
+ if (typeof document === "undefined") return null;
5795
+ const svgNS = "http://www.w3.org/2000/svg";
5796
+ const svg = document.createElementNS(svgNS, "svg");
5797
+ const path = document.createElementNS(svgNS, "path");
5798
+ path.setAttribute("d", d);
5799
+ svg.appendChild(path);
5800
+ return path;
5801
+ }
5802
+ function resolveTextPathAlphabeticBaselineDy(ctx, sampleText, fontSize) {
5803
+ const prevBaseline = ctx.textBaseline;
5804
+ try {
5805
+ ctx.textBaseline = "alphabetic";
5806
+ const metrics = ctx.measureText(sampleText || "M");
5807
+ const fontAscent = Number(metrics.fontBoundingBoxAscent);
5808
+ const fontDescent = Number(metrics.fontBoundingBoxDescent);
5809
+ if (Number.isFinite(fontAscent) && Number.isFinite(fontDescent) && fontAscent + fontDescent > 0) {
5810
+ return (fontAscent - fontDescent) / 2;
5811
+ }
5812
+ const actualAscent = Number(metrics.actualBoundingBoxAscent);
5813
+ const actualDescent = Number(metrics.actualBoundingBoxDescent);
5814
+ if (Number.isFinite(actualAscent) && Number.isFinite(actualDescent) && actualAscent + actualDescent > 0) {
5815
+ return (actualAscent - actualDescent) / 2;
5816
+ }
5817
+ } catch {
5818
+ } finally {
5819
+ ctx.textBaseline = prevBaseline;
5820
+ }
5821
+ return fontSize / 2;
5822
+ }
5698
5823
  const TextboxProto = fabric.Textbox.prototype;
5699
5824
  if (!TextboxProto.__pixldocsOrigCalcTextHeight) {
5700
5825
  TextboxProto.__pixldocsOrigCalcTextHeight = TextboxProto.calcTextHeight;
@@ -5736,23 +5861,988 @@ const stateProps = fabric.Textbox.prototype.stateProperties;
5736
5861
  if (Array.isArray(stateProps)) {
5737
5862
  if (!stateProps.includes("minBoxHeight")) stateProps.push("minBoxHeight");
5738
5863
  if (!stateProps.includes("verticalAlign")) stateProps.push("verticalAlign");
5864
+ if (!stateProps.includes("textPath")) stateProps.push("textPath");
5739
5865
  }
5740
5866
  const cacheProps = fabric.Textbox.prototype.cacheProperties;
5741
5867
  if (Array.isArray(cacheProps)) {
5742
5868
  if (!cacheProps.includes("minBoxHeight")) cacheProps.push("minBoxHeight");
5743
5869
  if (!cacheProps.includes("verticalAlign")) cacheProps.push("verticalAlign");
5870
+ if (!cacheProps.includes("textPath")) cacheProps.push("textPath");
5871
+ }
5872
+ const hasActiveTextPath = (obj) => {
5873
+ const tp = obj.textPath;
5874
+ return !!tp && !!tp.preset && tp.preset !== "none";
5875
+ };
5876
+ function applyWarpFillStyle(ctx, obj) {
5877
+ const filler = obj.fill;
5878
+ if (filler && typeof filler === "object" && Array.isArray(filler.colorStops) && filler.coords) {
5879
+ try {
5880
+ const halfW = (obj.width || 0) / 2;
5881
+ const halfH = (obj.height || 0) / 2;
5882
+ const c = filler.coords || {};
5883
+ let live = null;
5884
+ if (filler.type === "radial") {
5885
+ live = ctx.createRadialGradient(
5886
+ (Number(c.x1) || 0) - halfW,
5887
+ (Number(c.y1) || 0) - halfH,
5888
+ Math.max(0, Number(c.r1) || 0),
5889
+ (Number(c.x2 ?? c.x1) || 0) - halfW,
5890
+ (Number(c.y2 ?? c.y1) || 0) - halfH,
5891
+ Math.max(0.1, Number(c.r2 ?? c.r) || Math.max(obj.width || 1, obj.height || 1) / 2)
5892
+ );
5893
+ } else {
5894
+ live = ctx.createLinearGradient(
5895
+ (Number(c.x1) || 0) - halfW,
5896
+ (Number(c.y1) || 0) - halfH,
5897
+ (Number(c.x2 ?? obj.width) || 0) - halfW,
5898
+ (Number(c.y2) || 0) - halfH
5899
+ );
5900
+ }
5901
+ for (const stop of filler.colorStops) {
5902
+ live.addColorStop(Math.max(0, Math.min(1, Number(stop.offset) || 0)), stop.color || "#000");
5903
+ }
5904
+ ctx.fillStyle = live;
5905
+ return { offsetX: 0, offsetY: 0 };
5906
+ } catch {
5907
+ }
5908
+ }
5909
+ if (typeof obj.handleFiller === "function") {
5910
+ try {
5911
+ return obj.handleFiller(ctx, "fillStyle", filler || "#000") || { offsetX: 0, offsetY: 0 };
5912
+ } catch {
5913
+ }
5914
+ }
5915
+ if (filler && typeof filler.toLive === "function") {
5916
+ try {
5917
+ ctx.fillStyle = filler.toLive(ctx) || "#000";
5918
+ return { offsetX: 0, offsetY: 0 };
5919
+ } catch {
5920
+ }
5921
+ }
5922
+ ctx.fillStyle = typeof obj.fill === "string" ? obj.fill : "#000";
5923
+ return { offsetX: 0, offsetY: 0 };
5924
+ }
5925
+ function parseCssColor(input) {
5926
+ const fallback = [0, 0, 0, 1];
5927
+ if (!input) return fallback;
5928
+ const s = String(input).trim();
5929
+ if (s.startsWith("#")) {
5930
+ let hex = s.slice(1);
5931
+ if (hex.length === 3) hex = hex.split("").map((c) => c + c).join("");
5932
+ if (hex.length === 4) hex = hex.split("").map((c) => c + c).join("");
5933
+ if (hex.length === 6) {
5934
+ const n = parseInt(hex, 16);
5935
+ return [n >> 16 & 255, n >> 8 & 255, n & 255, 1];
5936
+ }
5937
+ if (hex.length === 8) {
5938
+ const n = parseInt(hex, 16);
5939
+ return [n >> 24 & 255, n >> 16 & 255, n >> 8 & 255, (n & 255) / 255];
5940
+ }
5941
+ }
5942
+ const m = s.match(/^rgba?\s*\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:[\s,/]+([\d.]+%?))?\s*\)$/i);
5943
+ if (m) {
5944
+ let a = 1;
5945
+ if (m[4] != null) a = m[4].endsWith("%") ? parseFloat(m[4]) / 100 : parseFloat(m[4]);
5946
+ return [parseFloat(m[1]), parseFloat(m[2]), parseFloat(m[3]), Number.isFinite(a) ? a : 1];
5947
+ }
5948
+ try {
5949
+ const c = document.createElement("canvas").getContext("2d");
5950
+ if (c) {
5951
+ c.fillStyle = "#000";
5952
+ c.fillStyle = s;
5953
+ const computed = c.fillStyle;
5954
+ return parseCssColor(computed.startsWith("#") || computed.startsWith("rgb") ? computed : "#000");
5955
+ }
5956
+ } catch {
5957
+ }
5958
+ return fallback;
5959
+ }
5960
+ function sampleGradientColor(stops, t) {
5961
+ if (!stops || !stops.length) return "#000";
5962
+ const sorted = [...stops].sort((a, b) => (a.offset || 0) - (b.offset || 0));
5963
+ const u = Math.max(0, Math.min(1, t));
5964
+ if (u <= (sorted[0].offset || 0)) return sorted[0].color || "#000";
5965
+ if (u >= (sorted[sorted.length - 1].offset || 1)) return sorted[sorted.length - 1].color || "#000";
5966
+ for (let i = 0; i < sorted.length - 1; i++) {
5967
+ const a = sorted[i];
5968
+ const b = sorted[i + 1];
5969
+ const ao = a.offset || 0;
5970
+ const bo = b.offset || 0;
5971
+ if (u >= ao && u <= bo) {
5972
+ const span = bo - ao || 1;
5973
+ const k = (u - ao) / span;
5974
+ const ca = parseCssColor(a.color);
5975
+ const cb = parseCssColor(b.color);
5976
+ const r = Math.round(ca[0] + (cb[0] - ca[0]) * k);
5977
+ const g = Math.round(ca[1] + (cb[1] - ca[1]) * k);
5978
+ const bl = Math.round(ca[2] + (cb[2] - ca[2]) * k);
5979
+ const al = ca[3] + (cb[3] - ca[3]) * k;
5980
+ return `rgba(${r}, ${g}, ${bl}, ${al.toFixed(3)})`;
5981
+ }
5982
+ }
5983
+ return sorted[sorted.length - 1].color || "#000";
5984
+ }
5985
+ function getGradientStopsForFlow(obj) {
5986
+ const f = obj.fill;
5987
+ if (f && typeof f === "object" && Array.isArray(f.colorStops) && f.colorStops.length) {
5988
+ return f.colorStops.map((s) => ({ offset: Number(s.offset) || 0, color: s.color || "#000" }));
5989
+ }
5990
+ return null;
5991
+ }
5992
+ function localPointFromCanvas(target, x, y) {
5993
+ const point = new fabric.Point(x, y);
5994
+ try {
5995
+ return target.toLocalPoint(point, "left", "top");
5996
+ } catch {
5997
+ const inv = fabric.util.invertTransform(target.calcTransformMatrix());
5998
+ const local = fabric.util.transformPoint(point, inv);
5999
+ return new fabric.Point(local.x + (target.width || 0) / 2, local.y + (target.height || 0) / 2);
6000
+ }
6001
+ }
6002
+ function localPointFromFrozenMatrix(target, x, y, matrix) {
6003
+ const local = fabric.util.transformPoint(new fabric.Point(x, y), fabric.util.invertTransform(matrix));
6004
+ return new fabric.Point(local.x + (target.width || 0) / 2, local.y + (target.height || 0) / 2);
6005
+ }
6006
+ function vectorFromFrozenMatrix(matrix, dx, dy) {
6007
+ return new fabric.Point(matrix[0] * dx + matrix[2] * dy, matrix[1] * dx + matrix[3] * dy);
6008
+ }
6009
+ function scaleLocalToScreen(target, p) {
6010
+ var _a;
6011
+ const vpt = ((_a = target == null ? void 0 : target.canvas) == null ? void 0 : _a.viewportTransform) || [1, 0, 0, 1, 0, 0];
6012
+ const zx = Math.abs(vpt[0] || 1);
6013
+ const zy = Math.abs(vpt[3] || 1);
6014
+ const sx = Math.abs((target == null ? void 0 : target.scaleX) || 1);
6015
+ const sy = Math.abs((target == null ? void 0 : target.scaleY) || 1);
6016
+ return new fabric.Point(p.x * sx * zx, p.y * sy * zy);
6017
+ }
6018
+ function applyTextPathControls(textbox) {
6019
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
6020
+ const obj = textbox;
6021
+ if (!hasActiveTextPath(obj)) {
6022
+ obj.__pdTextPathHovered = false;
6023
+ if (obj.__pdTextPathControls) {
6024
+ try {
6025
+ const cu2 = fabric.controlsUtils;
6026
+ const defaults = ((_a = cu2 == null ? void 0 : cu2.createTextboxDefaultControls) == null ? void 0 : _a.call(cu2)) ?? ((_b = cu2 == null ? void 0 : cu2.createObjectDefaultControls) == null ? void 0 : _b.call(cu2));
6027
+ if (defaults) obj.controls = defaults;
6028
+ } catch {
6029
+ }
6030
+ delete obj.controls.bzP0;
6031
+ delete obj.controls.bzC0;
6032
+ delete obj.controls.bzC1;
6033
+ delete obj.controls.bzP1;
6034
+ delete obj.controls.rsL;
6035
+ delete obj.controls.rsR;
6036
+ delete obj.controls.rsC;
6037
+ delete obj.controls.bzMid;
6038
+ delete obj.controls.bzMidT0;
6039
+ delete obj.controls.bzMidT1;
6040
+ delete obj.controls.tpRot;
6041
+ delete obj.controls.tpPivot;
6042
+ (_c = obj.setControlsVisibility) == null ? void 0 : _c.call(obj, { tl: true, tr: true, bl: true, br: true, mt: true, mb: true, ml: true, mr: true, mtr: true });
6043
+ obj.hasBorders = true;
6044
+ obj.__pdTextPathControls = false;
6045
+ obj.setCoords();
6046
+ }
6047
+ return;
6048
+ }
6049
+ if (!obj.__pdTextPathHoverWired) {
6050
+ obj.on("mouseover", () => {
6051
+ var _a2;
6052
+ if (!hasActiveTextPath(obj)) return;
6053
+ obj.__pdTextPathHovered = true;
6054
+ (_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
6055
+ });
6056
+ obj.on("mouseout", () => {
6057
+ var _a2;
6058
+ obj.__pdTextPathHovered = false;
6059
+ (_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
6060
+ });
6061
+ obj.__pdTextPathHoverWired = true;
6062
+ }
6063
+ obj.controls = {};
6064
+ const halfWOf = (t) => (t.width || 0) / 2;
6065
+ const halfHOf = (t) => (t.height || 0) / 2;
6066
+ const cu = fabric.controlsUtils;
6067
+ const renderRotation = (ctx, left, top) => {
6068
+ ctx.save();
6069
+ ctx.translate(left, top);
6070
+ ctx.shadowColor = "rgba(0,0,0,0.25)";
6071
+ ctx.shadowBlur = 2;
6072
+ ctx.shadowOffsetY = 0.5;
6073
+ ctx.fillStyle = "#ffffff";
6074
+ ctx.strokeStyle = "#1d9bf0";
6075
+ ctx.lineWidth = 1.5;
6076
+ ctx.beginPath();
6077
+ ctx.arc(0, 0, 6, 0, Math.PI * 2);
6078
+ ctx.fill();
6079
+ ctx.shadowColor = "transparent";
6080
+ ctx.stroke();
6081
+ ctx.strokeStyle = "#1d9bf0";
6082
+ ctx.lineWidth = 1.25;
6083
+ ctx.beginPath();
6084
+ ctx.arc(0, 0, 3, -Math.PI * 0.85, Math.PI * 0.75);
6085
+ ctx.stroke();
6086
+ ctx.restore();
6087
+ };
6088
+ const renderPivot = (ctx, left, top) => {
6089
+ ctx.save();
6090
+ ctx.translate(left, top);
6091
+ ctx.strokeStyle = "#1d9bf0";
6092
+ ctx.fillStyle = "#ffffff";
6093
+ ctx.lineWidth = 1.25;
6094
+ ctx.beginPath();
6095
+ ctx.arc(0, 0, 5, 0, Math.PI * 2);
6096
+ ctx.fill();
6097
+ ctx.stroke();
6098
+ ctx.beginPath();
6099
+ ctx.moveTo(-3.5, 0);
6100
+ ctx.lineTo(3.5, 0);
6101
+ ctx.moveTo(0, -3.5);
6102
+ ctx.lineTo(0, 3.5);
6103
+ ctx.stroke();
6104
+ ctx.fillStyle = "#1d9bf0";
6105
+ ctx.beginPath();
6106
+ ctx.arc(0, 0, 1.25, 0, Math.PI * 2);
6107
+ ctx.fill();
6108
+ ctx.restore();
6109
+ };
6110
+ const addRotationAndPivot = () => {
6111
+ var _a2, _b2;
6112
+ obj.controls.tpRot = new fabric.Control({
6113
+ x: 0,
6114
+ y: -0.5,
6115
+ offsetY: -28,
6116
+ cursorStyleHandler: cu == null ? void 0 : cu.rotationStyleHandler,
6117
+ actionHandler: cu == null ? void 0 : cu.rotationWithSnapping,
6118
+ actionName: "rotate",
6119
+ render: renderRotation,
6120
+ withConnection: false
6121
+ });
6122
+ obj.controls.tpPivot = new fabric.Control({
6123
+ x: 0,
6124
+ y: 0,
6125
+ cursorStyle: "default",
6126
+ actionName: "tpPivot",
6127
+ actionHandler: () => false,
6128
+ render: renderPivot
6129
+ });
6130
+ (_a2 = obj.setControlVisible) == null ? void 0 : _a2.call(obj, "tpRot", true);
6131
+ (_b2 = obj.setControlVisible) == null ? void 0 : _b2.call(obj, "tpPivot", true);
6132
+ };
6133
+ if (((_d = obj.textPath) == null ? void 0 : _d.preset) === "circle") {
6134
+ const getRadius = (target) => {
6135
+ const tp = target.textPath || {};
6136
+ const fs = target.fontSize || 16;
6137
+ const w = target.width || 0;
6138
+ const auto = Math.max(fs * 1.5, w / Math.PI);
6139
+ const r = tp.radius;
6140
+ return Math.max(fs * 0.75, Number.isFinite(r) && r > 0 ? r : auto);
6141
+ };
6142
+ const setRadius = (target, r) => {
6143
+ var _a2;
6144
+ const fs = target.fontSize || 16;
6145
+ const clamped = Math.max(fs * 0.75, r);
6146
+ if (!target.textPath) target.textPath = { preset: "circle" };
6147
+ target.textPath.preset = "circle";
6148
+ target.textPath.radius = clamped;
6149
+ target.dirty = true;
6150
+ (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6151
+ };
6152
+ const ringPoint = (target, dir) => {
6153
+ const r = getRadius(target);
6154
+ const cx = r - halfWOf(target);
6155
+ const cy = r - halfHOf(target);
6156
+ switch (dir) {
6157
+ case "N":
6158
+ return new fabric.Point(cx, cy - r);
6159
+ case "E":
6160
+ return new fabric.Point(cx + r, cy);
6161
+ case "S":
6162
+ return new fabric.Point(cx, cy + r);
6163
+ case "W":
6164
+ return new fabric.Point(cx - r, cy);
6165
+ }
6166
+ };
6167
+ const positionAtRing = (dir) => (_d2, finalMatrix, target) => scaleLocalToScreen(target, ringPoint(target, dir)).transform(finalMatrix);
6168
+ const dragRadius = (dir) => (_e2, transform, x, y) => {
6169
+ const target = transform.target;
6170
+ const state = transform.__pdCircleRadiusDrag || (transform.__pdCircleRadiusDrag = {
6171
+ dir,
6172
+ startRadius: getRadius(target),
6173
+ startLeft: target.left || 0,
6174
+ startTop: target.top || 0,
6175
+ startMatrix: target.calcTransformMatrix(),
6176
+ startLocal: null
6177
+ });
6178
+ if (!state.startLocal) state.startLocal = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
6179
+ const local = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
6180
+ const dx = local.x - state.startLocal.x;
6181
+ const dy = local.y - state.startLocal.y;
6182
+ let next = state.startRadius;
6183
+ if (dir === "E") next = state.startRadius + dx / 2;
6184
+ else if (dir === "W") next = state.startRadius - dx / 2;
6185
+ else if (dir === "S") next = state.startRadius + dy / 2;
6186
+ else next = state.startRadius - dy / 2;
6187
+ const fs = target.fontSize || 16;
6188
+ next = Math.max(fs * 0.75, next);
6189
+ if (dir === "W") {
6190
+ const appliedDx = (state.startRadius - next) * 2;
6191
+ const move = vectorFromFrozenMatrix(state.startMatrix, appliedDx, 0);
6192
+ target.set({ left: state.startLeft + move.x, top: state.startTop + move.y });
6193
+ } else if (dir === "N") {
6194
+ const appliedDy = (state.startRadius - next) * 2;
6195
+ const move = vectorFromFrozenMatrix(state.startMatrix, 0, appliedDy);
6196
+ target.set({ left: state.startLeft + move.x, top: state.startTop + move.y });
6197
+ }
6198
+ setRadius(target, next);
6199
+ return true;
6200
+ };
6201
+ const renderRingHandle = (ctx, left, top) => {
6202
+ ctx.save();
6203
+ ctx.translate(left, top);
6204
+ ctx.shadowColor = "rgba(0,0,0,0.25)";
6205
+ ctx.shadowBlur = 2;
6206
+ ctx.shadowOffsetY = 0.5;
6207
+ ctx.fillStyle = "#ffffff";
6208
+ ctx.strokeStyle = "#1d9bf0";
6209
+ ctx.lineWidth = 1.5;
6210
+ ctx.beginPath();
6211
+ ctx.arc(0, 0, 5.5, 0, Math.PI * 2);
6212
+ ctx.fill();
6213
+ ctx.shadowColor = "transparent";
6214
+ ctx.stroke();
6215
+ ctx.restore();
6216
+ };
6217
+ obj.controls.crN = new fabric.Control({ x: 0, y: -0.5, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragRadius("N"), positionHandler: positionAtRing("N"), render: renderRingHandle });
6218
+ obj.controls.crE = new fabric.Control({ x: 0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("E"), positionHandler: positionAtRing("E"), render: renderRingHandle });
6219
+ obj.controls.crS = new fabric.Control({ x: 0, y: 0.5, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragRadius("S"), positionHandler: positionAtRing("S"), render: renderRingHandle });
6220
+ obj.controls.crW = new fabric.Control({ x: -0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("W"), positionHandler: positionAtRing("W"), render: renderRingHandle });
6221
+ (_e = obj.setControlVisible) == null ? void 0 : _e.call(obj, "crN", true);
6222
+ (_f = obj.setControlVisible) == null ? void 0 : _f.call(obj, "crE", true);
6223
+ (_g = obj.setControlVisible) == null ? void 0 : _g.call(obj, "crS", true);
6224
+ (_h = obj.setControlVisible) == null ? void 0 : _h.call(obj, "crW", true);
6225
+ addRotationAndPivot();
6226
+ obj.hasBorders = false;
6227
+ obj.hasControls = true;
6228
+ obj.objectCaching = false;
6229
+ obj.__pdTextPathControls = true;
6230
+ obj.setCoords();
6231
+ return;
6232
+ }
6233
+ if (((_i = obj.textPath) == null ? void 0 : _i.preset) === "rise") {
6234
+ const getEndpoints = (target) => {
6235
+ const w = target.width || 0;
6236
+ const fs = target.fontSize || 16;
6237
+ const tp = target.textPath || {};
6238
+ const ep = tp.endpoints;
6239
+ const defaultLeftY = fs * 1.5;
6240
+ const defaultRightY = fs * 0.5;
6241
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
6242
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
6243
+ const lineMid = (leftY + rightY) / 2;
6244
+ const rawCurve = Number.isFinite(tp.curve) ? tp.curve : 0;
6245
+ const curveAmp = Math.min(w * 0.18, fs * 4);
6246
+ const centerY = ep && Number.isFinite(ep.centerY) ? ep.centerY : lineMid - Math.max(-1, Math.min(1, rawCurve)) * curveAmp;
6247
+ return { leftY, centerY, rightY };
6248
+ };
6249
+ const setEndpoints = (target, next) => {
6250
+ var _a2;
6251
+ target.width || 1;
6252
+ target.fontSize || 16;
6253
+ const lineMid = (next.leftY + next.rightY) / 2;
6254
+ const straight = { leftY: next.leftY, centerY: lineMid, rightY: next.rightY };
6255
+ if (!target.textPath) target.textPath = { preset: "rise" };
6256
+ target.textPath = {
6257
+ ...target.textPath,
6258
+ preset: "rise",
6259
+ curve: 0,
6260
+ endpoints: straight
6261
+ };
6262
+ if (target.skewY) target.set("skewY", 0);
6263
+ target.dirty = true;
6264
+ (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6265
+ };
6266
+ const positionAtAngleHandle = (key) => (_d2, finalMatrix, target) => {
6267
+ const ep = getEndpoints(target);
6268
+ const x = key === "leftY" ? 0 : key === "rightY" ? target.width || 0 : (target.width || 0) / 2;
6269
+ return scaleLocalToScreen(target, new fabric.Point(x - halfWOf(target), ep[key] - halfHOf(target))).transform(finalMatrix);
6270
+ };
6271
+ const dragAngleHandle = (key) => (_e2, transform, x, y) => {
6272
+ const target = transform.target;
6273
+ const local = localPointFromCanvas(target, x, y);
6274
+ const current = getEndpoints(target);
6275
+ const next = { ...current, [key]: local.y };
6276
+ setEndpoints(target, next);
6277
+ return true;
6278
+ };
6279
+ const renderAngleHandle = (ctx, left, top) => {
6280
+ ctx.save();
6281
+ ctx.translate(left, top);
6282
+ ctx.shadowColor = "rgba(0,0,0,0.25)";
6283
+ ctx.shadowBlur = 2;
6284
+ ctx.shadowOffsetY = 0.5;
6285
+ ctx.fillStyle = "#ffffff";
6286
+ ctx.strokeStyle = "#1d9bf0";
6287
+ ctx.lineWidth = 1.5;
6288
+ ctx.beginPath();
6289
+ ctx.arc(0, 0, 5.5, 0, Math.PI * 2);
6290
+ ctx.fill();
6291
+ ctx.shadowColor = "transparent";
6292
+ ctx.stroke();
6293
+ ctx.restore();
6294
+ };
6295
+ if (obj.skewY) obj.set("skewY", 0);
6296
+ obj.controls.rsL = new fabric.Control({ x: -0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("leftY"), positionHandler: positionAtAngleHandle("leftY"), render: renderAngleHandle });
6297
+ obj.controls.rsR = new fabric.Control({ x: 0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("rightY"), positionHandler: positionAtAngleHandle("rightY"), render: renderAngleHandle });
6298
+ (_j = obj.setControlVisible) == null ? void 0 : _j.call(obj, "rsL", true);
6299
+ (_k = obj.setControlVisible) == null ? void 0 : _k.call(obj, "rsR", true);
6300
+ addRotationAndPivot();
6301
+ obj.hasBorders = false;
6302
+ obj.hasControls = true;
6303
+ obj.objectCaching = false;
6304
+ obj.__pdTextPathControls = true;
6305
+ obj.setCoords();
6306
+ return;
6307
+ }
6308
+ const ensureBezier = (target) => {
6309
+ const tp = target.textPath;
6310
+ if (tp == null ? void 0 : tp.bezier) return tp.bezier;
6311
+ const resolved = resolveTextPath(tp, target.width || 0, target.fontSize || 16);
6312
+ const path = resolved ? measurePath(resolved.d) : null;
6313
+ if (!path) {
6314
+ const w = target.width || 0;
6315
+ const fs = target.fontSize || 16;
6316
+ const h = target.height || fs * 1.4;
6317
+ const cy = h / 2;
6318
+ const handleLen = w * 0.25;
6319
+ const fallback = {
6320
+ p0: [0, cy],
6321
+ c0: [handleLen, cy],
6322
+ c1: [w - handleLen, cy],
6323
+ p1: [w, cy]
6324
+ };
6325
+ target.textPath = { ...tp || { preset: "custom" }, bezier: fallback };
6326
+ return fallback;
6327
+ }
6328
+ const len = path.getTotalLength();
6329
+ const sample = (u) => {
6330
+ const p = path.getPointAtLength(u * len);
6331
+ return [p.x, p.y];
6332
+ };
6333
+ const p0 = sample(0);
6334
+ const a = sample(1 / 3);
6335
+ const b = sample(2 / 3);
6336
+ const p1 = sample(1);
6337
+ const c0 = [
6338
+ (-5 * p0[0] + 18 * a[0] - 9 * b[0] + 2 * p1[0]) / 6,
6339
+ (-5 * p0[1] + 18 * a[1] - 9 * b[1] + 2 * p1[1]) / 6
6340
+ ];
6341
+ const c1 = [
6342
+ (2 * p0[0] - 9 * a[0] + 18 * b[0] - 5 * p1[0]) / 6,
6343
+ (2 * p0[1] - 9 * a[1] + 18 * b[1] - 5 * p1[1]) / 6
6344
+ ];
6345
+ const solved = { p0, c0, c1, p1 };
6346
+ target.textPath = { ...tp || { preset: "custom" }, bezier: solved };
6347
+ return solved;
6348
+ };
6349
+ ensureBezier(obj);
6350
+ const positionAtBezier = (key) => (_d2, finalMatrix, target) => {
6351
+ const bz = ensureBezier(target);
6352
+ const [bx, by] = bz[key];
6353
+ return scaleLocalToScreen(target, new fabric.Point(bx - halfWOf(target), by - halfHOf(target))).transform(finalMatrix);
6354
+ };
6355
+ const bezierMidpoint = (bz) => [
6356
+ 0.125 * bz.p0[0] + 0.375 * bz.c0[0] + 0.375 * bz.c1[0] + 0.125 * bz.p1[0],
6357
+ 0.125 * bz.p0[1] + 0.375 * bz.c0[1] + 0.375 * bz.c1[1] + 0.125 * bz.p1[1]
6358
+ ];
6359
+ const positionAtMid = (_d2, finalMatrix, target) => {
6360
+ const bz = ensureBezier(target);
6361
+ const [mx, my] = bezierMidpoint(bz);
6362
+ return scaleLocalToScreen(target, new fabric.Point(mx - halfWOf(target), my - halfHOf(target))).transform(finalMatrix);
6363
+ };
6364
+ const midTangentVector = (bz) => {
6365
+ let dx = bz.p1[0] + 3 * bz.c1[0] - 3 * bz.c0[0] - bz.p0[0];
6366
+ let dy = bz.p1[1] + 3 * bz.c1[1] - 3 * bz.c0[1] - bz.p0[1];
6367
+ const dlen = Math.hypot(dx, dy) || 1;
6368
+ dx /= dlen;
6369
+ dy /= dlen;
6370
+ const mx = 0.125 * bz.p0[0] + 0.375 * bz.c0[0] + 0.375 * bz.c1[0] + 0.125 * bz.p1[0];
6371
+ const my = 0.125 * bz.p0[1] + 0.375 * bz.c0[1] + 0.375 * bz.c1[1] + 0.125 * bz.p1[1];
6372
+ const projC1 = (bz.c1[0] - mx) * dx + (bz.c1[1] - my) * dy;
6373
+ const projC0 = (mx - bz.c0[0]) * dx + (my - bz.c0[1]) * dy;
6374
+ const reach = Math.max(8, (Math.abs(projC1) + Math.abs(projC0)) / 2);
6375
+ return { vx: dx * reach, vy: dy * reach };
6376
+ };
6377
+ const positionAtMidTangent = (side) => (_d2, finalMatrix, target) => {
6378
+ const bz = ensureBezier(target);
6379
+ const [mx, my] = bezierMidpoint(bz);
6380
+ const { vx, vy } = midTangentVector(bz);
6381
+ const px = mx + side * vx;
6382
+ const py = my + side * vy;
6383
+ return scaleLocalToScreen(target, new fabric.Point(px - halfWOf(target), py - halfHOf(target))).transform(finalMatrix);
6384
+ };
6385
+ const makeMidTangentDrag = (side) => (_e2, transform, x, y) => {
6386
+ var _a2;
6387
+ const target = transform.target;
6388
+ const local = localPointFromCanvas(target, x, y);
6389
+ const current = ensureBezier(target);
6390
+ const bz = {
6391
+ p0: [...current.p0],
6392
+ c0: [...current.c0],
6393
+ c1: [...current.c1],
6394
+ p1: [...current.p1]
6395
+ };
6396
+ const [mx, my] = bezierMidpoint(bz);
6397
+ const oldV = midTangentVector(bz);
6398
+ const nvx = (local.x - mx) * side;
6399
+ const nvy = (local.y - my) * side;
6400
+ const oldLen2 = oldV.vx * oldV.vx + oldV.vy * oldV.vy;
6401
+ if (oldLen2 < 1e-6) return true;
6402
+ const a = (oldV.vx * nvx + oldV.vy * nvy) / oldLen2;
6403
+ const b = (oldV.vx * nvy - oldV.vy * nvx) / oldLen2;
6404
+ const apply = (px, py) => {
6405
+ const rx = px - mx;
6406
+ const ry = py - my;
6407
+ return [mx + a * rx - b * ry, my + b * rx + a * ry];
6408
+ };
6409
+ bz.c0 = apply(bz.c0[0], bz.c0[1]);
6410
+ bz.c1 = apply(bz.c1[0], bz.c1[1]);
6411
+ target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6412
+ target.dirty = true;
6413
+ (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6414
+ return true;
6415
+ };
6416
+ const makeDrag = (key) => (_e2, transform, x, y) => {
6417
+ var _a2;
6418
+ const target = transform.target;
6419
+ const local = localPointFromCanvas(target, x, y);
6420
+ const current = ensureBezier(target);
6421
+ const bz = { p0: [...current.p0], c0: [...current.c0], c1: [...current.c1], p1: [...current.p1] };
6422
+ if (key === "p0" || key === "p1") {
6423
+ const ctrlKey = key === "p0" ? "c0" : "c1";
6424
+ const oldAnchor = bz[key];
6425
+ const oldCtrl = bz[ctrlKey];
6426
+ const dx = local.x - oldAnchor[0];
6427
+ const dy = local.y - oldAnchor[1];
6428
+ bz[key] = [local.x, local.y];
6429
+ bz[ctrlKey] = [oldCtrl[0] + dx, oldCtrl[1] + dy];
6430
+ } else {
6431
+ bz[key] = [local.x, local.y];
6432
+ }
6433
+ target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6434
+ target.dirty = true;
6435
+ (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6436
+ return true;
6437
+ };
6438
+ const makeMidDrag = () => (_e2, transform, x, y) => {
6439
+ var _a2;
6440
+ const target = transform.target;
6441
+ const local = localPointFromCanvas(target, x, y);
6442
+ const current = ensureBezier(target);
6443
+ const bz = {
6444
+ p0: [...current.p0],
6445
+ c0: [...current.c0],
6446
+ c1: [...current.c1],
6447
+ p1: [...current.p1]
6448
+ };
6449
+ const [mx, my] = bezierMidpoint(bz);
6450
+ const dx = (local.x - mx) / 0.75;
6451
+ const dy = (local.y - my) / 0.75;
6452
+ bz.c0 = [bz.c0[0] + dx, bz.c0[1] + dy];
6453
+ bz.c1 = [bz.c1[0] + dx, bz.c1[1] + dy];
6454
+ target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6455
+ target.dirty = true;
6456
+ (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6457
+ return true;
6458
+ };
6459
+ const renderAnchor = (ctx, left, top) => {
6460
+ ctx.save();
6461
+ ctx.translate(left, top);
6462
+ ctx.shadowColor = "rgba(0,0,0,0.25)";
6463
+ ctx.shadowBlur = 2;
6464
+ ctx.shadowOffsetY = 0.5;
6465
+ ctx.fillStyle = "#ffffff";
6466
+ ctx.strokeStyle = "#1d9bf0";
6467
+ ctx.lineWidth = 1.5;
6468
+ ctx.beginPath();
6469
+ ctx.arc(0, 0, 5, 0, Math.PI * 2);
6470
+ ctx.fill();
6471
+ ctx.shadowColor = "transparent";
6472
+ ctx.stroke();
6473
+ ctx.restore();
6474
+ };
6475
+ const renderControlHandle = (ctx, left, top) => {
6476
+ ctx.save();
6477
+ ctx.translate(left, top);
6478
+ ctx.shadowColor = "rgba(0,0,0,0.25)";
6479
+ ctx.shadowBlur = 2;
6480
+ ctx.shadowOffsetY = 0.5;
6481
+ ctx.fillStyle = "#1d9bf0";
6482
+ ctx.strokeStyle = "#ffffff";
6483
+ ctx.lineWidth = 1.5;
6484
+ ctx.beginPath();
6485
+ ctx.arc(0, 0, 4, 0, Math.PI * 2);
6486
+ ctx.fill();
6487
+ ctx.shadowColor = "transparent";
6488
+ ctx.stroke();
6489
+ ctx.restore();
6490
+ };
6491
+ obj.controls.bzP0 = new fabric.Control({ x: -0.5, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("p0"), positionHandler: positionAtBezier("p0"), render: renderAnchor });
6492
+ obj.controls.bzP1 = new fabric.Control({ x: 0.5, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("p1"), positionHandler: positionAtBezier("p1"), render: renderAnchor });
6493
+ obj.controls.bzC0 = new fabric.Control({ x: -0.25, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("c0"), positionHandler: positionAtBezier("c0"), render: renderControlHandle });
6494
+ obj.controls.bzC1 = new fabric.Control({ x: 0.25, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("c1"), positionHandler: positionAtBezier("c1"), render: renderControlHandle });
6495
+ obj.controls.bzMid = new fabric.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidDrag(), positionHandler: positionAtMid, render: renderAnchor });
6496
+ obj.controls.bzMidT0 = new fabric.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(-1), positionHandler: positionAtMidTangent(-1), render: renderControlHandle });
6497
+ obj.controls.bzMidT1 = new fabric.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(1), positionHandler: positionAtMidTangent(1), render: renderControlHandle });
6498
+ (_l = obj.setControlVisible) == null ? void 0 : _l.call(obj, "bzP0", true);
6499
+ (_m = obj.setControlVisible) == null ? void 0 : _m.call(obj, "bzC0", true);
6500
+ (_n = obj.setControlVisible) == null ? void 0 : _n.call(obj, "bzC1", true);
6501
+ (_o = obj.setControlVisible) == null ? void 0 : _o.call(obj, "bzP1", true);
6502
+ (_p = obj.setControlVisible) == null ? void 0 : _p.call(obj, "bzMid", true);
6503
+ (_q = obj.setControlVisible) == null ? void 0 : _q.call(obj, "bzMidT0", true);
6504
+ (_r = obj.setControlVisible) == null ? void 0 : _r.call(obj, "bzMidT1", true);
6505
+ addRotationAndPivot();
6506
+ obj.hasBorders = false;
6507
+ obj.hasControls = true;
6508
+ obj.__pdTextPathControls = true;
6509
+ obj.setCoords();
6510
+ }
6511
+ function computeWarpBoundsLocal(obj) {
6512
+ const resolved = resolveTextPath(obj.textPath, obj.width || 0, obj.fontSize || 16);
6513
+ const path = resolved ? measurePath(resolved.d) : null;
6514
+ if (!path) return null;
6515
+ const len = path.getTotalLength();
6516
+ if (!Number.isFinite(len) || len <= 0) return null;
6517
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
6518
+ const steps = 96;
6519
+ for (let i = 0; i <= steps; i++) {
6520
+ const p = path.getPointAtLength(len * i / steps);
6521
+ if (p.x < minX) minX = p.x;
6522
+ if (p.x > maxX) maxX = p.x;
6523
+ if (p.y < minY) minY = p.y;
6524
+ if (p.y > maxY) maxY = p.y;
6525
+ }
6526
+ const fs = obj.fontSize || 16;
6527
+ const halfW = (obj.width || 0) / 2;
6528
+ const halfH = (obj.height || 0) / 2;
6529
+ return {
6530
+ minX: minX - fs * 0.2 - halfW,
6531
+ maxX: maxX + fs * 0.2 - halfW,
6532
+ minY: minY - fs * 1.05 - halfH,
6533
+ maxY: maxY + fs * 0.35 - halfH
6534
+ };
6535
+ }
6536
+ function computeCircleWarpBoundsLocal(obj) {
6537
+ var _a;
6538
+ if (((_a = obj.textPath) == null ? void 0 : _a.preset) !== "circle") return null;
6539
+ const fs = obj.fontSize || 16;
6540
+ const w = obj.width || 0;
6541
+ const auto = Math.max(fs * 1.5, w / Math.PI);
6542
+ const rRaw = obj.textPath.radius;
6543
+ const r = Math.max(fs * 0.75, Number.isFinite(rRaw) && rRaw > 0 ? rRaw : auto);
6544
+ const halfW = w / 2;
6545
+ const halfH = (obj.height || 0) / 2;
6546
+ const cx = r - halfW;
6547
+ const cy = r - halfH;
6548
+ return { minX: cx - r - fs * 0.2, maxX: cx + r + fs * 0.2, minY: cy - r - fs * 0.6, maxY: cy + r + fs * 0.6 };
6549
+ }
6550
+ function getTextPathHitBounds(obj) {
6551
+ var _a;
6552
+ return ((_a = obj.textPath) == null ? void 0 : _a.preset) === "circle" ? computeCircleWarpBoundsLocal(obj) : computeWarpBoundsLocal(obj);
6553
+ }
6554
+ function textPathBoundsContainScenePoint(obj, point) {
6555
+ const bounds = getTextPathHitBounds(obj);
6556
+ if (!bounds) return false;
6557
+ try {
6558
+ const inv = fabric.util.invertTransform(obj.calcTransformMatrix());
6559
+ const local = fabric.util.transformPoint(point, inv);
6560
+ return local.x >= bounds.minX && local.x <= bounds.maxX && local.y >= bounds.minY && local.y <= bounds.maxY;
6561
+ } catch {
6562
+ return false;
6563
+ }
6564
+ }
6565
+ function drawTextPathBounds(ctx, obj, bounds) {
6566
+ var _a;
6567
+ if (!obj.canvas) return;
6568
+ const retina = ((_a = obj.getCanvasRetinaScaling) == null ? void 0 : _a.call(obj)) || 1;
6569
+ const matrix = fabric.util.multiplyTransformMatrices(obj.canvas.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
6570
+ const corners = [
6571
+ new fabric.Point(bounds.minX, bounds.minY),
6572
+ new fabric.Point(bounds.maxX, bounds.minY),
6573
+ new fabric.Point(bounds.maxX, bounds.maxY),
6574
+ new fabric.Point(bounds.minX, bounds.maxY)
6575
+ ].map((p) => fabric.util.transformPoint(p, matrix));
6576
+ ctx.save();
6577
+ ctx.setTransform(retina, 0, 0, retina, 0, 0);
6578
+ ctx.strokeStyle = "rgba(29, 155, 240, 0.9)";
6579
+ ctx.lineWidth = 1.25;
6580
+ ctx.setLineDash([5, 4]);
6581
+ ctx.beginPath();
6582
+ ctx.moveTo(corners[0].x, corners[0].y);
6583
+ for (let i = 1; i < corners.length; i++) ctx.lineTo(corners[i].x, corners[i].y);
6584
+ ctx.closePath();
6585
+ ctx.stroke();
6586
+ ctx.restore();
6587
+ }
6588
+ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldocsOrigRenderControls) {
6589
+ let drawWarpGuides = function(ctx) {
6590
+ var _a, _b, _c, _d, _e, _f, _g;
6591
+ if (!this.canvas) return;
6592
+ const hoverBounds = getTextPathHitBounds(this);
6593
+ if (hoverBounds && (this.__pdTextPathHovered || ((_b = (_a = this.canvas).getActiveObject) == null ? void 0 : _b.call(_a)) === this)) {
6594
+ drawTextPathBounds(ctx, this, hoverBounds);
6595
+ }
6596
+ const resolved = resolveTextPath(this.textPath, this.width || 0, this.fontSize || 16);
6597
+ const path = resolved ? measurePath(resolved.d) : null;
6598
+ if (!path) return;
6599
+ const len = path.getTotalLength();
6600
+ if (!Number.isFinite(len) || len <= 0) return;
6601
+ const retina = ((_c = this.getCanvasRetinaScaling) == null ? void 0 : _c.call(this)) || 1;
6602
+ const matrix = fabric.util.multiplyTransformMatrices(
6603
+ this.canvas.viewportTransform || [1, 0, 0, 1, 0, 0],
6604
+ this.calcTransformMatrix()
6605
+ );
6606
+ const halfW = (this.width || 0) / 2;
6607
+ const halfH = (this.height || 0) / 2;
6608
+ const toScreen = (t) => {
6609
+ const p = path.getPointAtLength(Math.max(0, Math.min(len, len * t)));
6610
+ return fabric.util.transformPoint(new fabric.Point(p.x - halfW, p.y - halfH), matrix);
6611
+ };
6612
+ const toScreenXY = (x, y) => fabric.util.transformPoint(new fabric.Point(x, y), matrix);
6613
+ ctx.save();
6614
+ ctx.setTransform(retina, 0, 0, retina, 0, 0);
6615
+ const isCircle = ((_d = this.textPath) == null ? void 0 : _d.preset) === "circle";
6616
+ const isAngle = ((_e = this.textPath) == null ? void 0 : _e.preset) === "rise" || ((_f = this.textPath) == null ? void 0 : _f.preset) === "angle";
6617
+ ctx.strokeStyle = "rgba(29, 155, 240, 0.95)";
6618
+ ctx.lineWidth = 1.25;
6619
+ ctx.setLineDash([]);
6620
+ if (isAngle) {
6621
+ const tp = this.textPath;
6622
+ const w = this.width || 0;
6623
+ const fs = this.fontSize || 16;
6624
+ const ep = tp.endpoints;
6625
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : fs * 1.5;
6626
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : fs * 0.5;
6627
+ const a = toScreenXY(0 - halfW, leftY - halfH);
6628
+ const b = toScreenXY(w - halfW, rightY - halfH);
6629
+ ctx.beginPath();
6630
+ ctx.moveTo(a.x, a.y);
6631
+ ctx.lineTo(b.x, b.y);
6632
+ ctx.stroke();
6633
+ } else {
6634
+ ctx.beginPath();
6635
+ for (let i = 0; i <= 96; i++) {
6636
+ const p = toScreen(i / 96);
6637
+ if (i === 0) ctx.moveTo(p.x, p.y);
6638
+ else ctx.lineTo(p.x, p.y);
6639
+ }
6640
+ ctx.stroke();
6641
+ }
6642
+ if (isCircle) {
6643
+ const tp = this.textPath || {};
6644
+ const fs = this.fontSize || 16;
6645
+ const w = this.width || 0;
6646
+ const auto = Math.max(fs * 1.5, w / Math.PI);
6647
+ const rRaw = tp.radius;
6648
+ const r = Math.max(fs * 0.75, Number.isFinite(rRaw) && rRaw > 0 ? rRaw : auto);
6649
+ const cx = r - halfW;
6650
+ const cy = r - halfH;
6651
+ const steps = 96;
6652
+ ctx.beginPath();
6653
+ for (let i = 0; i <= steps; i++) {
6654
+ const a = i / steps * Math.PI * 2;
6655
+ const p = toScreenXY(cx + Math.cos(a) * r, cy + Math.sin(a) * r);
6656
+ if (i === 0) ctx.moveTo(p.x, p.y);
6657
+ else ctx.lineTo(p.x, p.y);
6658
+ }
6659
+ ctx.closePath();
6660
+ ctx.stroke();
6661
+ }
6662
+ const bz = isCircle ? null : (_g = this.textPath) == null ? void 0 : _g.bezier;
6663
+ if (bz) {
6664
+ const a = toScreenXY(bz.p0[0] - halfW, bz.p0[1] - halfH);
6665
+ const ah = toScreenXY(bz.c0[0] - halfW, bz.c0[1] - halfH);
6666
+ const b = toScreenXY(bz.p1[0] - halfW, bz.p1[1] - halfH);
6667
+ const bh = toScreenXY(bz.c1[0] - halfW, bz.c1[1] - halfH);
6668
+ ctx.strokeStyle = "rgba(29, 155, 240, 0.7)";
6669
+ ctx.lineWidth = 1;
6670
+ ctx.setLineDash([]);
6671
+ ctx.beginPath();
6672
+ ctx.moveTo(a.x, a.y);
6673
+ ctx.lineTo(ah.x, ah.y);
6674
+ ctx.moveTo(b.x, b.y);
6675
+ ctx.lineTo(bh.x, bh.y);
6676
+ ctx.stroke();
6677
+ const midX = 0.125 * bz.p0[0] + 0.375 * bz.c0[0] + 0.375 * bz.c1[0] + 0.125 * bz.p1[0];
6678
+ const midY = 0.125 * bz.p0[1] + 0.375 * bz.c0[1] + 0.375 * bz.c1[1] + 0.125 * bz.p1[1];
6679
+ let tdx = bz.p1[0] + 3 * bz.c1[0] - 3 * bz.c0[0] - bz.p0[0];
6680
+ let tdy = bz.p1[1] + 3 * bz.c1[1] - 3 * bz.c0[1] - bz.p0[1];
6681
+ const tlen = Math.hypot(tdx, tdy) || 1;
6682
+ tdx /= tlen;
6683
+ tdy /= tlen;
6684
+ const pC1 = (bz.c1[0] - midX) * tdx + (bz.c1[1] - midY) * tdy;
6685
+ const pC0 = (midX - bz.c0[0]) * tdx + (midY - bz.c0[1]) * tdy;
6686
+ const LEG = Math.max(8, (Math.abs(pC1) + Math.abs(pC0)) / 2);
6687
+ const m = toScreenXY(midX - halfW, midY - halfH);
6688
+ const t0 = toScreenXY(midX - tdx * LEG - halfW, midY - tdy * LEG - halfH);
6689
+ const t1 = toScreenXY(midX + tdx * LEG - halfW, midY + tdy * LEG - halfH);
6690
+ ctx.beginPath();
6691
+ ctx.moveTo(m.x, m.y);
6692
+ ctx.lineTo(t0.x, t0.y);
6693
+ ctx.moveTo(m.x, m.y);
6694
+ ctx.lineTo(t1.x, t1.y);
6695
+ ctx.stroke();
6696
+ }
6697
+ ctx.restore();
6698
+ };
6699
+ TextboxProto.__pixldocsOrigRenderControls = TextboxProto._renderControls;
6700
+ TextboxProto._renderControls = function(ctx, styleOverride) {
6701
+ if (hasActiveTextPath(this)) {
6702
+ const prevBorders = this.hasBorders;
6703
+ this.hasBorders = false;
6704
+ try {
6705
+ drawWarpGuides.call(this, ctx);
6706
+ TextboxProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride);
6707
+ } finally {
6708
+ this.hasBorders = prevBorders;
6709
+ }
6710
+ return;
6711
+ }
6712
+ TextboxProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride);
6713
+ if (!this.canvas) return;
6714
+ };
6715
+ }
6716
+ if (!TextboxProto.__pixldocsOrigRender && typeof TextboxProto._render === "function") {
6717
+ TextboxProto.__pixldocsOrigRender = TextboxProto._render;
6718
+ TextboxProto._render = function(ctx) {
6719
+ const tp = this.textPath;
6720
+ const orig = TextboxProto.__pixldocsOrigRender;
6721
+ if (!hasActiveTextPath(this)) {
6722
+ return orig.call(this, ctx);
6723
+ }
6724
+ if (tp && (tp.preset === "rise" || tp.preset === "angle")) {
6725
+ const w = this.width || 0;
6726
+ const h = this.height || 0;
6727
+ const fs2 = this.fontSize || 16;
6728
+ const ep = tp.endpoints;
6729
+ const defaultLeftY = fs2 * 1.5;
6730
+ const defaultRightY = fs2 * 0.5;
6731
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
6732
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
6733
+ const slope = w > 0 ? (rightY - leftY) / w : 0;
6734
+ const dy = (leftY + rightY) / 2 - h / 2;
6735
+ ctx.save();
6736
+ ctx.transform(1, slope, 0, 1, 0, dy);
6737
+ orig.call(this, ctx);
6738
+ ctx.restore();
6739
+ return;
6740
+ }
6741
+ const resolved = resolveTextPath(tp, this.width || 0, this.fontSize || 16);
6742
+ if (!resolved) return orig.call(this, ctx);
6743
+ const pathEl = measurePath(resolved.d);
6744
+ if (!pathEl) return orig.call(this, ctx);
6745
+ const totalLen = pathEl.getTotalLength();
6746
+ if (!Number.isFinite(totalLen) || totalLen <= 0) return orig.call(this, ctx);
6747
+ const plain = String(this.text || "").replace(/\n/g, " ");
6748
+ if (!plain) return;
6749
+ const weight = this.fontWeight || 400;
6750
+ const style = this.fontStyle || "normal";
6751
+ const family = this.fontFamily || "Open Sans";
6752
+ const fs = this.fontSize || 16;
6753
+ ctx.save();
6754
+ ctx.font = `${style} ${weight} ${fs}px "${family}"`;
6755
+ ctx.textAlign = "center";
6756
+ ctx.textBaseline = "alphabetic";
6757
+ const chars = Array.from(plain);
6758
+ const spacing = (this.charSpacing || 0) * fs / 1e3;
6759
+ const widths = chars.map((c) => ctx.measureText(c).width + spacing);
6760
+ const totalWidth = widths.reduce((a, b) => a + b, 0);
6761
+ const baselineDy = resolveTextPathAlphabeticBaselineDy(ctx, plain, fs);
6762
+ let cursor;
6763
+ if (this.textAlign === "center") cursor = Math.max(0, (totalLen - totalWidth) / 2);
6764
+ else if (this.textAlign === "right") cursor = Math.max(0, totalLen - totalWidth);
6765
+ else cursor = 0;
6766
+ const flowStops = getGradientStopsForFlow(this);
6767
+ const fillOffsets = flowStops ? { offsetX: 0, offsetY: 0 } : applyWarpFillStyle(ctx, this);
6768
+ const halfW = (this.width || 0) / 2;
6769
+ const halfH = (this.height || 0) / 2;
6770
+ const strokeColor = this.stroke;
6771
+ const strokeWidth = Number(this.strokeWidth) || 0;
6772
+ const hasStroke = !!strokeColor && strokeColor !== "transparent" && strokeWidth > 0;
6773
+ if (hasStroke) {
6774
+ ctx.strokeStyle = String(strokeColor);
6775
+ ctx.lineWidth = strokeWidth;
6776
+ ctx.lineJoin = "round";
6777
+ ctx.miterLimit = 4;
6778
+ }
6779
+ for (let i = 0; i < chars.length; i++) {
6780
+ const ch = chars[i];
6781
+ const cw = widths[i];
6782
+ const mid = cursor + cw / 2;
6783
+ cursor += cw;
6784
+ if (mid > totalLen) break;
6785
+ const p = pathEl.getPointAtLength(Math.max(0, mid));
6786
+ const ahead = pathEl.getPointAtLength(Math.min(totalLen, mid + 0.5));
6787
+ const angle = Math.atan2(ahead.y - p.y, ahead.x - p.x);
6788
+ if (flowStops) {
6789
+ const tt = chars.length > 1 ? i / (chars.length - 1) : 0;
6790
+ ctx.fillStyle = sampleGradientColor(flowStops, tt);
6791
+ }
6792
+ ctx.save();
6793
+ ctx.translate(p.x - halfW - fillOffsets.offsetX, p.y - halfH - fillOffsets.offsetY);
6794
+ ctx.rotate(angle);
6795
+ ctx.fillText(ch, 0, baselineDy);
6796
+ if (hasStroke) ctx.strokeText(ch, 0, baselineDy);
6797
+ ctx.restore();
6798
+ }
6799
+ ctx.restore();
6800
+ };
5744
6801
  }
5745
6802
  TextboxProto.__pixldocsTextboxExtended = true;
6803
+ const TextboxProtoHit = fabric.Textbox.prototype;
6804
+ if (!TextboxProtoHit.__pixldocsOrigGetCoords && typeof TextboxProtoHit.getCoords === "function") {
6805
+ TextboxProtoHit.__pixldocsOrigGetCoords = TextboxProtoHit.getCoords;
6806
+ TextboxProtoHit.getCoords = function() {
6807
+ if (!hasActiveTextPath(this)) return TextboxProtoHit.__pixldocsOrigGetCoords.call(this);
6808
+ const bounds = getTextPathHitBounds(this);
6809
+ if (!bounds) return TextboxProtoHit.__pixldocsOrigGetCoords.call(this);
6810
+ const matrix = this.calcTransformMatrix();
6811
+ const coords = [
6812
+ new fabric.Point(bounds.minX, bounds.minY),
6813
+ new fabric.Point(bounds.maxX, bounds.minY),
6814
+ new fabric.Point(bounds.maxX, bounds.maxY),
6815
+ new fabric.Point(bounds.minX, bounds.maxY)
6816
+ ].map((p) => fabric.util.transformPoint(p, matrix));
6817
+ if (this.group) {
6818
+ const groupMatrix = this.group.calcTransformMatrix();
6819
+ return coords.map((p) => fabric.util.transformPoint(p, groupMatrix));
6820
+ }
6821
+ return coords;
6822
+ };
6823
+ }
6824
+ if (!TextboxProtoHit.__pixldocsOrigContainsPoint && typeof TextboxProtoHit.containsPoint === "function") {
6825
+ TextboxProtoHit.__pixldocsOrigContainsPoint = TextboxProtoHit.containsPoint;
6826
+ TextboxProtoHit.containsPoint = function(point) {
6827
+ const origHit = TextboxProtoHit.__pixldocsOrigContainsPoint.call(this, point);
6828
+ if (origHit) return true;
6829
+ if (!hasActiveTextPath(this)) return false;
6830
+ return textPathBoundsContainScenePoint(this, point);
6831
+ };
6832
+ }
5746
6833
  const PD_BG_KEY = "__pdBg";
5747
6834
  const PATCHED_KEY = "__pdBgPatched";
6835
+ const LINE_SHADOW_STROKE_WIDTH = 0.5;
5748
6836
  function extractTextBgConfig(element) {
5749
6837
  const legacy = Math.max(0, Number(element.textBgPadding ?? 0)) || 0;
5750
6838
  const pick = (v) => {
5751
6839
  const n = Number(v);
5752
6840
  return Number.isFinite(n) && n >= 0 ? n : void 0;
5753
6841
  };
6842
+ const grad = element.textBgGradient;
5754
6843
  return {
5755
6844
  color: element.textBgColor,
6845
+ gradient: isGradientConfig(grad) && grad.stops && grad.stops.length >= 2 ? grad : void 0,
5756
6846
  padTop: pick(element.textBgPaddingTop) ?? legacy,
5757
6847
  padRight: pick(element.textBgPaddingRight) ?? legacy,
5758
6848
  padBottom: pick(element.textBgPaddingBottom) ?? legacy,
@@ -5768,11 +6858,16 @@ function extractTextBgConfig(element) {
5768
6858
  })(),
5769
6859
  shadowAffectsBg: element.textShadowAffectsBg !== false,
5770
6860
  shadowAffectsText: element.textShadowAffectsText !== false,
5771
- fitToText: element.textBgFitToText === true
6861
+ fitToText: element.textBgFitToText === true,
6862
+ shadowType: element.textShadowType,
6863
+ shadowColor: element.textShadowColor,
6864
+ shadowOffsetX: Number(element.textShadowOffsetX ?? 0) || 0,
6865
+ shadowOffsetY: Number(element.textShadowOffsetY ?? 0) || 0
5772
6866
  };
5773
6867
  }
5774
6868
  function hasTextBackground(cfg) {
5775
6869
  if (!cfg) return false;
6870
+ if (cfg.gradient && cfg.gradient.stops && cfg.gradient.stops.length >= 2) return true;
5776
6871
  const c = (cfg.color || "").toString().trim().toLowerCase();
5777
6872
  return !!c && c !== "transparent" && c !== "none" && c !== "rgba(0,0,0,0)";
5778
6873
  }
@@ -5782,6 +6877,8 @@ function buildTextShadow(element) {
5782
6877
  const ox = Number(element.textShadowOffsetX ?? 0);
5783
6878
  const oy = Number(element.textShadowOffsetY ?? 0);
5784
6879
  if (!color || color === "transparent") return null;
6880
+ const type = element.textShadowType;
6881
+ if (type && type !== "drop") return null;
5785
6882
  return new fabric.Shadow({
5786
6883
  color: String(color),
5787
6884
  blur: blur || 0,
@@ -5812,11 +6909,35 @@ function buildRoundedRectPath2D(ctx, x, y, w, h, rTL, rTR, rBR, rBL) {
5812
6909
  function applyTextBackground(obj, cfg) {
5813
6910
  var _a;
5814
6911
  obj[PD_BG_KEY] = { ...cfg };
6912
+ try {
6913
+ const hasOffset = (Number(cfg == null ? void 0 : cfg.shadowOffsetX) || 0) !== 0 || (Number(cfg == null ? void 0 : cfg.shadowOffsetY) || 0) !== 0;
6914
+ const isLineOrBlock = (cfg == null ? void 0 : cfg.shadowType) === "line" || (cfg == null ? void 0 : cfg.shadowType) === "block";
6915
+ if (isLineOrBlock && hasOffset && !!(cfg == null ? void 0 : cfg.shadowColor) && cfg.shadowColor !== "transparent") {
6916
+ obj.objectCaching = false;
6917
+ obj.dirty = true;
6918
+ }
6919
+ } catch {
6920
+ }
5815
6921
  if (obj[PATCHED_KEY]) return;
5816
6922
  obj[PATCHED_KEY] = true;
5817
6923
  const originalRender = obj._render.bind(obj);
5818
6924
  obj._render = function(ctx) {
5819
6925
  const bg = this[PD_BG_KEY];
6926
+ const extOX = Number((bg == null ? void 0 : bg.shadowOffsetX) ?? 0) || 0;
6927
+ const extOY = Number((bg == null ? void 0 : bg.shadowOffsetY) ?? 0) || 0;
6928
+ const extDist = Math.hypot(extOX, extOY);
6929
+ const hasShadowColor = !!(bg == null ? void 0 : bg.shadowColor) && bg.shadowColor !== "transparent";
6930
+ const blockShadowActive = !!bg && bg.shadowType === "block" && hasShadowColor && extDist > 0;
6931
+ const lineShadowActive = !!bg && bg.shadowType === "line" && hasShadowColor && extDist > 0;
6932
+ let blockSteps = 0;
6933
+ let blockStepX = 0;
6934
+ let blockStepY = 0;
6935
+ if (blockShadowActive) {
6936
+ const STEP = 0.5;
6937
+ blockSteps = Math.min(600, Math.max(1, Math.ceil(extDist / STEP)));
6938
+ blockStepX = extOX / blockSteps;
6939
+ blockStepY = extOY / blockSteps;
6940
+ }
5820
6941
  if (hasTextBackground(bg)) {
5821
6942
  const w = this.width ?? 0;
5822
6943
  const h = this.height ?? 0;
@@ -5834,24 +6955,172 @@ function applyTextBackground(obj, cfg) {
5834
6955
  }
5835
6956
  const op = typeof bg.opacity === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
5836
6957
  if (op < 1) ctx.globalAlpha = (ctx.globalAlpha ?? 1) * op;
5837
- ctx.fillStyle = bg.color;
5838
- const rects = computeBgRects(this, w, h, pT, pR, pB, pL, !!bg.fitToText);
5839
- for (const r of rects) {
5840
- buildRoundedRectPath2D(
5841
- ctx,
5842
- r.x,
5843
- r.y,
5844
- r.w,
5845
- r.h,
5846
- bg.rxTL ?? 0,
5847
- bg.rxTR ?? 0,
5848
- bg.rxBR ?? 0,
5849
- bg.rxBL ?? 0
5850
- );
5851
- ctx.fill();
6958
+ const tpAny = this.textPath;
6959
+ const isShear = tpAny && (tpAny.preset === "rise" || tpAny.preset === "angle");
6960
+ const ribbonD = !isShear ? buildWarpRibbonD(
6961
+ this,
6962
+ pT,
6963
+ pR,
6964
+ pB,
6965
+ pL,
6966
+ bg.rxTL ?? 0,
6967
+ bg.rxTR ?? 0,
6968
+ bg.rxBR ?? 0,
6969
+ bg.rxBL ?? 0
6970
+ ) : null;
6971
+ let bgBounds;
6972
+ let bgRectsForFill = null;
6973
+ if (ribbonD) {
6974
+ bgBounds = computeRibbonBoundsFor(this, pT, pR, pB, pL);
6975
+ } else {
6976
+ bgRectsForFill = computeBgRects(this, w, h, pT, pR, pB, pL, !!bg.fitToText);
6977
+ bgBounds = unionBounds(bgRectsForFill);
6978
+ }
6979
+ if (blockShadowActive && bg.shadowAffectsBg !== false) {
6980
+ ctx.save();
6981
+ ctx.fillStyle = bg.shadowColor;
6982
+ for (let i = blockSteps; i >= 1; i--) {
6983
+ ctx.save();
6984
+ ctx.translate(blockStepX * i, blockStepY * i);
6985
+ if (ribbonD) {
6986
+ try {
6987
+ ctx.fill(new Path2D(ribbonD));
6988
+ } catch {
6989
+ }
6990
+ } else {
6991
+ const rects = bgRectsForFill;
6992
+ for (const r of rects) {
6993
+ buildRoundedRectPath2D(
6994
+ ctx,
6995
+ r.x,
6996
+ r.y,
6997
+ r.w,
6998
+ r.h,
6999
+ bg.rxTL ?? 0,
7000
+ bg.rxTR ?? 0,
7001
+ bg.rxBR ?? 0,
7002
+ bg.rxBL ?? 0
7003
+ );
7004
+ ctx.fill();
7005
+ }
7006
+ }
7007
+ ctx.restore();
7008
+ }
7009
+ ctx.restore();
7010
+ }
7011
+ if (lineShadowActive && bg.shadowAffectsBg !== false) {
7012
+ ctx.save();
7013
+ ctx.translate(extOX, extOY);
7014
+ ctx.strokeStyle = bg.shadowColor;
7015
+ ctx.lineWidth = 1;
7016
+ ctx.lineJoin = "round";
7017
+ if (ribbonD) {
7018
+ try {
7019
+ ctx.stroke(new Path2D(ribbonD));
7020
+ } catch {
7021
+ }
7022
+ } else {
7023
+ const rects = bgRectsForFill;
7024
+ for (const r of rects) {
7025
+ buildRoundedRectPath2D(
7026
+ ctx,
7027
+ r.x,
7028
+ r.y,
7029
+ r.w,
7030
+ r.h,
7031
+ bg.rxTL ?? 0,
7032
+ bg.rxTR ?? 0,
7033
+ bg.rxBR ?? 0,
7034
+ bg.rxBL ?? 0
7035
+ );
7036
+ ctx.stroke();
7037
+ }
7038
+ }
7039
+ ctx.restore();
7040
+ }
7041
+ ctx.fillStyle = bg.gradient ? buildCanvasGradient(ctx, bg.gradient, bgBounds.x, bgBounds.y, bgBounds.w, bgBounds.h) : bg.color || "#000";
7042
+ if (ribbonD) {
7043
+ try {
7044
+ const p2 = new Path2D(ribbonD);
7045
+ ctx.fill(p2);
7046
+ } catch {
7047
+ }
7048
+ } else {
7049
+ if (isShear) {
7050
+ const fs = this.fontSize || 16;
7051
+ const ep = tpAny.endpoints;
7052
+ const dL = fs * 1.5;
7053
+ const dR = fs * 0.5;
7054
+ const lY = ep && Number.isFinite(ep.leftY) ? ep.leftY : dL;
7055
+ const rY = ep && Number.isFinite(ep.rightY) ? ep.rightY : dR;
7056
+ const slope = w > 0 ? (rY - lY) / w : 0;
7057
+ const dy = (lY + rY) / 2 - h / 2;
7058
+ ctx.transform(1, slope, 0, 1, 0, dy);
7059
+ }
7060
+ const rects = bgRectsForFill;
7061
+ for (const r of rects) {
7062
+ buildRoundedRectPath2D(
7063
+ ctx,
7064
+ r.x,
7065
+ r.y,
7066
+ r.w,
7067
+ r.h,
7068
+ bg.rxTL ?? 0,
7069
+ bg.rxTR ?? 0,
7070
+ bg.rxBR ?? 0,
7071
+ bg.rxBL ?? 0
7072
+ );
7073
+ ctx.fill();
7074
+ }
5852
7075
  }
5853
7076
  ctx.restore();
5854
7077
  }
7078
+ if (blockShadowActive && bg.shadowAffectsText !== false) {
7079
+ const self = this;
7080
+ const origFill = self.fill;
7081
+ const origStyles = self.styles;
7082
+ const origShadow = self.shadow;
7083
+ try {
7084
+ self.fill = bg.shadowColor;
7085
+ self.styles = {};
7086
+ self.shadow = null;
7087
+ for (let i = blockSteps; i >= 1; i--) {
7088
+ ctx.save();
7089
+ ctx.translate(blockStepX * i, blockStepY * i);
7090
+ originalRender(ctx);
7091
+ ctx.restore();
7092
+ }
7093
+ } finally {
7094
+ self.fill = origFill;
7095
+ self.styles = origStyles;
7096
+ self.shadow = origShadow;
7097
+ }
7098
+ }
7099
+ if (lineShadowActive && bg.shadowAffectsText !== false) {
7100
+ const self = this;
7101
+ const origFill = self.fill;
7102
+ const origStroke = self.stroke;
7103
+ const origStrokeWidth = self.strokeWidth;
7104
+ const origStyles = self.styles;
7105
+ const origShadow = self.shadow;
7106
+ try {
7107
+ self.fill = "transparent";
7108
+ self.stroke = bg.shadowColor;
7109
+ self.strokeWidth = LINE_SHADOW_STROKE_WIDTH;
7110
+ self.styles = {};
7111
+ self.shadow = null;
7112
+ ctx.save();
7113
+ ctx.translate(extOX, extOY);
7114
+ originalRender(ctx);
7115
+ ctx.restore();
7116
+ } finally {
7117
+ self.fill = origFill;
7118
+ self.stroke = origStroke;
7119
+ self.strokeWidth = origStrokeWidth;
7120
+ self.styles = origStyles;
7121
+ self.shadow = origShadow;
7122
+ }
7123
+ }
5855
7124
  const suppressShadowOnText = bg && bg.shadowAffectsText === false;
5856
7125
  if (suppressShadowOnText) {
5857
7126
  ctx.save();
@@ -5870,19 +7139,27 @@ function applyTextBackground(obj, cfg) {
5870
7139
  const out = originalToObject(propertiesToInclude);
5871
7140
  const bg = this[PD_BG_KEY];
5872
7141
  if (hasTextBackground(bg)) {
5873
- out.__pdBg = { ...bg };
7142
+ out.__pdBg = { ...bg, gradient: bg.gradient ? { ...bg.gradient, stops: bg.gradient.stops.map((s) => ({ ...s })) } : void 0 };
5874
7143
  }
5875
7144
  return out;
5876
7145
  };
5877
7146
  const originalToSVG = (_a = obj.toSVG) == null ? void 0 : _a.bind(obj);
5878
7147
  if (typeof originalToSVG === "function") {
5879
7148
  obj.toSVG = function(reviver) {
7149
+ var _a2, _b;
5880
7150
  let svg = originalToSVG(reviver);
5881
7151
  const bg = this[PD_BG_KEY];
5882
7152
  const shadow = this.shadow;
5883
7153
  const hasBg = hasTextBackground(bg);
5884
7154
  const hasShadow = !!shadow && !!shadow.color && shadow.color !== "transparent";
5885
- if (!hasBg && !hasShadow) return svg;
7155
+ const extOX = Number((bg == null ? void 0 : bg.shadowOffsetX) ?? 0) || 0;
7156
+ const extOY = Number((bg == null ? void 0 : bg.shadowOffsetY) ?? 0) || 0;
7157
+ const extDist = Math.hypot(extOX, extOY);
7158
+ const hasExtShadowColor = !!(bg == null ? void 0 : bg.shadowColor) && bg.shadowColor !== "transparent";
7159
+ const hasBlockShadow = !!bg && bg.shadowType === "block" && hasExtShadowColor && extDist > 0;
7160
+ const hasLineShadow = !!bg && bg.shadowType === "line" && hasExtShadowColor && extDist > 0;
7161
+ if (!hasBg && !hasShadow && !hasBlockShadow && !hasLineShadow) return svg;
7162
+ const hasActiveTextPath2 = !!(((_a2 = this.textPath) == null ? void 0 : _a2.preset) && this.textPath.preset !== "none");
5886
7163
  const w = this.width ?? 0;
5887
7164
  const h = this.height ?? 0;
5888
7165
  const pT = Math.max(0, Number((bg == null ? void 0 : bg.padTop) ?? 0));
@@ -5891,7 +7168,18 @@ function applyTextBackground(obj, cfg) {
5891
7168
  const pL = Math.max(0, Number((bg == null ? void 0 : bg.padLeft) ?? 0));
5892
7169
  const fit = !!(bg == null ? void 0 : bg.fitToText);
5893
7170
  const rects = computeBgRects(this, w, h, pT, pR, pB, pL, fit);
5894
- const bgD = rects.map((r) => buildRoundedRectPathD(
7171
+ const ribbonD = buildWarpRibbonD(
7172
+ this,
7173
+ pT,
7174
+ pR,
7175
+ pB,
7176
+ pL,
7177
+ (bg == null ? void 0 : bg.rxTL) ?? 0,
7178
+ (bg == null ? void 0 : bg.rxTR) ?? 0,
7179
+ (bg == null ? void 0 : bg.rxBR) ?? 0,
7180
+ (bg == null ? void 0 : bg.rxBL) ?? 0
7181
+ );
7182
+ const bgD = ribbonD ?? rects.map((r) => buildRoundedRectPathD(
5895
7183
  r.x,
5896
7184
  r.y,
5897
7185
  r.w,
@@ -5904,7 +7192,16 @@ function applyTextBackground(obj, cfg) {
5904
7192
  const bgFill = (bg == null ? void 0 : bg.color) || "";
5905
7193
  const bgOpacity = typeof (bg == null ? void 0 : bg.opacity) === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
5906
7194
  const bgOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
5907
- const bgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(bgFill)}"${bgOpacityAttr} />` : "";
7195
+ let bgGradDefs = "";
7196
+ let bgFillAttr = escapeXmlAttr(bgFill);
7197
+ if (hasBg && (bg == null ? void 0 : bg.gradient) && ((_b = bg.gradient.stops) == null ? void 0 : _b.length) >= 2) {
7198
+ const bounds = ribbonD ? computeRibbonBoundsFor(this, pT, pR, pB, pL) : unionBounds(rects);
7199
+ const gid = `__pdBgGrad_${Math.random().toString(36).slice(2, 9)}`;
7200
+ const def = buildSvgGradientDef(bg.gradient, gid, bounds.x, bounds.y, bounds.w, bounds.h);
7201
+ bgGradDefs = `<defs>${def}</defs>`;
7202
+ bgFillAttr = `url(#${gid})`;
7203
+ }
7204
+ const bgPath = hasBg ? `${bgGradDefs}<path class="__pdTextBgShape" d="${bgD}" fill="${bgFillAttr}"${bgOpacityAttr} />` : "";
5908
7205
  svg = svg.replace(/style="[^"]*filter:\s*url\([^)]+\)[^"]*"/i, "");
5909
7206
  svg = svg.replace(/<filter[\s\S]*?<\/filter>/gi, "");
5910
7207
  let bgShadowMarker = "";
@@ -5930,14 +7227,63 @@ function applyTextBackground(obj, cfg) {
5930
7227
  const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}"${shadowOpacityAttr} />`;
5931
7228
  bgShadowMarker = wrapShadow(shadowBgPath);
5932
7229
  }
5933
- if ((bg == null ? void 0 : bg.shadowAffectsText) !== false) {
7230
+ if ((bg == null ? void 0 : bg.shadowAffectsText) !== false && !hasActiveTextPath2) {
5934
7231
  const inner = extractGInnerMarkup(svg);
5935
7232
  const recoloredText = recolorSvgFills(inner, shadowColor);
5936
7233
  if (recoloredText) textShadowMarker = wrapShadow(recoloredText);
5937
7234
  }
5938
7235
  }
7236
+ let bgBlockShadowMarker = "";
7237
+ let textBlockShadowMarker = "";
7238
+ if (hasBlockShadow) {
7239
+ const STEP = 0.5;
7240
+ const steps = Math.min(600, Math.max(1, Math.ceil(extDist / STEP)));
7241
+ const stepX = extOX / steps;
7242
+ const stepY = extOY / steps;
7243
+ const shadowColor = String(bg.shadowColor);
7244
+ const fillObj = this.fill;
7245
+ const parentTextIsGradient = !!fillObj && typeof fillObj === "object" && (Array.isArray(fillObj.colorStops) || fillObj.type === "linear" || fillObj.type === "radial");
7246
+ const cloneOutlineAttr = parentTextIsGradient ? ' data-pd-outline-text="1"' : "";
7247
+ const buildCopies = (markup, cls) => {
7248
+ const parts = [];
7249
+ for (let i = steps; i >= 1; i--) {
7250
+ parts.push(`<g class="${cls}"${cloneOutlineAttr} transform="translate(${(stepX * i).toFixed(3)} ${(stepY * i).toFixed(3)})">${markup}</g>`);
7251
+ }
7252
+ return parts.join("");
7253
+ };
7254
+ if (hasBg && bg.shadowAffectsBg !== false) {
7255
+ const shadowOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
7256
+ const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}"${shadowOpacityAttr} />`;
7257
+ bgBlockShadowMarker = buildCopies(shadowBgPath, "__pdBgShadowClone");
7258
+ }
7259
+ if (bg.shadowAffectsText !== false) {
7260
+ const inner = extractGInnerMarkup(svg);
7261
+ const recoloredText = recolorSvgFills(inner, shadowColor);
7262
+ if (recoloredText) textBlockShadowMarker = buildCopies(recoloredText, "__pdTextShadowClone");
7263
+ }
7264
+ }
7265
+ let bgLineShadowMarker = "";
7266
+ let textLineShadowMarker = "";
7267
+ if (hasLineShadow) {
7268
+ const shadowColor = String(bg.shadowColor);
7269
+ const tx = extOX.toFixed(3);
7270
+ const ty = extOY.toFixed(3);
7271
+ const fillObjLine = this.fill;
7272
+ const parentTextIsGradientLine = !!fillObjLine && typeof fillObjLine === "object" && (Array.isArray(fillObjLine.colorStops) || fillObjLine.type === "linear" || fillObjLine.type === "radial");
7273
+ const lineOutlineAttr = parentTextIsGradientLine ? ' data-pd-outline-text="1"' : "";
7274
+ if (hasBg && bg.shadowAffectsBg !== false) {
7275
+ const outlineBg = `<path d="${bgD}" fill="none" stroke="${escapeXmlAttr(shadowColor)}" stroke-width="1" stroke-linejoin="round" />`;
7276
+ bgLineShadowMarker = `<g class="__pdBgShadowClone"${lineOutlineAttr} transform="translate(${tx} ${ty})">${outlineBg}</g>`;
7277
+ }
7278
+ if (bg.shadowAffectsText !== false) {
7279
+ const inner = extractGInnerMarkup(svg);
7280
+ const strokeW = LINE_SHADOW_STROKE_WIDTH;
7281
+ const outlined = outlineTextSvgForLineShadow(inner, shadowColor, strokeW);
7282
+ if (outlined) textLineShadowMarker = `<g class="__pdTextShadowClone"${lineOutlineAttr} transform="translate(${tx} ${ty})">${outlined}</g>`;
7283
+ }
7284
+ }
5939
7285
  const openTagMatch = svg.match(/^\s*<g\b[^>]*>/);
5940
- const inserted = bgShadowMarker + bgPath + textShadowMarker;
7286
+ const inserted = bgBlockShadowMarker + bgLineShadowMarker + bgShadowMarker + bgPath + textBlockShadowMarker + textLineShadowMarker + textShadowMarker;
5941
7287
  const shadowBlur = hasShadow ? Math.max(0, Number(shadow.blur ?? 0)) : 0;
5942
7288
  const decorationTags = [
5943
7289
  shadowBlur > 0 ? 'data-pd-shadow-blur="1"' : "",
@@ -5957,7 +7303,38 @@ function recolorSvgFills(svg, color) {
5957
7303
  return _recolorSvgFills(svg, color);
5958
7304
  }
5959
7305
  function _recolorSvgFills(svg, color) {
7306
+ var _a;
5960
7307
  const safe = escapeXmlAttr(color);
7308
+ try {
7309
+ const wrapped = `<svg xmlns="http://www.w3.org/2000/svg">${svg}</svg>`;
7310
+ const doc = new DOMParser().parseFromString(wrapped, "image/svg+xml");
7311
+ const root = doc.documentElement;
7312
+ if (root && root.nodeName !== "parsererror") {
7313
+ for (const g of Array.from(root.querySelectorAll("linearGradient, radialGradient, pattern"))) {
7314
+ try {
7315
+ (_a = g.parentNode) == null ? void 0 : _a.removeChild(g);
7316
+ } catch {
7317
+ }
7318
+ }
7319
+ for (const el of Array.from(root.querySelectorAll("text, tspan, path, rect"))) {
7320
+ const cur = el.getAttribute("fill");
7321
+ if (cur && (cur.trim().toLowerCase() === "none" || cur.trim().toLowerCase() === "transparent")) continue;
7322
+ const style = el.getAttribute("style");
7323
+ if (style && /fill\s*:/i.test(style)) {
7324
+ const cleaned = style.replace(/(?:^|;)\s*fill\s*:[^;]*/gi, "").replace(/^;+/, "").trim();
7325
+ if (cleaned) el.setAttribute("style", cleaned);
7326
+ else el.removeAttribute("style");
7327
+ }
7328
+ el.setAttribute("fill", color);
7329
+ }
7330
+ let out2 = "";
7331
+ for (const child of Array.from(root.childNodes)) {
7332
+ out2 += new XMLSerializer().serializeToString(child);
7333
+ }
7334
+ return out2;
7335
+ }
7336
+ } catch {
7337
+ }
5961
7338
  let out = svg.replace(
5962
7339
  /(<(?:text|tspan|path|rect)\b[^>]*?\sfill=")([^"]*)("[^>]*>)/gi,
5963
7340
  (_m, pre, val, post) => {
@@ -5973,6 +7350,11 @@ function _recolorSvgFills(svg, color) {
5973
7350
  return pre + replaced + post;
5974
7351
  }
5975
7352
  );
7353
+ out = out.replace(/<(text|tspan|path)\b([^>]*)>/gi, (m, tag, attrs) => {
7354
+ if (/\sfill=/i.test(attrs)) return m;
7355
+ if (/style="[^"]*\bfill\s*:/i.test(attrs)) return m;
7356
+ return `<${tag}${attrs} fill="${safe}">`;
7357
+ });
5976
7358
  return out;
5977
7359
  }
5978
7360
  function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
@@ -6111,6 +7493,239 @@ function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
6111
7493
  function escapeXmlAttr(s) {
6112
7494
  return String(s).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
6113
7495
  }
7496
+ function buildWarpRibbonD(obj, pT, pR, pB, pL, rxTL, rxTR, rxBR, rxBL) {
7497
+ const tp = obj == null ? void 0 : obj.textPath;
7498
+ if (!tp || !tp.preset || tp.preset === "none") return null;
7499
+ if (tp.preset === "rise" || tp.preset === "angle") return null;
7500
+ const w = Number(obj.width) || 0;
7501
+ const h = Number(obj.height) || 0;
7502
+ const fs = Number(obj.fontSize) || 16;
7503
+ const resolved = resolveTextPath(tp, w, fs);
7504
+ if (!resolved) return null;
7505
+ const pathEl = measurePath(resolved.d);
7506
+ if (!pathEl) return null;
7507
+ const len = pathEl.getTotalLength();
7508
+ if (!Number.isFinite(len) || len <= 0) return null;
7509
+ const halfW = w / 2;
7510
+ const halfH = h / 2;
7511
+ const topT = halfH + Math.max(0, pT);
7512
+ const botT = halfH + Math.max(0, pB);
7513
+ const padL = Math.max(0, pL);
7514
+ const padR = Math.max(0, pR);
7515
+ const sample = (s) => {
7516
+ const ss = Math.max(0, Math.min(len, s));
7517
+ const p = pathEl.getPointAtLength(ss);
7518
+ const a = pathEl.getPointAtLength(Math.min(len, ss + 0.5));
7519
+ const b = pathEl.getPointAtLength(Math.max(0, ss - 0.5));
7520
+ let tx = a.x - b.x;
7521
+ let ty = a.y - b.y;
7522
+ const tl = Math.hypot(tx, ty) || 1;
7523
+ tx /= tl;
7524
+ ty /= tl;
7525
+ return { px: p.x - halfW, py: p.y - halfH, tx, ty, nx: ty, ny: -tx };
7526
+ };
7527
+ const SAMPLES = 96;
7528
+ const topPts = [];
7529
+ const botPts = [];
7530
+ for (let i = 0; i <= SAMPLES; i++) {
7531
+ const s = len * i / SAMPLES;
7532
+ const { px, py, nx, ny } = sample(s);
7533
+ topPts.push([px + nx * topT, py + ny * topT]);
7534
+ botPts.push([px - nx * botT, py - ny * botT]);
7535
+ }
7536
+ const s0 = sample(0);
7537
+ const s1 = sample(len);
7538
+ const TL = [s0.px - s0.tx * padL + s0.nx * topT, s0.py - s0.ty * padL + s0.ny * topT];
7539
+ const BL = [s0.px - s0.tx * padL - s0.nx * botT, s0.py - s0.ty * padL - s0.ny * botT];
7540
+ const TR = [s1.px + s1.tx * padR + s1.nx * topT, s1.py + s1.ty * padR + s1.ny * topT];
7541
+ const BR = [s1.px + s1.tx * padR - s1.nx * botT, s1.py + s1.ty * padR - s1.ny * botT];
7542
+ topPts[0] = TL;
7543
+ topPts[topPts.length - 1] = TR;
7544
+ botPts[0] = BL;
7545
+ botPts[botPts.length - 1] = BR;
7546
+ const capH = topT + botT;
7547
+ const maxLeftR = Math.min(capH * 0.5, len * 0.5 + padL);
7548
+ const maxRightR = Math.min(capH * 0.5, len * 0.5 + padR);
7549
+ const clamp2 = (r, m) => Math.max(0, Math.min(Number(r) || 0, m));
7550
+ const cTL = clamp2(rxTL, maxLeftR);
7551
+ const cBL = clamp2(rxBL, maxLeftR);
7552
+ const cTR = clamp2(rxTR, maxRightR);
7553
+ const cBR = clamp2(rxBR, maxRightR);
7554
+ const dist = (a, b) => Math.hypot(b[0] - a[0], b[1] - a[1]);
7555
+ const inset = (from, toward, d) => {
7556
+ const dx = toward[0] - from[0];
7557
+ const dy = toward[1] - from[1];
7558
+ const L = Math.hypot(dx, dy) || 1;
7559
+ const k = Math.min(d, L) / L;
7560
+ return [from[0] + dx * k, from[1] + dy * k];
7561
+ };
7562
+ const walkEdge = (pts, target, fromStart) => {
7563
+ if (target <= 0) {
7564
+ const idx = fromStart ? 0 : pts.length - 1;
7565
+ return { pt: [pts[idx][0], pts[idx][1]], cutIdx: idx };
7566
+ }
7567
+ let acc = 0;
7568
+ if (fromStart) {
7569
+ for (let i = 1; i < pts.length; i++) {
7570
+ const seg = dist(pts[i - 1], pts[i]);
7571
+ if (acc + seg >= target) {
7572
+ const k = (target - acc) / (seg || 1);
7573
+ const pt = [
7574
+ pts[i - 1][0] + (pts[i][0] - pts[i - 1][0]) * k,
7575
+ pts[i - 1][1] + (pts[i][1] - pts[i - 1][1]) * k
7576
+ ];
7577
+ return { pt, cutIdx: i - 1 };
7578
+ }
7579
+ acc += seg;
7580
+ }
7581
+ return { pt: pts[pts.length - 1], cutIdx: pts.length - 1 };
7582
+ }
7583
+ for (let i = pts.length - 2; i >= 0; i--) {
7584
+ const seg = dist(pts[i + 1], pts[i]);
7585
+ if (acc + seg >= target) {
7586
+ const k = (target - acc) / (seg || 1);
7587
+ const pt = [
7588
+ pts[i + 1][0] + (pts[i][0] - pts[i + 1][0]) * k,
7589
+ pts[i + 1][1] + (pts[i][1] - pts[i + 1][1]) * k
7590
+ ];
7591
+ return { pt, cutIdx: i + 1 };
7592
+ }
7593
+ acc += seg;
7594
+ }
7595
+ return { pt: pts[0], cutIdx: 0 };
7596
+ };
7597
+ const topStart = walkEdge(topPts, cTL, true);
7598
+ const topEnd = walkEdge(topPts, cTR, false);
7599
+ const botStart = walkEdge(botPts, cBL, true);
7600
+ const botEnd = walkEdge(botPts, cBR, false);
7601
+ const insTL_top = topStart.pt;
7602
+ const insTR_top = topEnd.pt;
7603
+ const insBL_bot = botStart.pt;
7604
+ const insBR_bot = botEnd.pt;
7605
+ const insTL_cap = inset(TL, BL, cTL);
7606
+ const insBL_cap = inset(BL, TL, cBL);
7607
+ const insBR_cap = inset(BR, TR, cBR);
7608
+ const insTR_cap = inset(TR, BR, cTR);
7609
+ const fmt = (p) => `${p[0].toFixed(2)} ${p[1].toFixed(2)}`;
7610
+ const parts = [];
7611
+ parts.push(`M ${fmt(insTL_top)}`);
7612
+ for (let i = topStart.cutIdx + 1; i <= topEnd.cutIdx; i++) parts.push(`L ${fmt(topPts[i])}`);
7613
+ parts.push(`L ${fmt(insTR_top)}`);
7614
+ parts.push(`Q ${fmt(TR)} ${fmt(insTR_cap)}`);
7615
+ parts.push(`L ${fmt(insBR_cap)}`);
7616
+ parts.push(`Q ${fmt(BR)} ${fmt(insBR_bot)}`);
7617
+ for (let i = botEnd.cutIdx - 1; i >= botStart.cutIdx + 1; i--) parts.push(`L ${fmt(botPts[i])}`);
7618
+ parts.push(`L ${fmt(insBL_bot)}`);
7619
+ parts.push(`Q ${fmt(BL)} ${fmt(insBL_cap)}`);
7620
+ parts.push(`L ${fmt(insTL_cap)}`);
7621
+ parts.push(`Q ${fmt(TL)} ${fmt(insTL_top)}`);
7622
+ parts.push("Z");
7623
+ return parts.join(" ");
7624
+ }
7625
+ function computeRibbonBoundsFor(obj, pT, pR, pB, pL) {
7626
+ const tp = obj == null ? void 0 : obj.textPath;
7627
+ if (!tp || !tp.preset || tp.preset === "none") {
7628
+ const w2 = Number(obj.width) || 0;
7629
+ const h2 = Number(obj.height) || 0;
7630
+ return { x: -w2 / 2 - pL, y: -h2 / 2 - pT, w: w2 + pL + pR, h: h2 + pT + pB };
7631
+ }
7632
+ const w = Number(obj.width) || 0;
7633
+ const h = Number(obj.height) || 0;
7634
+ const fs = Number(obj.fontSize) || 16;
7635
+ const resolved = resolveTextPath(tp, w, fs);
7636
+ const pathEl = resolved ? measurePath(resolved.d) : null;
7637
+ const len = pathEl ? pathEl.getTotalLength() : 0;
7638
+ if (!pathEl || !Number.isFinite(len) || len <= 0) {
7639
+ return { x: -w / 2 - pL, y: -h / 2 - pT, w: w + pL + pR, h: h + pT + pB };
7640
+ }
7641
+ const halfW = w / 2;
7642
+ const halfH = h / 2;
7643
+ const topT = halfH + Math.max(0, pT);
7644
+ const botT = halfH + Math.max(0, pB);
7645
+ const STEPS = 48;
7646
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
7647
+ const ext = (x, y) => {
7648
+ if (x < minX) minX = x;
7649
+ if (y < minY) minY = y;
7650
+ if (x > maxX) maxX = x;
7651
+ if (y > maxY) maxY = y;
7652
+ };
7653
+ for (let i = 0; i <= STEPS; i++) {
7654
+ const s = len * i / STEPS;
7655
+ const p = pathEl.getPointAtLength(s);
7656
+ const a = pathEl.getPointAtLength(Math.min(len, s + 0.5));
7657
+ const b = pathEl.getPointAtLength(Math.max(0, s - 0.5));
7658
+ let tx = a.x - b.x;
7659
+ let ty = a.y - b.y;
7660
+ const tl = Math.hypot(tx, ty) || 1;
7661
+ tx /= tl;
7662
+ ty /= tl;
7663
+ const nx = ty, ny = -tx;
7664
+ const px = p.x - halfW, py = p.y - halfH;
7665
+ ext(px + nx * topT, py + ny * topT);
7666
+ ext(px - nx * botT, py - ny * botT);
7667
+ }
7668
+ if (pL > 0 || pR > 0) {
7669
+ minX -= pL;
7670
+ maxX += pR;
7671
+ }
7672
+ return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };
7673
+ }
7674
+ function normalizeStops(stops) {
7675
+ const out = stops.map((s) => ({ color: s.color, offset: Math.max(0, Math.min(1, Number(s.offset) || 0)) })).sort((a, b) => a.offset - b.offset);
7676
+ if (out.length === 0) return out;
7677
+ if (out[0].offset > 0) out.unshift({ color: out[0].color, offset: 0 });
7678
+ if (out[out.length - 1].offset < 1) out.push({ color: out[out.length - 1].color, offset: 1 });
7679
+ return out;
7680
+ }
7681
+ function buildCanvasGradient(ctx, g, bx, by, bw, bh) {
7682
+ const stops = normalizeStops(g.stops);
7683
+ if (stops.length === 0) return "#000";
7684
+ if (g.type === "radial") {
7685
+ const cx = bx + (g.cx ?? 0.5) * bw;
7686
+ const cy = by + (g.cy ?? 0.5) * bh;
7687
+ const r = Math.max(1, (g.r ?? 0.5) * Math.max(bw, bh));
7688
+ const cg2 = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);
7689
+ stops.forEach((s) => {
7690
+ try {
7691
+ cg2.addColorStop(s.offset, s.color);
7692
+ } catch {
7693
+ }
7694
+ });
7695
+ return cg2;
7696
+ }
7697
+ const angle = g.angle ?? 90;
7698
+ const rad = angle * Math.PI / 180;
7699
+ const x1 = bx + (0.5 - Math.sin(rad) * 0.5) * bw;
7700
+ const y1 = by + (0.5 + Math.cos(rad) * 0.5) * bh;
7701
+ const x2 = bx + (0.5 + Math.sin(rad) * 0.5) * bw;
7702
+ const y2 = by + (0.5 - Math.cos(rad) * 0.5) * bh;
7703
+ const cg = ctx.createLinearGradient(x1, y1, x2, y2);
7704
+ stops.forEach((s) => {
7705
+ try {
7706
+ cg.addColorStop(s.offset, s.color);
7707
+ } catch {
7708
+ }
7709
+ });
7710
+ return cg;
7711
+ }
7712
+ function buildSvgGradientDef(g, id, bx, by, bw, bh) {
7713
+ const stops = normalizeStops(g.stops);
7714
+ const stopsXml = stops.map((s) => `<stop offset="${s.offset}" stop-color="${escapeXmlAttr(s.color)}" />`).join("");
7715
+ if (g.type === "radial") {
7716
+ const cx = bx + (g.cx ?? 0.5) * bw;
7717
+ const cy = by + (g.cy ?? 0.5) * bh;
7718
+ const r = Math.max(1, (g.r ?? 0.5) * Math.max(bw, bh));
7719
+ return `<radialGradient id="${id}" gradientUnits="userSpaceOnUse" cx="${cx.toFixed(3)}" cy="${cy.toFixed(3)}" r="${r.toFixed(3)}" fx="${cx.toFixed(3)}" fy="${cy.toFixed(3)}">${stopsXml}</radialGradient>`;
7720
+ }
7721
+ const angle = g.angle ?? 90;
7722
+ const rad = angle * Math.PI / 180;
7723
+ const x1 = bx + (0.5 - Math.sin(rad) * 0.5) * bw;
7724
+ const y1 = by + (0.5 + Math.cos(rad) * 0.5) * bh;
7725
+ const x2 = bx + (0.5 + Math.sin(rad) * 0.5) * bw;
7726
+ const y2 = by + (0.5 - Math.cos(rad) * 0.5) * bh;
7727
+ return `<linearGradient id="${id}" gradientUnits="userSpaceOnUse" x1="${x1.toFixed(3)}" y1="${y1.toFixed(3)}" x2="${x2.toFixed(3)}" y2="${y2.toFixed(3)}">${stopsXml}</linearGradient>`;
7728
+ }
6114
7729
  function extractGInnerMarkup(markup) {
6115
7730
  const openMatch = markup.match(/^\s*<g\b[^>]*>/);
6116
7731
  if (!openMatch) return markup;
@@ -6118,6 +7733,37 @@ function extractGInnerMarkup(markup) {
6118
7733
  if (closeIdx <= openMatch[0].length) return markup;
6119
7734
  return markup.slice(openMatch[0].length, closeIdx);
6120
7735
  }
7736
+ function outlineTextSvgForLineShadow(inner, strokeColor, strokeWidth) {
7737
+ if (!inner) return "";
7738
+ try {
7739
+ const wrapped = `<svg xmlns="http://www.w3.org/2000/svg">${inner}</svg>`;
7740
+ const doc = new DOMParser().parseFromString(wrapped, "image/svg+xml");
7741
+ const root = doc.documentElement;
7742
+ if (!root || root.nodeName === "parsererror") return "";
7743
+ const targets = Array.from(root.querySelectorAll("text, tspan"));
7744
+ if (!targets.length) return "";
7745
+ for (const el of targets) {
7746
+ const style = el.getAttribute("style");
7747
+ if (style) {
7748
+ const cleaned = style.replace(/(?:^|;)\s*fill\s*:[^;]*/gi, "").replace(/(?:^|;)\s*stroke(?:-[a-z]+)?\s*:[^;]*/gi, "").replace(/^;+/, "").trim();
7749
+ if (cleaned) el.setAttribute("style", cleaned);
7750
+ else el.removeAttribute("style");
7751
+ }
7752
+ el.setAttribute("fill", "none");
7753
+ el.setAttribute("stroke", strokeColor);
7754
+ el.setAttribute("stroke-width", strokeWidth.toFixed(3));
7755
+ el.setAttribute("stroke-linejoin", "round");
7756
+ el.setAttribute("paint-order", "stroke");
7757
+ }
7758
+ let out = "";
7759
+ for (const child of Array.from(root.childNodes)) {
7760
+ out += new XMLSerializer().serializeToString(child);
7761
+ }
7762
+ return out;
7763
+ } catch {
7764
+ return "";
7765
+ }
7766
+ }
6121
7767
  const TRIANGLE_STROKE_MITER_LIMIT = 1e6;
6122
7768
  const toSafeNumber = (value, fallback = 0) => Number.isFinite(value) ? Math.max(0, Number(value)) : fallback;
6123
7769
  function normalizeShapeType(shapeType) {
@@ -6746,7 +8392,8 @@ function createText(element) {
6746
8392
  // same value as a fit-target, so the rendered box and the shrink target
6747
8393
  // stay in sync (parity with the Use page / EC2 renderer).
6748
8394
  ...(element.minBoxHeight ?? 0) > 0 ? { minBoxHeight: element.minBoxHeight } : {},
6749
- verticalAlign: element.verticalAlign || "top"
8395
+ verticalAlign: element.verticalAlign || "top",
8396
+ ...element.textPath && element.textPath.preset && element.textPath.preset !== "none" ? { textPath: element.textPath } : {}
6750
8397
  });
6751
8398
  textbox.__formattingEnabled = formattingEnabled;
6752
8399
  textbox.initDimensions();
@@ -6853,6 +8500,9 @@ function createFabricObject(element) {
6853
8500
  if (element.type === "shape" || element.type === "line" || element.type === "text") {
6854
8501
  applyInitialGradients(obj, element);
6855
8502
  }
8503
+ if (element.type === "text" && obj instanceof fabric.Textbox) {
8504
+ applyTextPathControls(obj);
8505
+ }
6856
8506
  }
6857
8507
  return obj;
6858
8508
  }
@@ -7039,7 +8689,7 @@ const progressDefinition = {
7039
8689
  ],
7040
8690
  render: renderProgressSvg
7041
8691
  };
7042
- function escapeXml(str) {
8692
+ function escapeXml$1(str) {
7043
8693
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7044
8694
  }
7045
8695
  function estimateTextWidth(text, fontSize, fontWeight) {
@@ -7086,7 +8736,7 @@ function renderTableSvg(props, width, height) {
7086
8736
  if (text) {
7087
8737
  const maxChars = Math.max(3, Math.floor(cellW / (fontSize * 0.55)));
7088
8738
  const displayText = text.length > maxChars ? text.slice(0, maxChars - 1) + "…" : text;
7089
- svg += `<text x="${x + cellW / 2}" y="${y + cellH / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml(displayText)}</text>`;
8739
+ svg += `<text x="${x + cellW / 2}" y="${y + cellH / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml$1(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml$1(displayText)}</text>`;
7090
8740
  }
7091
8741
  }
7092
8742
  }
@@ -7153,7 +8803,7 @@ function renderAvatarSvg(props, width, height) {
7153
8803
  }
7154
8804
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
7155
8805
  ${shapeSvg}
7156
- <text x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml(fontFamily)}" font-weight="600" fill="${textColor}">${initials}</text>
8806
+ <text x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml$1(fontFamily)}" font-weight="600" fill="${textColor}">${initials}</text>
7157
8807
  </svg>`;
7158
8808
  }
7159
8809
  const avatarDefinition = {
@@ -7244,7 +8894,7 @@ function renderBadgeInternal(props, width, height) {
7244
8894
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${finalWidth}" height="${height}" viewBox="0 0 ${finalWidth} ${height}">
7245
8895
  <rect x="${inset}" y="${inset}" width="${finalWidth - borderWidth}" height="${height - borderWidth}" rx="${rx}" fill="${bgColor}" stroke="${borderColor}" stroke-width="${borderWidth}"/>
7246
8896
  ${iconSvg}
7247
- <text x="${textX}" y="${height / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml(displayText)}</text>
8897
+ <text x="${textX}" y="${height / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml$1(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml$1(displayText)}</text>
7248
8898
  </svg>`;
7249
8899
  return { svg, computedWidth, anchor };
7250
8900
  }
@@ -8918,6 +10568,9 @@ const PageCanvas = forwardRef(
8918
10568
  if (typeof baked === "number" && baked > 0) {
8919
10569
  elementUpdate.minBoxHeight = baked;
8920
10570
  }
10571
+ if (obj.textPath) {
10572
+ elementUpdate.textPath = obj.textPath;
10573
+ }
8921
10574
  }
8922
10575
  if (sourceElement && sourceElement.opacity !== void 0) {
8923
10576
  elementUpdate.opacity = sourceElement.opacity;
@@ -9652,6 +11305,7 @@ const PageCanvas = forwardRef(
9652
11305
  (existingObj.verticalAlign ?? "top") !== (element.verticalAlign ?? "top") || Math.abs((existingObj.minBoxHeight ?? 0) - (element.minBoxHeight ?? 0)) > 0.1 || // Detect text background + shadow changes so panel edits flow into Fabric.
9653
11306
  JSON.stringify({
9654
11307
  c: element.textBgColor ?? null,
11308
+ g: element.textBgGradient ?? null,
9655
11309
  p: element.textBgPadding ?? 0,
9656
11310
  pt: element.textBgPaddingTop ?? null,
9657
11311
  pr: element.textBgPaddingRight ?? null,
@@ -9670,7 +11324,7 @@ const PageCanvas = forwardRef(
9670
11324
  st: element.textShadowAffectsText !== false,
9671
11325
  sa: element.textShadowAffectsBg !== false
9672
11326
  }) !== (existingObj.__lastTextBgShadowJson ?? "") || // CRITICAL: Detect gradient fill/stroke changes — serialise to JSON for deep comparison
9673
- JSON.stringify(element.fillGradient || null) !== (existingObj.__lastFillGradientJson ?? "null") || JSON.stringify(element.strokeGradient || null) !== (existingObj.__lastStrokeGradientJson ?? "null");
11327
+ JSON.stringify(element.fillGradient || null) !== (existingObj.__lastFillGradientJson ?? "null") || JSON.stringify(element.strokeGradient || null) !== (existingObj.__lastStrokeGradientJson ?? "null") || JSON.stringify(element.textPath || null) !== JSON.stringify(existingObj.textPath || null);
9674
11328
  const forceApplyFromPanel = syncTriggeredByPanelRef.current;
9675
11329
  const noPropsOrPositionChanged = !positionChanged && !otherPropsChanged;
9676
11330
  if (noPropsOrPositionChanged && !forceApplyFromPanel || visibilityUpdateInProgressRef.current) {
@@ -10104,7 +11758,7 @@ const PageCanvas = forwardRef(
10104
11758
  });
10105
11759
  }, [selectedIds, isActive, ready, elements]);
10106
11760
  const updateFabricObject = (obj, element, skipPositionUpdate = false) => {
10107
- var _a, _b;
11761
+ var _a, _b, _c;
10108
11762
  const fc = fabricRef.current;
10109
11763
  if (fc && isTransforming(fc)) {
10110
11764
  return;
@@ -10381,6 +12035,8 @@ const PageCanvas = forwardRef(
10381
12035
  obj.setCoords();
10382
12036
  }
10383
12037
  if (!isLine) {
12038
+ const angleTextPathActive = isTextbox && ((_b = element.textPath) == null ? void 0 : _b.preset) === "rise";
12039
+ const appliedSkewY = angleTextPathActive ? 0 : element.skewY ?? 0;
10384
12040
  let posIfNotSkipped = skipPositionUpdate ? {} : { left: fabricPos.left, top: fabricPos.top };
10385
12041
  if (!skipPositionUpdate && obj instanceof fabric.FabricImage && obj.originX === "center") {
10386
12042
  const vW = rW * effectiveScaleX;
@@ -10396,7 +12052,7 @@ const PageCanvas = forwardRef(
10396
12052
  scaleY: effectiveScaleY,
10397
12053
  angle: element.angle ?? 0,
10398
12054
  skewX: element.skewX ?? 0,
10399
- skewY: element.skewY ?? 0
12055
+ skewY: appliedSkewY
10400
12056
  });
10401
12057
  } else {
10402
12058
  obj.set({
@@ -10416,7 +12072,7 @@ const PageCanvas = forwardRef(
10416
12072
  width: rW,
10417
12073
  angle: element.angle ?? 0,
10418
12074
  skewX: element.skewX ?? 0,
10419
- skewY: element.skewY ?? 0,
12075
+ skewY: appliedSkewY,
10420
12076
  scaleX: effectiveScaleX * baseScaleX,
10421
12077
  scaleY: effectiveScaleY * baseScaleY
10422
12078
  });
@@ -10548,7 +12204,9 @@ const PageCanvas = forwardRef(
10548
12204
  dynamicMinWidth: 0,
10549
12205
  fontSize,
10550
12206
  fontFamily: element.fontFamily || "Open Sans",
10551
- fill: element.fill || "#1a1a1a",
12207
+ // If a gradient fill is active, do not briefly overwrite it with the
12208
+ // stored solid fallback while applying textPath/panel updates.
12209
+ fill: element.fillGradient && isGradientConfig(element.fillGradient) ? obj.fill : element.fill || "#1a1a1a",
10552
12210
  fontWeight: element.fontWeight || 400,
10553
12211
  textAlign: element.textAlign || "left",
10554
12212
  fontStyle: element.fontStyle || "normal",
@@ -10565,6 +12223,13 @@ const PageCanvas = forwardRef(
10565
12223
  const minBoxH = Math.max(0, Number(element.minBoxHeight) || 0);
10566
12224
  obj.verticalAlign = valign;
10567
12225
  obj.minBoxHeight = minBoxH;
12226
+ const nextTextPath = element.textPath;
12227
+ if (nextTextPath && nextTextPath.preset && nextTextPath.preset !== "none") {
12228
+ obj.textPath = nextTextPath;
12229
+ } else {
12230
+ obj.textPath = void 0;
12231
+ }
12232
+ applyTextPathControls(obj);
10568
12233
  if (element.formattingEnabled === true) {
10569
12234
  obj.styles = parsedStyles || {};
10570
12235
  } else {
@@ -10587,9 +12252,10 @@ const PageCanvas = forwardRef(
10587
12252
  } catch {
10588
12253
  }
10589
12254
  obj.dirty = true;
10590
- (_b = obj.setCoords) == null ? void 0 : _b.call(obj);
12255
+ (_c = obj.setCoords) == null ? void 0 : _c.call(obj);
10591
12256
  obj.__lastTextBgShadowJson = JSON.stringify({
10592
12257
  c: element.textBgColor ?? null,
12258
+ g: element.textBgGradient ?? null,
10593
12259
  p: element.textBgPadding ?? 0,
10594
12260
  pt: element.textBgPaddingTop ?? null,
10595
12261
  pr: element.textBgPaddingRight ?? null,
@@ -10606,7 +12272,8 @@ const PageCanvas = forwardRef(
10606
12272
  sx: element.textShadowOffsetX ?? 0,
10607
12273
  sy: element.textShadowOffsetY ?? 0,
10608
12274
  st: element.textShadowAffectsText !== false,
10609
- sa: element.textShadowAffectsBg !== false
12275
+ sa: element.textShadowAffectsBg !== false,
12276
+ sty: element.textShadowType ?? null
10610
12277
  });
10611
12278
  obj.dirty = true;
10612
12279
  } catch (err) {
@@ -11019,9 +12686,7 @@ const PageCanvas = forwardRef(
11019
12686
  }
11020
12687
  try {
11021
12688
  let url = getProxiedImageUrl(imageUrl);
11022
- const hasColorOverrides = Boolean(element.svgColorMap && Object.keys(element.svgColorMap).length > 0);
11023
- const isInlineSvgDataUrl = imageUrl.startsWith("data:image/svg+xml");
11024
- if (isSvgImage(imageUrl, element.sourceFormat) && (!isInlineSvgDataUrl || hasColorOverrides)) {
12689
+ if (isSvgImage(imageUrl, element.sourceFormat)) {
11025
12690
  const normalized = await getNormalizedSvgUrl(imageUrl, element.svgColorMap, element.sourceFormat);
11026
12691
  if (!isLatestRequest()) return;
11027
12692
  if (normalized) url = normalized;
@@ -15718,7 +17383,7 @@ async function resolveTemplateData(options) {
15718
17383
  }
15719
17384
  }
15720
17385
  if (repeatableSectionsInput.length > 0) {
15721
- paintRepeatableSections(config, repeatableSectionsInput, inlineFormSchema == null ? void 0 : inlineFormSchema.entryFilters);
17386
+ paintRepeatableSections(config, repeatableSectionsInput);
15722
17387
  }
15723
17388
  }
15724
17389
  const mergedFormData = {
@@ -15789,7 +17454,7 @@ async function resolveFromForm(options) {
15789
17454
  normalizeLayoutModes(templateConfig);
15790
17455
  const repeatableFromSchema = templateFormSchema == null ? void 0 : templateFormSchema.repeatableSections;
15791
17456
  if ((repeatableFromSchema == null ? void 0 : repeatableFromSchema.length) && templateConfig.pages) {
15792
- paintRepeatableSections(templateConfig, repeatableFromSchema, templateFormSchema == null ? void 0 : templateFormSchema.entryFilters);
17457
+ paintRepeatableSections(templateConfig, repeatableFromSchema);
15793
17458
  }
15794
17459
  const schemaSections = getRenderableFormSections(formSchema);
15795
17460
  const repeatableNodeMap = /* @__PURE__ */ new Map();
@@ -16788,6 +18453,312 @@ function normalizeSvgDimensions(svg, targetWidth, targetHeight) {
16788
18453
  function isTextboxLike(obj) {
16789
18454
  return !!obj && (obj instanceof fabric.Textbox || obj.type === "textbox" || Array.isArray(obj == null ? void 0 : obj._textLines) && typeof obj.getLineWidth === "function");
16790
18455
  }
18456
+ function escapeXml(s) {
18457
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
18458
+ }
18459
+ function ensureFabricGradientDef(doc, obj, width, height) {
18460
+ const grad = obj == null ? void 0 : obj.fill;
18461
+ if (!grad || typeof grad !== "object" || !Array.isArray(grad.colorStops) || !grad.coords) return "";
18462
+ const id = `pixldocs_text_grad_${String(obj.__docuforgeId || grad.id || Math.random()).replace(/[^a-zA-Z0-9_-]/g, "_")}`;
18463
+ if (doc.getElementById(id)) return `url(#${id})`;
18464
+ const ns = "http://www.w3.org/2000/svg";
18465
+ let defs = doc.querySelector("defs");
18466
+ if (!defs) {
18467
+ defs = doc.createElementNS(ns, "defs");
18468
+ doc.documentElement.insertBefore(defs, doc.documentElement.firstChild);
18469
+ }
18470
+ const c = grad.coords || {};
18471
+ const el = doc.createElementNS(ns, grad.type === "radial" ? "radialGradient" : "linearGradient");
18472
+ el.setAttribute("id", id);
18473
+ el.setAttribute("gradientUnits", "userSpaceOnUse");
18474
+ if (grad.type === "radial") {
18475
+ el.setAttribute("cx", (Number(c.x2 ?? c.x1 ?? width / 2) - width / 2).toFixed(3));
18476
+ el.setAttribute("cy", (Number(c.y2 ?? c.y1 ?? height / 2) - height / 2).toFixed(3));
18477
+ el.setAttribute("fx", (Number(c.x1 ?? c.x2 ?? width / 2) - width / 2).toFixed(3));
18478
+ el.setAttribute("fy", (Number(c.y1 ?? c.y2 ?? height / 2) - height / 2).toFixed(3));
18479
+ el.setAttribute("r", Math.max(0.1, Number(c.r2 ?? c.r ?? Math.max(width, height) / 2)).toFixed(3));
18480
+ } else {
18481
+ el.setAttribute("x1", (Number(c.x1) - width / 2).toFixed(3));
18482
+ el.setAttribute("y1", (Number(c.y1) - height / 2).toFixed(3));
18483
+ el.setAttribute("x2", (Number(c.x2 ?? width) - width / 2).toFixed(3));
18484
+ el.setAttribute("y2", (Number(c.y2) - height / 2).toFixed(3));
18485
+ }
18486
+ for (const stop of grad.colorStops) {
18487
+ const stopEl = doc.createElementNS(ns, "stop");
18488
+ stopEl.setAttribute("offset", String(Math.max(0, Math.min(1, Number(stop.offset) || 0))));
18489
+ stopEl.setAttribute("stop-color", stop.color || "#000000");
18490
+ el.appendChild(stopEl);
18491
+ }
18492
+ defs.appendChild(el);
18493
+ return `url(#${id})`;
18494
+ }
18495
+ function warpTextboxSvgAlongPath(svg, obj) {
18496
+ var _a, _b, _c, _d, _e;
18497
+ const tp = obj == null ? void 0 : obj.textPath;
18498
+ if (!tp || !tp.preset || tp.preset === "none") return svg;
18499
+ if (tp.preset === "rise" || tp.preset === "angle") {
18500
+ const w2 = Number(obj.width) || 0;
18501
+ const h2 = Number(obj.height) || 0;
18502
+ const fs2 = Number(obj.fontSize) || 16;
18503
+ const ep = tp.endpoints;
18504
+ const defaultLeftY = fs2 * 1.5;
18505
+ const defaultRightY = fs2 * 0.5;
18506
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
18507
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
18508
+ const slope = w2 > 0 ? (rightY - leftY) / w2 : 0;
18509
+ const dy = (leftY + rightY) / 2 - h2 / 2;
18510
+ if (Math.abs(slope) < 1e-6 && Math.abs(dy) < 1e-6) return svg;
18511
+ let doc2;
18512
+ try {
18513
+ doc2 = new DOMParser().parseFromString(svg, "image/svg+xml");
18514
+ } catch {
18515
+ return svg;
18516
+ }
18517
+ const textEls2 = Array.from(doc2.querySelectorAll("text"));
18518
+ if (!textEls2.length) return svg;
18519
+ const matrix = `matrix(1 ${slope.toFixed(6)} 0 1 0 ${dy.toFixed(3)})`;
18520
+ for (const textEl2 of textEls2) {
18521
+ const existing = textEl2.getAttribute("transform");
18522
+ textEl2.setAttribute("transform", existing ? `${matrix} ${existing}` : matrix);
18523
+ }
18524
+ const bgShapes = Array.from(doc2.querySelectorAll("path.__pdTextBgShape"));
18525
+ for (const bgEl of bgShapes) {
18526
+ const existing = bgEl.getAttribute("transform");
18527
+ bgEl.setAttribute("transform", existing ? `${matrix} ${existing}` : matrix);
18528
+ }
18529
+ return new XMLSerializer().serializeToString(doc2.documentElement);
18530
+ }
18531
+ const resolved = resolveTextPath(tp, Number(obj.width) || 0, Number(obj.fontSize) || 16);
18532
+ if (!resolved) return svg;
18533
+ const pathEl = measurePath(resolved.d);
18534
+ if (!pathEl) return svg;
18535
+ const totalLen = pathEl.getTotalLength();
18536
+ if (!Number.isFinite(totalLen) || totalLen <= 0) return svg;
18537
+ const plain = String(obj.text || "").replace(/\n/g, " ");
18538
+ if (!plain) return svg;
18539
+ let doc;
18540
+ try {
18541
+ doc = new DOMParser().parseFromString(svg, "image/svg+xml");
18542
+ } catch {
18543
+ return svg;
18544
+ }
18545
+ for (const marker of Array.from(doc.querySelectorAll("g.__pdShadowRaster"))) {
18546
+ try {
18547
+ (_a = marker.parentNode) == null ? void 0 : _a.removeChild(marker);
18548
+ } catch {
18549
+ }
18550
+ }
18551
+ for (const clone of Array.from(doc.querySelectorAll("g.__pdTextShadowClone"))) {
18552
+ try {
18553
+ (_b = clone.parentNode) == null ? void 0 : _b.removeChild(clone);
18554
+ } catch {
18555
+ }
18556
+ }
18557
+ const textEls = Array.from(doc.querySelectorAll("text"));
18558
+ if (!textEls.length) return svg;
18559
+ const hasFilterInChain = (el) => {
18560
+ let cur = el;
18561
+ while (cur && cur !== doc.documentElement) {
18562
+ if (cur.getAttribute("filter") || /filter\s*:/i.test(cur.getAttribute("style") || "")) return true;
18563
+ cur = cur.parentElement;
18564
+ }
18565
+ return false;
18566
+ };
18567
+ const textEl = textEls.find((el) => !hasFilterInChain(el)) || textEls[textEls.length - 1] || textEls[0];
18568
+ const ff = obj.fontFamily || "Open Sans";
18569
+ const fs = Number(obj.fontSize) || 16;
18570
+ const fw = obj.fontWeight ?? 400;
18571
+ const fst = obj.fontStyle || "normal";
18572
+ const readFill = (el) => {
18573
+ var _a2, _b2;
18574
+ if (!el) return "";
18575
+ return el.getAttribute("fill") || ((_b2 = (_a2 = (el.getAttribute("style") || "").match(/(?:^|;)\s*fill\s*:\s*([^;]+)/i)) == null ? void 0 : _a2[1]) == null ? void 0 : _b2.trim()) || "";
18576
+ };
18577
+ const w = Number(obj.width) || 0;
18578
+ const h = Number(obj.height) || 0;
18579
+ const synthesizedGradientFill = ensureFabricGradientDef(doc, obj, w, h);
18580
+ const fabricGradientFill = obj.fill && typeof obj.fill === "object" && obj.fill.id != null ? `url(#SVGID_${obj.fill.id})` : "";
18581
+ const fillAttr = synthesizedGradientFill || readFill(textEl) || readFill(textEl.querySelector("tspan")) || fabricGradientFill || (typeof obj.fill === "string" ? obj.fill : "#000");
18582
+ const stripFilter = (el) => {
18583
+ if (!el) return;
18584
+ el.removeAttribute("filter");
18585
+ const style = el.getAttribute("style");
18586
+ if (style && /filter\s*:/i.test(style)) {
18587
+ el.setAttribute("style", style.replace(/(?:^|;)\s*filter\s*:[^;]*/gi, "").replace(/^;+/, ""));
18588
+ }
18589
+ };
18590
+ for (const el of Array.from(doc.querySelectorAll("*"))) stripFilter(el);
18591
+ for (const filter of Array.from(doc.querySelectorAll("filter"))) {
18592
+ try {
18593
+ (_c = filter.parentNode) == null ? void 0 : _c.removeChild(filter);
18594
+ } catch {
18595
+ }
18596
+ }
18597
+ let shadowConfig = null;
18598
+ if (obj.shadow) {
18599
+ const sh = obj.shadow;
18600
+ const color = sh.color || "rgba(0,0,0,0.5)";
18601
+ const blur = Math.max(0, Number(sh.blur) || 0);
18602
+ const dx = Number(sh.offsetX) || 0;
18603
+ const dy = Number(sh.offsetY) || 0;
18604
+ shadowConfig = { color, dx, dy, blur };
18605
+ }
18606
+ const bgCfg = obj.__pdBg;
18607
+ const extOX = Number((bgCfg == null ? void 0 : bgCfg.shadowOffsetX) ?? 0) || 0;
18608
+ const extOY = Number((bgCfg == null ? void 0 : bgCfg.shadowOffsetY) ?? 0) || 0;
18609
+ const extDist = Math.hypot(extOX, extOY);
18610
+ const extColor = bgCfg == null ? void 0 : bgCfg.shadowColor;
18611
+ const hasExtShadowColor = !!extColor && extColor !== "transparent";
18612
+ const affectsText = !bgCfg || bgCfg.shadowAffectsText !== false;
18613
+ const blockShadowActive = !!bgCfg && bgCfg.shadowType === "block" && hasExtShadowColor && extDist > 0 && affectsText;
18614
+ const lineShadowActive = !!bgCfg && bgCfg.shadowType === "line" && hasExtShadowColor && extDist > 0 && affectsText;
18615
+ let blockSteps = 0;
18616
+ let blockStepX = 0;
18617
+ let blockStepY = 0;
18618
+ if (blockShadowActive) {
18619
+ const STEP = 1;
18620
+ blockSteps = Math.min(200, Math.max(1, Math.ceil(extDist / STEP)));
18621
+ blockStepX = extOX / blockSteps;
18622
+ blockStepY = extOY / blockSteps;
18623
+ }
18624
+ const flowStops = (obj == null ? void 0 : obj.fill) && typeof obj.fill === "object" && Array.isArray(obj.fill.colorStops) && obj.fill.colorStops.length ? obj.fill.colorStops.map((s) => ({ offset: Number(s.offset) || 0, color: s.color || "#000" })) : null;
18625
+ const gradId = (fillAttr.match(/url\(#([^)]+)\)/) || [])[1];
18626
+ if (gradId && w > 0 && h > 0) {
18627
+ const grad = doc.getElementById(gradId);
18628
+ if (grad && grad.getAttribute("gradientUnits") !== "userSpaceOnUse") {
18629
+ const tag = grad.tagName.toLowerCase();
18630
+ const num = (v, fallback) => {
18631
+ if (v == null) return fallback;
18632
+ const n = parseFloat(v);
18633
+ return Number.isFinite(n) ? n : fallback;
18634
+ };
18635
+ const mapX = (u) => -w / 2 + u * w;
18636
+ const mapY = (u) => -h / 2 + u * h;
18637
+ grad.setAttribute("gradientUnits", "userSpaceOnUse");
18638
+ if (tag === "lineargradient") {
18639
+ const x1 = num(grad.getAttribute("x1"), 0);
18640
+ const y1 = num(grad.getAttribute("y1"), 0);
18641
+ const x2 = num(grad.getAttribute("x2"), 1);
18642
+ const y2 = num(grad.getAttribute("y2"), 0);
18643
+ grad.setAttribute("x1", mapX(x1).toFixed(3));
18644
+ grad.setAttribute("y1", mapY(y1).toFixed(3));
18645
+ grad.setAttribute("x2", mapX(x2).toFixed(3));
18646
+ grad.setAttribute("y2", mapY(y2).toFixed(3));
18647
+ } else if (tag === "radialgradient") {
18648
+ const cx = num(grad.getAttribute("cx"), 0.5);
18649
+ const cy = num(grad.getAttribute("cy"), 0.5);
18650
+ const r = num(grad.getAttribute("r"), 0.5);
18651
+ const fx = num(grad.getAttribute("fx"), cx);
18652
+ const fy = num(grad.getAttribute("fy"), cy);
18653
+ grad.setAttribute("cx", mapX(cx).toFixed(3));
18654
+ grad.setAttribute("cy", mapY(cy).toFixed(3));
18655
+ grad.setAttribute("fx", mapX(fx).toFixed(3));
18656
+ grad.setAttribute("fy", mapY(fy).toFixed(3));
18657
+ grad.setAttribute("r", (r * Math.max(w, h)).toFixed(3));
18658
+ }
18659
+ }
18660
+ }
18661
+ const measure = document.createElement("canvas").getContext("2d");
18662
+ if (!measure) return svg;
18663
+ measure.font = `${fst} ${fw} ${fs}px "${ff}"`;
18664
+ const chars = Array.from(plain);
18665
+ const spacing = (Number(obj.charSpacing) || 0) * fs / 1e3;
18666
+ const widths = chars.map((c) => measure.measureText(c).width + spacing);
18667
+ const totalWidth = widths.reduce((a, b) => a + b, 0);
18668
+ const baselineDy = resolveTextPathAlphabeticBaselineDy(measure, plain, fs);
18669
+ let cursor = 0;
18670
+ if (obj.textAlign === "center") cursor = Math.max(0, (totalLen - totalWidth) / 2);
18671
+ else if (obj.textAlign === "right") cursor = Math.max(0, totalLen - totalWidth);
18672
+ const halfW = (Number(obj.width) || 0) / 2;
18673
+ const halfH = (Number(obj.height) || 0) / 2;
18674
+ const glyphSvg = [];
18675
+ const shadowSvg = [];
18676
+ const blockShadowSvg = [];
18677
+ const lineShadowSvg = [];
18678
+ let minX = Number.POSITIVE_INFINITY;
18679
+ let minY = Number.POSITIVE_INFINITY;
18680
+ let maxX = Number.NEGATIVE_INFINITY;
18681
+ let maxY = Number.NEGATIVE_INFINITY;
18682
+ for (let i = 0; i < chars.length; i++) {
18683
+ const cw = widths[i];
18684
+ const mid = cursor + cw / 2;
18685
+ cursor += cw;
18686
+ if (mid > totalLen) break;
18687
+ const p = pathEl.getPointAtLength(Math.max(0, mid));
18688
+ const ahead = pathEl.getPointAtLength(Math.min(totalLen, mid + 0.5));
18689
+ const deg = Math.atan2(ahead.y - p.y, ahead.x - p.x) * 180 / Math.PI;
18690
+ const x = p.x - halfW;
18691
+ const y = p.y - halfH;
18692
+ const glyphPad = Math.max(fs, cw) * 0.75;
18693
+ minX = Math.min(minX, x - glyphPad);
18694
+ minY = Math.min(minY, y - glyphPad - fs);
18695
+ maxX = Math.max(maxX, x + glyphPad);
18696
+ maxY = Math.max(maxY, y + glyphPad);
18697
+ const glyphFill = flowStops ? sampleGradientColor(flowStops, chars.length > 1 ? i / (chars.length - 1) : 0) : fillAttr;
18698
+ if (blockShadowActive) {
18699
+ for (let s = blockSteps; s >= 1; s--) {
18700
+ const bx = x + blockStepX * s;
18701
+ const by = y + blockStepY * s;
18702
+ blockShadowSvg.push(
18703
+ `<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="${escapeXml(String(extColor))}" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-block-shadow="true" transform="translate(${bx.toFixed(3)} ${by.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
18704
+ );
18705
+ }
18706
+ }
18707
+ if (lineShadowActive) {
18708
+ const lx = x + extOX;
18709
+ const ly = y + extOY;
18710
+ const lineStrokeW = LINE_SHADOW_STROKE_WIDTH;
18711
+ lineShadowSvg.push(
18712
+ `<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="none" stroke="${escapeXml(String(extColor))}" stroke-width="${lineStrokeW.toFixed(3)}" stroke-linejoin="round" paint-order="stroke" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-line-shadow="true" transform="translate(${lx.toFixed(3)} ${ly.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
18713
+ );
18714
+ }
18715
+ if (shadowConfig) {
18716
+ const sx = x + shadowConfig.dx;
18717
+ const sy = y + shadowConfig.dy;
18718
+ shadowSvg.push(
18719
+ `<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="${escapeXml(shadowConfig.color)}" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-shadow="true" transform="translate(${sx.toFixed(3)} ${sy.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
18720
+ );
18721
+ }
18722
+ glyphSvg.push(
18723
+ `<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="${escapeXml(glyphFill)}" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-glyph="true" transform="translate(${x.toFixed(3)} ${y.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
18724
+ );
18725
+ }
18726
+ const replacement = doc.createElementNS("http://www.w3.org/2000/svg", "g");
18727
+ replacement.setAttribute("data-pixldocs-warped", "true");
18728
+ let innerHtml = "";
18729
+ if (shadowConfig && shadowSvg.length) {
18730
+ const blur = Math.max(0, Number(shadowConfig.blur) || 0);
18731
+ if (blur > 0 && Number.isFinite(minX) && Number.isFinite(maxX)) {
18732
+ const pad = Math.max(8, blur * 3);
18733
+ const sMinX = minX + shadowConfig.dx - pad;
18734
+ const sMinY = minY + shadowConfig.dy - pad;
18735
+ const sMaxX = maxX + shadowConfig.dx + pad;
18736
+ const sMaxY = maxY + shadowConfig.dy + pad;
18737
+ const bw = Math.max(1, sMaxX - sMinX);
18738
+ const bh = Math.max(1, sMaxY - sMinY);
18739
+ innerHtml += `<g class="__pdShadowRaster" data-pixldocs-warp-shadow-group="true" data-blur="${blur}" data-ox="0" data-oy="0" data-bx="${sMinX.toFixed(3)}" data-by="${sMinY.toFixed(3)}" data-bw="${bw.toFixed(3)}" data-bh="${bh.toFixed(3)}">${shadowSvg.join("")}</g>`;
18740
+ } else {
18741
+ innerHtml += `<g data-pixldocs-warp-shadow-group="true">${shadowSvg.join("")}</g>`;
18742
+ }
18743
+ }
18744
+ if (lineShadowSvg.length) {
18745
+ innerHtml = `<g data-pixldocs-warp-line-shadow-group="true">${lineShadowSvg.join("")}</g>` + innerHtml;
18746
+ }
18747
+ if (blockShadowSvg.length) {
18748
+ innerHtml = `<g data-pixldocs-warp-block-shadow-group="true">${blockShadowSvg.join("")}</g>` + innerHtml;
18749
+ }
18750
+ innerHtml += glyphSvg.join("");
18751
+ replacement.innerHTML = innerHtml;
18752
+ (_d = textEl.parentNode) == null ? void 0 : _d.replaceChild(replacement, textEl);
18753
+ for (let i = 1; i < textEls.length; i++) {
18754
+ try {
18755
+ (_e = textEls[i].parentNode) == null ? void 0 : _e.removeChild(textEls[i]);
18756
+ } catch {
18757
+ }
18758
+ }
18759
+ const serialized = new XMLSerializer().serializeToString(doc.documentElement);
18760
+ return serialized;
18761
+ }
16791
18762
  function stampFabricLineMetricsOnTextSvg(svg, obj) {
16792
18763
  const lines = Array.isArray(obj == null ? void 0 : obj._textLines) ? obj._textLines : [];
16793
18764
  if (!lines.length || typeof (obj == null ? void 0 : obj.getLineWidth) !== "function") return svg;
@@ -16858,6 +18829,7 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16858
18829
  obj.toSVG = (reviver) => {
16859
18830
  let svg = originalToSVG(reviver);
16860
18831
  if (isTextboxLike(obj)) svg = stampFabricLineMetricsOnTextSvg(svg, obj);
18832
+ if (isTextboxLike(obj)) svg = warpTextboxSvgAlongPath(svg, obj);
16861
18833
  if (imageId) svg = stampPixldocsImageIdOnSvg(svg, imageId);
16862
18834
  return svg;
16863
18835
  };
@@ -16952,9 +18924,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16952
18924
  }
16953
18925
  return svgString;
16954
18926
  }
16955
- const resolvedPackageVersion = "0.5.205";
18927
+ const resolvedPackageVersion = "0.5.206";
16956
18928
  const PACKAGE_VERSION = resolvedPackageVersion;
16957
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.205";
18929
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.206";
16958
18930
  const roundParityValue = (value) => {
16959
18931
  if (typeof value !== "number") return value;
16960
18932
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -17633,7 +19605,7 @@ class PixldocsRenderer {
17633
19605
  await this.waitForCanvasScene(container, cloned, i);
17634
19606
  }
17635
19607
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
17636
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-CZyBCnFF.js");
19608
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-CyNCzRhQ.js");
17637
19609
  const prepared = preparePagesForExport(
17638
19610
  cloned.pages,
17639
19611
  canvasWidth,
@@ -19817,7 +21789,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
19817
21789
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
19818
21790
  sanitizeSvgTreeForPdf(svgToDraw);
19819
21791
  try {
19820
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-CZyBCnFF.js");
21792
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-CyNCzRhQ.js");
19821
21793
  try {
19822
21794
  await logTextMeasurementDiagnostic(svgToDraw);
19823
21795
  } catch {
@@ -19949,7 +21921,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19949
21921
  );
19950
21922
  }
19951
21923
  try {
19952
- const { prepareSvgTextForPdfMode } = await import("./svgTextToPath-BoT6H7Lz.js");
21924
+ const { prepareSvgTextForPdfMode } = await import("./svgTextToPath-Bw974R9h.js");
19953
21925
  pageSvg = await prepareSvgTextForPdfMode(pageSvg, textMode, fontBaseUrl);
19954
21926
  try {
19955
21927
  dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-shared-text-prep");
@@ -20217,4 +22189,4 @@ export {
20217
22189
  buildTeaserBlurFlatKeys as y,
20218
22190
  collectFontDescriptorsFromConfig as z
20219
22191
  };
20220
- //# sourceMappingURL=index-DBuMPh9u.js.map
22192
+ //# sourceMappingURL=index-CyxNh5Y9.js.map