@pixldocs/canvas-renderer 0.3.13 → 0.3.15
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.
- package/dist/index.cjs +125 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +125 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -181,7 +181,8 @@ export declare class PixldocsRenderer {
|
|
|
181
181
|
renderById(templateId: string, formData?: Record<string, any>, options?: RenderOptions): Promise<RenderResult>;
|
|
182
182
|
/**
|
|
183
183
|
* Wait until every image on the Fabric canvas inside the container has loaded.
|
|
184
|
-
*
|
|
184
|
+
* Checks both DOM <img> elements AND Fabric canvas image objects to ensure
|
|
185
|
+
* all async assets are fully painted before capture.
|
|
185
186
|
*/
|
|
186
187
|
private waitForCanvasImages;
|
|
187
188
|
private getNormalizedGradientStops;
|
package/dist/index.js
CHANGED
|
@@ -10369,79 +10369,6 @@ function paintRepeatableSections(config, repeatableSections) {
|
|
|
10369
10369
|
}
|
|
10370
10370
|
}
|
|
10371
10371
|
}
|
|
10372
|
-
function PixldocsPreview(props) {
|
|
10373
|
-
const {
|
|
10374
|
-
pageIndex = 0,
|
|
10375
|
-
zoom = 1,
|
|
10376
|
-
absoluteZoom = false,
|
|
10377
|
-
imageProxyUrl,
|
|
10378
|
-
className,
|
|
10379
|
-
style,
|
|
10380
|
-
onDynamicFieldClick,
|
|
10381
|
-
onReady,
|
|
10382
|
-
onError
|
|
10383
|
-
} = props;
|
|
10384
|
-
useEffect(() => {
|
|
10385
|
-
setPackageApiUrl(imageProxyUrl);
|
|
10386
|
-
}, [imageProxyUrl]);
|
|
10387
|
-
const [resolvedConfig, setResolvedConfig] = useState(null);
|
|
10388
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
10389
|
-
const isResolveMode = !("config" in props && props.config);
|
|
10390
|
-
useEffect(() => {
|
|
10391
|
-
if (!isResolveMode) {
|
|
10392
|
-
setResolvedConfig(null);
|
|
10393
|
-
return;
|
|
10394
|
-
}
|
|
10395
|
-
const p = props;
|
|
10396
|
-
if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;
|
|
10397
|
-
let cancelled = false;
|
|
10398
|
-
setIsLoading(true);
|
|
10399
|
-
resolveFromForm({
|
|
10400
|
-
templateId: p.templateId,
|
|
10401
|
-
formSchemaId: p.formSchemaId,
|
|
10402
|
-
sectionState: p.sectionState,
|
|
10403
|
-
themeId: p.themeId,
|
|
10404
|
-
supabaseUrl: p.supabaseUrl,
|
|
10405
|
-
supabaseAnonKey: p.supabaseAnonKey
|
|
10406
|
-
}).then((resolved) => {
|
|
10407
|
-
if (!cancelled) {
|
|
10408
|
-
setResolvedConfig(resolved.config);
|
|
10409
|
-
setIsLoading(false);
|
|
10410
|
-
}
|
|
10411
|
-
}).catch((err) => {
|
|
10412
|
-
if (!cancelled) {
|
|
10413
|
-
setIsLoading(false);
|
|
10414
|
-
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
10415
|
-
}
|
|
10416
|
-
});
|
|
10417
|
-
return () => {
|
|
10418
|
-
cancelled = true;
|
|
10419
|
-
};
|
|
10420
|
-
}, [
|
|
10421
|
-
isResolveMode,
|
|
10422
|
-
// For resolve mode, re-resolve when these change
|
|
10423
|
-
isResolveMode ? props.templateId : void 0,
|
|
10424
|
-
isResolveMode ? props.formSchemaId : void 0,
|
|
10425
|
-
isResolveMode ? JSON.stringify(props.sectionState) : void 0,
|
|
10426
|
-
isResolveMode ? props.themeId : void 0
|
|
10427
|
-
]);
|
|
10428
|
-
const config = isResolveMode ? resolvedConfig : props.config;
|
|
10429
|
-
if (isLoading) {
|
|
10430
|
-
return /* @__PURE__ */ jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
10431
|
-
}
|
|
10432
|
-
if (!config) return null;
|
|
10433
|
-
return /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsx(
|
|
10434
|
-
PreviewCanvas,
|
|
10435
|
-
{
|
|
10436
|
-
config,
|
|
10437
|
-
pageIndex,
|
|
10438
|
-
zoom,
|
|
10439
|
-
absoluteZoom,
|
|
10440
|
-
onDynamicFieldClick,
|
|
10441
|
-
onReady
|
|
10442
|
-
}
|
|
10443
|
-
) });
|
|
10444
|
-
}
|
|
10445
10372
|
function normalizeFontFamily(fontStack) {
|
|
10446
10373
|
const first = fontStack.split(",")[0].trim();
|
|
10447
10374
|
return first.replace(/^['"]|['"]$/g, "");
|
|
@@ -10456,12 +10383,7 @@ async function loadGoogleFontCSS(rawFontFamily) {
|
|
|
10456
10383
|
const existing = loadingPromises.get(fontFamily);
|
|
10457
10384
|
if (existing) return existing;
|
|
10458
10385
|
const promise = (async () => {
|
|
10459
|
-
var _a;
|
|
10460
10386
|
try {
|
|
10461
|
-
if ((_a = document.fonts) == null ? void 0 : _a.check(`16px "${fontFamily}"`)) {
|
|
10462
|
-
loadedFonts.add(fontFamily);
|
|
10463
|
-
return;
|
|
10464
|
-
}
|
|
10465
10387
|
const encoded = encodeURIComponent(fontFamily);
|
|
10466
10388
|
const url = `https://fonts.googleapis.com/css?family=${encoded}:300,400,500,600,700&display=swap`;
|
|
10467
10389
|
const link = document.createElement("link");
|
|
@@ -10490,6 +10412,7 @@ function collectFontsFromConfig(config) {
|
|
|
10490
10412
|
var _a;
|
|
10491
10413
|
const fonts = /* @__PURE__ */ new Set();
|
|
10492
10414
|
fonts.add("Open Sans");
|
|
10415
|
+
fonts.add("Hind");
|
|
10493
10416
|
function walk(nodes) {
|
|
10494
10417
|
var _a2;
|
|
10495
10418
|
if (!nodes) return;
|
|
@@ -10542,12 +10465,18 @@ function collectFontDescriptorsFromConfig(config) {
|
|
|
10542
10465
|
for (const node of nodes) {
|
|
10543
10466
|
if (node.fontFamily) {
|
|
10544
10467
|
add(node.fontFamily, node.fontWeight, node.fontStyle);
|
|
10468
|
+
if (node.type === "text") {
|
|
10469
|
+
for (const w of [300, 400, 500, 600, 700]) {
|
|
10470
|
+
add(node.fontFamily, w, node.fontStyle);
|
|
10471
|
+
}
|
|
10472
|
+
}
|
|
10545
10473
|
}
|
|
10546
10474
|
if ((_a2 = node.smartProps) == null ? void 0 : _a2.fontFamily) {
|
|
10547
10475
|
add(node.smartProps.fontFamily, node.smartProps.fontWeight, node.smartProps.fontStyle);
|
|
10548
10476
|
}
|
|
10549
|
-
if (node.styles
|
|
10550
|
-
|
|
10477
|
+
if (node.styles) {
|
|
10478
|
+
const styleEntries = Array.isArray(node.styles) ? node.styles : Object.values(node.styles);
|
|
10479
|
+
for (const lineStyle of styleEntries) {
|
|
10551
10480
|
if (lineStyle && typeof lineStyle === "object") {
|
|
10552
10481
|
for (const charStyle of Object.values(lineStyle)) {
|
|
10553
10482
|
if (charStyle == null ? void 0 : charStyle.fontFamily) {
|
|
@@ -10561,6 +10490,8 @@ function collectFontDescriptorsFromConfig(config) {
|
|
|
10561
10490
|
}
|
|
10562
10491
|
}
|
|
10563
10492
|
add("Open Sans", 400, "normal");
|
|
10493
|
+
add("Hind", 400, "normal");
|
|
10494
|
+
add("Hind", 700, "normal");
|
|
10564
10495
|
for (const page of config.pages || []) {
|
|
10565
10496
|
walk(page.children || []);
|
|
10566
10497
|
}
|
|
@@ -10592,6 +10523,95 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
10592
10523
|
await document.fonts.ready;
|
|
10593
10524
|
}
|
|
10594
10525
|
}
|
|
10526
|
+
function PixldocsPreview(props) {
|
|
10527
|
+
const {
|
|
10528
|
+
pageIndex = 0,
|
|
10529
|
+
zoom = 1,
|
|
10530
|
+
absoluteZoom = false,
|
|
10531
|
+
imageProxyUrl,
|
|
10532
|
+
className,
|
|
10533
|
+
style,
|
|
10534
|
+
onDynamicFieldClick,
|
|
10535
|
+
onReady,
|
|
10536
|
+
onError
|
|
10537
|
+
} = props;
|
|
10538
|
+
useEffect(() => {
|
|
10539
|
+
setPackageApiUrl(imageProxyUrl);
|
|
10540
|
+
}, [imageProxyUrl]);
|
|
10541
|
+
const [resolvedConfig, setResolvedConfig] = useState(null);
|
|
10542
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
10543
|
+
const [fontsReady, setFontsReady] = useState(false);
|
|
10544
|
+
const isResolveMode = !("config" in props && props.config);
|
|
10545
|
+
useEffect(() => {
|
|
10546
|
+
if (!isResolveMode) {
|
|
10547
|
+
setResolvedConfig(null);
|
|
10548
|
+
return;
|
|
10549
|
+
}
|
|
10550
|
+
const p = props;
|
|
10551
|
+
if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;
|
|
10552
|
+
let cancelled = false;
|
|
10553
|
+
setIsLoading(true);
|
|
10554
|
+
resolveFromForm({
|
|
10555
|
+
templateId: p.templateId,
|
|
10556
|
+
formSchemaId: p.formSchemaId,
|
|
10557
|
+
sectionState: p.sectionState,
|
|
10558
|
+
themeId: p.themeId,
|
|
10559
|
+
supabaseUrl: p.supabaseUrl,
|
|
10560
|
+
supabaseAnonKey: p.supabaseAnonKey
|
|
10561
|
+
}).then((resolved) => {
|
|
10562
|
+
if (!cancelled) {
|
|
10563
|
+
setResolvedConfig(resolved.config);
|
|
10564
|
+
ensureFontsForResolvedConfig(resolved.config).then(() => {
|
|
10565
|
+
if (!cancelled) {
|
|
10566
|
+
setFontsReady(true);
|
|
10567
|
+
setIsLoading(false);
|
|
10568
|
+
}
|
|
10569
|
+
}).catch(() => {
|
|
10570
|
+
if (!cancelled) {
|
|
10571
|
+
setFontsReady(true);
|
|
10572
|
+
setIsLoading(false);
|
|
10573
|
+
}
|
|
10574
|
+
});
|
|
10575
|
+
}
|
|
10576
|
+
}).catch((err) => {
|
|
10577
|
+
if (!cancelled) {
|
|
10578
|
+
setIsLoading(false);
|
|
10579
|
+
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
10580
|
+
}
|
|
10581
|
+
});
|
|
10582
|
+
return () => {
|
|
10583
|
+
cancelled = true;
|
|
10584
|
+
};
|
|
10585
|
+
}, [
|
|
10586
|
+
isResolveMode,
|
|
10587
|
+
// For resolve mode, re-resolve when these change
|
|
10588
|
+
isResolveMode ? props.templateId : void 0,
|
|
10589
|
+
isResolveMode ? props.formSchemaId : void 0,
|
|
10590
|
+
isResolveMode ? JSON.stringify(props.sectionState) : void 0,
|
|
10591
|
+
isResolveMode ? props.themeId : void 0
|
|
10592
|
+
]);
|
|
10593
|
+
const config = isResolveMode ? resolvedConfig : props.config;
|
|
10594
|
+
useEffect(() => {
|
|
10595
|
+
if (isResolveMode || !config) return;
|
|
10596
|
+
setFontsReady(false);
|
|
10597
|
+
ensureFontsForResolvedConfig(config).then(() => setFontsReady(true)).catch(() => setFontsReady(true));
|
|
10598
|
+
}, [isResolveMode, config]);
|
|
10599
|
+
if (isLoading) {
|
|
10600
|
+
return /* @__PURE__ */ jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
10601
|
+
}
|
|
10602
|
+
if (!config) return null;
|
|
10603
|
+
return /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsx(
|
|
10604
|
+
PreviewCanvas,
|
|
10605
|
+
{
|
|
10606
|
+
config,
|
|
10607
|
+
pageIndex,
|
|
10608
|
+
zoom,
|
|
10609
|
+
absoluteZoom,
|
|
10610
|
+
onDynamicFieldClick,
|
|
10611
|
+
onReady
|
|
10612
|
+
}
|
|
10613
|
+
) });
|
|
10614
|
+
}
|
|
10595
10615
|
class PixldocsRenderer {
|
|
10596
10616
|
constructor(config) {
|
|
10597
10617
|
__publicField(this, "config");
|
|
@@ -10671,7 +10691,8 @@ class PixldocsRenderer {
|
|
|
10671
10691
|
// ─── Internal: render a page using the full PreviewCanvas engine ───
|
|
10672
10692
|
/**
|
|
10673
10693
|
* Wait until every image on the Fabric canvas inside the container has loaded.
|
|
10674
|
-
*
|
|
10694
|
+
* Checks both DOM <img> elements AND Fabric canvas image objects to ensure
|
|
10695
|
+
* all async assets are fully painted before capture.
|
|
10675
10696
|
*/
|
|
10676
10697
|
waitForCanvasImages(container, maxWaitMs = 15e3, pollMs = 200) {
|
|
10677
10698
|
return new Promise((resolve) => {
|
|
@@ -10682,6 +10703,29 @@ class PixldocsRenderer {
|
|
|
10682
10703
|
images.forEach((img) => {
|
|
10683
10704
|
if (!img.complete) allLoaded = false;
|
|
10684
10705
|
});
|
|
10706
|
+
if (allLoaded) {
|
|
10707
|
+
const canvasEl = container.querySelector("canvas.lower-canvas, canvas");
|
|
10708
|
+
const fabricCanvas = canvasEl && canvasEl.__fabric;
|
|
10709
|
+
if (fabricCanvas && typeof fabricCanvas.getObjects === "function") {
|
|
10710
|
+
for (const obj of fabricCanvas.getObjects()) {
|
|
10711
|
+
const el = obj._element || obj._originalElement;
|
|
10712
|
+
if (el instanceof HTMLImageElement && !el.complete) {
|
|
10713
|
+
allLoaded = false;
|
|
10714
|
+
break;
|
|
10715
|
+
}
|
|
10716
|
+
if (obj._objects) {
|
|
10717
|
+
for (const child of obj._objects) {
|
|
10718
|
+
const childEl = child._element || child._originalElement;
|
|
10719
|
+
if (childEl instanceof HTMLImageElement && !childEl.complete) {
|
|
10720
|
+
allLoaded = false;
|
|
10721
|
+
break;
|
|
10722
|
+
}
|
|
10723
|
+
}
|
|
10724
|
+
if (!allLoaded) break;
|
|
10725
|
+
}
|
|
10726
|
+
}
|
|
10727
|
+
}
|
|
10728
|
+
}
|
|
10685
10729
|
if (allLoaded || Date.now() - start > maxWaitMs) {
|
|
10686
10730
|
requestAnimationFrame(() => setTimeout(resolve, 400));
|
|
10687
10731
|
return;
|