@pixldocs/canvas-renderer 0.5.135 → 0.5.137

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.
@@ -14626,6 +14626,38 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
14626
14626
  resolveFontWeight,
14627
14627
  rewriteSvgFontsForJsPDF
14628
14628
  }, Symbol.toStringTag, { value: "Module" }));
14629
+ const FONTSHARE_SLUGS = {
14630
+ "Satoshi": "satoshi",
14631
+ "Cabinet Grotesk": "cabinet-grotesk",
14632
+ "Clash Display": "clash-display",
14633
+ "Clash Grotesk": "clash-grotesk",
14634
+ "General Sans": "general-sans",
14635
+ "Switzer": "switzer",
14636
+ "Supreme": "supreme",
14637
+ "Author": "author",
14638
+ "Boska": "boska",
14639
+ "Excon": "excon",
14640
+ "Khand": "khand",
14641
+ "Sentient": "sentient",
14642
+ "Synonym": "synonym",
14643
+ "Erode": "erode",
14644
+ "Ranade": "ranade",
14645
+ "Tanker": "tanker",
14646
+ "Zodiak": "zodiak",
14647
+ "Gambarino": "gambarino",
14648
+ "Melodrama": "melodrama",
14649
+ "Bespoke Serif": "bespoke-serif",
14650
+ "Bespoke Stencil": "bespoke-stencil",
14651
+ "Panchang": "panchang",
14652
+ "Quincy CF": "quincy-cf",
14653
+ "Pally": "pally",
14654
+ "Tabular": "tabular",
14655
+ "Sharpie": "sharpie",
14656
+ "Stardom": "stardom",
14657
+ "Rebond Grotesque": "rebond-grotesque",
14658
+ "Telma": "telma",
14659
+ "Nippo": "nippo"
14660
+ };
14629
14661
  function normalizeFontFamily(fontStack) {
14630
14662
  const first = fontStack.split(",")[0].trim();
14631
14663
  return first.replace(/^['"]|['"]$/g, "");
@@ -14633,6 +14665,8 @@ function normalizeFontFamily(fontStack) {
14633
14665
  const loadedFonts = /* @__PURE__ */ new Set();
14634
14666
  const loadingPromises = /* @__PURE__ */ new Map();
14635
14667
  const registeredLocalFontFaces = /* @__PURE__ */ new Set();
14668
+ const registeredRemoteFontFaces = /* @__PURE__ */ new Set();
14669
+ const remoteFontDataUriPromises = /* @__PURE__ */ new Map();
14636
14670
  let localFontFaceStyleEl = null;
14637
14671
  function ensureLocalFontFaceStyle() {
14638
14672
  if (typeof document === "undefined") return null;
@@ -14653,6 +14687,92 @@ function appendLocalFontFaceRule(family, weight, style, file) {
14653
14687
  `;
14654
14688
  styleEl.appendChild(document.createTextNode(cssText));
14655
14689
  }
14690
+ function appendDataUriFontFaceRule(family, weight, style, dataUri) {
14691
+ const styleEl = ensureLocalFontFaceStyle();
14692
+ if (!styleEl) return;
14693
+ const cssText = `@font-face{font-family:"${family}";src:url("${dataUri}") format("truetype");font-weight:${weight};font-style:${style};font-display:swap;}
14694
+ `;
14695
+ styleEl.appendChild(document.createTextNode(cssText));
14696
+ }
14697
+ function resolveHarnessFontProxyUrl() {
14698
+ var _a, _b;
14699
+ try {
14700
+ const runtimeBase = typeof window !== "undefined" && (window.__PIXLDOCS_SUPABASE_URL || ((_a = window.__CONFIG__) == null ? void 0 : _a.supabaseUrl)) || typeof globalThis !== "undefined" && (globalThis.__PIXLDOCS_SUPABASE_URL || ((_b = globalThis.__CONFIG__) == null ? void 0 : _b.supabaseUrl)) || "";
14701
+ const base = String(runtimeBase || "").replace(/\/$/, "");
14702
+ return base ? `${base}/functions/v1/font-proxy` : "";
14703
+ } catch {
14704
+ return "";
14705
+ }
14706
+ }
14707
+ function isEmbeddableTrueType(bytes) {
14708
+ if (bytes.length < 12) return false;
14709
+ const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);
14710
+ return signature === "\0\0\0" || signature === "true";
14711
+ }
14712
+ async function arrayBufferToDataUri(buf) {
14713
+ const blob = new Blob([buf], { type: "font/ttf" });
14714
+ return await new Promise((resolve, reject) => {
14715
+ const reader = new FileReader();
14716
+ reader.onload = () => resolve(String(reader.result));
14717
+ reader.onerror = () => reject(reader.error || new Error("Failed to read font bytes"));
14718
+ reader.readAsDataURL(blob);
14719
+ });
14720
+ }
14721
+ async function fetchFontProxyDataUri(family, weight, style, source) {
14722
+ const proxyUrl = resolveHarnessFontProxyUrl();
14723
+ if (!proxyUrl) return null;
14724
+ const key = `${source}|${family}|${weight}|${style}`;
14725
+ const existing = remoteFontDataUriPromises.get(key);
14726
+ if (existing) return existing;
14727
+ const promise = (async () => {
14728
+ try {
14729
+ const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${style === "italic" ? 1 : 0}&source=${source}`;
14730
+ const res = await fetch(url, { credentials: "omit" });
14731
+ if (!res.ok) return null;
14732
+ const contentType = res.headers.get("content-type") || "";
14733
+ if (/application\/json/i.test(contentType)) return null;
14734
+ const buf = await res.arrayBuffer();
14735
+ const bytes = new Uint8Array(buf);
14736
+ if (!isEmbeddableTrueType(bytes)) return null;
14737
+ return await arrayBufferToDataUri(buf);
14738
+ } catch {
14739
+ return null;
14740
+ }
14741
+ })();
14742
+ remoteFontDataUriPromises.set(key, promise);
14743
+ return promise;
14744
+ }
14745
+ async function registerRemoteFontFaceViaProxy(family, requestedWeight, styleRaw) {
14746
+ if (typeof document === "undefined" || typeof FontFace === "undefined" || !document.fonts) return false;
14747
+ if (!resolveHarnessFontProxyUrl()) return false;
14748
+ const style = /italic|oblique/i.test(styleRaw || "") ? "italic" : "normal";
14749
+ const parsed = typeof requestedWeight === "number" ? requestedWeight : Number.parseInt(String(requestedWeight || "400"), 10);
14750
+ const resolved = Number.isFinite(parsed) ? parsed <= 350 ? 300 : parsed <= 450 ? 400 : parsed <= 550 ? 500 : parsed <= 650 ? 600 : 700 : 400;
14751
+ const weightLadder = [resolved];
14752
+ for (const w of [400, 500, 700, 600, 300]) if (!weightLadder.includes(w)) weightLadder.push(w);
14753
+ const sourceOrder = FONTSHARE_SLUGS[family] ? ["fontshare", "google"] : ["google", "fontshare"];
14754
+ for (const actualWeight of weightLadder) {
14755
+ for (const source of sourceOrder) {
14756
+ const faceKey = `${family}|${actualWeight}|${style}|${source}`;
14757
+ if (registeredRemoteFontFaces.has(faceKey)) return true;
14758
+ const dataUri = await fetchFontProxyDataUri(family, actualWeight, style, source);
14759
+ if (!dataUri) continue;
14760
+ try {
14761
+ const face = new FontFace(family, `url("${dataUri}")`, {
14762
+ weight: String(actualWeight),
14763
+ style
14764
+ });
14765
+ await face.load();
14766
+ document.fonts.add(face);
14767
+ appendDataUriFontFaceRule(family, actualWeight, style, dataUri);
14768
+ registeredRemoteFontFaces.add(faceKey);
14769
+ return true;
14770
+ } catch {
14771
+ }
14772
+ }
14773
+ }
14774
+ return false;
14775
+ }
14656
14776
  const LOCAL_FONT_FACE_VARIANTS = [
14657
14777
  { key: "regular", weight: 400, style: "normal" },
14658
14778
  { key: "bold", weight: 700, style: "normal" },
@@ -14847,6 +14967,9 @@ async function ensureFontsForResolvedConfig(config) {
14847
14967
  const descriptors = collectFontDescriptorsFromConfig(config);
14848
14968
  const families = new Set(descriptors.map((d) => d.family));
14849
14969
  await withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 3500);
14970
+ await withTimeout(Promise.all(
14971
+ descriptors.map((d) => registerRemoteFontFaceViaProxy(d.family, d.weight, d.style))
14972
+ ), 5e3);
14850
14973
  if (document.fonts) {
14851
14974
  descriptors.forEach((d) => {
14852
14975
  const stylePrefix = d.style === "italic" ? "italic " : "";
@@ -15834,7 +15957,7 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
15834
15957
  }
15835
15958
  return svgString;
15836
15959
  }
15837
- const PACKAGE_VERSION = "0.5.135";
15960
+ const PACKAGE_VERSION = "0.5.136";
15838
15961
  const roundParityValue = (value) => {
15839
15962
  if (typeof value !== "number") return value;
15840
15963
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16253,7 +16376,7 @@ class PixldocsRenderer {
16253
16376
  await this.waitForCanvasScene(container, cloned, i);
16254
16377
  }
16255
16378
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16256
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-DFgDiZck.cjs"));
16379
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-Cp712xzF.cjs"));
16257
16380
  const prepared = preparePagesForExport(
16258
16381
  cloned.pages,
16259
16382
  canvasWidth,
@@ -16870,6 +16993,12 @@ class PixldocsRenderer {
16870
16993
  const waitForPaint = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));
16871
16994
  const primeCharBounds = (obj) => {
16872
16995
  if (obj instanceof fabric__namespace.Textbox) {
16996
+ try {
16997
+ obj.__lineWidths = [];
16998
+ obj.__lineHeights = [];
16999
+ obj.__charBounds = [];
17000
+ } catch {
17001
+ }
16873
17002
  const lines = obj._textLines;
16874
17003
  if (Array.isArray(lines)) {
16875
17004
  for (let i = 0; i < lines.length; i++) {
@@ -18345,7 +18474,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18345
18474
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18346
18475
  sanitizeSvgTreeForPdf(svgToDraw);
18347
18476
  try {
18348
- const { bakeTextAnchorPositionsFromLiveSvg } = await Promise.resolve().then(() => require("./vectorPdfExport-DFgDiZck.cjs"));
18477
+ const { bakeTextAnchorPositionsFromLiveSvg } = await Promise.resolve().then(() => require("./vectorPdfExport-Cp712xzF.cjs"));
18349
18478
  await bakeTextAnchorPositionsFromLiveSvg(svgToDraw);
18350
18479
  } catch (e) {
18351
18480
  console.warn("[canvas-renderer][pdf-export] anchor-bake pass failed (continuing):", e);
@@ -18687,4 +18816,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
18687
18816
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
18688
18817
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
18689
18818
  exports.warmTemplateFromForm = warmTemplateFromForm;
18690
- //# sourceMappingURL=index-BCvB875s.cjs.map
18819
+ //# sourceMappingURL=index-4hpM5w7h.cjs.map