@pixldocs/canvas-renderer 0.5.172 → 0.5.173

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.
@@ -2782,6 +2782,19 @@ const EXTENDED_FONT_LIST = [
2782
2782
  { name: "Petrona", category: "Serif", local: false },
2783
2783
  { name: "Rozha One", category: "Serif", local: false },
2784
2784
  { name: "Tiro Devanagari Hindi", category: "Serif", local: false },
2785
+ // ── Newly added popular serif families ──
2786
+ { name: "Roboto Serif", category: "Serif", local: false, popular: true },
2787
+ { name: "Roboto Slab", category: "Serif", local: false, popular: true },
2788
+ { name: "Inria Serif", category: "Serif", local: false },
2789
+ { name: "Instrument Serif", category: "Serif", local: false, popular: true },
2790
+ { name: "Young Serif", category: "Serif", local: false },
2791
+ { name: "Gloock", category: "Serif", local: false },
2792
+ { name: "Castoro", category: "Serif", local: false },
2793
+ { name: "Source Serif 4", category: "Serif", local: false },
2794
+ { name: "IBM Plex Serif", category: "Serif", local: false },
2795
+ { name: "Pridi", category: "Serif", local: false },
2796
+ { name: "Eczar", category: "Serif", local: false },
2797
+ { name: "Faustina", category: "Serif", local: false },
2785
2798
  // ═══════════════════════════════════════════════════════════════════
2786
2799
  // SANS-SERIF — clean, modern, workhorse
2787
2800
  // ═══════════════════════════════════════════════════════════════════
@@ -2837,6 +2850,43 @@ const EXTENDED_FONT_LIST = [
2837
2850
  { name: "Anek Devanagari", category: "Sans-Serif", local: false },
2838
2851
  { name: "Hind", category: "Sans-Serif", local: true },
2839
2852
  { name: "Hind Vadodara", category: "Sans-Serif", local: false },
2853
+ // ── Newly added popular sans-serif families (Google Fonts; loaded on demand) ──
2854
+ { name: "Ubuntu", category: "Sans-Serif", local: false, popular: true },
2855
+ { name: "Ubuntu Condensed", category: "Sans-Serif", local: false },
2856
+ { name: "Ubuntu Sans", category: "Sans-Serif", local: false },
2857
+ { name: "Roboto Condensed", category: "Sans-Serif", local: false, popular: true },
2858
+ { name: "Roboto Flex", category: "Sans-Serif", local: false },
2859
+ { name: "Jost", category: "Sans-Serif", local: false, popular: true },
2860
+ { name: "Inter Tight", category: "Sans-Serif", local: false },
2861
+ { name: "Mona Sans", category: "Sans-Serif", local: false },
2862
+ { name: "Hubot Sans", category: "Sans-Serif", local: false },
2863
+ { name: "Funnel Sans", category: "Sans-Serif", local: false },
2864
+ { name: "Funnel Display", category: "Sans-Serif", local: false },
2865
+ { name: "Geologica", category: "Sans-Serif", local: false },
2866
+ { name: "Bricolage Grotesque", category: "Sans-Serif", local: false, popular: true },
2867
+ { name: "Familjen Grotesk", category: "Sans-Serif", local: false },
2868
+ { name: "Wix Madefor Display", category: "Sans-Serif", local: false },
2869
+ { name: "Wix Madefor Text", category: "Sans-Serif", local: false },
2870
+ { name: "Atkinson Hyperlegible", category: "Sans-Serif", local: false },
2871
+ { name: "Maven Pro", category: "Sans-Serif", local: false },
2872
+ { name: "Asap", category: "Sans-Serif", local: false },
2873
+ { name: "Asap Condensed", category: "Sans-Serif", local: false },
2874
+ { name: "Saira", category: "Sans-Serif", local: false },
2875
+ { name: "Saira Condensed", category: "Sans-Serif", local: false },
2876
+ { name: "Saira Semi Condensed", category: "Sans-Serif", local: false },
2877
+ { name: "Yanone Kaffeesatz", category: "Sans-Serif", local: false },
2878
+ { name: "Sarabun", category: "Sans-Serif", local: false },
2879
+ { name: "Prompt", category: "Sans-Serif", local: false },
2880
+ { name: "Kanit", category: "Sans-Serif", local: false, popular: true },
2881
+ { name: "Chivo", category: "Sans-Serif", local: false },
2882
+ { name: "Commissioner", category: "Sans-Serif", local: false },
2883
+ { name: "Inria Sans", category: "Sans-Serif", local: false },
2884
+ { name: "Tomorrow", category: "Sans-Serif", local: false },
2885
+ { name: "Catamaran", category: "Sans-Serif", local: false },
2886
+ { name: "Heebo", category: "Sans-Serif", local: false },
2887
+ { name: "Assistant", category: "Sans-Serif", local: false },
2888
+ { name: "Cairo", category: "Sans-Serif", local: false },
2889
+ { name: "Tajawal", category: "Sans-Serif", local: false },
2840
2890
  // ═══════════════════════════════════════════════════════════════════
2841
2891
  // DISPLAY — bold, attention-grabbing headlines
2842
2892
  // ═══════════════════════════════════════════════════════════════════
@@ -2891,6 +2941,12 @@ const EXTENDED_FONT_LIST = [
2891
2941
  { name: "Audiowide", category: "Display", local: false },
2892
2942
  { name: "Orbitron", category: "Display", local: false },
2893
2943
  { name: "Plaster", category: "Display", local: false },
2944
+ // ── Newly added display families ──
2945
+ { name: "Black Han Sans", category: "Display", local: false },
2946
+ { name: "Bungee Spice", category: "Display", local: false },
2947
+ { name: "Sansita Swashed", category: "Display", local: false },
2948
+ { name: "Honk", category: "Display", local: false },
2949
+ { name: "Sixtyfour", category: "Display", local: false },
2894
2950
  // ═══════════════════════════════════════════════════════════════════
2895
2951
  // HANDWRITING / SCRIPT — fluid, personal, calligraphic
2896
2952
  // ═══════════════════════════════════════════════════════════════════
@@ -2980,7 +3036,13 @@ const EXTENDED_FONT_LIST = [
2980
3036
  { name: "Cutive Mono", category: "Monospace", local: false },
2981
3037
  { name: "Major Mono Display", category: "Monospace", local: false },
2982
3038
  { name: "VT323", category: "Monospace", local: false },
2983
- { name: "Share Tech Mono", category: "Monospace", local: false }
3039
+ { name: "Share Tech Mono", category: "Monospace", local: false },
3040
+ // ── Newly added monospace families ──
3041
+ { name: "Ubuntu Mono", category: "Monospace", local: false, popular: true },
3042
+ { name: "Ubuntu Sans Mono", category: "Monospace", local: false },
3043
+ { name: "Noto Sans Mono", category: "Monospace", local: false },
3044
+ { name: "Martian Mono", category: "Monospace", local: false },
3045
+ { name: "Atkinson Hyperlegible Mono", category: "Monospace", local: false }
2984
3046
  ];
2985
3047
  const _fontLookupCache = /* @__PURE__ */ new Map();
2986
3048
  function findFontEntry(name) {
@@ -6206,6 +6268,87 @@ function parseTextMarkdown(input, themeColors) {
6206
6268
  }
6207
6269
  return { plainText: plain, styles, hasFormatting };
6208
6270
  }
6271
+ function angleToCoords(angleDeg) {
6272
+ const rad = angleDeg * Math.PI / 180;
6273
+ const x1 = 0.5 - Math.sin(rad) * 0.5;
6274
+ const y1 = 0.5 + Math.cos(rad) * 0.5;
6275
+ const x2 = 0.5 + Math.sin(rad) * 0.5;
6276
+ const y2 = 0.5 - Math.cos(rad) * 0.5;
6277
+ return { x1, y1, x2, y2 };
6278
+ }
6279
+ function normalizeGradientStops(stops) {
6280
+ const normalized = stops.map((stop) => ({
6281
+ color: stop.color,
6282
+ offset: Math.max(0, Math.min(1, Number(stop.offset) || 0))
6283
+ })).sort((a, b) => a.offset - b.offset);
6284
+ if (normalized.length === 0) return normalized;
6285
+ if (normalized[0].offset > 0) {
6286
+ normalized.unshift({ color: normalized[0].color, offset: 0 });
6287
+ }
6288
+ if (normalized[normalized.length - 1].offset < 1) {
6289
+ normalized.push({ color: normalized[normalized.length - 1].color, offset: 1 });
6290
+ }
6291
+ return normalized;
6292
+ }
6293
+ function gradientToFabric(gradient, width, height) {
6294
+ const colorStops = normalizeGradientStops(gradient.stops).map((s) => ({
6295
+ offset: s.offset,
6296
+ color: s.color
6297
+ }));
6298
+ if (gradient.type === "linear" || gradient.type === "conic") {
6299
+ const coords = angleToCoords(gradient.angle ?? 90);
6300
+ return new fabric.Gradient({
6301
+ type: "linear",
6302
+ coords: {
6303
+ x1: coords.x1 * width,
6304
+ y1: coords.y1 * height,
6305
+ x2: coords.x2 * width,
6306
+ y2: coords.y2 * height
6307
+ },
6308
+ colorStops
6309
+ });
6310
+ }
6311
+ const cx = (gradient.cx ?? 0.5) * width;
6312
+ const cy = (gradient.cy ?? 0.5) * height;
6313
+ const r = (gradient.r ?? 0.5) * Math.max(width, height);
6314
+ return new fabric.Gradient({
6315
+ type: "radial",
6316
+ coords: {
6317
+ x1: cx,
6318
+ y1: cy,
6319
+ r1: 0,
6320
+ x2: cx,
6321
+ y2: cy,
6322
+ r2: r
6323
+ },
6324
+ colorStops
6325
+ });
6326
+ }
6327
+ function applyInitialGradients(obj, element) {
6328
+ const w = typeof obj.width === "number" && obj.width > 0 ? obj.width : Number(element.width) || 0;
6329
+ const h = typeof obj.height === "number" && obj.height > 0 ? obj.height : Number(element.height) || 0;
6330
+ if (w <= 0 || h <= 0) return;
6331
+ const fg = element.fillGradient;
6332
+ if (fg && isGradientConfig(fg)) {
6333
+ try {
6334
+ obj.set({ fill: gradientToFabric(fg, w, h), objectCaching: false });
6335
+ obj.__lastFillGradientJson = JSON.stringify(fg);
6336
+ obj.dirty = true;
6337
+ } catch (e) {
6338
+ console.warn("[fabricObjectCreators] fillGradient apply failed:", e);
6339
+ }
6340
+ }
6341
+ const sg = element.strokeGradient;
6342
+ if (sg && isGradientConfig(sg)) {
6343
+ try {
6344
+ obj.set({ stroke: gradientToFabric(sg, w, h), objectCaching: false });
6345
+ obj.__lastStrokeGradientJson = JSON.stringify(sg);
6346
+ obj.dirty = true;
6347
+ } catch (e) {
6348
+ console.warn("[fabricObjectCreators] strokeGradient apply failed:", e);
6349
+ }
6350
+ }
6351
+ }
6209
6352
  const roundDiag = (value) => {
6210
6353
  if (typeof value !== "number") return value;
6211
6354
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -6605,6 +6748,9 @@ function createFabricObject(element) {
6605
6748
  flipY: element.flipY ?? false
6606
6749
  });
6607
6750
  setObjectData(obj, element.id);
6751
+ if (element.type === "shape" || element.type === "line" || element.type === "text") {
6752
+ applyInitialGradients(obj, element);
6753
+ }
6608
6754
  }
6609
6755
  return obj;
6610
6756
  }
@@ -6651,6 +6797,9 @@ function createFabricObjectForGroupMember(element) {
6651
6797
  flipY: element.flipY ?? false
6652
6798
  });
