@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.
@@ -12019,6 +12019,59 @@ const DEFAULT_DATA_V2_VERSION = 2;
12019
12019
  function isDefaultDataV2(data) {
12020
12020
  return typeof data === "object" && data !== null && !Array.isArray(data) && data.version === DEFAULT_DATA_V2_VERSION && typeof data.sectionState === "object" && data.sectionState !== null;
12021
12021
  }
12022
+ function defaultSectionState(sections) {
12023
+ const state = {};
12024
+ const repeatables = sections.filter((s) => s.type === "repeatable");
12025
+ const childrenByParent = /* @__PURE__ */ new Map();
12026
+ for (const section of repeatables) {
12027
+ if (!section.parentId) continue;
12028
+ if (!childrenByParent.has(section.parentId)) childrenByParent.set(section.parentId, []);
12029
+ childrenByParent.get(section.parentId).push(section);
12030
+ }
12031
+ const createEmptyEntry = (section) => {
12032
+ const entry = {};
12033
+ for (const field of section.entryFields) {
12034
+ entry[field.key] = field.type === "list" ? [] : field.type === "toggle" ? "false" : "";
12035
+ }
12036
+ return entry;
12037
+ };
12038
+ const createInitialEntries = (section) => {
12039
+ const count = Math.max(0, section.initialEntryCount ?? 1);
12040
+ return Array.from({ length: count }, () => createEmptyEntry(section));
12041
+ };
12042
+ const seedNested = (parentSection, parentStateKey, parentEntryIndex) => {
12043
+ const children = childrenByParent.get(parentSection.id) ?? [];
12044
+ for (const child of children) {
12045
+ const childStateKey = `${parentStateKey}_${parentEntryIndex}_${child.id}`;
12046
+ const childEntries = createInitialEntries(child);
12047
+ state[childStateKey] = childEntries;
12048
+ childEntries.forEach((_, childEntryIndex) => seedNested(child, childStateKey, childEntryIndex));
12049
+ }
12050
+ };
12051
+ for (const section of sections) {
12052
+ if (section.type !== "single") continue;
12053
+ const obj = {};
12054
+ for (const f of section.fields) {
12055
+ obj[f.key] = f.type === "list" ? [] : f.type === "toggle" ? "false" : "";
12056
+ }
12057
+ state[section.id] = obj;
12058
+ }
12059
+ const topLevelRepeatables = repeatables.filter((s) => !s.parentId);
12060
+ for (const section of topLevelRepeatables) {
12061
+ const entries = createInitialEntries(section);
12062
+ state[section.id] = entries;
12063
+ entries.forEach((_, entryIndex) => seedNested(section, section.id, entryIndex));
12064
+ }
12065
+ const singleSectionIds = new Set(sections.filter((s) => s.type === "single").map((s) => s.id));
12066
+ for (const section of repeatables) {
12067
+ if (section.parentId && singleSectionIds.has(section.parentId)) {
12068
+ const entries = createInitialEntries(section);
12069
+ state[section.id] = entries;
12070
+ entries.forEach((_, entryIndex) => seedNested(section, section.id, entryIndex));
12071
+ }
12072
+ }
12073
+ return state;
12074
+ }
12022
12075
  function flattenSectionStateToFormData(sectionState, sections) {
12023
12076
  const flat = {};
12024
12077
  const repeatables = sections.filter((s) => s.type === "repeatable");
@@ -15769,6 +15822,74 @@ function paintRepeatableSections(config, repeatableSections) {
15769
15822
  }
15770
15823
  }
15771
15824
  }
