@pixldocs/canvas-renderer 0.5.135 → 0.5.136

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.
@@ -14608,6 +14608,38 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
14608
14608
  resolveFontWeight,
14609
14609
  rewriteSvgFontsForJsPDF
14610
14610
  }, Symbol.toStringTag, { value: "Module" }));
14611
+ const FONTSHARE_SLUGS = {
14612
+ "Satoshi": "satoshi",
14613
+ "Cabinet Grotesk": "cabinet-grotesk",
14614
+ "Clash Display": "clash-display",
14615
+ "Clash Grotesk": "clash-grotesk",
14616
+ "General Sans": "general-sans",
14617
+ "Switzer": "switzer",
14618
+ "Supreme": "supreme",
14619
+ "Author": "author",
14620
+ "Boska": "boska",
14621
+ "Excon": "excon",
14622
+ "Khand": "khand",
14623
+ "Sentient": "sentient",
14624
+ "Synonym": "synonym",
14625
+ "Erode": "erode",
14626
+ "Ranade": "ranade",
14627
+ "Tanker": "tanker",
14628
+ "Zodiak": "zodiak",
14629
+ "Gambarino": "gambarino",
14630
+ "Melodrama": "melodrama",
14631
+ "Bespoke Serif": "bespoke-serif",
14632
+ "Bespoke Stencil": "bespoke-stencil",
14633
+ "Panchang": "panchang",
14634
+ "Quincy CF": "quincy-cf",
14635
+ "Pally": "pally",
14636
+ "Tabular": "tabular",
14637
+ "Sharpie": "sharpie",
14638
+ "Stardom": "stardom",
14639
+ "Rebond Grotesque": "rebond-grotesque",
14640
+ "Telma": "telma",
14641
+ "Nippo": "nippo"
14642
+ };
14611
14643
  function normalizeFontFamily(fontStack) {
14612
14644
  const first = fontStack.split(",")[0].trim();
14613
14645
  return first.replace(/^['"]|['"]$/g, "");
@@ -14615,6 +14647,8 @@ function normalizeFontFamily(fontStack) {
14615
14647
  const loadedFonts = /* @__PURE__ */ new Set();
14616
14648
  const loadingPromises = /* @__PURE__ */ new Map();
14617
14649
  const registeredLocalFontFaces = /* @__PURE__ */ new Set();
14650
+ const registeredRemoteFontFaces = /* @__PURE__ */ new Set();
14651
+ const remoteFontDataUriPromises = /* @__PURE__ */ new Map();
14618
14652
  let localFontFaceStyleEl = null;
14619
14653
  function ensureLocalFontFaceStyle() {
14620
14654
  if (typeof document === "undefined") return null;
@@ -14635,6 +14669,92 @@ function appendLocalFontFaceRule(family, weight, style, file) {
14635
14669
  `;
14636
14670
  styleEl.appendChild(document.createTextNode(cssText));
14637
14671
  }
14672
+ function appendDataUriFontFaceRule(family, weight, style, dataUri) {
14673
+ const styleEl = ensureLocalFontFaceStyle();
14674
+ if (!styleEl) return;
14675
+ const cssText = `@font-face{font-family:"${family}";src:url("${dataUri}") format("truetype");font-weight:${weight};font-style:${style};font-display:swap;}
14676
+ `;
14677
+ styleEl.appendChild(document.createTextNode(cssText));
14678
+ }
14679
+ function resolveHarnessFontProxyUrl() {
14680
+ var _a, _b;
14681
+ try {
14682
+ 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)) || "";
14683
+ const base = String(runtimeBase || "").replace(/\/$/, "");
14684
+ return base ? `${base}/functions/v1/font-proxy` : "";
14685
+ } catch {
14686
+ return "";
14687
+ }
14688
+ }
14689
+ function isEmbeddableTrueType(bytes) {
14690
+ if (bytes.length < 12) return false;
14691
+ const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);
14692
+ return signature === "\0\0\0" || signature === "true";
14693
+ }
14694
+ async function arrayBufferToDataUri(buf) {
14695
+ const blob = new Blob([buf], { type: "font/ttf" });
14696
+ return await new Promise((resolve, reject) => {
14697
+ const reader = new FileReader();
14698
+ reader.onload = () => resolve(String(reader.result));
14699
+ reader.onerror = () => reject(reader.error || new Error("Failed to read font bytes"));
14700
+ reader.readAsDataURL(blob);
14701
+ });
14702
+ }
14703
+ async function fetchFontProxyDataUri(family, weight, style, source) {
14704
+ const proxyUrl = resolveHarnessFontProxyUrl();
14705
+ if (!proxyUrl) return null;
14706
+ const key = `${source}|${family}|${weight}|${style}`;
14707
+ const existing = remoteFontDataUriPromises.get(key);
14708
+ if (existing) return existing;
14709
+ const promise = (async () => {
14710
+ try {
14711
+ const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${style === "italic" ? 1 : 0}&source=${source}`;
14712
+ const res = await fetch(url, { credentials: "omit" });
14713
+ if (!res.ok) return null;
14714
+ const contentType = res.headers.get("content-type") || "";
14715
+ if (/application\/json/i.test(contentType)) return null;
14716
+ const buf = await res.arrayBuffer();
14717
+ const bytes = new Uint8Array(buf);
14718
+ if (!isEmbeddableTrueType(bytes)) return null;
14719
+ return await arrayBufferToDataUri(buf);
14720
+ } catch {
14721
+ return null;
14722
+ }
14723
+ })();
14724
+ remoteFontDataUriPromises.set(key, promise);
14725
+ return promise;
14726
+ }
14727
+ async function registerRemoteFontFaceViaProxy(family, requestedWeight, styleRaw) {
14728
+ if (typeof document === "undefined" || typeof FontFace === "undefined" || !document.fonts) return false;
14729
+ if (!resolveHarnessFontProxyUrl()) return false;
14730
+ const style = /italic|oblique/i.test(styleRaw || "") ? "italic" : "normal";
14731
+ const parsed = typeof requestedWeight === "number" ? requestedWeight : Number.parseInt(String(requestedWeight || "400"), 10);
14732
+ const resolved = Number.isFinite(parsed) ? parsed <= 350 ? 300 : parsed <= 450 ? 400 : parsed <= 550 ? 500 : parsed <= 650 ? 600 : 700 : 400;
14733
+ const weightLadder = [resolved];
14734
+ for (const w of [400, 500, 700, 600, 300]) if (!weightLadder.includes(w)) weightLadder.push(w);
14735
+ const sourceOrder = FONTSHARE_SLUGS[family] ? ["fontshare", "google"] : ["google", "fontshare"];
14736
+ for (const actualWeight of weightLadder) {
14737
+ for (const source of sourceOrder) {
14738
+ const faceKey = `${family}|${actualWeight}|${style}|${source}`;
14739
+ if (registeredRemoteFontFaces.has(faceKey)) return true;
14740
+ const dataUri = await fetchFontProxyDataUri(family, actualWeight, style, source);
14741
+ if (!dataUri) continue;
14742
+ try {
14743
+ const face = new FontFace(family, `url("${dataUri}")`, {
14744
+ weight: String(actualWeight),
14745
+ style
14746
+ });
14747
+ await face.load();
14748
+ document.fonts.add(face);
14749
+ appendDataUriFontFaceRule(family, actualWeight, style, dataUri);
14750
+ registeredRemoteFontFaces.add(faceKey);
14751
+ return true;
14752
+ } catch {
14753
+ }
14754
+ }
14755
+ }
14756
+ return false;
14757
+ }
14638
14758
  const LOCAL_FONT_FACE_VARIANTS = [
14639
14759
  { key: "regular", weight: 400, style: "normal" },
14640
14760
  { key: "bold", weight: 700, style: "normal" },
@@ -14829,6 +14949,9 @@ async function ensureFontsForResolvedConfig(config) {
14829
14949
  const descriptors = collectFontDescriptorsFromConfig(config);
14830
14950
  const families = new Set(descriptors.map((d) => d.family));
14831
14951
  await withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 3500);
14952
+ await withTimeout(Promise.all(
14953
+ descriptors.map((d) => registerRemoteFontFaceViaProxy(d.family, d.weight, d.style))
14954
+ ), 5e3);
14832
14955
  if (document.fonts) {
14833
14956
  descriptors.forEach((d) => {
14834
14957
  const stylePrefix = d.style === "italic" ? "italic " : "";
@@ -15816,7 +15939,7 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
15816
15939
  }
15817
15940
  return svgString;
15818
15941
  }
15819
- const PACKAGE_VERSION = "0.5.135";
15942
+ const PACKAGE_VERSION = "0.5.136";
15820
15943
  const roundParityValue = (value) => {
15821
15944
  if (typeof value !== "number") return value;
15822
15945
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16235,7 +16358,7 @@ class PixldocsRenderer {
16235
16358
  await this.waitForCanvasScene(container, cloned, i);
16236
16359
  }
16237
16360
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16238
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-CyHRXea-.js");
16361
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-D3L64sAJ.js");
16239
16362
  const prepared = preparePagesForExport(
16240
16363
  cloned.pages,
16241
16364
  canvasWidth,
@@ -18327,7 +18450,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18327
18450
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18328
18451
  sanitizeSvgTreeForPdf(svgToDraw);
18329
18452
  try {
18330
- const { bakeTextAnchorPositionsFromLiveSvg } = await import("./vectorPdfExport-CyHRXea-.js");
18453
+ const { bakeTextAnchorPositionsFromLiveSvg } = await import("./vectorPdfExport-D3L64sAJ.js");
18331
18454
  await bakeTextAnchorPositionsFromLiveSvg(svgToDraw);
18332
18455
  } catch (e) {
18333
18456
  console.warn("[canvas-renderer][pdf-export] anchor-bake pass failed (continuing):", e);
@@ -18672,4 +18795,4 @@ export {
18672
18795
  collectFontDescriptorsFromConfig as y,
18673
18796
  collectFontsFromConfig as z
18674
18797
  };
18675
- //# sourceMappingURL=index-WM3oV4wa.js.map
18798
+ //# sourceMappingURL=index-BHa3ekoF.js.map