@pramen/cms-editor 0.0.28 → 0.0.30
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/app.css +1 -1
- package/dist/index.html +1 -1
- package/dist/main.wjbaszqq.js +251 -0
- package/package.json +1 -1
- package/src/components.tsx +28 -9
- package/src/types.ts +1 -0
- package/dist/main.e0yd6v1m.js +0 -251
package/package.json
CHANGED
package/src/components.tsx
CHANGED
|
@@ -164,7 +164,6 @@ export function PageEditor({ api, page, blockTypes, tab, onTab, onBack, onChange
|
|
|
164
164
|
const [ct, setCt] = useState<ContentType | null>(null);
|
|
165
165
|
const [assembled, setAssembled] = useState<AssembledPage | null>(null);
|
|
166
166
|
const [err, setErr] = useState("");
|
|
167
|
-
const [msg, setMsg] = useState("");
|
|
168
167
|
|
|
169
168
|
const btBySlug = useMemo(() => new Map(blockTypes.map((b) => [b.slug, b])), [blockTypes]);
|
|
170
169
|
|
|
@@ -180,14 +179,31 @@ export function PageEditor({ api, page, blockTypes, tab, onTab, onBack, onChange
|
|
|
180
179
|
useEffect(() => { reload(); }, [reload]);
|
|
181
180
|
|
|
182
181
|
const regions: RegionDefinition[] = ct?.regions ?? [];
|
|
183
|
-
|
|
182
|
+
|
|
183
|
+
const patchRegion = (region: string, fn: (list: RenderedBlock[]) => RenderedBlock[]) =>
|
|
184
|
+
setAssembled((prev) => (prev ? { ...prev, regions: { ...prev.regions, [region]: fn(prev.regions[region] ?? []) } } : prev));
|
|
184
185
|
|
|
185
186
|
const addBlock = async (region: string, slug: string) => {
|
|
187
|
+
// Optimistic: show a placeholder immediately (no wait for the round trip), then
|
|
188
|
+
// reconcile with the persisted row addBlock echoes — or roll it back on failure.
|
|
189
|
+
const tempId = `tmp:${crypto.randomUUID()}`;
|
|
190
|
+
patchRegion(region, (list) => [...list, { id: tempId, block_id: tempId, block_type: slug, title: null, fields: {}, is_shared: false, pending: true }]);
|
|
186
191
|
try {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
const { block, placement } = await api.call<{
|
|
193
|
+
block: { id: string; title?: string | null; fields?: Record<string, unknown> | null };
|
|
194
|
+
placement: { id: string; isShared?: boolean | number };
|
|
195
|
+
}>("addBlock", { pageId: page.id, blockTypeSlug: slug, region, fields: {} });
|
|
196
|
+
const rb: RenderedBlock = {
|
|
197
|
+
id: String(placement.id),
|
|
198
|
+
block_id: String(block.id),
|
|
199
|
+
block_type: slug,
|
|
200
|
+
title: block.title ?? null,
|
|
201
|
+
fields: block.fields ?? {},
|
|
202
|
+
is_shared: Boolean(placement.isShared),
|
|
203
|
+
};
|
|
204
|
+
patchRegion(region, (list) => list.map((b) => (b.id === tempId ? rb : b)));
|
|
190
205
|
} catch (e) {
|
|
206
|
+
patchRegion(region, (list) => list.filter((b) => b.id !== tempId));
|
|
191
207
|
setErr(errMsg(e));
|
|
192
208
|
}
|
|
193
209
|
};
|
|
@@ -255,7 +271,6 @@ export function PageEditor({ api, page, blockTypes, tab, onTab, onBack, onChange
|
|
|
255
271
|
|
|
256
272
|
<div className="overflow-auto py-1.5">
|
|
257
273
|
{err ? <Banner>{err}</Banner> : null}
|
|
258
|
-
{msg ? <Banner ok>{msg}</Banner> : null}
|
|
259
274
|
{regions.map((r) => {
|
|
260
275
|
const blocks = assembled?.regions[r.name] ?? [];
|
|
261
276
|
const allowed = r.allowedTypes && r.allowedTypes.length ? r.allowedTypes : blockTypes.map((b) => b.slug);
|
|
@@ -337,13 +352,17 @@ function BlockCard({ api, block, blockType, isFirst, isLast, onMove, onRemove, o
|
|
|
337
352
|
const placementId = block.id;
|
|
338
353
|
|
|
339
354
|
// Load RAW fields (media as ids, richtext as HTML) so the value round-trips on save.
|
|
355
|
+
// A pending optimistic block has no persisted row yet — start empty and skip the fetch
|
|
356
|
+
// (its temp id would 404); when it reconciles to real ids the card remounts and fetches.
|
|
340
357
|
useEffect(() => {
|
|
358
|
+
if (block.pending) { setFields({}); return; }
|
|
341
359
|
let alive = true;
|
|
342
360
|
api.call<{ fields?: Record<string, unknown> }>("getBlock", { blockId }).then((b) => { if (alive) setFields(b?.fields ?? {}); }).catch((e) => onError(errMsg(e)));
|
|
343
361
|
return () => { alive = false; };
|
|
344
|
-
}, [api, blockId, onError]);
|
|
362
|
+
}, [api, blockId, onError, block.pending]);
|
|
345
363
|
|
|
346
364
|
const flush = useCallback(async () => {
|
|
365
|
+
if (block.pending) return; // don't write against a placeholder's temp id
|
|
347
366
|
if (timer.current) { clearTimeout(timer.current); timer.current = undefined; }
|
|
348
367
|
const next = pending.current;
|
|
349
368
|
if (!next) return;
|
|
@@ -358,7 +377,7 @@ function BlockCard({ api, block, blockType, isFirst, isLast, onMove, onRemove, o
|
|
|
358
377
|
onError(errMsg(e));
|
|
359
378
|
setSaveState("idle");
|
|
360
379
|
}
|
|
361
|
-
}, [api, blockId, placementId, onPatch, onError]);
|
|
380
|
+
}, [api, blockId, placementId, onPatch, onError, block.pending]);
|
|
362
381
|
|
|
363
382
|
// Flush a pending edit if the card unmounts (nav away, reorder remount) before the debounce.
|
|
364
383
|
useEffect(() => () => { if (pending.current) void flush(); }, [flush]);
|
|
@@ -379,7 +398,7 @@ function BlockCard({ api, block, blockType, isFirst, isLast, onMove, onRemove, o
|
|
|
379
398
|
// image is set to the whole card so you drag a preview of the block, not just the grip.
|
|
380
399
|
<div
|
|
381
400
|
ref={cardRef}
|
|
382
|
-
className={`mb-2.5 rounded-panel border bg-surface-card transition-colors ${isOver ? "border-brand-green" : "border-border"} ${dragging ? "opacity-40" : ""}`}
|
|
401
|
+
className={`mb-2.5 rounded-panel border bg-surface-card transition-colors ${isOver ? "border-brand-green" : "border-border"} ${dragging ? "opacity-40" : ""} ${block.pending ? "pointer-events-none opacity-60" : ""}`}
|
|
383
402
|
onDragOver={(e) => { e.preventDefault(); onDragOverBlock(); }}
|
|
384
403
|
onDrop={(e) => { e.preventDefault(); onDropBlock(); }}
|
|
385
404
|
>
|
package/src/types.ts
CHANGED