@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.
@@ -2800,6 +2800,19 @@ const EXTENDED_FONT_LIST = [
2800
2800
  { name: "Petrona", category: "Serif", local: false },
2801
2801
  { name: "Rozha One", category: "Serif", local: false },
2802
2802
  { name: "Tiro Devanagari Hindi", category: "Serif", local: false },
2803
+ // ── Newly added popular serif families ──
2804
+ { name: "Roboto Serif", category: "Serif", local: false, popular: true },
2805
+ { name: "Roboto Slab", category: "Serif", local: false, popular: true },
2806
+ { name: "Inria Serif", category: "Serif", local: false },
2807
+ { name: "Instrument Serif", category: "Serif", local: false, popular: true },
2808
+ { name: "Young Serif", category: "Serif", local: false },
2809
+ { name: "Gloock", category: "Serif", local: false },
2810
+ { name: "Castoro", category: "Serif", local: false },
2811
+ { name: "Source Serif 4", category: "Serif", local: false },
2812
+ { name: "IBM Plex Serif", category: "Serif", local: false },
2813
+ { name: "Pridi", category: "Serif", local: false },
2814
+ { name: "Eczar", category: "Serif", local: false },
2815
+ { name: "Faustina", category: "Serif", local: false },
2803
2816
  // ═══════════════════════════════════════════════════════════════════
2804
2817
  // SANS-SERIF — clean, modern, workhorse
2805
2818
  // ═══════════════════════════════════════════════════════════════════
@@ -2855,6 +2868,43 @@ const EXTENDED_FONT_LIST = [
2855
2868
  { name: "Anek Devanagari", category: "Sans-Serif", local: false },
2856
2869
  { name: "Hind", category: "Sans-Serif", local: true },
2857
2870
  { name: "Hind Vadodara", category: "Sans-Serif", local: false },
2871
+ // ── Newly added popular sans-serif families (Google Fonts; loaded on demand) ──
2872
+ { name: "Ubuntu", category: "Sans-Serif", local: false, popular: true },
2873
+ { name: "Ubuntu Condensed", category: "Sans-Serif", local: false },
2874
+ { name: "Ubuntu Sans", category: "Sans-Serif", local: false },
2875
+ { name: "Roboto Condensed", category: "Sans-Serif", local: false, popular: true },
2876
+ { name: "Roboto Flex", category: "Sans-Serif", local: false },
2877
+ { name: "Jost", category: "Sans-Serif", local: false, popular: true },
2878
+ { name: "Inter Tight", category: "Sans-Serif", local: false },
2879
+ { name: "Mona Sans", category: "Sans-Serif", local: false },
2880
+ { name: "Hubot Sans", category: "Sans-Serif", local: false },
2881
+ { name: "Funnel Sans", category: "Sans-Serif", local: false },
2882
+ { name: "Funnel Display", category: "Sans-Serif", local: false },
2883
+ { name: "Geologica", category: "Sans-Serif", local: false },
2884
+ { name: "Bricolage Grotesque", category: "Sans-Serif", local: false, popular: true },
2885
+ { name: "Familjen Grotesk", category: "Sans-Serif", local: false },
2886
+ { name: "Wix Madefor Display", category: "Sans-Serif", local: false },
2887
+ { name: "Wix Madefor Text", category: "Sans-Serif", local: false },
2888
+ { name: "Atkinson Hyperlegible", category: "Sans-Serif", local: false },
2889
+ { name: "Maven Pro", category: "Sans-Serif", local: false },
2890
+ { name: "Asap", category: "Sans-Serif", local: false },
2891
+ { name: "Asap Condensed", category: "Sans-Serif", local: false },
2892
+ { name: "Saira", category: "Sans-Serif", local: false },
2893
+ { name: "Saira Condensed", category: "Sans-Serif", local: false },
2894
+ { name: "Saira Semi Condensed", category: "Sans-Serif", local: false },
2895
+ { name: "Yanone Kaffeesatz", category: "Sans-Serif", local: false },
2896
+ { name: "Sarabun", category: "Sans-Serif", local: false },
2897
+ { name: "Prompt", category: "Sans-Serif", local: false },
2898
+ { name: "Kanit", category: "Sans-Serif", local: false, popular: true },
2899
+ { name: "Chivo", category: "Sans-Serif", local: false },
2900
+ { name: "Commissioner", category: "Sans-Serif", local: false },
2901
+ { name: "Inria Sans", category: "Sans-Serif", local: false },
2902
+ { name: "Tomorrow", category: "Sans-Serif", local: false },
2903
+ { name: "Catamaran", category: "Sans-Serif", local: false },
2904
+ { name: "Heebo", category: "Sans-Serif", local: false },
2905
+ { name: "Assistant", category: "Sans-Serif", local: false },
2906
+ { name: "Cairo", category: "Sans-Serif", local: false },
2907
+ { name: "Tajawal", category: "Sans-Serif", local: false },
2858
2908
  // ═══════════════════════════════════════════════════════════════════
2859
2909
  // DISPLAY — bold, attention-grabbing headlines
2860
2910
  // ═══════════════════════════════════════════════════════════════════
@@ -2909,6 +2959,12 @@ const EXTENDED_FONT_LIST = [
2909
2959
  { name: "Audiowide", category: "Display", local: false },
2910
2960
  { name: "Orbitron", category: "Display", local: false },
2911
2961
  { name: "Plaster", category: "Display", local: false },
2962
+ // ── Newly added display families ──
2963
+ { name: "Black Han Sans", category: "Display", local: false },
2964
+ { name: "Bungee Spice", category: "Display", local: false },
2965
+ { name: "Sansita Swashed", category: "Display", local: false },
2966
+ { name: "Honk", category: "Display", local: false },
2967
+ { name: "Sixtyfour", category: "Display", local: false },
2912
2968
  // ═══════════════════════════════════════════════════════════════════
2913
2969
  // HANDWRITING / SCRIPT — fluid, personal, calligraphic
2914
2970
  // ═══════════════════════════════════════════════════════════════════
@@ -2998,7 +3054,13 @@ const EXTENDED_FONT_LIST = [
2998
3054
  { name: "Cutive Mono", category: "Monospace", local: false },
2999
3055
  { name: "Major Mono Display", category: "Monospace", local: false },
3000
3056
  { name: "VT323", category: "Monospace", local: false },
3001
- { name: "Share Tech Mono", category: "Monospace", local: false }
3057
+ { name: "Share Tech Mono", category: "Monospace", local: false },
3058
+ // ── Newly added monospace families ──
3059
+ { name: "Ubuntu Mono", category: "Monospace", local: false, popular: true },
3060
+ { name: "Ubuntu Sans Mono", category: "Monospace", local: false },
3061
+ { name: "Noto Sans Mono", category: "Monospace", local: false },
3062
+ { name: "Martian Mono", category: "Monospace", local: false },
3063
+ { name: "Atkinson Hyperlegible Mono", category: "Monospace", local: false }
3002
3064
  ];
3003
3065
  const _fontLookupCache = /* @__PURE__ */ new Map();
3004
3066
  function findFontEntry(name) {
@@ -6224,6 +6286,87 @@ function parseTextMarkdown(input, themeColors) {
6224
6286
  }
6225
6287
  return { plainText: plain, styles, hasFormatting };
6226
6288
  }
6289
+ function angleToCoords(angleDeg) {
6290
+ const rad = angleDeg * Math.PI / 180;
6291
+ const x1 = 0.5 - Math.sin(rad) * 0.5;
6292
+ const y1 = 0.5 + Math.cos(rad) * 0.5;
6293
+ const x2 = 0.5 + Math.sin(rad) * 0.5;
6294
+ const y2 = 0.5 - Math.cos(rad) * 0.5;
6295
+ return { x1, y1, x2, y2 };
6296
+ }
6297
+ function normalizeGradientStops(stops) {
6298
+ const normalized = stops.map((stop) => ({
6299
+ color: stop.color,
6300
+ offset: Math.max(0, Math.min(1, Number(stop.offset) || 0))
6301
+ })).sort((a, b) => a.offset - b.offset);
6302
+ if (normalized.length === 0) return normalized;
6303
+ if (normalized[0].offset > 0) {
6304
+ normalized.unshift({ color: normalized[0].color, offset: 0 });
6305
+ }
6306
+ if (normalized[normalized.length - 1].offset < 1) {
6307
+ normalized.push({ color: normalized[normalized.length - 1].color, offset: 1 });
6308
+ }
6309
+ return normalized;
6310
+ }
6311
+ function gradientToFabric(gradient, width, height) {
6312
+ const colorStops = normalizeGradientStops(gradient.stops).map((s) => ({
6313
+ offset: s.offset,
6314
+ color: s.color
6315
+ }));
6316
+ if (gradient.type === "linear" || gradient.type === "conic") {
6317
+ const coords = angleToCoords(gradient.angle ?? 90);
6318
+ return new fabric__namespace.Gradient({
6319
+ type: "linear",
6320
+ coords: {
6321
+ x1: coords.x1 * width,
6322
+ y1: coords.y1 * height,
6323
+ x2: coords.x2 * width,
6324
+ y2: coords.y2 * height
6325
+ },
6326
+ colorStops
6327
+ });
6328
+ }
6329
+ const cx = (gradient.cx ?? 0.5) * width;
6330
+ const cy = (gradient.cy ?? 0.5) * height;
6331
+ const r = (gradient.r ?? 0.5) * Math.max(width, height);
6332
+ return new fabric__namespace.Gradient({
6333
+ type: "radial",
6334
+ coords: {
6335
+ x1: cx,
6336
+ y1: cy,
6337
+ r1: 0,
6338
+ x2: cx,
6339
+ y2: cy,
6340
+ r2: r
6341
+ },
6342
+ colorStops
6343
+ });
6344
+ }
6345
+ function applyInitialGradients(obj, element) {
6346
+ const w = typeof obj.width === "number" && obj.width > 0 ? obj.width : Number(element.width) || 0;
6347
+ const h = typeof obj.height === "number" && obj.height > 0 ? obj.height : Number(element.height) || 0;
6348
+ if (w <= 0 || h <= 0) return;
6349
+ const fg = element.fillGradient;
6350
+ if (fg && isGradientConfig(fg)) {
6351
+ try {
6352
+ obj.set({ fill: gradientToFabric(fg, w, h), objectCaching: false });
6353
+ obj.__lastFillGradientJson = JSON.stringify(fg);
6354
+ obj.dirty = true;
6355
+ } catch (e) {
6356
+ console.warn("[fabricObjectCreators] fillGradient apply failed:", e);
6357
+ }
6358
+ }
6359
+ const sg = element.strokeGradient;
6360
+ if (sg && isGradientConfig(sg)) {
6361
+ try {
6362
+ obj.set({ stroke: gradientToFabric(sg, w, h), objectCaching: false });
6363
+ obj.__lastStrokeGradientJson = JSON.stringify(sg);
6364
+ obj.dirty = true;
6365
+ } catch (e) {
6366
+ console.warn("[fabricObjectCreators] strokeGradient apply failed:", e);
6367
+ }
6368
+ }
6369
+ }
6227
6370
  const roundDiag = (value) => {
6228
6371
  if (typeof value !== "number") return value;
6229
6372
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -6623,6 +6766,9 @@ function createFabricObject(element) {
6623
6766
  flipY: element.flipY ?? false
6624
6767
  });
6625
6768
  setObjectData(obj, element.id);
6769
+ if (element.type === "shape" || element.type === "line" || element.type === "text") {
6770
+ applyInitialGradients(obj, element);
6771
+ }
6626
6772
  }
6627
6773
  return obj;
6628
6774
  }
@@ -6669,6 +6815,9 @@ function createFabricObjectForGroupMember(element) {
6669
6815
  flipY: element.flipY ?? false
6670
6816
  });
