@pixldocs/canvas-renderer 0.5.42 → 0.5.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4804,9 +4804,17 @@ function calculateScaleSnapGuides(scalingObj, corner, canvas, canvasWidth, canva
4804
4804
  const PD_BG_KEY = "__pdBg";
4805
4805
  const PATCHED_KEY = "__pdBgPatched";
4806
4806
  function extractTextBgConfig(element) {
4807
+ const legacy = Math.max(0, Number(element.textBgPadding ?? 0)) || 0;
4808
+ const pick = (v) => {
4809
+ const n = Number(v);
4810
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
4811
+ };
4807
4812
  return {
4808
4813
  color: element.textBgColor,
4809
- padding: Math.max(0, Number(element.textBgPadding ?? 0)) || 0,
4814
+ padTop: pick(element.textBgPaddingTop) ?? legacy,
4815
+ padRight: pick(element.textBgPaddingRight) ?? legacy,
4816
+ padBottom: pick(element.textBgPaddingBottom) ?? legacy,
4817
+ padLeft: pick(element.textBgPaddingLeft) ?? legacy,
4810
4818
  rxTL: Math.max(0, Number(element.textBgRxTL ?? 0)) || 0,
4811
4819
  rxTR: Math.max(0, Number(element.textBgRxTR ?? 0)) || 0,
4812
4820
  rxBR: Math.max(0, Number(element.textBgRxBR ?? 0)) || 0,
@@ -4824,9 +4832,8 @@ function buildTextShadow(element) {
4824
4832
  const ox = Number(element.textShadowOffsetX ?? 0);
4825
4833
  const oy = Number(element.textShadowOffsetY ?? 0);
4826
4834
  if (!color || color === "transparent") return null;
4827
- if (blur === 0 && ox === 0 && oy === 0) return null;
4828
4835
  return new fabric__namespace.Shadow({
4829
- color,
4836
+ color: String(color),
4830
4837
  blur: blur || 0,
4831
4838
  offsetX: ox || 0,
4832
4839
  offsetY: oy || 0,
@@ -4863,11 +4870,14 @@ function applyTextBackground(obj, cfg) {
4863
4870
  if (hasTextBackground(bg)) {
4864
4871
  const w = this.width ?? 0;
4865
4872
  const h = this.height ?? 0;
4866
- const pad = Math.max(0, Number(bg.padding ?? 0));
4867
- const x = -w / 2 - pad;
4868
- const y = -h / 2 - pad;
4869
- const bgW = w + pad * 2;
4870
- const bgH = h + pad * 2;
4873
+ const pT = Math.max(0, Number(bg.padTop ?? 0));
4874
+ const pR = Math.max(0, Number(bg.padRight ?? 0));
4875
+ const pB = Math.max(0, Number(bg.padBottom ?? 0));
4876
+ const pL = Math.max(0, Number(bg.padLeft ?? 0));
4877
+ const x = -w / 2 - pL;
4878
+ const y = -h / 2 - pT;
4879
+ const bgW = w + pL + pR;
4880
+ const bgH = h + pT + pB;
4871
4881
  ctx.save();
4872
4882
  buildRoundedRectPath2D(
4873
4883
  ctx,
@@ -4898,37 +4908,107 @@ function applyTextBackground(obj, cfg) {
4898
4908
  const originalToSVG = (_a = obj.toSVG) == null ? void 0 : _a.bind(obj);
4899
4909
  if (typeof originalToSVG === "function") {
4900
4910
  obj.toSVG = function(reviver) {
4901
- const svg = originalToSVG(reviver);
4911
+ let svg = originalToSVG(reviver);
4902
4912
  const bg = this[PD_BG_KEY];
4903
- if (!hasTextBackground(bg)) return svg;
4913
+ const shadow = this.shadow;
4914
+ const hasBg = hasTextBackground(bg);
4915
+ const hasShadow = !!shadow && !!shadow.color && shadow.color !== "transparent";
4916
+ if (!hasBg && !hasShadow) return svg;
4904
4917
  const w = this.width ?? 0;
4905
4918
  const h = this.height ?? 0;
4906
- const pad = Math.max(0, Number(bg.padding ?? 0));
4907
- const x = -w / 2 - pad;
4908
- const y = -h / 2 - pad;
4909
- const bgW = w + pad * 2;
4910
- const bgH = h + pad * 2;
4911
- const d = buildRoundedRectPathD(
4919
+ const pT = Math.max(0, Number((bg == null ? void 0 : bg.padTop) ?? 0));
4920
+ const pR = Math.max(0, Number((bg == null ? void 0 : bg.padRight) ?? 0));
4921
+ const pB = Math.max(0, Number((bg == null ? void 0 : bg.padBottom) ?? 0));
4922
+ const pL = Math.max(0, Number((bg == null ? void 0 : bg.padLeft) ?? 0));
4923
+ const x = -w / 2 - pL;
4924
+ const y = -h / 2 - pT;
4925
+ const bgW = w + pL + pR;
4926
+ const bgH = h + pT + pB;
4927
+ const bgD = buildRoundedRectPathD(
4912
4928
  x,
4913
4929
  y,
4914
4930
  bgW,
4915
4931
  bgH,
4916
- bg.rxTL ?? 0,
4917
- bg.rxTR ?? 0,
4918
- bg.rxBR ?? 0,
4919
- bg.rxBL ?? 0
4932
+ (bg == null ? void 0 : bg.rxTL) ?? 0,
4933
+ (bg == null ? void 0 : bg.rxTR) ?? 0,
4934
+ (bg == null ? void 0 : bg.rxBR) ?? 0,
4935
+ (bg == null ? void 0 : bg.rxBL) ?? 0
4920
4936
  );
4921
- const fill = bg.color;
4922
- const bgPath = `<path d="${d}" fill="${escapeXmlAttr(fill)}" />`;
4937
+ const bgFill = (bg == null ? void 0 : bg.color) || "";
4938
+ const bgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(bgFill)}" />` : "";
4939
+ svg = svg.replace(/style="[^"]*filter:\s*url\([^)]+\)[^"]*"/i, "");
4940
+ svg = svg.replace(/<filter[\s\S]*?<\/filter>/gi, "");
4941
+ let shadowLayer = "";
4942
+ if (hasShadow) {
4943
+ const ox = Number(shadow.offsetX ?? 0) || 0;
4944
+ const oy = Number(shadow.offsetY ?? 0) || 0;
4945
+ const blur = Math.max(0, Number(shadow.blur ?? 0));
4946
+ const shadowColor = String(shadow.color);
4947
+ const shadowBgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}" />` : "";
4948
+ const inner = extractGInnerMarkup(svg);
4949
+ const recoloredText = recolorSvgFills(inner, shadowColor);
4950
+ const layers = [];
4951
+ if (blur > 0) {
4952
+ const ringCount = Math.min(6, Math.max(2, Math.round(blur / 2)));
4953
+ for (let i = 1; i <= ringCount; i++) {
4954
+ const t = i / ringCount;
4955
+ const dist = blur * t * 0.6;
4956
+ const op = (0.18 * (1 - t * 0.7)).toFixed(3);
4957
+ const ringOffsets = [
4958
+ [dist, 0],
4959
+ [-dist, 0],
4960
+ [0, dist],
4961
+ [0, -dist],
4962
+ [dist * 0.7, dist * 0.7],
4963
+ [-dist * 0.7, dist * 0.7],
4964
+ [dist * 0.7, -dist * 0.7],
4965
+ [-dist * 0.7, -dist * 0.7]
4966
+ ];
4967
+ for (const [dx, dy] of ringOffsets) {
4968
+ layers.push(
4969
+ `<g transform="translate(${(ox + dx).toFixed(3)} ${(oy + dy).toFixed(3)})" opacity="${op}">${shadowBgPath}${recoloredText}</g>`
4970
+ );
4971
+ }
4972
+ }
4973
+ layers.push(
4974
+ `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})" opacity="0.25">${shadowBgPath}${recoloredText}</g>`
4975
+ );
4976
+ } else {
4977
+ layers.push(
4978
+ `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${shadowBgPath}${recoloredText}</g>`
4979
+ );
4980
+ }
4981
+ shadowLayer = layers.join("");
4982
+ }
4923
4983
  const openTagMatch = svg.match(/^\s*<g\b[^>]*>/);
4984
+ const inserted = shadowLayer + bgPath;
4924
4985
  if (openTagMatch) {
4925
4986
  const openTag = openTagMatch[0];
4926
- return svg.replace(openTag, openTag + bgPath);
4987
+ return svg.replace(openTag, openTag + inserted);
4927
4988
  }
4928
- return `<g>${bgPath}${svg}</g>`;
4989
+ return `<g>${inserted}${svg}</g>`;
4929
4990
  };
4930
4991
  }
4931
4992
  }
4993
+ function recolorSvgFills(svg, color) {
4994
+ const safe = escapeXmlAttr(color);
4995
+ let out = svg.replace(
4996
+ /(<(?:text|tspan|path|rect)\b[^>]*?\sfill=")([^"]*)("[^>]*>)/gi,
4997
+ (_m, pre, val, post) => {
4998
+ const v = val.trim().toLowerCase();
4999
+ if (v === "none" || v === "transparent") return pre + val + post;
5000
+ return pre + safe + post;
5001
+ }
5002
+ );
5003
+ out = out.replace(
5004
+ /(<(?:text|tspan|path|rect)\b[^>]*?\sstyle=")([^"]*)("[^>]*>)/gi,
5005
+ (_m, pre, styleVal, post) => {
5006
+ const replaced = styleVal.replace(/fill\s*:\s*[^;"]+/gi, `fill: ${color}`);
5007
+ return pre + replaced + post;
5008
+ }
5009
+ );
5010
+ return out;
5011
+ }
4932
5012
  function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
4933
5013
  const maxR = Math.min(w, h) / 2;
4934
5014
  const tl = Math.min(Math.max(0, rTL), maxR);
@@ -4952,6 +5032,13 @@ function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
4952
5032
  function escapeXmlAttr(s) {
4953
5033
  return String(s).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4954
5034
  }
5035
+ function extractGInnerMarkup(markup) {
5036
+ const openMatch = markup.match(/^\s*<g\b[^>]*>/);
5037
+ if (!openMatch) return markup;
5038
+ const closeIdx = markup.lastIndexOf("</g>");
5039
+ if (closeIdx <= openMatch[0].length) return markup;
5040
+ return markup.slice(openMatch[0].length, closeIdx);
5041
+ }
4955
5042
  const TRIANGLE_STROKE_MITER_LIMIT = 1e6;
4956
5043
  const toSafeNumber = (value, fallback = 0) => Number.isFinite(value) ? Math.max(0, Number(value)) : fallback;
4957
5044
  function normalizeShapeType(shapeType) {
@@ -7871,6 +7958,10 @@ const PageCanvas = react.forwardRef(
7871
7958
  JSON.stringify({
7872
7959
  c: element.textBgColor ?? null,
7873
7960
  p: element.textBgPadding ?? 0,
7961
+ pt: element.textBgPaddingTop ?? null,
7962
+ pr: element.textBgPaddingRight ?? null,
7963
+ pb: element.textBgPaddingBottom ?? null,
7964
+ pl: element.textBgPaddingLeft ?? null,
7874
7965
  tl: element.textBgRxTL ?? 0,
7875
7966
  tr: element.textBgRxTR ?? 0,
7876
7967
  br: element.textBgRxBR ?? 0,
@@ -8314,7 +8405,7 @@ const PageCanvas = react.forwardRef(
8314
8405
  });
8315
8406
  }, [selectedIds, isActive, ready, elements]);
8316
8407
  const updateFabricObject = (obj, element, skipPositionUpdate = false) => {
8317
- var _a, _b;
8408
+ var _a, _b, _c;
8318
8409
  const fc = fabricRef.current;
8319
8410
  if (fc && isTransforming(fc)) {
8320
8411
  return;
@@ -8778,9 +8869,20 @@ const PageCanvas = react.forwardRef(
8778
8869
  applyTextBackground(obj, extractTextBgConfig(element));
8779
8870
  const shadow = buildTextShadow(element);
8780
8871
  obj.set("shadow", shadow ?? null);
8872
+ try {
8873
+ obj._cacheCanvas = null;
8874
+ obj._cacheContext = null;
8875
+ } catch {
8876
+ }
8877
+ obj.dirty = true;
8878
+ (_c = obj.setCoords) == null ? void 0 : _c.call(obj);
8781
8879
  obj.__lastTextBgShadowJson = JSON.stringify({
8782
8880
  c: element.textBgColor ?? null,
8783
8881
  p: element.textBgPadding ?? 0,
8882
+ pt: element.textBgPaddingTop ?? null,
8883
+ pr: element.textBgPaddingRight ?? null,
8884
+ pb: element.textBgPaddingBottom ?? null,
8885
+ pl: element.textBgPaddingLeft ?? null,
8784
8886
  tl: element.textBgRxTL ?? 0,
8785
8887
  tr: element.textBgRxTR ?? 0,
8786
8888
  br: element.textBgRxBR ?? 0,
@@ -12258,7 +12360,7 @@ function PixldocsPreview(props) {
12258
12360
  !canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
12259
12361
  ] });
12260
12362
  }
12261
- const PACKAGE_VERSION = "0.5.42";
12363
+ const PACKAGE_VERSION = "0.5.44";
12262
12364
  let __underlineFixInstalled = false;
12263
12365
  function installUnderlineFix(fab) {
12264
12366
  var _a;