@pixldocs/canvas-renderer 0.5.170 → 0.5.172

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.
@@ -12001,6 +12001,59 @@ const DEFAULT_DATA_V2_VERSION = 2;
12001
12001
  function isDefaultDataV2(data) {
12002
12002
  return typeof data === "object" && data !== null && !Array.isArray(data) && data.version === DEFAULT_DATA_V2_VERSION && typeof data.sectionState === "object" && data.sectionState !== null;
12003
12003
  }
12004
+ function defaultSectionState(sections) {
12005
+ const state = {};
12006
+ const repeatables = sections.filter((s) => s.type === "repeatable");
12007
+ const childrenByParent = /* @__PURE__ */ new Map();
12008
+ for (const section of repeatables) {
12009
+ if (!section.parentId) continue;
12010
+ if (!childrenByParent.has(section.parentId)) childrenByParent.set(section.parentId, []);
12011
+ childrenByParent.get(section.parentId).push(section);
12012
+ }
12013
+ const createEmptyEntry = (section) => {
12014
+ const entry = {};
12015
+ for (const field of section.entryFields) {
12016
+ entry[field.key] = field.type === "list" ? [] : field.type === "toggle" ? "false" : "";
12017
+ }
12018
+ return entry;
12019
+ };
12020
+ const createInitialEntries = (section) => {
12021
+ const count = Math.max(0, section.initialEntryCount ?? 1);
12022
+ return Array.from({ length: count }, () => createEmptyEntry(section));
12023
+ };
12024
+ const seedNested = (parentSection, parentStateKey, parentEntryIndex) => {
12025
+ const children = childrenByParent.get(parentSection.id) ?? [];
12026
+ for (const child of children) {
12027
+ const childStateKey = `${parentStateKey}_${parentEntryIndex}_${child.id}`;
12028
+ const childEntries = createInitialEntries(child);
12029
+ state[childStateKey] = childEntries;
12030
+ childEntries.forEach((_, childEntryIndex) => seedNested(child, childStateKey, childEntryIndex));
12031
+ }
12032
+ };
12033
+ for (const section of sections) {
12034
+ if (section.type !== "single") continue;
12035
+ const obj = {};
12036
+ for (const f of section.fields) {
12037
+ obj[f.key] = f.type === "list" ? [] : f.type === "toggle" ? "false" : "";
12038
+ }
12039
+ state[section.id] = obj;
12040
+ }
12041
+ const topLevelRepeatables = repeatables.filter((s) => !s.parentId);
12042
+ for (const section of topLevelRepeatables) {
12043
+ const entries = createInitialEntries(section);
12044
+ state[section.id] = entries;
12045
+ entries.forEach((_, entryIndex) => seedNested(section, section.id, entryIndex));
12046
+ }
12047
+ const singleSectionIds = new Set(sections.filter((s) => s.type === "single").map((s) => s.id));
12048
+ for (const section of repeatables) {
12049
+ if (section.parentId && singleSectionIds.has(section.parentId)) {
12050
+ const entries = createInitialEntries(section);
12051
+ state[section.id] = entries;
12052
+ entries.forEach((_, entryIndex) => seedNested(section, section.id, entryIndex));
12053
+ }
12054
+ }
12055
+ return state;
12056
+ }
12004
12057
  function flattenSectionStateToFormData(sectionState, sections) {
12005
12058
  const flat = {};
12006
12059
  const repeatables = sections.filter((s) => s.type === "repeatable");
@@ -15751,6 +15804,74 @@ function paintRepeatableSections(config, repeatableSections) {
15751
15804
  }
15752
15805
  }
15753
15806
  }
