@pixldocs/canvas-renderer 0.5.172 → 0.5.174

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.174";
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.174";
16262
16355
  const roundParityValue = (value) => {
16263
16356
  if (typeof value !== "number") return value;
16264
16357
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16632,7 +16725,8 @@ class PixldocsRenderer {
16632
16725
  */
16633
16726
  async renderPdf(templateConfig, options) {
16634
16727
  return this.renderPdfViaClientExport(templateConfig, {
16635
- title: options == null ? void 0 : options.title
16728
+ title: options == null ? void 0 : options.title,
16729
+ textMode: options == null ? void 0 : options.textMode
16636
16730
  });
16637
16731
  }
16638
16732
  /**
@@ -16640,7 +16734,7 @@ class PixldocsRenderer {
16640
16734
  * This is the primary PDF export API — mirrors renderFromForm() but returns a PDF.
16641
16735
  */
16642
16736
  async renderPdfFromForm(options) {
16643
- const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched, title, fontBaseUrl } = options;
16737
+ const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched, title, fontBaseUrl, textMode } = options;
16644
16738
  const resolved = await resolveFromForm({
16645
16739
  templateId,
16646
16740
  formSchemaId,
@@ -16658,7 +16752,8 @@ class PixldocsRenderer {
16658
16752
  }
16659
16753
  return this.renderPdfViaClientExport(configToRender, {
16660
16754
  title: title ?? resolved.config.name,
16661
- watermark: shouldWatermark
16755
+ watermark: shouldWatermark,
16756
+ textMode
16662
16757
  });
16663
16758
  }
16664
16759
  async renderById(templateId, formData, options) {
@@ -16692,6 +16787,7 @@ class PixldocsRenderer {
16692
16787
  * same fonts, same gradients, same draw order, same selectable text.
16693
16788
  */
16694
16789
  async renderPdfViaClientExport(templateConfig, options = {}) {
16790
+ var _a;
16695
16791
  await ensureFontsForResolvedConfig(templateConfig);
16696
16792
  const hasAutoShrink = configHasAutoShrinkText(templateConfig);
16697
16793
  await this.awaitFontsForConfig(templateConfig, hasAutoShrink ? 4e3 : 1800);
@@ -16756,7 +16852,7 @@ class PixldocsRenderer {
16756
16852
  await this.waitForCanvasScene(container, cloned, i);
16757
16853
  }
16758
16854
  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"));
16855
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-wyGn4ybk.cjs"));
16760
16856
  const prepared = preparePagesForExport(
16761
16857
  cloned.pages,
16762
16858
  canvasWidth,
@@ -16765,7 +16861,8 @@ class PixldocsRenderer {
16765
16861
  const result = await exportMultiPagePdf(prepared, {
16766
16862
  title: options.title,
16767
16863
  watermark: !!options.watermark,
16768
- returnBlob: true
16864
+ returnBlob: true,
16865
+ pdfTextMode: options.textMode ?? (cloned == null ? void 0 : cloned.pdfTextMode) ?? ((_a = cloned.canvas) == null ? void 0 : _a.n) ?? "auto"
16769
16866
  });
16770
16867
  if (!result || typeof result === "undefined") {
16771
16868
  throw new Error("exportMultiPagePdf returned no blob (returnBlob path failed)");
@@ -18891,7 +18988,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18891
18988
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18892
18989
  sanitizeSvgTreeForPdf(svgToDraw);
18893
18990
  try {
18894
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CDOztP1H.cjs"));
18991
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-wyGn4ybk.cjs"));
18895
18992
  try {
18896
18993
  await logTextMeasurementDiagnostic(svgToDraw);
18897
18994
  } catch {
@@ -19026,7 +19123,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19026
19123
  }
19027
19124
  if (shouldOutlineText) {
19028
19125
  try {
19029
- const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-IM1f6F-f.cjs"));
19126
+ const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-BLk_mcqi.cjs"));
19030
19127
  pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
19031
19128
  try {
19032
19129
  dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
@@ -19038,6 +19135,16 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
19038
19135
  outlineErr
19039
19136
  );
19040
19137
  }
19138
+ } else {
19139
+ try {
19140
+ const { replaceGradientTextFillsWithFirstStop } = await Promise.resolve().then(() => require("./svgTextToPath-BLk_mcqi.cjs"));
19141
+ pageSvg = replaceGradientTextFillsWithFirstStop(pageSvg);
19142
+ } catch (gradErr) {
19143
+ console.warn(
19144
+ "[canvas-renderer][pdf] gradient-text fill resolution failed:",
19145
+ gradErr
19146
+ );
19147
+ }
19041
19148
  }
19042
19149
  let processedSvg = await prepareLiveCanvasSvgForPdf(pageSvg, page.width, page.height, `page-${i + 1}`, {
19043
19150
  stripPageBackground: shouldStripBg
@@ -19291,4 +19398,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
19291
19398
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
19292
19399
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
19293
19400
  exports.warmTemplateFromForm = warmTemplateFromForm;
19294
- //# sourceMappingURL=index-DYtJJzdk.cjs.map
19401
+ //# sourceMappingURL=index-BH1kJLpb.cjs.map