6671
6817
  setObjectData(obj, element.id);
6818
+ if (element.type === "shape" || element.type === "line" || element.type === "text") {
6819
+ applyInitialGradients(obj, element);
6820
+ }
6672
6821
  }
6673
6822
  return obj;
6674
6823
  }
@@ -7208,62 +7357,6 @@ function bakeEdgeFade(source, fade) {
7208
7357
  }
7209
7358
  return canvas;
7210
7359
  }
7211
- function angleToCoords(angleDeg) {
7212
- const rad = angleDeg * Math.PI / 180;
7213
- const x1 = 0.5 - Math.sin(rad) * 0.5;
7214
- const y1 = 0.5 + Math.cos(rad) * 0.5;
7215
- const x2 = 0.5 + Math.sin(rad) * 0.5;
7216
- const y2 = 0.5 - Math.cos(rad) * 0.5;
7217
- return { x1, y1, x2, y2 };
7218
- }
7219
- function normalizeGradientStops(stops) {
7220
- const normalized = stops.map((stop) => ({
7221
- color: stop.color,
7222
- offset: Math.max(0, Math.min(1, Number(stop.offset) || 0))
7223
- })).sort((a, b) => a.offset - b.offset);
7224
- if (normalized.length === 0) return normalized;
7225
- if (normalized[0].offset > 0) {
7226
- normalized.unshift({ color: normalized[0].color, offset: 0 });
7227
- }
7228
- if (normalized[normalized.length - 1].offset < 1) {
7229
- normalized.push({ color: normalized[normalized.length - 1].color, offset: 1 });
7230
- }
7231
- return normalized;
7232
- }
7233
- function gradientToFabric(gradient, width, height) {
7234
- const colorStops = normalizeGradientStops(gradient.stops).map((s) => ({
7235
- offset: s.offset,
7236
- color: s.color
7237
- }));
7238
- if (gradient.type === "linear" || gradient.type === "conic") {
7239
- const coords = angleToCoords(gradient.angle ?? 90);
7240
- return new fabric__namespace.Gradient({
7241
- type: "linear",
7242
- coords: {
7243
- x1: coords.x1 * width,
7244
- y1: coords.y1 * height,
7245
- x2: coords.x2 * width,
7246
- y2: coords.y2 * height
7247
- },
7248
- colorStops
7249
- });
7250
- }
7251
- const cx = (gradient.cx ?? 0.5) * width;
7252
- const cy = (gradient.cy ?? 0.5) * height;
7253
- const r = (gradient.r ?? 0.5) * Math.max(width, height);
7254
- return new fabric__namespace.Gradient({
7255
- type: "radial",
7256
- coords: {
7257
- x1: cx,
7258
- y1: cy,
7259
- r1: 0,
7260
- x2: cx,
7261
- y2: cy,
7262
- r2: r
7263
- },
7264
- colorStops
7265
- });
7266
- }
7267
7360
  const PageCanvas = react.forwardRef(
7268
7361
  ({
7269
7362
  pageId,
@@ -16256,9 +16349,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16256
16349
  }
16257
16350
  return svgString;
16258
16351
  }
16259
- const resolvedPackageVersion = "0.5.172";
16352
+ const resolvedPackageVersion = "0.5.173";
16260
16353
  const PACKAGE_VERSION = resolvedPackageVersion;
16261
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.172";
16354
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.173";
16262
16355
  const roundParityValue = (value) => {
16263
16356
  if (typeof value !== "number") return value;
16264
16357
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16692,6 +16785,7 @@ class PixldocsRenderer {
16692
16785
  * same fonts, same gradients, same draw order, same selectable text.
16693
16786
  */
16694
16787
  async renderPdfViaClientExport(templateConfig, options = {}) {
16788
+ var _a;
16695
16789
  await ensureFontsForResolvedConfig(templateConfig);
16696
16790
  const hasAutoShrink = configHasAutoShrinkText(templateConfig);
16697
16791
  await this.awaitFontsForConfig(templateConfig, hasAutoShrink ? 4e3 : 1800);
@@ -16756,7 +16850,7 @@ class PixldocsRenderer {
16756
16850
  await this.waitForCanvasScene(container, cloned, i);
16757
16851
  }
16758
16852
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16759
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-CDOztP1H.cjs"));
16853
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BWDj55kq.cjs"));
16760
16854
  const prepared = preparePagesForExport(
16761
16855
  cloned.pages,
16762
16856
  canvasWidth,
@@ -16765,7 +16859,8 @@ class PixldocsRenderer {
16765
16859
  const result = await exportMultiPagePdf(prepared, {
16766
16860
  title: options.title,
16767
16861
  watermark: !!options.watermark,
16768
- returnBlob: true
16862
+ returnBlob: true,
16863
+ pdfTextMode: ((_a = cloned.canvas) == null ? void 0 : _a.n) ?? "selectable"
16769
16864
  });
16770
16865
  if (!result || typeof result === "undefined") {
16771
16866
  throw new Error("exportMultiPagePdf returned no blob (returnBlob path failed)");
@@ -18891,7 +18986,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18891
18986
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18892
18987
  sanitizeSvgTreeForPdf(svgToDraw);
18893
18988
  try {
18894
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CDOztP1H.cjs"));
18989
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BWDj55kq.cjs"));
18895
18990
  try {
18896
18991
  await logTextMeasurementDiagnostic(svgToDraw);
18897
18992
  } catch {
@@ -19026,7 +19121,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19026
19121
  }
19027
19122
  if (shouldOutlineText) {
19028
19123
  try {
19029
- const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-IM1f6F-f.cjs"));
19124
+ const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-BLk_mcqi.cjs"));
19030
19125
  pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
19031
19126
  try {
19032
19127
  dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
@@ -19038,6 +19133,16 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19038
19133
  outlineErr
19039
19134
  );
19040
19135
  }
19136
+ } else {
19137
+ try {
19138
+ const { replaceGradientTextFillsWithFirstStop } = await Promise.resolve().then(() => require("./svgTextToPath-BLk_mcqi.cjs"));
19139
+ pageSvg = replaceGradientTextFillsWithFirstStop(pageSvg);
19140
+ } catch (gradErr) {
19141
+ console.warn(
19142
+ "[canvas-renderer][pdf] gradient-text fill resolution failed:",
19143
+ gradErr
19144
+ );
19145
+ }
19041
19146
  }
19042
19147
  let processedSvg = await prepareLiveCanvasSvgForPdf(pageSvg, page.width, page.height, `page-${i + 1}`, {
19043
19148
  stripPageBackground: shouldStripBg
@@ -19291,4 +19396,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
19291
19396
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
19292
19397
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
19293
19398
  exports.warmTemplateFromForm = warmTemplateFromForm;
19294
- //# sourceMappingURL=index-DYtJJzdk.cjs.map
19399
+ //# sourceMappingURL=index-ZehEOqUB.cjs.map