15825
+ async function getTemplateForm(options) {
15826
+ var _a, _b;
15827
+ const { templateId, supabaseUrl, supabaseAnonKey } = options;
15828
+ if (!supabaseUrl || !supabaseAnonKey) {
15829
+ throw new Error("[getTemplateForm] supabaseUrl and supabaseAnonKey are required");
15830
+ }
15831
+ const templateRow = await fetchRow(supabaseUrl, supabaseAnonKey, "templates", templateId);
15832
+ const templateConfig = templateRow.config;
15833
+ const templateFormSchema = templateRow.form_schema;
15834
+ const boundFormSchemaId = options.formSchemaId ?? (typeof templateRow.form_schema_id === "string" ? templateRow.form_schema_id : null);
15835
+ if (templateFormSchema) {
15836
+ if (!Array.isArray(templateConfig.dynamicFields) && Array.isArray(templateFormSchema.dynamicFields)) {
15837
+ templateConfig.dynamicFields = templateFormSchema.dynamicFields;
15838
+ }
15839
+ if (!Array.isArray(templateConfig.fieldGroups) && Array.isArray(templateFormSchema.fieldGroups)) {
15840
+ templateConfig.fieldGroups = templateFormSchema.fieldGroups;
15841
+ }
15842
+ }
15843
+ let formSchema;
15844
+ let defaultForm = null;
15845
+ if (boundFormSchemaId) {
15846
+ const [schemaRow, defForm] = await Promise.all([
15847
+ fetchRow(supabaseUrl, supabaseAnonKey, "form_schemas", boundFormSchemaId).catch(() => null),
15848
+ fetchDefaultForm(supabaseUrl, supabaseAnonKey, boundFormSchemaId)
15849
+ ]);
15850
+ formSchema = schemaRow == null ? void 0 : schemaRow.schema;
15851
+ defaultForm = defForm;
15852
+ }
15853
+ const repeatableNodeMap = /* @__PURE__ */ new Map();
15854
+ const repeatableFromSchema = templateFormSchema == null ? void 0 : templateFormSchema.repeatableSections;
15855
+ if (repeatableFromSchema) {
15856
+ for (const r of repeatableFromSchema) {
15857
+ if (!repeatableNodeMap.has(r.label)) repeatableNodeMap.set(r.label, r.nodeId);
15858
+ const labelKey = r.label.trim().toLowerCase();
15859
+ if (!repeatableNodeMap.has(labelKey)) repeatableNodeMap.set(labelKey, r.nodeId);
15860
+ }
15861
+ }
15862
+ const schemaSections = getRenderableFormSections(formSchema);
15863
+ let sections;
15864
+ if (schemaSections == null ? void 0 : schemaSections.length) {
15865
+ sections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);
15866
+ } else if ((_a = templateConfig.dynamicFields) == null ? void 0 : _a.length) {
15867
+ sections = inferFormSchemaFromTemplate(
15868
+ templateConfig.dynamicFields,
15869
+ templateConfig.fieldGroups || [],
15870
+ ((_b = templateConfig.pages) == null ? void 0 : _b.length) ? { pages: templateConfig.pages } : void 0
15871
+ );
15872
+ } else {
15873
+ sections = [];
15874
+ }
15875
+ const seeded = defaultSectionState(sections);
15876
+ const templateDefaultData = templateRow.default_data;
15877
+ let overlay = null;
15878
+ if (templateDefaultData && isDefaultDataV2(templateDefaultData)) {
15879
+ overlay = templateDefaultData.sectionState;
15880
+ } else {
15881
+ overlay = extractSectionStateCandidate(defaultForm == null ? void 0 : defaultForm.values, sections) ?? extractSectionStateCandidate(defaultForm == null ? void 0 : defaultForm.saved_data, sections) ?? null;
15882
+ }
15883
+ const initialSectionState = overlay ? { ...seeded, ...overlay } : seeded;
15884
+ return {
15885
+ templateId,
15886
+ templateName: templateRow.name || "Untitled",
15887
+ price: templateRow.price ?? 0,
15888
+ formSchemaId: boundFormSchemaId,
15889
+ sections,
15890
+ initialSectionState
15891
+ };
15892
+ }
15772
15893
  const PREVIEW_DEBUG_PREFIX = "[canvas-renderer][preview-debug]";
15773
15894
  function computeFontSignature(config) {
15774
15895
  var _a;
@@ -16135,9 +16256,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16135
16256
  }
16136
16257
  return svgString;
16137
16258
  }
16138
- const resolvedPackageVersion = "0.5.170";
16259
+ const resolvedPackageVersion = "0.5.172";
16139
16260
  const PACKAGE_VERSION = resolvedPackageVersion;