15807
+ async function getTemplateForm(options) {
15808
+ var _a, _b;
15809
+ const { templateId, supabaseUrl, supabaseAnonKey } = options;
15810
+ if (!supabaseUrl || !supabaseAnonKey) {
15811
+ throw new Error("[getTemplateForm] supabaseUrl and supabaseAnonKey are required");
15812
+ }
15813
+ const templateRow = await fetchRow(supabaseUrl, supabaseAnonKey, "templates", templateId);
15814
+ const templateConfig = templateRow.config;
15815
+ const templateFormSchema = templateRow.form_schema;
15816
+ const boundFormSchemaId = options.formSchemaId ?? (typeof templateRow.form_schema_id === "string" ? templateRow.form_schema_id : null);
15817
+ if (templateFormSchema) {
15818
+ if (!Array.isArray(templateConfig.dynamicFields) && Array.isArray(templateFormSchema.dynamicFields)) {
15819
+ templateConfig.dynamicFields = templateFormSchema.dynamicFields;
15820
+ }
15821
+ if (!Array.isArray(templateConfig.fieldGroups) && Array.isArray(templateFormSchema.fieldGroups)) {
15822
+ templateConfig.fieldGroups = templateFormSchema.fieldGroups;
15823
+ }
15824
+ }
15825
+ let formSchema;
15826
+ let defaultForm = null;
15827
+ if (boundFormSchemaId) {
15828
+ const [schemaRow, defForm] = await Promise.all([
15829
+ fetchRow(supabaseUrl, supabaseAnonKey, "form_schemas", boundFormSchemaId).catch(() => null),
15830
+ fetchDefaultForm(supabaseUrl, supabaseAnonKey, boundFormSchemaId)
15831
+ ]);
15832
+ formSchema = schemaRow == null ? void 0 : schemaRow.schema;
15833
+ defaultForm = defForm;
15834
+ }
15835
+ const repeatableNodeMap = /* @__PURE__ */ new Map();
15836
+ const repeatableFromSchema = templateFormSchema == null ? void 0 : templateFormSchema.repeatableSections;
15837
+ if (repeatableFromSchema) {
15838
+ for (const r of repeatableFromSchema) {
15839
+ if (!repeatableNodeMap.has(r.label)) repeatableNodeMap.set(r.label, r.nodeId);
15840
+ const labelKey = r.label.trim().toLowerCase();
15841
+ if (!repeatableNodeMap.has(labelKey)) repeatableNodeMap.set(labelKey, r.nodeId);
15842
+ }
15843
+ }
15844
+ const schemaSections = getRenderableFormSections(formSchema);
15845
+ let sections;
15846
+ if (schemaSections == null ? void 0 : schemaSections.length) {
15847
+ sections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);
15848
+ } else if ((_a = templateConfig.dynamicFields) == null ? void 0 : _a.length) {
15849
+ sections = inferFormSchemaFromTemplate(
15850
+ templateConfig.dynamicFields,
15851
+ templateConfig.fieldGroups || [],
15852
+ ((_b = templateConfig.pages) == null ? void 0 : _b.length) ? { pages: templateConfig.pages } : void 0
15853
+ );
15854
+ } else {
15855
+ sections = [];
15856
+ }
15857
+ const seeded = defaultSectionState(sections);
15858
+ const templateDefaultData = templateRow.default_data;
15859
+ let overlay = null;
15860
+ if (templateDefaultData && isDefaultDataV2(templateDefaultData)) {
15861
+ overlay = templateDefaultData.sectionState;
15862
+ } else {
15863
+ overlay = extractSectionStateCandidate(defaultForm == null ? void 0 : defaultForm.values, sections) ?? extractSectionStateCandidate(defaultForm == null ? void 0 : defaultForm.saved_data, sections) ?? null;
15864
+ }
15865
+ const initialSectionState = overlay ? { ...seeded, ...overlay } : seeded;
15866
+ return {
15867
+ templateId,
15868
+ templateName: templateRow.name || "Untitled",
15869
+ price: templateRow.price ?? 0,
15870
+ formSchemaId: boundFormSchemaId,
15871
+ sections,
15872
+ initialSectionState
15873
+ };
15874
+ }
15754
15875
  const PREVIEW_DEBUG_PREFIX = "[canvas-renderer][preview-debug]";
15755
15876
  function computeFontSignature(config) {
15756
15877
  var _a;
@@ -16117,9 +16238,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16117
16238
  }
16118
16239
  return svgString;
16119
16240
  }
16120
- const resolvedPackageVersion = "0.5.170";
16241
+ const resolvedPackageVersion = "0.5.172";
16121
16242
  const PACKAGE_VERSION = resolvedPackageVersion;
