@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.cjs
CHANGED
|
@@ -10388,79 +10388,6 @@ function paintRepeatableSections(config, repeatableSections) {
|
|
|
10388
10388
|
}
|
|
10389
10389
|
}
|
|
10390
10390
|
}
|
|
10391
|
-
function PixldocsPreview(props) {
|
|
10392
|
-
const {
|
|
10393
|
-
pageIndex = 0,
|
|
10394
|
-
zoom = 1,
|
|
10395
|
-
absoluteZoom = false,
|
|
10396
|
-
imageProxyUrl,
|
|
10397
|
-
className,
|
|
10398
|
-
style,
|
|
10399
|
-
onDynamicFieldClick,
|
|
10400
|
-
onReady,
|
|
10401
|
-
onError
|
|
10402
|
-
} = props;
|
|
10403
|
-
react.useEffect(() => {
|
|
10404
|
-
setPackageApiUrl(imageProxyUrl);
|
|
10405
|
-
}, [imageProxyUrl]);
|
|
10406
|
-
const [resolvedConfig, setResolvedConfig] = react.useState(null);
|
|
10407
|
-
const [isLoading, setIsLoading] = react.useState(false);
|
|
10408
|
-
const isResolveMode = !("config" in props && props.config);
|
|
10409
|
-
react.useEffect(() => {
|
|
10410
|
-
if (!isResolveMode) {
|
|
10411
|
-
setResolvedConfig(null);
|
|
10412
|
-
return;
|
|
10413
|
-
}
|
|
10414
|
-
const p = props;
|
|
10415
|
-
if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;
|
|
10416
|
-
let cancelled = false;
|
|
10417
|
-
setIsLoading(true);
|
|
10418
|
-
resolveFromForm({
|
|
10419
|
-
templateId: p.templateId,
|
|
10420
|
-
formSchemaId: p.formSchemaId,
|
|
10421
|
-
sectionState: p.sectionState,
|
|
10422
|
-
themeId: p.themeId,
|
|
10423
|
-
supabaseUrl: p.supabaseUrl,
|
|
10424
|
-
supabaseAnonKey: p.supabaseAnonKey
|
|
10425
|
-
}).then((resolved) => {
|
|
10426
|
-
if (!cancelled) {
|
|
10427
|
-
setResolvedConfig(resolved.config);
|
|
10428
|
-
setIsLoading(false);
|
|
10429
|
-
}
|
|
10430
|
-
}).catch((err) => {
|
|
10431
|
-
if (!cancelled) {
|
|
10432
|
-
setIsLoading(false);
|
|
10433
|
-
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
10434
|
-
}
|
|
10435
|
-
});
|
|
10436
|
-
return () => {
|
|
10437
|
-
cancelled = true;
|
|
10438
|
-
};
|
|
10439
|
-
}, [
|
|
10440
|
-
isResolveMode,
|
|
10441
|
-
// For resolve mode, re-resolve when these change
|
|
10442
|
-
isResolveMode ? props.templateId : void 0,
|
|
10443
|
-
isResolveMode ? props.formSchemaId : void 0,
|
|
10444
|
-
isResolveMode ? JSON.stringify(props.sectionState) : void 0,
|
|
10445
|
-
isResolveMode ? props.themeId : void 0
|
|
10446
|
-
]);
|
|
10447
|
-
const config = isResolveMode ? resolvedConfig : props.config;
|
|
10448
|
-
if (isLoading) {
|
|
10449
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
10450
|
-
}
|
|
10451
|
-
if (!config) return null;
|
|
10452
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10453
|
-
PreviewCanvas,
|
|
10454
|
-
{
|
|
10455
|
-
config,
|
|
10456
|
-
pageIndex,
|
|
10457
|
-
zoom,
|
|
10458
|
-
absoluteZoom,
|
|
10459
|
-
onDynamicFieldClick,
|
|
10460
|
-
onReady
|
|
10461
|
-
}
|
|
10462
|
-
) });
|
|
10463
|
-
}
|
|
10464
10391
|
function normalizeFontFamily(fontStack) {
|
|
10465
10392
|
const first = fontStack.split(",")[0].trim();
|
|
10466
10393
|
return first.replace(/^['"]|['"]$/g, "");
|
|
@@ -10475,12 +10402,7 @@ async function loadGoogleFontCSS(rawFontFamily) {
|
|
|
10475
10402
|
const existing = loadingPromises.get(fontFamily);
|
|
10476
10403
|
if (existing) return existing;
|
|
10477
10404
|
const promise = (async () => {
|
|
10478
|
-
var _a;
|
|
10479
10405
|
try {
|
|
10480
|
-
if ((_a = document.fonts) == null ? void 0 : _a.check(`16px "${fontFamily}"`)) {
|
|
10481
|
-
loadedFonts.add(fontFamily);
|
|
10482
|
-
return;
|
|
10483
|
-
}
|
|
10484
10406
|
const encoded = encodeURIComponent(fontFamily);
|
|
10485
10407
|
const url = `https://fonts.googleapis.com/css?family=${encoded}:300,400,500,600,700&display=swap`;
|
|
10486
10408
|
const link = document.createElement("link");
|
|
@@ -10509,6 +10431,7 @@ function collectFontsFromConfig(config) {
|
|
|
10509
10431
|
var _a;
|
|
10510
10432
|
const fonts = /* @__PURE__ */ new Set();
|
|
10511
10433
|
fonts.add("Open Sans");
|
|
10434
|
+
fonts.add("Hind");
|
|
10512
10435
|
function walk(nodes) {
|
|
10513
10436
|
var _a2;
|
|
10514
10437
|
if (!nodes) return;
|
|
@@ -10561,12 +10484,18 @@ function collectFontDescriptorsFromConfig(config) {
|
|
|
10561
10484
|
for (const node of nodes) {
|
|
10562
10485
|
if (node.fontFamily) {
|
|
10563
10486
|
add(node.fontFamily, node.fontWeight, node.fontStyle);
|
|
10487
|
+
if (node.type === "text") {
|
|
10488
|
+
for (const w of [300, 400, 500, 600, 700]) {
|
|
10489
|
+
add(node.fontFamily, w, node.fontStyle);
|
|
10490
|
+
}
|
|
10491
|
+
}
|
|
10564
10492
|
}
|
|
10565
10493
|
if ((_a2 = node.smartProps) == null ? void 0 : _a2.fontFamily) {
|
|
10566
10494
|
add(node.smartProps.fontFamily, node.smartProps.fontWeight, node.smartProps.fontStyle);
|
|
10567
10495
|
}
|
|
10568
|
-
if (node.styles
|
|
10569
|
-
|
|
10496
|
+
if (node.styles) {
|
|
10497
|
+
const styleEntries = Array.isArray(node.styles) ? node.styles : Object.values(node.styles);
|
|
10498
|
+
for (const lineStyle of styleEntries) {
|
|
10570
10499
|
if (lineStyle && typeof lineStyle === "object") {
|
|
10571
10500
|
for (const charStyle of Object.values(lineStyle)) {
|
|
10572
10501
|
if (charStyle == null ? void 0 : charStyle.fontFamily) {
|
|
@@ -10580,6 +10509,8 @@ function collectFontDescriptorsFromConfig(config) {
|
|
|
10580
10509
|
}
|
|
10581
10510
|
}
|
|
10582
10511
|
add("Open Sans", 400, "normal");
|
|
10512
|
+
add("Hind", 400, "normal");
|
|
10513
|
+
add("Hind", 700, "normal");
|
|
10583
10514
|
for (const page of config.pages || []) {
|
|
10584
10515
|
walk(page.children || []);
|
|
10585
10516
|
}
|
|
@@ -10611,6 +10542,95 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
10611
10542
|
await document.fonts.ready;
|
|
10612
10543
|
}
|
|
10613
10544
|
}
|
|
10545
|
+
function PixldocsPreview(props) {
|
|
10546
|
+
const {
|
|
10547
|
+
pageIndex = 0,
|
|
10548
|
+
zoom = 1,
|
|
10549
|
+
absoluteZoom = false,
|
|
10550
|
+
imageProxyUrl,
|
|
10551
|
+
className,
|
|
10552
|
+
style,
|
|
10553
|
+
onDynamicFieldClick,
|
|
10554
|
+
onReady,
|
|
10555
|
+
onError
|
|
10556
|
+
} = props;
|
|
10557
|
+
react.useEffect(() => {
|
|
10558
|
+
setPackageApiUrl(imageProxyUrl);
|
|
10559
|
+
}, [imageProxyUrl]);
|
|
10560
|
+
const [resolvedConfig, setResolvedConfig] = react.useState(null);
|
|
10561
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
10562
|
+
const [fontsReady, setFontsReady] = react.useState(false);
|
|
10563
|
+
const isResolveMode = !("config" in props && props.config);
|
|
10564
|
+
react.useEffect(() => {
|
|
10565
|
+
if (!isResolveMode) {
|
|
10566
|
+
setResolvedConfig(null);
|
|
10567
|
+
return;
|
|
10568
|
+
}
|
|
10569
|
+
const p = props;
|
|
10570
|
+
if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;
|
|
10571
|
+
let cancelled = false;
|
|
10572
|
+
setIsLoading(true);
|
|
10573
|
+
resolveFromForm({
|
|
10574
|
+
templateId: p.templateId,
|
|
10575
|
+
formSchemaId: p.formSchemaId,
|
|
10576
|
+
sectionState: p.sectionState,
|
|
10577
|
+
themeId: p.themeId,
|
|
10578
|
+
supabaseUrl: p.supabaseUrl,
|
|
10579
|
+
supabaseAnonKey: p.supabaseAnonKey
|
|
10580
|
+
}).then((resolved) => {
|
|
10581
|
+
if (!cancelled) {
|
|
10582
|
+
setResolvedConfig(resolved.config);
|
|
10583
|
+
ensureFontsForResolvedConfig(resolved.config).then(() => {
|
|
10584
|
+
if (!cancelled) {
|
|
10585
|
+
setFontsReady(true);
|
|
10586
|
+
setIsLoading(false);
|
|
10587
|
+
}
|
|
10588
|
+
}).catch(() => {
|
|
10589
|
+
if (!cancelled) {
|
|
10590
|
+
setFontsReady(true);
|
|
10591
|
+
setIsLoading(false);
|
|
10592
|
+
}
|
|
10593
|
+
});
|
|
10594
|
+
}
|
|
10595
|
+
}).catch((err) => {
|
|
10596
|
+
if (!cancelled) {
|
|
10597
|
+
setIsLoading(false);
|
|
10598
|
+
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
10599
|
+
}
|
|
10600
|
+
});
|
|
10601
|
+
return () => {
|
|
10602
|
+
cancelled = true;
|
|
10603
|
+
};
|
|
10604
|
+
}, [
|
|
10605
|
+
isResolveMode,
|
|
10606
|
+
// For resolve mode, re-resolve when these change
|
|
10607
|
+
isResolveMode ? props.templateId : void 0,
|
|
10608
|
+
isResolveMode ? props.formSchemaId : void 0,
|
|
10609
|
+
isResolveMode ? JSON.stringify(props.sectionState) : void 0,
|
|
10610
|
+
isResolveMode ? props.themeId : void 0
|
|
10611
|
+
]);
|
|
10612
|
+
const config = isResolveMode ? resolvedConfig : props.config;
|
|
10613
|
+
react.useEffect(() => {
|
|
10614
|
+
if (isResolveMode || !config) return;
|
|
10615
|
+
setFontsReady(false);
|
|
10616
|
+
ensureFontsForResolvedConfig(config).then(() => setFontsReady(true)).catch(() => setFontsReady(true));
|
|
10617
|
+
}, [isResolveMode, config]);
|
|
10618
|
+
if (isLoading) {
|
|
10619
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
10620
|
+
}
|
|
10621
|
+
if (!config) return null;
|
|
10622
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10623
|
+
PreviewCanvas,
|
|
10624
|
+
{
|
|
10625
|
+
config,
|
|
10626
|
+
pageIndex,
|
|
10627
|
+
zoom,
|
|
10628
|
+
absoluteZoom,
|
|
10629
|
+
onDynamicFieldClick,
|
|
10630
|
+
onReady
|
|
10631
|
+
}
|
|
10632
|
+
) });
|
|
10633
|
+
}
|
|
10614
10634
|
class PixldocsRenderer {
|
|
10615
10635
|
constructor(config) {
|
|
10616
10636
|
__publicField(this, "config");
|
|
@@ -10690,7 +10710,8 @@ class PixldocsRenderer {
|
|
|
10690
10710
|
// ─── Internal: render a page using the full PreviewCanvas engine ───
|
|
10691
10711
|
/**
|
|
10692
10712
|
* Wait until every image on the Fabric canvas inside the container has loaded.
|
|
10693
|
-
*
|
|
10713
|
+
* Checks both DOM <img> elements AND Fabric canvas image objects to ensure
|
|
10714
|
+
* all async assets are fully painted before capture.
|
|
10694
10715
|
*/
|
|
10695
10716
|
waitForCanvasImages(container, maxWaitMs = 15e3, pollMs = 200) {
|
|
10696
10717
|
return new Promise((resolve) => {
|
|
@@ -10701,6 +10722,29 @@ class PixldocsRenderer {
|
|
|
10701
10722
|
images.forEach((img) => {
|
|
10702
10723
|
if (!img.complete) allLoaded = false;
|
|
10703
10724
|
});
|
|
10725
|
+
if (allLoaded) {
|
|
10726
|
+
const canvasEl = container.querySelector("canvas.lower-canvas, canvas");
|
|
10727
|
+
const fabricCanvas = canvasEl && canvasEl.__fabric;
|
|
10728
|
+
if (fabricCanvas && typeof fabricCanvas.getObjects === "function") {
|
|
10729
|
+
for (const obj of fabricCanvas.getObjects()) {
|
|
10730
|
+
const el = obj._element || obj._originalElement;
|
|
10731
|
+
if (el instanceof HTMLImageElement && !el.complete) {
|
|
10732
|
+
allLoaded = false;
|
|
10733
|
+
break;
|
|
10734
|
+
}
|
|
10735
|
+
if (obj._objects) {
|
|
10736
|
+
for (const child of obj._objects) {
|
|
10737
|
+
const childEl = child._element || child._originalElement;
|
|
10738
|
+
if (childEl instanceof HTMLImageElement && !childEl.complete) {
|
|
10739
|
+
allLoaded = false;
|
|
10740
|
+
break;
|
|
10741
|
+
}
|
|
10742
|
+
}
|
|
10743
|
+
if (!allLoaded) break;
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10704
10748
|
if (allLoaded || Date.now() - start > maxWaitMs) {
|
|
10705
10749
|
requestAnimationFrame(() => setTimeout(resolve, 400));
|
|
10706
10750
|
return;
|