6653
6799
  setObjectData(obj, element.id);
6800
+ if (element.type === "shape" || element.type === "line" || element.type === "text") {
6801
+ applyInitialGradients(obj, element);
6802
+ }
6654
6803
  }
6655
6804
  return obj;
6656
6805
  }
@@ -7190,62 +7339,6 @@ function bakeEdgeFade(source, fade) {
7190
7339
  }
7191
7340
  return canvas;
7192
7341
  }
7193
- function angleToCoords(angleDeg) {
7194
- const rad = angleDeg * Math.PI / 180;
7195
- const x1 = 0.5 - Math.sin(rad) * 0.5;
7196
- const y1 = 0.5 + Math.cos(rad) * 0.5;
7197
- const x2 = 0.5 + Math.sin(rad) * 0.5;
7198
- const y2 = 0.5 - Math.cos(rad) * 0.5;
7199
- return { x1, y1, x2, y2 };
7200
- }
7201
- function normalizeGradientStops(stops) {
7202
- const normalized = stops.map((stop) => ({
7203
- color: stop.color,
7204
- offset: Math.max(0, Math.min(1, Number(stop.offset) || 0))
7205
- })).sort((a, b) => a.offset - b.offset);
7206
- if (normalized.length === 0) return normalized;
7207
- if (normalized[0].offset > 0) {
7208
- normalized.unshift({ color: normalized[0].color, offset: 0 });
7209
- }
7210
- if (normalized[normalized.length - 1].offset < 1) {
7211
- normalized.push({ color: normalized[normalized.length - 1].color, offset: 1 });
7212
- }
7213
- return normalized;
7214
- }
7215
- function gradientToFabric(gradient, width, height) {
7216
- const colorStops = normalizeGradientStops(gradient.stops).map((s) => ({
7217
- offset: s.offset,
7218
- color: s.color
7219
- }));
7220
- if (gradient.type === "linear" || gradient.type === "conic") {
7221
- const coords = angleToCoords(gradient.angle ?? 90);
7222
- return new fabric.Gradient({
7223
- type: "linear",
7224
- coords: {
7225
- x1: coords.x1 * width,
7226
- y1: coords.y1 * height,
7227
- x2: coords.x2 * width,
7228
- y2: coords.y2 * height
7229
- },
7230
- colorStops
7231
- });
7232
- }
7233
- const cx = (gradient.cx ?? 0.5) * width;
7234
- const cy = (gradient.cy ?? 0.5) * height;
7235
- const r = (gradient.r ?? 0.5) * Math.max(width, height);
7236
- return new fabric.Gradient({
7237
- type: "radial",
7238
- coords: {
7239
- x1: cx,
7240
- y1: cy,
7241
- r1: 0,
7242
- x2: cx,
7243
- y2: cy,
7244
- r2: r
7245
- },
7246
- colorStops
7247
- });
7248
- }
7249
7342
  const PageCanvas = forwardRef(
7250
7343
  ({
7251
7344
  pageId,
@@ -16238,9 +16331,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16238
16331
  }
16239
16332
  return svgString;
16240
16333
  }
16241
- const resolvedPackageVersion = "0.5.172";
16334
+ const resolvedPackageVersion = "0.5.173";
16242
16335
  const PACKAGE_VERSION = resolvedPackageVersion;
16243
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.172";
16336
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.173";
16244
16337
  const roundParityValue = (value) => {
16245
16338
  if (typeof value !== "number") return value;
16246
16339
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16674,6 +16767,7 @@ class PixldocsRenderer {
16674
16767
  * same fonts, same gradients, same draw order, same selectable text.
16675
16768
  */
16676
16769
  async renderPdfViaClientExport(templateConfig, options = {}) {
16770
+ var _a;
16677
16771
  await ensureFontsForResolvedConfig(templateConfig);
16678
16772
  const hasAutoShrink = configHasAutoShrinkText(templateConfig);
16679
16773
  await this.awaitFontsForConfig(templateConfig, hasAutoShrink ? 4e3 : 1800);
@@ -16738,7 +16832,7 @@ class PixldocsRenderer {
16738
16832
  await this.waitForCanvasScene(container, cloned, i);
16739
16833
  }
16740
16834
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16741
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-wH2x4QIj.js");
16835
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-CyTa-D1p.js");
16742
16836
  const prepared = preparePagesForExport(
16743
16837
  cloned.pages,
16744
16838
  canvasWidth,
@@ -16747,7 +16841,8 @@ class PixldocsRenderer {
16747
16841
  const result = await exportMultiPagePdf(prepared, {
16748
16842
  title: options.title,
16749
16843
  watermark: !!options.watermark,
16750
- returnBlob: true
16844
+ returnBlob: true,
16845
+ pdfTextMode: ((_a = cloned.canvas) == null ? void 0 : _a.n) ?? "selectable"
16751
16846
  });
16752
16847
  if (!result || typeof result === "undefined") {
16753
16848
  throw new Error("exportMultiPagePdf returned no blob (returnBlob path failed)");
@@ -18873,7 +18968,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18873
18968
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18874
18969
  sanitizeSvgTreeForPdf(svgToDraw);
18875
18970
  try {
18876
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-wH2x4QIj.js");
18971
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-CyTa-D1p.js");
18877
18972
  try {
18878
18973
  await logTextMeasurementDiagnostic(svgToDraw);
18879
18974
  } catch {
@@ -19008,7 +19103,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19008
19103
  }
19009
19104
  if (shouldOutlineText) {
19010
19105
  try {
19011
- const { convertAllTextToPath } = await import("./svgTextToPath-BXAzwaaR.js");
19106
+ const { convertAllTextToPath } = await import("./svgTextToPath-ra4EhtBL.js");
19012
19107
  pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
19013
19108
  try {
19014
19109
  dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
@@ -19020,6 +19115,16 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19020
19115
  outlineErr
19021
19116
  );
19022
19117
  }
19118
+ } else {
19119
+ try {
19120
+ const { replaceGradientTextFillsWithFirstStop } = await import("./svgTextToPath-ra4EhtBL.js");
19121
+ pageSvg = replaceGradientTextFillsWithFirstStop(pageSvg);
19122
+ } catch (gradErr) {
19123
+ console.warn(
19124
+ "[canvas-renderer][pdf] gradient-text fill resolution failed:",
19125
+ gradErr
19126
+ );
19127
+ }
19023
19128
  }
19024
19129
  let processedSvg = await prepareLiveCanvasSvgForPdf(pageSvg, page.width, page.height, `page-${i + 1}`, {
19025
19130
  stripPageBackground: shouldStripBg
@@ -19276,4 +19381,4 @@ export {
19276
19381
  collectFontDescriptorsFromConfig as y,
19277
19382
  collectFontsFromConfig as z
19278
19383
  };
19279
- //# sourceMappingURL=index-DuI8QJDd.js.map
19384
+ //# sourceMappingURL=index-ChHYFk0E.js.map