@pixldocs/canvas-renderer 0.4.8 → 0.5.0
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 +72 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +72 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2184,6 +2184,18 @@ const useEditorStore = create((set, get) => ({
|
|
|
2184
2184
|
const committed = commitFromState(state, nextCanvas);
|
|
2185
2185
|
return { canvas: nextCanvas, ...committed };
|
|
2186
2186
|
}),
|
|
2187
|
+
setPageBoundRepeatablePage: (pageId, repeatablePageId) => set((state) => {
|
|
2188
|
+
const updatedPages = state.canvas.pages.map((p) => {
|
|
2189
|
+
if (p.id !== pageId) return p;
|
|
2190
|
+
const next = { ...p };
|
|
2191
|
+
if (repeatablePageId) next.boundRepeatablePageId = repeatablePageId;
|
|
2192
|
+
else delete next.boundRepeatablePageId;
|
|
2193
|
+
return next;
|
|
2194
|
+
});
|
|
2195
|
+
const nextCanvas = { ...state.canvas, pages: updatedPages };
|
|
2196
|
+
const committed = commitFromState(state, nextCanvas);
|
|
2197
|
+
return { canvas: nextCanvas, ...committed };
|
|
2198
|
+
}),
|
|
2187
2199
|
moveElementsToPage: (elementIds, targetPageId) => set((state) => {
|
|
2188
2200
|
const currentPage = getCurrentPageFromCanvas(state.canvas);
|
|
2189
2201
|
const nodesToMove = [];
|
|
@@ -2328,7 +2340,8 @@ const useEditorStore = create((set, get) => ({
|
|
|
2328
2340
|
id: p.id,
|
|
2329
2341
|
name: p.name,
|
|
2330
2342
|
children,
|
|
2331
|
-
settings: { backgroundColor: "#ffffff", ...p.settings }
|
|
2343
|
+
settings: { backgroundColor: "#ffffff", ...p.settings },
|
|
2344
|
+
...p.boundRepeatablePageId ? { boundRepeatablePageId: p.boundRepeatablePageId } : {}
|
|
2332
2345
|
};
|
|
2333
2346
|
});
|
|
2334
2347
|
pagesWithPositions = pagesWithPositions.map((p) => {
|
|
@@ -4861,6 +4874,7 @@ const PageCanvas = forwardRef(
|
|
|
4861
4874
|
const prevCanvasUpdateVersionRef = useRef(canvasUpdateVersion);
|
|
4862
4875
|
const syncTriggeredByPanelRef = useRef(false);
|
|
4863
4876
|
const hasRunPostReadyReflowForPageRef = useRef(null);
|
|
4877
|
+
const hasNotifiedReadyForPageRef = useRef(null);
|
|
4864
4878
|
const hasClearedCachesBeforeFirstSyncRef = useRef(false);
|
|
4865
4879
|
const [guides, setGuides] = useState([]);
|
|
4866
4880
|
const [gridResizeLabel, setGridResizeLabel] = useState(null);
|
|
@@ -5123,10 +5137,8 @@ const PageCanvas = forwardRef(
|
|
|
5123
5137
|
clearFabricCharCache();
|
|
5124
5138
|
clearMeasurementCache();
|
|
5125
5139
|
setReady(true);
|
|
5126
|
-
if (onReady) onReady();
|
|
5127
5140
|
} catch (e) {
|
|
5128
5141
|
setReady(true);
|
|
5129
|
-
if (onReady) onReady();
|
|
5130
5142
|
}
|
|
5131
5143
|
};
|
|
5132
5144
|
initFonts();
|
|
@@ -7098,6 +7110,11 @@ const PageCanvas = forwardRef(
|
|
|
7098
7110
|
if (!ready || hasRunPostReadyReflowForPageRef.current === pageId) return;
|
|
7099
7111
|
hasRunPostReadyReflowForPageRef.current = pageId;
|
|
7100
7112
|
let cancelled = false;
|
|
7113
|
+
const notifyReady = () => {
|
|
7114
|
+
if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
|
|
7115
|
+
hasNotifiedReadyForPageRef.current = pageId;
|
|
7116
|
+
onReady == null ? void 0 : onReady();
|
|
7117
|
+
};
|
|
7101
7118
|
const runReflowAndPersist = () => {
|
|
7102
7119
|
const fc = fabricRef.current;
|
|
7103
7120
|
if (!fc || cancelled) return;
|
|
@@ -7139,6 +7156,7 @@ const PageCanvas = forwardRef(
|
|
|
7139
7156
|
requestAnimationFrame(() => {
|
|
7140
7157
|
if (cancelled) return;
|
|
7141
7158
|
runReflowAndPersist();
|
|
7159
|
+
notifyReady();
|
|
7142
7160
|
});
|
|
7143
7161
|
});
|
|
7144
7162
|
});
|
|
@@ -7147,7 +7165,7 @@ const PageCanvas = forwardRef(
|
|
|
7147
7165
|
cancelled = true;
|
|
7148
7166
|
cancelAnimationFrame(raf1);
|
|
7149
7167
|
};
|
|
7150
|
-
}, [ready, pageId]);
|
|
7168
|
+
}, [ready, pageId, onReady]);
|
|
7151
7169
|
useEffect(() => {
|
|
7152
7170
|
const fc = fabricRef.current;
|
|
7153
7171
|
if (!fc || isRebuildingRef.current || !isActive) return;
|
|
@@ -8761,13 +8779,14 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
|
|
|
8761
8779
|
const labelPrefix = rawPrefix.startsWith("field_") ? rawPrefix : `field_${rawPrefix}`;
|
|
8762
8780
|
const treeNodeId = repeatableNodeMap == null ? void 0 : repeatableNodeMap.get(def.label.trim().toLowerCase());
|
|
8763
8781
|
const prefix = treeNodeId ? `field_${treeNodeId}` : labelPrefix;
|
|
8782
|
+
const minEntries = def.minEntries != null ? Math.max(0, def.minEntries) : 1;
|
|
8764
8783
|
const section = {
|
|
8765
8784
|
id: def.id,
|
|
8766
8785
|
label: def.label,
|
|
8767
8786
|
order: def.order ?? 0,
|
|
8768
8787
|
type: "repeatable",
|
|
8769
8788
|
templateKeyPrefix: prefix,
|
|
8770
|
-
minEntries
|
|
8789
|
+
minEntries,
|
|
8771
8790
|
maxEntries: def.maxEntries,
|
|
8772
8791
|
entryFields: def.fields.map((f, i) => ({
|
|
8773
8792
|
key: f.key,
|
|
@@ -8777,7 +8796,8 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
|
|
|
8777
8796
|
templateKey: f.key,
|
|
8778
8797
|
placeholder: f.placeholder
|
|
8779
8798
|
})),
|
|
8780
|
-
|
|
8799
|
+
// Honor minEntries: 0 — start with no entries, user adds via "+ Add" button.
|
|
8800
|
+
initialEntryCount: minEntries,
|
|
8781
8801
|
parentId
|
|
8782
8802
|
};
|
|
8783
8803
|
if (treeNodeId) section.treeNodeId = treeNodeId;
|
|
@@ -9333,11 +9353,11 @@ function idPrefix(node) {
|
|
|
9333
9353
|
if (t === "shape") return "shape";
|
|
9334
9354
|
return "el";
|
|
9335
9355
|
}
|
|
9336
|
-
function cloneNodeWithNewIds$1(node) {
|
|
9356
|
+
function cloneNodeWithNewIds$1(node, cloneSuffix) {
|
|
9337
9357
|
const oldToNew = /* @__PURE__ */ new Map();
|
|
9338
9358
|
function clone(n) {
|
|
9339
9359
|
var _a;
|
|
9340
|
-
const newId = generateId(idPrefix(n));
|
|
9360
|
+
const newId = cloneSuffix ? `${baseId(n.id)}__c${cloneSuffix}` : generateId(idPrefix(n));
|
|
9341
9361
|
oldToNew.set(n.id, newId);
|
|
9342
9362
|
const base = baseId(n.id);
|
|
9343
9363
|
const withMeta = { ...n, id: newId, __baseNodeId: base, __sourceId: n.id };
|
|
@@ -9503,12 +9523,12 @@ function getNestedRepeatableEntryCount(parentId, parentIndex, childId, formValue
|
|
|
9503
9523
|
}
|
|
9504
9524
|
return Math.max(1, maxIndex);
|
|
9505
9525
|
}
|
|
9506
|
-
function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsFromSchema, repeatableEntryCounts, repeatableNestedEntryCounts, displayFormatMap) {
|
|
9526
|
+
function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsFromSchema, repeatableEntryCounts, repeatableNestedEntryCounts, displayFormatMap, repeatablePagesFromSchema) {
|
|
9507
9527
|
var _a, _b, _c, _d, _e;
|
|
9508
9528
|
const cloned = JSON.parse(JSON.stringify(config));
|
|
9509
9529
|
if (!cloned.pages) return cloned;
|
|
9510
9530
|
const dynamicFields = cloned.dynamicFields;
|
|
9511
|
-
|
|
9531
|
+
let pages = cloned.pages;
|
|
9512
9532
|
const repeatableList = (repeatableSectionsFromSchema == null ? void 0 : repeatableSectionsFromSchema.length) ? repeatableSectionsFromSchema : getRepeatableFromConfig(pages);
|
|
9513
9533
|
const nodeIds = repeatableList.map((r) => r.nodeId);
|
|
9514
9534
|
const entryCountFromList = (baseNodeId) => {
|
|
@@ -9551,7 +9571,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
|
|
|
9551
9571
|
const N = Math.max(1, countFromState ?? getRepeatableEntryCount(baseNodeId, formValues));
|
|
9552
9572
|
const clones = [];
|
|
9553
9573
|
for (let i = 1; i <= N; i++) {
|
|
9554
|
-
const [clone, oldToNew] = cloneNodeWithNewIds$1(node);
|
|
9574
|
+
const [clone, oldToNew] = cloneNodeWithNewIds$1(node, `${baseNodeId}_e${i}`);
|
|
9555
9575
|
delete clone.repeatableSection;
|
|
9556
9576
|
clones.push(clone);
|
|
9557
9577
|
const newToOriginal = /* @__PURE__ */ new Map();
|
|
@@ -9587,7 +9607,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
|
|
|
9587
9607
|
const phase1Map = phase1NewToOriginal.get(`${parentBaseNodeId}_${parentIndex1Based}`);
|
|
9588
9608
|
const clones = [];
|
|
9589
9609
|
for (let i = 1; i <= N; i++) {
|
|
9590
|
-
const [clone, oldToNew] = cloneNodeWithNewIds$1(node);
|
|
9610
|
+
const [clone, oldToNew] = cloneNodeWithNewIds$1(node, `${parentBaseNodeId}_p${parentIndex1Based}_${baseNodeId}_e${i}`);
|
|
9591
9611
|
delete clone.repeatableSection;
|
|
9592
9612
|
clones.push(clone);
|
|
9593
9613
|
for (const [oldId, newId] of oldToNew) {
|
|
@@ -9801,9 +9821,20 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
|
|
|
9801
9821
|
}
|
|
9802
9822
|
}
|
|
9803
9823
|
}
|
|
9824
|
+
const repeatablePagePrefixSet = new Set(
|
|
9825
|
+
[].map((p) => `field_${p.templateKeyPrefix}_`)
|
|
9826
|
+
);
|
|
9804
9827
|
if (dynamicFields == null ? void 0 : dynamicFields.length) {
|
|
9805
9828
|
for (const key of Object.keys(formValues)) {
|
|
9806
9829
|
if (NESTED_REPEATABLE_KEY_REGEX.test(key)) continue;
|
|
9830
|
+
let isPageKey = false;
|
|
9831
|
+
for (const pfx of repeatablePagePrefixSet) {
|
|
9832
|
+
if (key.startsWith(pfx)) {
|
|
9833
|
+
isPageKey = true;
|
|
9834
|
+
break;
|
|
9835
|
+
}
|
|
9836
|
+
}
|
|
9837
|
+
if (isPageKey) continue;
|
|
9807
9838
|
const match = key.match(REPEATABLE_KEY_REGEX);
|
|
9808
9839
|
if (!match) continue;
|
|
9809
9840
|
const [, nodeId, indexStr, fieldId] = match;
|
|
@@ -10710,6 +10741,7 @@ function PixldocsPreview(props) {
|
|
|
10710
10741
|
const [resolvedConfig, setResolvedConfig] = useState(null);
|
|
10711
10742
|
const [isLoading, setIsLoading] = useState(false);
|
|
10712
10743
|
const [fontsReady, setFontsReady] = useState(false);
|
|
10744
|
+
const [fontsReadyVersion, setFontsReadyVersion] = useState(0);
|
|
10713
10745
|
const isResolveMode = !("config" in props && props.config);
|
|
10714
10746
|
useEffect(() => {
|
|
10715
10747
|
if (!isResolveMode) {
|
|
@@ -10720,6 +10752,7 @@ function PixldocsPreview(props) {
|
|
|
10720
10752
|
if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;
|
|
10721
10753
|
let cancelled = false;
|
|
10722
10754
|
setIsLoading(true);
|
|
10755
|
+
setFontsReady(false);
|
|
10723
10756
|
resolveFromForm({
|
|
10724
10757
|
templateId: p.templateId,
|
|
10725
10758
|
formSchemaId: p.formSchemaId,
|
|
@@ -10761,7 +10794,28 @@ function PixldocsPreview(props) {
|
|
|
10761
10794
|
]);
|
|
10762
10795
|
const config = isResolveMode ? resolvedConfig : props.config;
|
|
10763
10796
|
useEffect(() => {
|
|
10764
|
-
|
|
10797
|
+
var _a, _b;
|
|
10798
|
+
if (!config) return;
|
|
10799
|
+
let cancelled = false;
|
|
10800
|
+
const bump = () => {
|
|
10801
|
+
if (cancelled) return;
|
|
10802
|
+
clearMeasurementCache();
|
|
10803
|
+
setFontsReadyVersion((v) => v + 1);
|
|
10804
|
+
};
|
|
10805
|
+
(_b = (_a = document.fonts) == null ? void 0 : _a.ready) == null ? void 0 : _b.then(bump);
|
|
10806
|
+
const timeoutId = window.setTimeout(bump, 350);
|
|
10807
|
+
return () => {
|
|
10808
|
+
cancelled = true;
|
|
10809
|
+
window.clearTimeout(timeoutId);
|
|
10810
|
+
};
|
|
10811
|
+
}, [config]);
|
|
10812
|
+
const previewKey = useMemo(() => `${pageIndex}-${fontsReadyVersion}`, [pageIndex, fontsReadyVersion]);
|
|
10813
|
+
useEffect(() => {
|
|
10814
|
+
if (isResolveMode) return;
|
|
10815
|
+
if (!config) {
|
|
10816
|
+
setFontsReady(false);
|
|
10817
|
+
return;
|
|
10818
|
+
}
|
|
10765
10819
|
setFontsReady(false);
|
|
10766
10820
|
ensureFontsForResolvedConfig(config).then(() => setFontsReady(true)).catch(() => setFontsReady(true));
|
|
10767
10821
|
}, [isResolveMode, config]);
|
|
@@ -10769,6 +10823,9 @@ function PixldocsPreview(props) {
|
|
|
10769
10823
|
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..." }) });
|
|
10770
10824
|
}
|
|
10771
10825
|
if (!config) return null;
|
|
10826
|
+
if (!fontsReady) {
|
|
10827
|
+
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..." }) });
|
|
10828
|
+
}
|
|
10772
10829
|
return /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsx(
|
|
10773
10830
|
PreviewCanvas,
|
|
10774
10831
|
{
|
|
@@ -10778,7 +10835,8 @@ function PixldocsPreview(props) {
|
|
|
10778
10835
|
absoluteZoom,
|
|
10779
10836
|
onDynamicFieldClick,
|
|
10780
10837
|
onReady
|
|
10781
|
-
}
|
|
10838
|
+
},
|
|
10839
|
+
previewKey
|
|
10782
10840
|
) });
|
|
10783
10841
|
}
|
|
10784
10842
|
class PixldocsRenderer {
|