@pixldocs/canvas-renderer 0.5.51 → 0.5.53

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.d.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import { FormConfig } from '../../../src/lib/formsApi';
2
+ import { getProxiedImageUrl } from '../../../src/lib/canvasImageLoader';
2
3
  import { InferredSection } from '../../../src/lib/inferFormSchemaFromTemplate';
4
+ import { isBundledAssetUrl } from '../../../src/lib/canvasImageLoader';
5
+ import { isPrivateUrl } from '../../../src/lib/canvasImageLoader';
3
6
  import { jsPDF } from 'jspdf';
4
7
  import { JSX as JSX_2 } from 'react/jsx-runtime';
5
8
  import { SectionFormState } from '../../../src/lib/inferFormSchemaFromTemplate';
9
+ import { setBundledAssetPrefixes } from '../../../src/lib/canvasImageLoader';
6
10
  import { SmartElementProps } from '../../../shared/smart-elements/types';
7
11
  import { SmartElementType } from '../../../shared/smart-elements/types';
8
12
 
@@ -200,11 +204,17 @@ declare type FormDefSection = {
200
204
  */
201
205
  export declare function getEmbeddedJsPDFFontName(fontName: string, weight: number, isItalic?: boolean): string;
202
206
 
207
+ export { getProxiedImageUrl }
208
+
203
209
  export { InferredSection }
204
210
 
211
+ export { isBundledAssetUrl }
212
+
205
213
  /** Check if a font is in our local mapping */
206
214
  export declare function isFontAvailable(fontName: string): boolean;
207
215
 
216
+ export { isPrivateUrl }
217
+
208
218
  /**
209
219
  * Load a Google Font by injecting a <link> stylesheet.
210
220
  * Resolves when the font is ready for use.
@@ -221,7 +231,7 @@ export declare function normalizeFontFamily(fontStack: string): string;
221
231
  * Package version banner. Bump alongside package.json so we can confirm
222
232
  * (via browser:log) that the deployed bundle matches the expected build.
223
233
  */
224
- export declare const PACKAGE_VERSION = "0.5.50";
234
+ export declare const PACKAGE_VERSION = "0.5.52";
225
235
 
226
236
  export declare interface PageSettings {
227
237
  backgroundColor?: string;
@@ -540,6 +550,8 @@ export declare function rewriteSvgFontsForJsPDF(svgStr: string): string;
540
550
 
541
551
  export { SectionFormState }
542
552
 
553
+ export { setBundledAssetPrefixes }
554
+
543
555
  export { SmartElementProps }
544
556
 
545
557
  export { SmartElementType }
package/dist/index.js CHANGED
@@ -2839,6 +2839,49 @@ function isPrivateUrl(url) {
2839
2839
  return false;
2840
2840
  }
2841
2841
  }
2842
+ const DEFAULT_BUNDLED_PREFIXES = ["/pixldocs-bundled-assets/"];
2843
+ let bundledPrefixes = [...DEFAULT_BUNDLED_PREFIXES];
2844
+ function setBundledAssetPrefixes(prefixes) {
2845
+ const combined = /* @__PURE__ */ new Set([...DEFAULT_BUNDLED_PREFIXES]);
2846
+ for (const p of prefixes || []) {
2847
+ if (typeof p === "string" && p.startsWith("/")) combined.add(p);
2848
+ }
2849
+ bundledPrefixes = Array.from(combined);
2850
+ }
2851
+ function pathnameStartsWithBundledPrefix(pathname) {
2852
+ return bundledPrefixes.some((prefix) => pathname.startsWith(prefix));
2853
+ }
2854
+ function isBundledAssetUrl(url) {
2855
+ if (!url) return false;
2856
+ if (url.startsWith("/") && !url.startsWith("//")) {
2857
+ return pathnameStartsWithBundledPrefix(url);
2858
+ }
2859
+ try {
2860
+ const parsed = new URL(url);
2861
+ if (typeof window !== "undefined" && parsed.origin !== window.location.origin) {
2862
+ return false;
2863
+ }
2864
+ return pathnameStartsWithBundledPrefix(parsed.pathname);
2865
+ } catch {
2866
+ return false;
2867
+ }
2868
+ }
2869
+ function resolveBundledAssetUrl(url) {
2870
+ if (!url) return null;
2871
+ if (url.startsWith("/") && !url.startsWith("//") && pathnameStartsWithBundledPrefix(url)) {
2872
+ const origin = typeof window !== "undefined" ? window.location.origin : "";
2873
+ return origin ? new URL(url, origin).toString() : url;
2874
+ }
2875
+ try {
2876
+ const parsed = new URL(url);
2877
+ if (typeof window !== "undefined" && parsed.origin !== window.location.origin) return null;
2878
+ if (pathnameStartsWithBundledPrefix(parsed.pathname)) return parsed.toString();
2879
+ } catch {
2880
+ return null;
2881
+ }
2882
+ return null;
2883
+ }
2884
+ const loggedPrivateSkips = /* @__PURE__ */ new Set();
2842
2885
  function toPublicStorageUrl(url) {
2843
2886
  try {
2844
2887
  const parsed = new URL(url);
@@ -2856,8 +2899,17 @@ function toPublicStorageUrl(url) {
2856
2899
  function getProxiedImageUrl(imageUrl) {
2857
2900
  if (!imageUrl) return "";
2858
2901
  if (imageUrl.startsWith("data:") || imageUrl.startsWith("blob:")) return imageUrl;
2902
+ const bundled = resolveBundledAssetUrl(imageUrl);
2903
+ if (bundled) return bundled;
2904
+ if (imageUrl.startsWith("/") && !imageUrl.startsWith("//")) {
2905
+ if (typeof window !== "undefined") return new URL(imageUrl, window.location.origin).toString();
2906
+ return imageUrl;
2907
+ }
2859
2908
  if (isPrivateUrl(imageUrl)) {
2860
- console.warn("[image-proxy] Skipping private URL:", imageUrl.substring(0, 80));
2909
+ if (!loggedPrivateSkips.has(imageUrl)) {
2910
+ loggedPrivateSkips.add(imageUrl);
2911
+ console.debug("[image-proxy] Skipping private URL:", imageUrl.substring(0, 80));
2912
+ }
2861
2913
  return "";
2862
2914
  }
2863
2915
  const publicUrl = toPublicStorageUrl(imageUrl);
@@ -4799,7 +4851,13 @@ function extractTextBgConfig(element) {
4799
4851
  rxTL: Math.max(0, Number(element.textBgRxTL ?? 0)) || 0,
4800
4852
  rxTR: Math.max(0, Number(element.textBgRxTR ?? 0)) || 0,
4801
4853
  rxBR: Math.max(0, Number(element.textBgRxBR ?? 0)) || 0,
4802
- rxBL: Math.max(0, Number(element.textBgRxBL ?? 0)) || 0
4854
+ rxBL: Math.max(0, Number(element.textBgRxBL ?? 0)) || 0,
4855
+ opacity: (() => {
4856
+ const n = Number(element.textBgOpacity);
4857
+ if (!Number.isFinite(n)) return void 0;
4858
+ return Math.max(0, Math.min(1, n));
4859
+ })(),
4860
+ shadowAffectsBg: element.textShadowAffectsBg !== false
4803
4861
  };
4804
4862
  }
4805
4863
  function hasTextBackground(cfg) {
@@ -4860,6 +4918,13 @@ function applyTextBackground(obj, cfg) {
4860
4918
  const bgW = w + pL + pR;
4861
4919
  const bgH = h + pT + pB;
4862
4920
  ctx.save();
4921
+ const suppressShadowOnBg = bg.shadowAffectsBg === false;
4922
+ if (suppressShadowOnBg) {
4923
+ ctx.shadowColor = "transparent";
4924
+ ctx.shadowBlur = 0;
4925
+ ctx.shadowOffsetX = 0;
4926
+ ctx.shadowOffsetY = 0;
4927
+ }
4863
4928
  buildRoundedRectPath2D(
4864
4929
  ctx,
4865
4930
  x,
@@ -4871,6 +4936,8 @@ function applyTextBackground(obj, cfg) {
4871
4936
  bg.rxBR ?? 0,
4872
4937
  bg.rxBL ?? 0
4873
4938
  );
4939
+ const op = typeof bg.opacity === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
4940
+ if (op < 1) ctx.globalAlpha = (ctx.globalAlpha ?? 1) * op;
4874
4941
  ctx.fillStyle = bg.color;
4875
4942
  ctx.fill();
4876
4943
  ctx.restore();
@@ -4916,7 +4983,9 @@ function applyTextBackground(obj, cfg) {
4916
4983
  (bg == null ? void 0 : bg.rxBL) ?? 0
4917
4984
  );
4918
4985
  const bgFill = (bg == null ? void 0 : bg.color) || "";
4919
- const bgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(bgFill)}" />` : "";
4986
+ const bgOpacity = typeof (bg == null ? void 0 : bg.opacity) === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
4987
+ const bgOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
4988
+ const bgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(bgFill)}"${bgOpacityAttr} />` : "";
4920
4989
  svg = svg.replace(/style="[^"]*filter:\s*url\([^)]+\)[^"]*"/i, "");
4921
4990
  svg = svg.replace(/<filter[\s\S]*?<\/filter>/gi, "");
4922
4991
  let bgShadowMarker = "";
@@ -4933,7 +5002,7 @@ function applyTextBackground(obj, cfg) {
4933
5002
  const bh = h + pT + pB + pad * 2;
4934
5003
  const dataAttrs = `data-blur="${blur.toFixed(3)}" data-ox="${ox.toFixed(3)}" data-oy="${oy.toFixed(3)}" data-bx="${bx.toFixed(3)}" data-by="${by.toFixed(3)}" data-bw="${bw.toFixed(3)}" data-bh="${bh.toFixed(3)}" data-color="${escapeXmlAttr(shadowColor)}"`;
4935
5004
  const wrapShadow = (markup) => blur <= 0 ? `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${markup}</g>` : `<g class="__pdShadowRaster" ${dataAttrs}>${markup}</g>`;
4936
- if (hasBg) {
5005
+ if (hasBg && (bg == null ? void 0 : bg.shadowAffectsBg) !== false) {
4937
5006
  const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}" />`;
4938
5007
  bgShadowMarker = wrapShadow(shadowBgPath);
4939
5008
  }
@@ -12321,7 +12390,7 @@ function PixldocsPreview(props) {
12321
12390
  !canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
12322
12391
  ] });
12323
12392
  }
12324
- const PACKAGE_VERSION = "0.5.50";
12393
+ const PACKAGE_VERSION = "0.5.52";
12325
12394
  let __underlineFixInstalled = false;
12326
12395
  function installUnderlineFix(fab) {
12327
12396
  var _a;
@@ -13985,6 +14054,7 @@ const SVG_STYLE_PROPS = /* @__PURE__ */ new Set([
13985
14054
  const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradientTransform", "spreadMethod"];
13986
14055
  const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
13987
14056
  const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
14057
+ const SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;
13988
14058
  function parseColor(color) {
13989
14059
  if (!color) return null;
13990
14060
  const raw = color.trim().toLowerCase();
@@ -15030,6 +15100,7 @@ async function rasterizeShadowMarkers(svg) {
15030
15100
  img.setAttribute("y", String(by));
15031
15101
  img.setAttribute("width", String(bw));
15032
15102
  img.setAttribute("height", String(bh));
15103
+ img.setAttribute("opacity", String(SHADOW_RASTER_ALPHA_COMPENSATION));
15033
15104
  img.setAttribute("preserveAspectRatio", "none");
15034
15105
  img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
15035
15106
  img.setAttribute("href", dataUrl);
@@ -15243,7 +15314,14 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
15243
15314
  const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
15244
15315
  drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
15245
15316
  const shouldStripBg = stripPageBackground ?? hasGradient;
15246
- let processedSvg = await prepareLiveCanvasSvgForPdf(page.svg, page.width, page.height, `page-${i + 1}`, {
15317
+ let pageSvg = page.svg;
15318
+ try {
15319
+ const mod = await import("./svgTextToPath-BP0Kppla.js");
15320
+ pageSvg = await mod.convertAllTextToPath(pageSvg, fontBaseUrl);
15321
+ } catch (outlineErr) {
15322
+ console.warn(`[canvas-renderer pdf] page ${i + 1}: text outliner unavailable, continuing with text-as-text`, outlineErr);
15323
+ }
15324
+ let processedSvg = await prepareLiveCanvasSvgForPdf(pageSvg, page.width, page.height, `page-${i + 1}`, {
15247
15325
  stripPageBackground: shouldStripBg
15248
15326
  });
15249
15327
  if (processedSvg) {
@@ -15302,9 +15380,16 @@ function collectImageUrls(config) {
15302
15380
  function normalizeAssetUrl(rawUrl, imageProxyUrl) {
15303
15381
  if (!rawUrl) return null;
15304
15382
  if (rawUrl.startsWith("data:") || rawUrl.startsWith("blob:")) return null;
15383
+ if (rawUrl.startsWith("/") && !rawUrl.startsWith("//")) {
15384
+ if (typeof window !== "undefined") return new URL(rawUrl, window.location.origin).toString();
15385
+ return null;
15386
+ }
15305
15387
  try {
15306
15388
  const h = new URL(rawUrl).hostname.toLowerCase();
15307
15389
  if (h === "localhost" || h === "127.0.0.1" || h === "0.0.0.0" || h.endsWith(".local") || /^(10\.|192\.168\.|169\.254\.)/.test(h)) {
15390
+ if (typeof window !== "undefined" && new URL(rawUrl).origin === window.location.origin) {
15391
+ return rawUrl;
15392
+ }
15308
15393
  return null;
15309
15394
  }
15310
15395
  } catch {
@@ -15372,13 +15457,17 @@ export {
15372
15457
  ensureFontsForResolvedConfig,
15373
15458
  extractFontFamiliesFromSvgs,
15374
15459
  getEmbeddedJsPDFFontName,
15460
+ getProxiedImageUrl,
15461
+ isBundledAssetUrl,
15375
15462
  isFontAvailable,
15463
+ isPrivateUrl,
15376
15464
  loadGoogleFontCSS,
15377
15465
  normalizeFontFamily,
15378
15466
  resolveFontWeight,
15379
15467
  resolveFromForm,
15380
15468
  resolveTemplateData,
15381
15469
  rewriteSvgFontsForJsPDF,
15470
+ setBundledAssetPrefixes,
15382
15471
  warmResolvedTemplateForPreview,
15383
15472
  warmTemplateFromForm
15384
15473
  };