@pixldocs/canvas-renderer 0.5.179 → 0.5.181
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/README.md +69 -0
- package/dist/{index-C3W71an-.js → index-Ck5VHk_Q.js} +154 -10
- package/dist/index-Ck5VHk_Q.js.map +1 -0
- package/dist/{index-BBOaToIA.cjs → index-DQBzPXXr.cjs} +154 -10
- package/dist/index-DQBzPXXr.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/previewBlur-BB8gxlmo.cjs +51 -0
- package/dist/previewBlur-BB8gxlmo.cjs.map +1 -0
- package/dist/previewBlur-Dj6dSSNO.js +51 -0
- package/dist/previewBlur-Dj6dSSNO.js.map +1 -0
- package/dist/{vectorPdfExport-Be8MJ_2c.cjs → vectorPdfExport-DPng52xI.cjs} +4 -4
- package/dist/{vectorPdfExport-Be8MJ_2c.cjs.map → vectorPdfExport-DPng52xI.cjs.map} +1 -1
- package/dist/{vectorPdfExport-FmQQMHmX.js → vectorPdfExport-KXmgWTkZ.js} +4 -4
- package/dist/{vectorPdfExport-FmQQMHmX.js.map → vectorPdfExport-KXmgWTkZ.js.map} +1 -1
- package/package.json +1 -1
- package/dist/index-BBOaToIA.cjs.map +0 -1
- package/dist/index-C3W71an-.js.map +0 -1
package/README.md
CHANGED
|
@@ -206,6 +206,48 @@ const result = await renderer.renderPdf(templateConfig, { title: 'My Doc' });
|
|
|
206
206
|
|
|
207
207
|
## API Reference
|
|
208
208
|
|
|
209
|
+
### Form schema shape (V2 `sectionState`)
|
|
210
|
+
|
|
211
|
+
`sectionState` accepts entries for both **repeatable sections** and
|
|
212
|
+
**repeatable pages**. Both look the same on the wire — an array of entry
|
|
213
|
+
objects keyed by the section/page `id`:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
sectionState = {
|
|
217
|
+
// single section
|
|
218
|
+
personal: { name: 'Jane' },
|
|
219
|
+
|
|
220
|
+
// repeatable section (e.g. Experience)
|
|
221
|
+
experience: [
|
|
222
|
+
{ title: 'Designer', company: 'Acme' },
|
|
223
|
+
{ title: 'Lead', company: 'Beta' },
|
|
224
|
+
],
|
|
225
|
+
|
|
226
|
+
// repeatable PAGE (e.g. Photo Page) — same shape as above, but at render
|
|
227
|
+
// time the bound template page is cloned once per entry.
|
|
228
|
+
photo_page: [
|
|
229
|
+
{ caption: 'Cover' },
|
|
230
|
+
{ caption: 'Back' },
|
|
231
|
+
],
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Fetch the schema from the Pixldocs form API to discover what keys/fields are
|
|
236
|
+
expected. The response exposes repeatable pages as a dedicated
|
|
237
|
+
`schema.repeatablePages[]` array (each entry mirrors a repeatable section:
|
|
238
|
+
`id`, `label`, `order`, `templateKeyPrefix`, `minEntries`, `maxEntries`,
|
|
239
|
+
`entryFields`).
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
const res = await fetch(
|
|
243
|
+
`${SUPABASE_URL}/functions/v1/form-api?form_schema_id=${SCHEMA_ID}&action=schema`,
|
|
244
|
+
{ headers: { apikey: SUPABASE_ANON_KEY } },
|
|
245
|
+
).then((r) => r.json());
|
|
246
|
+
|
|
247
|
+
res.schema.sections // single + repeatable sections
|
|
248
|
+
res.schema.repeatablePages // repeatable pages (clone-per-entry)
|
|
249
|
+
```
|
|
250
|
+
|
|
209
251
|
### `PixldocsPreview` (React Component)
|
|
210
252
|
|
|
211
253
|
| Prop | Type | Default | Description |
|
|
@@ -302,3 +344,30 @@ const { config } = await resolveTemplateData({
|
|
|
302
344
|
## License
|
|
303
345
|
|
|
304
346
|
UNLICENSED — Private package for Pixldocs ecosystem only.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Preview Blur (anti-screenshot)
|
|
351
|
+
|
|
352
|
+
Set `previewBlur: true` on any text or image element in your config to redact
|
|
353
|
+
it in watermarked previews — useful for protecting paid content (e.g. biodata
|
|
354
|
+
reference rows) from screenshot theft. The block characters (`█`) replace
|
|
355
|
+
the text content so layout/wrap stays identical, but content is unreadable.
|
|
356
|
+
|
|
357
|
+
Preview-blur is gated identically to the watermark: it only runs when
|
|
358
|
+
`watermark === true` (or, by default, when `template.price > 0` and the user
|
|
359
|
+
hasn't paid). Clean / paid downloads always render the original content.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
// In your template config
|
|
363
|
+
{
|
|
364
|
+
id: 'reference-1-name',
|
|
365
|
+
type: 'text',
|
|
366
|
+
text: 'John Doe',
|
|
367
|
+
previewBlur: true, // ← redacted in preview, full in paid download
|
|
368
|
+
...
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
No API change is required on the consumer side — the same `renderFromForm`,
|
|
373
|
+
`renderPdfFromForm`, etc. respect the flag automatically.
|
|
@@ -466,9 +466,19 @@ function resolveStackGroupEffectivePositions(group, pageChildren, options) {
|
|
|
466
466
|
const gap = group.stackSpacing ?? 8;
|
|
467
467
|
const padTop = group.paddingTop ?? 0;
|
|
468
468
|
const padLeft = group.paddingLeft ?? 0;
|
|
469
|
+
const padRight = group.paddingRight ?? 0;
|
|
470
|
+
const padBottom = group.paddingBottom ?? 0;
|
|
471
|
+
const justify = group.justifyContent ?? "start";
|
|
472
|
+
const align = group.alignItems ?? "start";
|
|
473
|
+
const isVertical = isVerticalStackLayoutMode(mode);
|
|
469
474
|
const kids = group.children ?? [];
|
|
470
475
|
const out = /* @__PURE__ */ new Map();
|
|
471
|
-
|
|
476
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
477
|
+
for (const c of kids) {
|
|
478
|
+
const b = getNodeBounds(c, pageChildren);
|
|
479
|
+
sizes.set(c.id, { width: b.width, height: b.height });
|
|
480
|
+
}
|
|
481
|
+
if (isVertical) {
|
|
472
482
|
let prevBottom = padTop;
|
|
473
483
|
let firstSeen = false;
|
|
474
484
|
for (let i = 0; i < kids.length; i++) {
|
|
@@ -480,7 +490,7 @@ function resolveStackGroupEffectivePositions(group, pageChildren, options) {
|
|
|
480
490
|
const effectiveTop = !firstSeen ? padTop + storedTop + mTop : prevBottom + gap + storedTop + mTop;
|
|
481
491
|
firstSeen = true;
|
|
482
492
|
out.set(child.id, { top: effectiveTop, left: padLeft + storedLeft + mLeft });
|
|
483
|
-
const h =
|
|
493
|
+
const h = sizes.get(child.id).height;
|
|
484
494
|
prevBottom = effectiveTop + h + (child.marginBottom ?? 0);
|
|
485
495
|
}
|
|
486
496
|
} else {
|
|
@@ -495,10 +505,99 @@ function resolveStackGroupEffectivePositions(group, pageChildren, options) {
|
|
|
495
505
|
const effectiveLeft = !firstSeen ? padLeft + storedLeft + mLeft : prevRight + gap + storedLeft + mLeft;
|
|
496
506
|
firstSeen = true;
|
|
497
507
|
out.set(child.id, { top: padTop + storedTop + mTop, left: effectiveLeft });
|
|
498
|
-
const w =
|
|
508
|
+
const w = sizes.get(child.id).width;
|
|
499
509
|
prevRight = effectiveLeft + w + (child.marginRight ?? 0);
|
|
500
510
|
}
|
|
501
511
|
}
|
|
512
|
+
const containerW = typeof group.width === "number" ? group.width : void 0;
|
|
513
|
+
const containerH = typeof group.height === "number" ? group.height : void 0;
|
|
514
|
+
const mainContainer = isVertical ? containerH : containerW;
|
|
515
|
+
const crossContainer = isVertical ? containerW : containerH;
|
|
516
|
+
if (align !== "start" && crossContainer != null && kids.length > 0) {
|
|
517
|
+
const crossPad0 = isVertical ? padLeft : padTop;
|
|
518
|
+
const crossPadEnd = isVertical ? padRight : padBottom;
|
|
519
|
+
const innerCross = Math.max(0, crossContainer - crossPad0 - crossPadEnd);
|
|
520
|
+
for (const child of kids) {
|
|
521
|
+
const pos = out.get(child.id);
|
|
522
|
+
if (!pos) continue;
|
|
523
|
+
const sz = sizes.get(child.id);
|
|
524
|
+
const childCross = isVertical ? sz.width : sz.height;
|
|
525
|
+
let crossPos;
|
|
526
|
+
if (align === "stretch") {
|
|
527
|
+
crossPos = crossPad0;
|
|
528
|
+
} else if (align === "center") {
|
|
529
|
+
crossPos = crossPad0 + (innerCross - childCross) / 2;
|
|
530
|
+
} else {
|
|
531
|
+
crossPos = crossPad0 + (innerCross - childCross);
|
|
532
|
+
}
|
|
533
|
+
if (isVertical) {
|
|
534
|
+
out.set(child.id, { top: pos.top, left: crossPos });
|
|
535
|
+
} else {
|
|
536
|
+
out.set(child.id, { top: crossPos, left: pos.left });
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (justify !== "start" && mainContainer != null && kids.length > 0) {
|
|
541
|
+
const mainPad0 = isVertical ? padTop : padLeft;
|
|
542
|
+
const mainPadEnd = isVertical ? padBottom : padRight;
|
|
543
|
+
const innerMain = Math.max(0, mainContainer - mainPad0 - mainPadEnd);
|
|
544
|
+
let totalMain = 0;
|
|
545
|
+
for (let i = 0; i < kids.length; i++) {
|
|
546
|
+
const child = kids[i];
|
|
547
|
+
const sz = sizes.get(child.id);
|
|
548
|
+
totalMain += isVertical ? sz.height : sz.width;
|
|
549
|
+
const marginStart = isVertical ? child.marginTop ?? 0 : child.marginLeft ?? 0;
|
|
550
|
+
const marginEnd = isVertical ? child.marginBottom ?? 0 : child.marginRight ?? 0;
|
|
551
|
+
totalMain += marginStart + marginEnd;
|
|
552
|
+
}
|
|
553
|
+
const baseGapTotal = gap * Math.max(0, kids.length - 1);
|
|
554
|
+
const free = innerMain - totalMain - baseGapTotal;
|
|
555
|
+
let offset = 0;
|
|
556
|
+
let extraGap = 0;
|
|
557
|
+
if (free > 0) {
|
|
558
|
+
switch (justify) {
|
|
559
|
+
case "center":
|
|
560
|
+
offset = free / 2;
|
|
561
|
+
break;
|
|
562
|
+
case "end":
|
|
563
|
+
offset = free;
|
|
564
|
+
break;
|
|
565
|
+
case "space-between":
|
|
566
|
+
if (kids.length > 1) extraGap = free / (kids.length - 1);
|
|
567
|
+
else offset = free / 2;
|
|
568
|
+
break;
|
|
569
|
+
case "space-around":
|
|
570
|
+
if (kids.length > 0) {
|
|
571
|
+
extraGap = free / kids.length;
|
|
572
|
+
offset = extraGap / 2;
|
|
573
|
+
}
|
|
574
|
+
break;
|
|
575
|
+
case "space-evenly":
|
|
576
|
+
extraGap = free / (kids.length + 1);
|
|
577
|
+
offset = extraGap;
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (offset !== 0 || extraGap !== 0) {
|
|
582
|
+
let cursor = mainPad0 + offset;
|
|
583
|
+
for (let i = 0; i < kids.length; i++) {
|
|
584
|
+
const child = kids[i];
|
|
585
|
+
const sz = sizes.get(child.id);
|
|
586
|
+
const marginStart = isVertical ? child.marginTop ?? 0 : child.marginLeft ?? 0;
|
|
587
|
+
const marginEnd = isVertical ? child.marginBottom ?? 0 : child.marginRight ?? 0;
|
|
588
|
+
const main = isVertical ? sz.height : sz.width;
|
|
589
|
+
const pos = out.get(child.id);
|
|
590
|
+
if (!pos) continue;
|
|
591
|
+
const startMain = cursor + marginStart;
|
|
592
|
+
if (isVertical) {
|
|
593
|
+
out.set(child.id, { top: startMain, left: pos.left });
|
|
594
|
+
} else {
|
|
595
|
+
out.set(child.id, { top: pos.top, left: startMain });
|
|
596
|
+
}
|
|
597
|
+
cursor = startMain + main + marginEnd + gap + extraGap;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
502
601
|
return out;
|
|
503
602
|
}
|
|
504
603
|
function groupBoundsFromChildren(group, pageChildren, options) {
|
|
@@ -7599,7 +7698,28 @@ const PageCanvas = forwardRef(
|
|
|
7599
7698
|
const element = id ? elementById.get(id) : void 0;
|
|
7600
7699
|
if (!element) return;
|
|
7601
7700
|
if (element.overflowPolicy === "auto-shrink") {
|
|
7701
|
+
try {
|
|
7702
|
+
const measured = createText(element);
|
|
7703
|
+
const newFontSize = measured.fontSize;
|
|
7704
|
+
const newWidth = measured.width;
|
|
7705
|
+
const currentFontSize = obj.fontSize;
|
|
7706
|
+
if (typeof newFontSize === "number" && newFontSize > 0 && newFontSize !== currentFontSize) {
|
|
7707
|
+
obj.set({ fontSize: newFontSize });
|
|
7708
|
+
if (typeof newWidth === "number" && newWidth > 0) {
|
|
7709
|
+
obj.width = newWidth;
|
|
7710
|
+
}
|
|
7711
|
+
obj.initDimensions();
|
|
7712
|
+
obj.setCoords();
|
|
7713
|
+
didReflow = true;
|
|
7714
|
+
}
|
|
7715
|
+
} catch {
|
|
7716
|
+
}
|
|
7602
7717
|
obj.dirty = true;
|
|
7718
|
+
try {
|
|
7719
|
+
obj._forceClearCache = true;
|
|
7720
|
+
if (typeof obj._clearCache === "function") obj._clearCache();
|
|
7721
|
+
} catch {
|
|
7722
|
+
}
|
|
7603
7723
|
return;
|
|
7604
7724
|
}
|
|
7605
7725
|
const targetWidth = Math.max(1, Number(element.width) > 0 ? Number(element.width) : Number(obj.width ?? 200));
|
|
@@ -9212,9 +9332,26 @@ const PageCanvas = forwardRef(
|
|
|
9212
9332
|
const needsCropGroupFadeUpdate = isCropGroup2 && fadeKeyChanged;
|
|
9213
9333
|
const hadUrlBefore = storedImageUrl && String(storedImageUrl).trim() !== "";
|
|
9214
9334
|
if (!hasUrl && hadUrlBefore) {
|
|
9215
|
-
const
|
|
9335
|
+
const resolvedSizeImg = (pageChildren == null ? void 0 : pageChildren.length) ? getNodeBounds(element, pageChildren) : { width: typeof element.width === "number" ? element.width : 200, height: typeof element.height === "number" ? element.height : 50 };
|
|
9336
|
+
const hasExplicitSize = typeof element.width === "number" && Number.isFinite(element.width) && element.width > 0 && typeof element.height === "number" && Number.isFinite(element.height) && element.height > 0;
|
|
9337
|
+
const minVisiblePlaceholder = hasExplicitSize ? 1 : 20;
|
|
9338
|
+
const nextWidth = Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.width) || 200);
|
|
9339
|
+
const nextHeight = Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.height) || 50);
|
|
9340
|
+
const storePosImg = pageChildren ? (() => {
|
|
9341
|
+
const node = findNodeById(pageChildren, element.id);
|
|
9342
|
+
return node ? getAbsoluteBounds(node, pageChildren) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
9343
|
+
})() : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
9344
|
+
const elementForPlaceholder = { ...element, width: nextWidth, height: nextHeight };
|
|
9345
|
+
const placeholder = isCropGroup2 ? createImagePlaceholderForGroup(elementForPlaceholder) : createImagePlaceholder(elementForPlaceholder);
|
|
9216
9346
|
setObjectData(placeholder, element.id);
|
|
9217
9347
|
placeholder.__imageSrc = "";
|
|
9348
|
+
placeholder.set({
|
|
9349
|
+
left: storePosImg.left + nextWidth / 2,
|
|
9350
|
+
top: storePosImg.top + nextHeight / 2,
|
|
9351
|
+
originX: "center",
|
|
9352
|
+
originY: "center"
|
|
9353
|
+
});
|
|
9354
|
+
placeholder.setCoords();
|
|
9218
9355
|
const idx = fc.getObjects().indexOf(existingObj);
|
|
9219
9356
|
fc.remove(existingObj);
|
|
9220
9357
|
if (idx >= 0) {
|
|
@@ -11738,7 +11875,8 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
|
|
|
11738
11875
|
// Honor minEntries: 0 — start with no entries, user adds via "+ Add" button.
|
|
11739
11876
|
initialEntryCount: minEntries,
|
|
11740
11877
|
parentId,
|
|
11741
|
-
entryNameFieldKey: def.entryNameFieldKey
|
|
11878
|
+
entryNameFieldKey: def.entryNameFieldKey,
|
|
11879
|
+
isRepeatablePage: def.isRepeatablePage
|
|
11742
11880
|
};
|
|
11743
11881
|
if (treeNodeId) section.treeNodeId = treeNodeId;
|
|
11744
11882
|
sections.push(section);
|
|
@@ -16342,9 +16480,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
16342
16480
|
}
|
|
16343
16481
|
return svgString;
|
|
16344
16482
|
}
|
|
16345
|
-
const resolvedPackageVersion = "0.5.
|
|
16483
|
+
const resolvedPackageVersion = "0.5.181";
|
|
16346
16484
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
16347
|
-
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.
|
|
16485
|
+
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.181";
|
|
16348
16486
|
const roundParityValue = (value) => {
|
|
16349
16487
|
if (typeof value !== "number") return value;
|
|
16350
16488
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -16643,6 +16781,8 @@ class PixldocsRenderer {
|
|
|
16643
16781
|
if (shouldWatermark) {
|
|
16644
16782
|
const { injectWatermark } = await import("./canvasWatermark-pkhacGge.js");
|
|
16645
16783
|
configToRender = injectWatermark(configToRender, watermarkOptions);
|
|
16784
|
+
const { injectPreviewBlur } = await import("./previewBlur-Dj6dSSNO.js");
|
|
16785
|
+
configToRender = injectPreviewBlur(configToRender);
|
|
16646
16786
|
}
|
|
16647
16787
|
return this.renderAllPages(configToRender, renderOpts);
|
|
16648
16788
|
}
|
|
@@ -16700,6 +16840,8 @@ class PixldocsRenderer {
|
|
|
16700
16840
|
if (shouldWatermark) {
|
|
16701
16841
|
const { injectWatermark } = await import("./canvasWatermark-pkhacGge.js");
|
|
16702
16842
|
configToRender = injectWatermark(configToRender, watermarkOptions);
|
|
16843
|
+
const { injectPreviewBlur } = await import("./previewBlur-Dj6dSSNO.js");
|
|
16844
|
+
configToRender = injectPreviewBlur(configToRender);
|
|
16703
16845
|
}
|
|
16704
16846
|
return this.renderAllPageSvgs(configToRender);
|
|
16705
16847
|
}
|
|
@@ -16742,6 +16884,8 @@ class PixldocsRenderer {
|
|
|
16742
16884
|
if (shouldWatermark) {
|
|
16743
16885
|
const { injectWatermark } = await import("./canvasWatermark-pkhacGge.js");
|
|
16744
16886
|
configToRender = injectWatermark(configToRender, watermarkOptions);
|
|
16887
|
+
const { injectPreviewBlur } = await import("./previewBlur-Dj6dSSNO.js");
|
|
16888
|
+
configToRender = injectPreviewBlur(configToRender);
|
|
16745
16889
|
}
|
|
16746
16890
|
return this.renderPdfViaClientExport(configToRender, {
|
|
16747
16891
|
title: title ?? resolved.config.name,
|
|
@@ -16846,7 +16990,7 @@ class PixldocsRenderer {
|
|
|
16846
16990
|
await this.waitForCanvasScene(container, cloned, i);
|
|
16847
16991
|
}
|
|
16848
16992
|
console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
|
|
16849
|
-
const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-
|
|
16993
|
+
const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-KXmgWTkZ.js");
|
|
16850
16994
|
const prepared = preparePagesForExport(
|
|
16851
16995
|
cloned.pages,
|
|
16852
16996
|
canvasWidth,
|
|
@@ -18991,7 +19135,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
18991
19135
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
18992
19136
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
18993
19137
|
try {
|
|
18994
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-
|
|
19138
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-KXmgWTkZ.js");
|
|
18995
19139
|
try {
|
|
18996
19140
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
18997
19141
|
} catch {
|
|
@@ -19387,4 +19531,4 @@ export {
|
|
|
19387
19531
|
collectFontDescriptorsFromConfig as y,
|
|
19388
19532
|
collectFontsFromConfig as z
|
|
19389
19533
|
};
|
|
19390
|
-
//# sourceMappingURL=index-
|
|
19534
|
+
//# sourceMappingURL=index-Ck5VHk_Q.js.map
|