16140
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.170";
16261
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.172";
16141
16262
  const roundParityValue = (value) => {
16142
16263
  if (typeof value !== "number") return value;
16143
16264
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16635,7 +16756,7 @@ class PixldocsRenderer {
16635
16756
  await this.waitForCanvasScene(container, cloned, i);
16636
16757
  }
16637
16758
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16638
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BnFtIh0l.cjs"));
16759
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-CDOztP1H.cjs"));
16639
16760
  const prepared = preparePagesForExport(
16640
16761
  cloned.pages,
16641
16762
  canvasWidth,
@@ -16655,28 +16776,46 @@ class PixldocsRenderer {
16655
16776
  }
16656
16777
  }
16657
16778
  getExpectedImageCount(config, pageIndex) {
16779
+ return this.getExpectedImageIds(config, pageIndex).length;
16780
+ }
16781
+ /**
16782
+ * Collects ids of nodes that the renderer expects to produce a renderable
16783
+ * fabric image. Excludes SVG sources because those are loaded as Groups,
16784
+ * not HTMLImageElement-backed Images, and would otherwise inflate the
16785
+ * `expected` counter forever.
16786
+ */
16787
+ getExpectedImageIds(config, pageIndex) {
16658
16788
  const page = config.pages[pageIndex];
16659
- if (!(page == null ? void 0 : page.children)) return 0;
16660
- let count = 0;
16789
+ if (!(page == null ? void 0 : page.children)) return [];
16790
+ const ids = [];
16791
+ const isSvgUrl = (u) => /\.svg(\?|#|$)/i.test(u) || u.startsWith("data:image/svg");
16661
16792
  const walk = (nodes) => {
16662
16793
  for (const node of nodes) {
16663
16794
  if (!node || node.visible === false) continue;
16664
16795
  const src = typeof node.src === "string" ? node.src.trim() : "";
16665
16796
  const imageUrl = typeof node.imageUrl === "string" ? node.imageUrl.trim() : "";
16666
- if (node.type === "image" && (src || imageUrl)) count += 1;
16797
+ const url = src || imageUrl;
16798
+ if (node.type === "image" && url && !isSvgUrl(url) && node.id) {
16799
+ ids.push(String(node.id));
16800
+ }
16667
16801
  if (Array.isArray(node.children) && node.children.length > 0) {
16668
16802
  walk(node.children);
16669
16803
  }
16670
16804
  }
16671
16805
  };
16672
16806
  walk(page.children);
16673
- return count;
16807
+ return ids;
16674
16808
  }
16675
- waitForCanvasImages(container, expectedImageCount, maxWaitMs = 15e3, pollMs = 120) {
16809
+ waitForCanvasImages(container, expectedImageCount, maxWaitMs, pollMs = 120) {
16810
+ const timeout = Math.max(500, maxWaitMs ?? this.config.assetWaitTimeoutMs ?? 15e3);
16811
+ const earlyExitMs = Math.max(250, this.config.assetWaitEarlyExitMs ?? 1500);
16812
+ const debug = !!this.config.debug;
16676
16813
  return new Promise((resolve) => {
16677
16814
  const start = Date.now();
16678
16815
  let stableFrames = 0;
16679
16816
  let lastSummary = "";
16817
+ let lastActual = -1;
16818
+ let lastProgressAt = Date.now();
16680
16819
  const isRenderableImage = (value) => value instanceof HTMLImageElement && value.complete && value.naturalWidth > 0 && value.naturalHeight > 0;
16681
16820
  const collectRenderableImages = (obj, seen) => {
16682
16821
  if (!obj || typeof obj !== "object") return;
@@ -16740,19 +16879,34 @@ class PixldocsRenderer {
16740
16879
  const summary = `expected=${expectedImageCount} actual=${actualImageCount} dom=${domImages.length} fabricReady=${fabricReady} domReady=${allDomLoaded} canvasReady=${canvasReady}`;
16741
16880
  if (summary !== lastSummary) {
16742
16881
  lastSummary = summary;
16743
- console.log(`[canvas-renderer][asset-wait] ${summary}`);
16882
+ if (debug) console.log(`[canvas-renderer][asset-wait] ${summary}`);
16883
+ }
16884
+ if (actualImageCount !== lastActual) {
16885
+ lastActual = actualImageCount;
16886
+ lastProgressAt = Date.now();
16744
16887
  }
16745
16888
  if (ready) {
16746
16889
  stableFrames += 1;
16747
16890
  if (stableFrames >= 2) {
16748
- console.log(`[canvas-renderer][asset-wait] ready after ${elapsed}ms (${summary})`);
16891
+ if (debug) console.log(`[canvas-renderer][asset-wait] ready after ${elapsed}ms (${summary})`);
16749
16892
  settle();
16750
16893
  return;
16751
16894
  }
16752
16895
  } else {
16753
16896
  stableFrames = 0;
16754
16897
  }
16755
- if (elapsed >= maxWaitMs) {
16898
+ const sceneSettled = fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;
16899
+ const idleFor = Date.now() - lastProgressAt;
16900
+ if (sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {
16901
+ if (debug) {
16902
+ console.log(
16903
+ `[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`
16904
+ );
16905
+ }
16906
+ settle();
16907
+ return;
16908
+ }
16909
+ if (elapsed >= timeout) {
16756
16910
  const fabricImageDebug = [];
16757
16911
  for (const obj of fabricObjects) {
16758
16912
  getImageDebugInfo(obj, fabricImageDebug);
@@ -18737,7 +18891,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18737
18891
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18738
18892
  sanitizeSvgTreeForPdf(svgToDraw);
18739
18893
  try {
18740
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BnFtIh0l.cjs"));
18894
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CDOztP1H.cjs"));
18741
18895
  try {
18742
18896
  await logTextMeasurementDiagnostic(svgToDraw);
18743
18897
  } catch {
@@ -19115,6 +19269,7 @@ exports.getImageProxyFetchOptions = getImageProxyFetchOptions;
19115
19269
  exports.getProxiedImageUrl = getProxiedImageUrl;
19116
19270
  exports.getPublishedTemplate = getPublishedTemplate;
19117
19271
  exports.getRoundedRectRadii = getRoundedRectRadii;
19272
+ exports.getTemplateForm = getTemplateForm;
19118
19273
  exports.getTrianglePoints = getTrianglePoints;
19119
19274
  exports.hasEdgeFade = hasEdgeFade;
19120
19275
  exports.isBundledAssetUrl = isBundledAssetUrl;
@@ -19136,4 +19291,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
19136
19291
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
19137
19292
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
19138
19293
  exports.warmTemplateFromForm = warmTemplateFromForm;
19139
- //# sourceMappingURL=index-CtWVrKc-.cjs.map
19294
+ //# sourceMappingURL=index-DYtJJzdk.cjs.map