16122
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.170";
16243
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.172";
16123
16244
  const roundParityValue = (value) => {
16124
16245
  if (typeof value !== "number") return value;
16125
16246
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16617,7 +16738,7 @@ class PixldocsRenderer {
16617
16738
  await this.waitForCanvasScene(container, cloned, i);
16618
16739
  }
16619
16740
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16620
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-BD0zlq42.js");
16741
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-wH2x4QIj.js");
16621
16742
  const prepared = preparePagesForExport(
16622
16743
  cloned.pages,
16623
16744
  canvasWidth,
@@ -16637,28 +16758,46 @@ class PixldocsRenderer {
16637
16758
  }
16638
16759
  }
16639
16760
  getExpectedImageCount(config, pageIndex) {
16761
+ return this.getExpectedImageIds(config, pageIndex).length;
16762
+ }
16763
+ /**
16764
+ * Collects ids of nodes that the renderer expects to produce a renderable
16765
+ * fabric image. Excludes SVG sources because those are loaded as Groups,
16766
+ * not HTMLImageElement-backed Images, and would otherwise inflate the
16767
+ * `expected` counter forever.
16768
+ */
16769
+ getExpectedImageIds(config, pageIndex) {
16640
16770
  const page = config.pages[pageIndex];
16641
- if (!(page == null ? void 0 : page.children)) return 0;
16642
- let count = 0;
16771
+ if (!(page == null ? void 0 : page.children)) return [];
16772
+ const ids = [];
16773
+ const isSvgUrl = (u) => /\.svg(\?|#|$)/i.test(u) || u.startsWith("data:image/svg");
16643
16774
  const walk = (nodes) => {
16644
16775
  for (const node of nodes) {
16645
16776
  if (!node || node.visible === false) continue;
16646
16777
  const src = typeof node.src === "string" ? node.src.trim() : "";
16647
16778
  const imageUrl = typeof node.imageUrl === "string" ? node.imageUrl.trim() : "";
16648
- if (node.type === "image" && (src || imageUrl)) count += 1;
16779
+ const url = src || imageUrl;
16780
+ if (node.type === "image" && url && !isSvgUrl(url) && node.id) {
16781
+ ids.push(String(node.id));
16782
+ }
16649
16783
  if (Array.isArray(node.children) && node.children.length > 0) {
16650
16784
  walk(node.children);
16651
16785
  }
16652
16786
  }
16653
16787
  };
16654
16788
  walk(page.children);
16655
- return count;
16789
+ return ids;
16656
16790
  }
16657
- waitForCanvasImages(container, expectedImageCount, maxWaitMs = 15e3, pollMs = 120) {
16791
+ waitForCanvasImages(container, expectedImageCount, maxWaitMs, pollMs = 120) {
16792
+ const timeout = Math.max(500, maxWaitMs ?? this.config.assetWaitTimeoutMs ?? 15e3);
16793
+ const earlyExitMs = Math.max(250, this.config.assetWaitEarlyExitMs ?? 1500);
16794
+ const debug = !!this.config.debug;
16658
16795
  return new Promise((resolve) => {
16659
16796
  const start = Date.now();
16660
16797
  let stableFrames = 0;
16661
16798
  let lastSummary = "";
16799
+ let lastActual = -1;
16800
+ let lastProgressAt = Date.now();
16662
16801
  const isRenderableImage = (value) => value instanceof HTMLImageElement && value.complete && value.naturalWidth > 0 && value.naturalHeight > 0;
16663
16802
  const collectRenderableImages = (obj, seen) => {
16664
16803
  if (!obj || typeof obj !== "object") return;
@@ -16722,19 +16861,34 @@ class PixldocsRenderer {
16722
16861
  const summary = `expected=${expectedImageCount} actual=${actualImageCount} dom=${domImages.length} fabricReady=${fabricReady} domReady=${allDomLoaded} canvasReady=${canvasReady}`;
16723
16862
  if (summary !== lastSummary) {
16724
16863
  lastSummary = summary;
16725
- console.log(`[canvas-renderer][asset-wait] ${summary}`);
16864
+ if (debug) console.log(`[canvas-renderer][asset-wait] ${summary}`);
16865
+ }
16866
+ if (actualImageCount !== lastActual) {
16867
+ lastActual = actualImageCount;
16868
+ lastProgressAt = Date.now();
16726
16869
  }
16727
16870
  if (ready) {
16728
16871
  stableFrames += 1;
16729
16872
  if (stableFrames >= 2) {
16730
- console.log(`[canvas-renderer][asset-wait] ready after ${elapsed}ms (${summary})`);
16873
+ if (debug) console.log(`[canvas-renderer][asset-wait] ready after ${elapsed}ms (${summary})`);
16731
16874
  settle();
16732
16875
  return;
16733
16876
  }
16734
16877
  } else {
16735
16878
  stableFrames = 0;
16736
16879
  }
16737
- if (elapsed >= maxWaitMs) {
16880
+ const sceneSettled = fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;
16881
+ const idleFor = Date.now() - lastProgressAt;
16882
+ if (sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {
16883
+ if (debug) {
16884
+ console.log(
16885
+ `[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`
16886
+ );
16887
+ }
16888
+ settle();
16889
+ return;
16890
+ }
16891
+ if (elapsed >= timeout) {
16738
16892
  const fabricImageDebug = [];
16739
16893
  for (const obj of fabricObjects) {
16740
16894
  getImageDebugInfo(obj, fabricImageDebug);
@@ -18719,7 +18873,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18719
18873
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18720
18874
  sanitizeSvgTreeForPdf(svgToDraw);
18721
18875
  try {
18722
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-BD0zlq42.js");
18876
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-wH2x4QIj.js");
18723
18877
  try {
18724
18878
  await logTextMeasurementDiagnostic(svgToDraw);
18725
18879
  } catch {
@@ -19064,7 +19218,7 @@ function setAutoShrinkDebug(enabled) {
19064
19218
  }
19065
19219
  }
19066
19220
  export {
19067
- warmResolvedTemplateForPreview as $,
19221
+ setBundledAssetPrefixes as $,
19068
19222
  API_URL as A,
19069
19223
  collectImageUrls as B,
19070
19224
  configHasAutoShrinkText$1 as C,
@@ -19078,23 +19232,24 @@ export {
19078
19232
  extractFontFamiliesFromSvgs as K,
19079
19233
  getEmbeddedJsPDFFontName as L,
19080
19234
  getPublishedTemplate as M,
19081
- isBundledAssetUrl as N,
19082
- isFontAvailable as O,
19235
+ getTemplateForm as N,
19236
+ isBundledAssetUrl as O,
19083
19237
  PACKAGE_VERSION as P,
19084
- isPrivateUrl as Q,
19085
- listPublishedTemplates as R,
19086
- loadGoogleFontCSS as S,
19238
+ isFontAvailable as Q,
19239
+ isPrivateUrl as R,
19240
+ listPublishedTemplates as S,
19087
19241
  TRIANGLE_STROKE_MITER_LIMIT as T,
19088
- normalizeFontFamily as U,
19089
- resolveFontWeight as V,
19090
- resolveFromForm as W,
19091
- resolveTemplateData as X,
19092
- rewriteSvgFontsForJsPDF as Y,
19093
- setAutoShrinkDebug as Z,
19094
- setBundledAssetPrefixes as _,
19242
+ loadGoogleFontCSS as U,
19243
+ normalizeFontFamily as V,
19244
+ resolveFontWeight as W,
19245
+ resolveFromForm as X,
19246
+ resolveTemplateData as Y,
19247
+ rewriteSvgFontsForJsPDF as Z,
19248
+ setAutoShrinkDebug as _,
19095
19249
  getAbsoluteBounds as a,
19096
- warmTemplateFromForm as a0,
19097
- canvasImageLoader as a1,
19250
+ warmResolvedTemplateForPreview as a0,
19251
+ warmTemplateFromForm as a1,
19252
+ canvasImageLoader as a2,
19098
19253
  getProxiedImageUrl as b,
19099
19254
  captureFabricCanvasSvgForPdf as c,
19100
19255
  bakeEdgeFade as d,
@@ -19121,4 +19276,4 @@ export {
19121
19276
  collectFontDescriptorsFromConfig as y,
19122
19277
  collectFontsFromConfig as z
19123
19278
  };
19124
- //# sourceMappingURL=index-BvYxWljO.js.map
19279
+ //# sourceMappingURL=index-DuI8QJDd.js.map