@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.cjs
CHANGED
|
@@ -2203,6 +2203,18 @@ const useEditorStore = zustand.create((set, get) => ({
|
|
|
2203
2203
|
const committed = commitFromState(state, nextCanvas);
|
|
2204
2204
|
return { canvas: nextCanvas, ...committed };
|
|
2205
2205
|
}),
|
|
2206
|
+
setPageBoundRepeatablePage: (pageId, repeatablePageId) => set((state) => {
|
|
2207
|
+
const updatedPages = state.canvas.pages.map((p) => {
|
|
2208
|
+
if (p.id !== pageId) return p;
|
|
2209
|
+
const next = { ...p };
|
|
2210
|
+
if (repeatablePageId) next.boundRepeatablePageId = repeatablePageId;
|
|
2211
|
+
else delete next.boundRepeatablePageId;
|
|
2212
|
+
return next;
|
|
2213
|
+
});
|
|
2214
|
+
const nextCanvas = { ...state.canvas, pages: updatedPages };
|
|
2215
|
+
const committed = commitFromState(state, nextCanvas);
|
|
2216
|
+
return { canvas: nextCanvas, ...committed };
|
|
2217
|
+
}),
|
|
2206
2218
|
moveElementsToPage: (elementIds, targetPageId) => set((state) => {
|
|
2207
2219
|
const currentPage = getCurrentPageFromCanvas(state.canvas);
|
|
2208
2220
|
const nodesToMove = [];
|
|
@@ -2347,7 +2359,8 @@ const useEditorStore = zustand.create((set, get) => ({
|
|
|
2347
2359
|
id: p.id,
|
|
2348
2360
|
name: p.name,
|
|
2349
2361
|
children,
|
|
2350
|
-
settings: { backgroundColor: "#ffffff", ...p.settings }
|
|
2362
|
+
settings: { backgroundColor: "#ffffff", ...p.settings },
|
|
2363
|
+
...p.boundRepeatablePageId ? { boundRepeatablePageId: p.boundRepeatablePageId } : {}
|
|
2351
2364
|
};
|
|
2352
2365
|
});
|
|
2353
2366
|
pagesWithPositions = pagesWithPositions.map((p) => {
|
|
@@ -4880,6 +4893,7 @@ const PageCanvas = react.forwardRef(
|
|
|
4880
4893
|
const prevCanvasUpdateVersionRef = react.useRef(canvasUpdateVersion);
|
|
4881
4894
|
const syncTriggeredByPanelRef = react.useRef(false);
|
|
4882
4895
|
const hasRunPostReadyReflowForPageRef = react.useRef(null);
|
|
4896
|
+
const hasNotifiedReadyForPageRef = react.useRef(null);
|
|
4883
4897
|
const hasClearedCachesBeforeFirstSyncRef = react.useRef(false);
|
|
4884
4898
|
const [guides, setGuides] = react.useState([]);
|
|
4885
4899
|
const [gridResizeLabel, setGridResizeLabel] = react.useState(null);
|
|
@@ -5142,10 +5156,8 @@ const PageCanvas = react.forwardRef(
|
|
|
5142
5156
|
clearFabricCharCache();
|
|
5143
5157
|
clearMeasurementCache();
|
|
5144
5158
|
setReady(true);
|
|
5145
|
-
if (onReady) onReady();
|
|
5146
5159
|
} catch (e) {
|
|
5147
5160
|
setReady(true);
|
|
5148
|
-
if (onReady) onReady();
|
|
5149
5161
|
}
|
|
5150
5162
|
};
|
|
5151
5163
|
initFonts();
|
|
@@ -7117,6 +7129,11 @@ const PageCanvas = react.forwardRef(
|
|
|
7117
7129
|
if (!ready || hasRunPostReadyReflowForPageRef.current === pageId) return;
|
|
7118
7130
|
hasRunPostReadyReflowForPageRef.current = pageId;
|
|
7119
7131
|
let cancelled = false;
|
|
7132
|
+
const notifyReady = () => {
|
|
7133
|
+
if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
|
|
7134
|
+
hasNotifiedReadyForPageRef.current = pageId;
|
|
7135
|
+
onReady == null ? void 0 : onReady();
|
|
7136
|
+
};
|
|
7120
7137
|
const runReflowAndPersist = () => {
|
|
7121
7138
|
const fc = fabricRef.current;
|
|
7122
7139
|
if (!fc || cancelled) return;
|
|
@@ -7158,6 +7175,7 @@ const PageCanvas = react.forwardRef(
|
|
|
7158
7175
|
requestAnimationFrame(() => {
|
|
7159
7176
|
if (cancelled) return;
|
|
7160
7177
|
runReflowAndPersist();
|
|
7178
|
+
notifyReady();
|
|
7161
7179
|
});
|
|
7162
7180
|
});
|
|
7163
7181
|
});
|
|
@@ -7166,7 +7184,7 @@ const PageCanvas = react.forwardRef(
|
|
|
7166
7184
|
cancelled = true;
|
|
7167
7185
|
cancelAnimationFrame(raf1);
|
|
7168
7186
|
};
|
|
7169
|
-
}, [ready, pageId]);
|
|
7187
|
+
}, [ready, pageId, onReady]);
|
|
7170
7188
|
react.useEffect(() => {
|
|
7171
7189
|
const fc = fabricRef.current;
|
|
7172
7190
|
if (!fc || isRebuildingRef.current || !isActive) return;
|
|
@@ -8780,13 +8798,14 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
|
|
|
8780
8798
|
const labelPrefix = rawPrefix.startsWith("field_") ? rawPrefix : `field_${rawPrefix}`;
|
|
8781
8799
|
const treeNodeId = repeatableNodeMap == null ? void 0 : repeatableNodeMap.get(def.label.trim().toLowerCase());
|
|
8782
8800
|
const prefix = treeNodeId ? `field_${treeNodeId}` : labelPrefix;
|
|
8801
|
+
const minEntries = def.minEntries != null ? Math.max(0, def.minEntries) : 1;
|
|
8783
8802
|
const section = {
|
|
8784
8803
|
id: def.id,
|
|
8785
8804
|
label: def.label,
|
|
8786
8805
|
order: def.order ?? 0,
|
|
8787
8806
|
type: "repeatable",
|
|
8788
8807
|
templateKeyPrefix: prefix,
|
|
8789
|
-
minEntries
|
|
8808
|
+
minEntries,
|
|
8790
8809
|
maxEntries: def.maxEntries,
|
|
8791
8810
|
entryFields: def.fields.map((f, i) => ({
|
|
8792
8811
|
key: f.key,
|
|
@@ -8796,7 +8815,8 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
|
|
|
8796
8815
|
templateKey: f.key,
|
|
8797
8816
|
placeholder: f.placeholder
|
|
8798
8817
|
})),
|
|
8799
|
-
|
|
8818
|
+
// Honor minEntries: 0 — start with no entries, user adds via "+ Add" button.
|
|
8819
|
+
initialEntryCount: minEntries,
|
|
8800
8820
|
parentId
|
|
8801
8821
|
};
|
|
8802
8822
|
if (treeNodeId) section.treeNodeId = treeNodeId;
|
|
@@ -9352,11 +9372,11 @@ function idPrefix(node) {
|
|
|
9352
9372
|
if (t === "shape") return "shape";
|
|
9353
9373
|
return "el";
|
|
9354
9374
|
}
|
|
9355
|
-
function cloneNodeWithNewIds$1(node) {
|
|
9375
|
+
function cloneNodeWithNewIds$1(node, cloneSuffix) {
|
|
9356
9376
|
const oldToNew = /* @__PURE__ */ new Map();
|
|
9357
9377
|
function clone(n) {
|
|
9358
9378
|
var _a;
|
|
9359
|
-
const newId = generateId(idPrefix(n));
|
|
9379
|
+
const newId = cloneSuffix ? `${baseId(n.id)}__c${cloneSuffix}` : generateId(idPrefix(n));
|
|
9360
9380
|
oldToNew.set(n.id, newId);
|
|
9361
9381
|
const base = baseId(n.id);
|
|
9362
9382
|
const withMeta = { ...n, id: newId, __baseNodeId: base, __sourceId: n.id };
|
|
@@ -9522,12 +9542,12 @@ function getNestedRepeatableEntryCount(parentId, parentIndex, childId, formValue
|
|
|
9522
9542
|
}
|
|
9523
9543
|
return Math.max(1, maxIndex);
|
|
9524
9544
|
}
|
|
9525
|
-
function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsFromSchema, repeatableEntryCounts, repeatableNestedEntryCounts, displayFormatMap) {
|
|
9545
|
+
function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsFromSchema, repeatableEntryCounts, repeatableNestedEntryCounts, displayFormatMap, repeatablePagesFromSchema) {
|
|
9526
9546
|
var _a, _b, _c, _d, _e;
|
|
9527
9547
|
const cloned = JSON.parse(JSON.stringify(config));
|
|
9528
9548
|
if (!cloned.pages) return cloned;
|
|
9529
9549
|
const dynamicFields = cloned.dynamicFields;
|
|
9530
|
-
|
|
9550
|
+
let pages = cloned.pages;
|
|
9531
9551
|
const repeatableList = (repeatableSectionsFromSchema == null ? void 0 : repeatableSectionsFromSchema.length) ? repeatableSectionsFromSchema : getRepeatableFromConfig(pages);
|
|
9532
9552
|
const nodeIds = repeatableList.map((r) => r.nodeId);
|
|
9533
9553
|
const entryCountFromList = (baseNodeId) => {
|
|
@@ -9570,7 +9590,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
|
|
|
9570
9590
|
const N = Math.max(1, countFromState ?? getRepeatableEntryCount(baseNodeId, formValues));
|
|
9571
9591
|
const clones = [];
|
|
9572
9592
|
for (let i = 1; i <= N; i++) {
|
|
9573
|
-
const [clone, oldToNew] = cloneNodeWithNewIds$1(node);
|
|
9593
|
+
const [clone, oldToNew] = cloneNodeWithNewIds$1(node, `${baseNodeId}_e${i}`);
|
|
9574
9594
|
delete clone.repeatableSection;
|
|
9575
9595
|
clones.push(clone);
|
|
9576
9596
|
const newToOriginal = /* @__PURE__ */ new Map();
|
|
@@ -9606,7 +9626,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
|
|
|
9606
9626
|
const phase1Map = phase1NewToOriginal.get(`${parentBaseNodeId}_${parentIndex1Based}`);
|
|
9607
9627
|
const clones = [];
|
|
9608
9628
|
for (let i = 1; i <= N; i++) {
|
|
9609
|
-
const [clone, oldToNew] = cloneNodeWithNewIds$1(node);
|
|
9629
|
+
const [clone, oldToNew] = cloneNodeWithNewIds$1(node, `${parentBaseNodeId}_p${parentIndex1Based}_${baseNodeId}_e${i}`);
|
|
9610
9630
|
delete clone.repeatableSection;
|
|
9611
9631
|
clones.push(clone);
|
|
9612
9632
|
for (const [oldId, newId] of oldToNew) {
|
|
@@ -9820,9 +9840,20 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
|
|
|
9820
9840
|
}
|
|
9821
9841
|
}
|
|
9822
9842
|
}
|
|
9843
|
+
const repeatablePagePrefixSet = new Set(
|
|
9844
|
+
[].map((p) => `field_${p.templateKeyPrefix}_`)
|
|
9845
|
+
);
|
|
9823
9846
|
if (dynamicFields == null ? void 0 : dynamicFields.length) {
|
|
9824
9847
|
for (const key of Object.keys(formValues)) {
|
|
9825
9848
|
if (NESTED_REPEATABLE_KEY_REGEX.test(key)) continue;
|
|
9849
|
+
let isPageKey = false;
|
|
9850
|
+
for (const pfx of repeatablePagePrefixSet) {
|
|
9851
|
+
if (key.startsWith(pfx)) {
|
|
9852
|
+
isPageKey = true;
|
|
9853
|
+
break;
|
|
9854
|
+
}
|
|
9855
|
+
}
|
|
9856
|
+
if (isPageKey) continue;
|
|
9826
9857
|
const match = key.match(REPEATABLE_KEY_REGEX);
|
|
9827
9858
|
if (!match) continue;
|
|
9828
9859
|
const [, nodeId, indexStr, fieldId] = match;
|
|
@@ -10729,6 +10760,7 @@ function PixldocsPreview(props) {
|
|
|
10729
10760
|
const [resolvedConfig, setResolvedConfig] = react.useState(null);
|
|
10730
10761
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
10731
10762
|
const [fontsReady, setFontsReady] = react.useState(false);
|
|
10763
|
+
const [fontsReadyVersion, setFontsReadyVersion] = react.useState(0);
|
|
10732
10764
|
const isResolveMode = !("config" in props && props.config);
|
|
10733
10765
|
react.useEffect(() => {
|
|
10734
10766
|
if (!isResolveMode) {
|
|
@@ -10739,6 +10771,7 @@ function PixldocsPreview(props) {
|
|
|
10739
10771
|
if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;
|
|
10740
10772
|
let cancelled = false;
|
|
10741
10773
|
setIsLoading(true);
|
|
10774
|
+
setFontsReady(false);
|
|
10742
10775
|
resolveFromForm({
|
|
10743
10776
|
templateId: p.templateId,
|
|
10744
10777
|
formSchemaId: p.formSchemaId,
|
|
@@ -10780,7 +10813,28 @@ function PixldocsPreview(props) {
|
|
|
10780
10813
|
]);
|
|
10781
10814
|
const config = isResolveMode ? resolvedConfig : props.config;
|
|
10782
10815
|
react.useEffect(() => {
|
|
10783
|
-
|
|
10816
|
+
var _a, _b;
|
|
10817
|
+
if (!config) return;
|
|
10818
|
+
let cancelled = false;
|
|
10819
|
+
const bump = () => {
|
|
10820
|
+
if (cancelled) return;
|
|
10821
|
+
clearMeasurementCache();
|
|
10822
|
+
setFontsReadyVersion((v) => v + 1);
|
|
10823
|
+
};
|
|
10824
|
+
(_b = (_a = document.fonts) == null ? void 0 : _a.ready) == null ? void 0 : _b.then(bump);
|
|
10825
|
+
const timeoutId = window.setTimeout(bump, 350);
|
|
10826
|
+
return () => {
|
|
10827
|
+
cancelled = true;
|
|
10828
|
+
window.clearTimeout(timeoutId);
|
|
10829
|
+
};
|
|
10830
|
+
}, [config]);
|
|
10831
|
+
const previewKey = react.useMemo(() => `${pageIndex}-${fontsReadyVersion}`, [pageIndex, fontsReadyVersion]);
|
|
10832
|
+
react.useEffect(() => {
|
|
10833
|
+
if (isResolveMode) return;
|
|
10834
|
+
if (!config) {
|
|
10835
|
+
setFontsReady(false);
|
|
10836
|
+
return;
|
|
10837
|
+
}
|
|
10784
10838
|
setFontsReady(false);
|
|
10785
10839
|
ensureFontsForResolvedConfig(config).then(() => setFontsReady(true)).catch(() => setFontsReady(true));
|
|
10786
10840
|
}, [isResolveMode, config]);
|
|
@@ -10788,6 +10842,9 @@ function PixldocsPreview(props) {
|
|
|
10788
10842
|
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..." }) });
|
|
10789
10843
|
}
|
|
10790
10844
|
if (!config) return null;
|
|
10845
|
+
if (!fontsReady) {
|
|
10846
|
+
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..." }) });
|
|
10847
|
+
}
|
|
10791
10848
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10792
10849
|
PreviewCanvas,
|
|
10793
10850
|
{
|
|
@@ -10797,7 +10854,8 @@ function PixldocsPreview(props) {
|
|
|
10797
10854
|
absoluteZoom,
|
|
10798
10855
|
onDynamicFieldClick,
|
|
10799
10856
|
onReady
|
|
10800
|
-
}
|
|
10857
|
+
},
|
|
10858
|
+
previewKey
|
|
10801
10859
|
) });
|
|
10802
10860
|
}
|
|
10803
10861
|
class PixldocsRenderer {
|