@pramen/cms-editor 0.0.29 → 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 +16 -10
- package/src/types.ts +1 -0
- package/dist/main.y75r3gyx.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,12 +179,16 @@ 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
|
-
// addBlock echoes the created block + placement, so append it locally instead of a
|
|
188
|
-
// full getContentType+getPage reload — one round trip instead of three.
|
|
189
192
|
const { block, placement } = await api.call<{
|
|
190
193
|
block: { id: string; title?: string | null; fields?: Record<string, unknown> | null };
|
|
191
194
|
placement: { id: string; isShared?: boolean | number };
|
|
@@ -198,9 +201,9 @@ export function PageEditor({ api, page, blockTypes, tab, onTab, onBack, onChange
|
|
|
198
201
|
fields: block.fields ?? {},
|
|
199
202
|
is_shared: Boolean(placement.isShared),
|
|
200
203
|
};
|
|
201
|
-
|
|
202
|
-
flash("block added");
|
|
204
|
+
patchRegion(region, (list) => list.map((b) => (b.id === tempId ? rb : b)));
|
|
203
205
|
} catch (e) {
|
|
206
|
+
patchRegion(region, (list) => list.filter((b) => b.id !== tempId));
|
|
204
207
|
setErr(errMsg(e));
|
|
205
208
|
}
|
|
206
209
|
};
|
|
@@ -268,7 +271,6 @@ export function PageEditor({ api, page, blockTypes, tab, onTab, onBack, onChange
|
|
|
268
271
|
|
|
269
272
|
<div className="overflow-auto py-1.5">
|
|
270
273
|
{err ? <Banner>{err}</Banner> : null}
|
|
271
|
-
{msg ? <Banner ok>{msg}</Banner> : null}
|
|
272
274
|
{regions.map((r) => {
|
|
273
275
|
const blocks = assembled?.regions[r.name] ?? [];
|
|
274
276
|
const allowed = r.allowedTypes && r.allowedTypes.length ? r.allowedTypes : blockTypes.map((b) => b.slug);
|
|
@@ -350,13 +352,17 @@ function BlockCard({ api, block, blockType, isFirst, isLast, onMove, onRemove, o
|
|
|
350
352
|
const placementId = block.id;
|
|
351
353
|
|
|
352
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.
|
|
353
357
|
useEffect(() => {
|
|
358
|
+
if (block.pending) { setFields({}); return; }
|
|
354
359
|
let alive = true;
|
|
355
360
|
api.call<{ fields?: Record<string, unknown> }>("getBlock", { blockId }).then((b) => { if (alive) setFields(b?.fields ?? {}); }).catch((e) => onError(errMsg(e)));
|
|
356
361
|
return () => { alive = false; };
|
|
357
|
-
}, [api, blockId, onError]);
|
|
362
|
+
}, [api, blockId, onError, block.pending]);
|
|
358
363
|
|
|
359
364
|
const flush = useCallback(async () => {
|
|
365
|
+
if (block.pending) return; // don't write against a placeholder's temp id
|
|
360
366
|
if (timer.current) { clearTimeout(timer.current); timer.current = undefined; }
|
|
361
367
|
const next = pending.current;
|
|
362
368
|
if (!next) return;
|
|
@@ -371,7 +377,7 @@ function BlockCard({ api, block, blockType, isFirst, isLast, onMove, onRemove, o
|
|
|
371
377
|
onError(errMsg(e));
|
|
372
378
|
setSaveState("idle");
|
|
373
379
|
}
|
|
374
|
-
}, [api, blockId, placementId, onPatch, onError]);
|
|
380
|
+
}, [api, blockId, placementId, onPatch, onError, block.pending]);
|
|
375
381
|
|
|
376
382
|
// Flush a pending edit if the card unmounts (nav away, reorder remount) before the debounce.
|
|
377
383
|
useEffect(() => () => { if (pending.current) void flush(); }, [flush]);
|
|
@@ -392,7 +398,7 @@ function BlockCard({ api, block, blockType, isFirst, isLast, onMove, onRemove, o
|
|
|
392
398
|
// image is set to the whole card so you drag a preview of the block, not just the grip.
|
|
393
399
|
<div
|
|
394
400
|
ref={cardRef}
|
|
395
|
-
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" : ""}`}
|
|
396
402
|
onDragOver={(e) => { e.preventDefault(); onDragOverBlock(); }}
|
|
397
403
|
onDrop={(e) => { e.preventDefault(); onDropBlock(); }}
|
|
398
404
|
>
|
package/src/types.ts
CHANGED