@particle-academy/fancy-cms-ui 0.9.0 → 0.10.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/CHANGELOG.md +31 -0
- package/README.md +46 -0
- package/dist/{chunk-BVMSHUQF.js → chunk-G7ULXTKI.js} +266 -33
- package/dist/chunk-G7ULXTKI.js.map +1 -0
- package/dist/editor.cjs +308 -75
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +1 -1
- package/dist/editor.d.ts +1 -1
- package/dist/editor.js +2 -2
- package/dist/index.cjs +263 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{useEditor-B2kVZJA0.d.cts → useEditor-fIQEaKzZ.d.cts} +54 -2
- package/dist/{useEditor-BQSictH3.d.ts → useEditor-wGEqxpJT.d.ts} +54 -2
- package/package.json +2 -2
- package/dist/chunk-BVMSHUQF.js.map +0 -1
package/dist/editor.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-
|
|
1
|
+
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-fIQEaKzZ.cjs';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { P as PageDoc, h as ElementRegistry, g as DataContext, N as Node, q as StyleProps, L as LayoutMode } from './registry-F2TAMjhx.cjs';
|
|
4
4
|
import '@particle-academy/fancy-doc-commons';
|
package/dist/editor.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-
|
|
1
|
+
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-wGEqxpJT.js';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { P as PageDoc, h as ElementRegistry, g as DataContext, N as Node, q as StyleProps, L as LayoutMode } from './registry-F2TAMjhx.js';
|
|
4
4
|
import '@particle-academy/fancy-doc-commons';
|
package/dist/editor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useEditor, useLatestRef, CONTAINER_TYPES, ADD_DEFAULTS, ADD_MENU } from './chunk-
|
|
2
|
-
export { Canvas, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor } from './chunk-
|
|
1
|
+
import { useEditor, useLatestRef, CONTAINER_TYPES, ADD_DEFAULTS, ADD_MENU } from './chunk-G7ULXTKI.js';
|
|
2
|
+
export { Canvas, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor } from './chunk-G7ULXTKI.js';
|
|
3
3
|
import { isBinding, lastRootId, childrenOf, CmsPage, defaultRegistry } from './chunk-IRG5IKKO.js';
|
|
4
4
|
import { useState, useRef, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
5
5
|
import { ContextMenu } from '@particle-academy/react-fancy';
|
package/dist/index.cjs
CHANGED
|
@@ -1005,16 +1005,42 @@ var input = {
|
|
|
1005
1005
|
font: "inherit",
|
|
1006
1006
|
fontSize: 13
|
|
1007
1007
|
};
|
|
1008
|
-
function Inspector({ doc, selection, apply }) {
|
|
1008
|
+
function Inspector({ doc, selection, apply, drafts }) {
|
|
1009
1009
|
const uid = react.useId();
|
|
1010
1010
|
const fieldId = (key) => `${uid}-${key}`;
|
|
1011
1011
|
const node = selection ? doc.nodes[selection] : null;
|
|
1012
1012
|
if (!node) {
|
|
1013
1013
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 16, color: "var(--fcms-muted)", fontFamily: "system-ui, sans-serif", fontSize: 13 }, children: "Select an element to edit." });
|
|
1014
1014
|
}
|
|
1015
|
-
const
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1015
|
+
const nodeId = node.id;
|
|
1016
|
+
const bind = (name, read, op, numeric = false) => {
|
|
1017
|
+
const key = JSON.stringify([nodeId, name]);
|
|
1018
|
+
const field = {
|
|
1019
|
+
key,
|
|
1020
|
+
label: `${nodeId} / ${name}`,
|
|
1021
|
+
op,
|
|
1022
|
+
read: (next) => {
|
|
1023
|
+
const item = next.nodes[nodeId];
|
|
1024
|
+
return item ? read(item) : void 0;
|
|
1025
|
+
},
|
|
1026
|
+
canonical: numeric ? (raw) => String(Number(raw) || 0) : (raw) => raw
|
|
1027
|
+
};
|
|
1028
|
+
const accepted = read(node);
|
|
1029
|
+
return {
|
|
1030
|
+
value: drafts ? drafts.value(key, accepted) : accepted,
|
|
1031
|
+
onChange: (event) => {
|
|
1032
|
+
if (drafts) drafts.change(field, event.target.value);
|
|
1033
|
+
else apply(op(event.target.value));
|
|
1034
|
+
},
|
|
1035
|
+
onFocus: () => drafts?.focus(key),
|
|
1036
|
+
onBlur: () => drafts?.blur(key),
|
|
1037
|
+
onCompositionStart: () => drafts?.composition(key, true),
|
|
1038
|
+
onCompositionEnd: () => drafts?.composition(key, false)
|
|
1039
|
+
};
|
|
1040
|
+
};
|
|
1041
|
+
const prop = (key) => bind(key, (item) => typeof item.props[key] === "string" ? item.props[key] : "", (raw) => ({ t: "set_node_props", id: nodeId, patch: { [key]: raw } }));
|
|
1042
|
+
const style = (key) => bind(key, (item) => item.style.base[key] ?? "", (raw) => ({ t: "set_style", id: nodeId, breakpoint: "base", patch: { [key]: raw } }));
|
|
1043
|
+
const length = (key) => bind(key, (item) => item.style.base[key]?.value?.toString() ?? "", (raw) => ({ t: "set_style", id: nodeId, breakpoint: "base", patch: { [key]: { value: Number(raw) || 0, unit: "px" } } }), true);
|
|
1018
1044
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { overflow: "auto", padding: 16, fontFamily: "system-ui, sans-serif", height: "100%", boxSizing: "border-box" }, children: [
|
|
1019
1045
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "var(--fcms-fg)" }, children: node.type }),
|
|
1020
1046
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "var(--fcms-muted)", marginBottom: 8 }, children: node.id }),
|
|
@@ -1026,8 +1052,7 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1026
1052
|
id: fieldId("content"),
|
|
1027
1053
|
"data-cms-field": "content",
|
|
1028
1054
|
style: { ...input, minHeight: 64, resize: "vertical" },
|
|
1029
|
-
|
|
1030
|
-
onChange: (e) => setProp("content", e.target.value)
|
|
1055
|
+
...prop("content")
|
|
1031
1056
|
}
|
|
1032
1057
|
)
|
|
1033
1058
|
] }) : null,
|
|
@@ -1039,8 +1064,7 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1039
1064
|
id: fieldId("src"),
|
|
1040
1065
|
"data-cms-field": "src",
|
|
1041
1066
|
style: input,
|
|
1042
|
-
|
|
1043
|
-
onChange: (e) => setProp("src", e.target.value)
|
|
1067
|
+
...prop("src")
|
|
1044
1068
|
}
|
|
1045
1069
|
)
|
|
1046
1070
|
] }) : null,
|
|
@@ -1052,8 +1076,7 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1052
1076
|
"data-cms-field": "background",
|
|
1053
1077
|
style: input,
|
|
1054
1078
|
placeholder: "#ffffff | gradient | url(\u2026)",
|
|
1055
|
-
|
|
1056
|
-
onChange: (e) => setStyle({ background: e.target.value })
|
|
1079
|
+
...style("background")
|
|
1057
1080
|
}
|
|
1058
1081
|
),
|
|
1059
1082
|
/* @__PURE__ */ jsxRuntime.jsx("label", { style: label, htmlFor: fieldId("color"), children: "Text color" }),
|
|
@@ -1064,8 +1087,7 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1064
1087
|
"data-cms-field": "color",
|
|
1065
1088
|
style: input,
|
|
1066
1089
|
placeholder: "#0f172a",
|
|
1067
|
-
|
|
1068
|
-
onChange: (e) => setStyle({ color: e.target.value })
|
|
1090
|
+
...style("color")
|
|
1069
1091
|
}
|
|
1070
1092
|
),
|
|
1071
1093
|
/* @__PURE__ */ jsxRuntime.jsx("label", { style: label, htmlFor: fieldId("fontSize"), children: "Font size (px)" }),
|
|
@@ -1076,8 +1098,7 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1076
1098
|
"data-cms-field": "fontSize",
|
|
1077
1099
|
type: "number",
|
|
1078
1100
|
style: input,
|
|
1079
|
-
|
|
1080
|
-
onChange: (e) => setStyle({ fontSize: { value: Number(e.target.value) || 0, unit: "px" } })
|
|
1101
|
+
...length("fontSize")
|
|
1081
1102
|
}
|
|
1082
1103
|
),
|
|
1083
1104
|
/* @__PURE__ */ jsxRuntime.jsx("label", { style: label, htmlFor: fieldId("padding"), children: "Padding (px)" }),
|
|
@@ -1088,8 +1109,7 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1088
1109
|
"data-cms-field": "padding",
|
|
1089
1110
|
type: "number",
|
|
1090
1111
|
style: input,
|
|
1091
|
-
|
|
1092
|
-
onChange: (e) => setStyle({ padding: { value: Number(e.target.value) || 0, unit: "px" } })
|
|
1112
|
+
...length("padding")
|
|
1093
1113
|
}
|
|
1094
1114
|
),
|
|
1095
1115
|
/* @__PURE__ */ jsxRuntime.jsx("label", { style: label, htmlFor: fieldId("opacity"), children: "Opacity" }),
|
|
@@ -1103,12 +1123,171 @@ function Inspector({ doc, selection, apply }) {
|
|
|
1103
1123
|
min: "0",
|
|
1104
1124
|
max: "1",
|
|
1105
1125
|
style: input,
|
|
1106
|
-
|
|
1107
|
-
onChange: (e) => setStyle({ opacity: Number(e.target.value) })
|
|
1126
|
+
...bind("opacity", (item) => item.style.base.opacity?.toString() ?? "", (raw) => ({ t: "set_style", id: nodeId, breakpoint: "base", patch: { opacity: Number(raw) } }), true)
|
|
1108
1127
|
}
|
|
1109
1128
|
)
|
|
1110
1129
|
] });
|
|
1111
1130
|
}
|
|
1131
|
+
|
|
1132
|
+
// src/editor/InspectorDrafts.ts
|
|
1133
|
+
var InspectorDrafts = class {
|
|
1134
|
+
constructor(doc) {
|
|
1135
|
+
this.doc = doc;
|
|
1136
|
+
this.drafts = /* @__PURE__ */ new Map();
|
|
1137
|
+
this.composing = /* @__PURE__ */ new Set();
|
|
1138
|
+
this.focused = null;
|
|
1139
|
+
this.flight = null;
|
|
1140
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1141
|
+
this.version = 0;
|
|
1142
|
+
this.disabled = false;
|
|
1143
|
+
this.emit = () => false;
|
|
1144
|
+
this.subscribe = (listener) => {
|
|
1145
|
+
this.listeners.add(listener);
|
|
1146
|
+
return () => {
|
|
1147
|
+
this.listeners.delete(listener);
|
|
1148
|
+
};
|
|
1149
|
+
};
|
|
1150
|
+
this.snapshot = () => this.version;
|
|
1151
|
+
}
|
|
1152
|
+
get busy() {
|
|
1153
|
+
return this.flight !== null || [...this.drafts.values()].some((draft) => draft.dirty || draft.conflict !== null);
|
|
1154
|
+
}
|
|
1155
|
+
get conflicts() {
|
|
1156
|
+
return [...this.drafts.values()].filter((draft) => draft.conflict !== null).map((draft) => ({
|
|
1157
|
+
key: draft.field.key,
|
|
1158
|
+
label: draft.field.label,
|
|
1159
|
+
message: draft.conflict,
|
|
1160
|
+
missing: draft.field.read(this.doc) === void 0
|
|
1161
|
+
}));
|
|
1162
|
+
}
|
|
1163
|
+
value(key, accepted) {
|
|
1164
|
+
return this.drafts.get(key)?.raw ?? accepted;
|
|
1165
|
+
}
|
|
1166
|
+
configure(doc, disabled, emit) {
|
|
1167
|
+
const settled = this.disabled && !disabled;
|
|
1168
|
+
this.doc = doc;
|
|
1169
|
+
this.disabled = disabled;
|
|
1170
|
+
this.emit = emit;
|
|
1171
|
+
let changed = false;
|
|
1172
|
+
for (const [key, draft] of this.drafts) {
|
|
1173
|
+
const accepted = draft.field.read(doc);
|
|
1174
|
+
if (this.flight?.draft === draft && accepted === this.flight.expected) {
|
|
1175
|
+
this.clearFlight();
|
|
1176
|
+
draft.base = accepted;
|
|
1177
|
+
draft.dirty = draft.field.canonical(draft.raw) !== accepted;
|
|
1178
|
+
if (!draft.dirty && !draft.focused) this.drafts.delete(key);
|
|
1179
|
+
changed = true;
|
|
1180
|
+
} else if (accepted !== draft.base) {
|
|
1181
|
+
this.conflict(draft, accepted === void 0 ? "The edited element was removed. Your draft is retained." : "The server changed this field. Your draft is retained.");
|
|
1182
|
+
draft.base = accepted;
|
|
1183
|
+
changed = true;
|
|
1184
|
+
} else if (settled && this.flight?.draft === draft) {
|
|
1185
|
+
this.conflict(draft, "The save was not accepted. Your draft is retained.");
|
|
1186
|
+
changed = true;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
if (changed) this.notify();
|
|
1190
|
+
this.arm();
|
|
1191
|
+
}
|
|
1192
|
+
focus(key) {
|
|
1193
|
+
this.focused = key;
|
|
1194
|
+
const draft = this.drafts.get(key);
|
|
1195
|
+
if (draft) draft.focused = true;
|
|
1196
|
+
}
|
|
1197
|
+
change(field, raw) {
|
|
1198
|
+
let draft = this.drafts.get(field.key);
|
|
1199
|
+
if (!draft) {
|
|
1200
|
+
draft = { field, raw, base: field.read(this.doc), focused: this.focused === field.key, dirty: true, conflict: null, readyAt: Date.now() + 250 };
|
|
1201
|
+
this.drafts.set(field.key, draft);
|
|
1202
|
+
} else {
|
|
1203
|
+
draft.field = field;
|
|
1204
|
+
draft.raw = raw;
|
|
1205
|
+
draft.readyAt = Date.now() + 250;
|
|
1206
|
+
}
|
|
1207
|
+
draft.dirty = field.canonical(raw) !== draft.base;
|
|
1208
|
+
this.notify();
|
|
1209
|
+
this.arm();
|
|
1210
|
+
}
|
|
1211
|
+
blur(key) {
|
|
1212
|
+
if (this.focused === key) this.focused = null;
|
|
1213
|
+
const draft = this.drafts.get(key);
|
|
1214
|
+
if (draft) {
|
|
1215
|
+
draft.focused = false;
|
|
1216
|
+
draft.readyAt = Date.now();
|
|
1217
|
+
if (!draft.dirty && !draft.conflict && this.flight?.draft !== draft) this.drafts.delete(key);
|
|
1218
|
+
this.notify();
|
|
1219
|
+
this.pump();
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
composition(key, active) {
|
|
1223
|
+
if (active) this.composing.add(key);
|
|
1224
|
+
else this.composing.delete(key);
|
|
1225
|
+
const draft = this.drafts.get(key);
|
|
1226
|
+
if (draft) draft.readyAt = Date.now() + 250;
|
|
1227
|
+
this.arm();
|
|
1228
|
+
}
|
|
1229
|
+
resolve(key, keep) {
|
|
1230
|
+
if (this.disabled) return;
|
|
1231
|
+
const draft = this.drafts.get(key);
|
|
1232
|
+
if (!draft) return;
|
|
1233
|
+
if (this.flight?.draft === draft) this.clearFlight();
|
|
1234
|
+
if (!keep) this.drafts.delete(key);
|
|
1235
|
+
else {
|
|
1236
|
+
const accepted = draft.field.read(this.doc);
|
|
1237
|
+
if (accepted === void 0) return;
|
|
1238
|
+
draft.base = accepted;
|
|
1239
|
+
draft.conflict = null;
|
|
1240
|
+
draft.dirty = draft.field.canonical(draft.raw) !== accepted;
|
|
1241
|
+
draft.readyAt = Date.now();
|
|
1242
|
+
if (!draft.dirty && !draft.focused) this.drafts.delete(key);
|
|
1243
|
+
}
|
|
1244
|
+
this.notify();
|
|
1245
|
+
this.pump();
|
|
1246
|
+
}
|
|
1247
|
+
dispose() {
|
|
1248
|
+
clearTimeout(this.timer);
|
|
1249
|
+
clearTimeout(this.ackTimer);
|
|
1250
|
+
}
|
|
1251
|
+
notify() {
|
|
1252
|
+
this.version++;
|
|
1253
|
+
for (const listener of this.listeners) listener();
|
|
1254
|
+
}
|
|
1255
|
+
clearFlight() {
|
|
1256
|
+
this.flight = null;
|
|
1257
|
+
clearTimeout(this.ackTimer);
|
|
1258
|
+
this.ackTimer = void 0;
|
|
1259
|
+
}
|
|
1260
|
+
conflict(draft, message) {
|
|
1261
|
+
draft.conflict = message;
|
|
1262
|
+
if (this.flight?.draft === draft) this.clearFlight();
|
|
1263
|
+
}
|
|
1264
|
+
arm() {
|
|
1265
|
+
clearTimeout(this.timer);
|
|
1266
|
+
this.timer = void 0;
|
|
1267
|
+
if (this.disabled || this.flight || this.conflicts.length > 0) return;
|
|
1268
|
+
const ready = [...this.drafts.values()].filter((draft) => draft.dirty && !this.composing.has(draft.field.key));
|
|
1269
|
+
if (ready.length) this.timer = setTimeout(() => this.pump(), Math.max(0, Math.min(...ready.map((draft) => draft.readyAt)) - Date.now()));
|
|
1270
|
+
}
|
|
1271
|
+
pump() {
|
|
1272
|
+
if (this.disabled || this.flight || this.conflicts.length > 0) return;
|
|
1273
|
+
const draft = [...this.drafts.values()].find((item) => item.dirty && item.readyAt <= Date.now() && !this.composing.has(item.field.key));
|
|
1274
|
+
if (!draft) {
|
|
1275
|
+
this.arm();
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
this.flight = { draft, expected: draft.field.canonical(draft.raw) };
|
|
1279
|
+
this.ackTimer = setTimeout(() => {
|
|
1280
|
+
this.conflict(draft, "The save has not been acknowledged. Your draft is retained.");
|
|
1281
|
+
this.notify();
|
|
1282
|
+
}, 1e4);
|
|
1283
|
+
try {
|
|
1284
|
+
if (!this.emit(draft.field.op(draft.raw))) this.conflict(draft, "This edit could not be submitted. Your draft is retained.");
|
|
1285
|
+
} catch {
|
|
1286
|
+
this.conflict(draft, "This edit could not be submitted. Your draft is retained.");
|
|
1287
|
+
}
|
|
1288
|
+
this.notify();
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1112
1291
|
var CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
1113
1292
|
"section",
|
|
1114
1293
|
"frame",
|
|
@@ -1182,18 +1361,59 @@ function buildInsertOp(doc, kind, selectedId, targetId) {
|
|
|
1182
1361
|
}
|
|
1183
1362
|
};
|
|
1184
1363
|
}
|
|
1185
|
-
function Editor({ defaultValue, onChange, registry, data }) {
|
|
1364
|
+
function Editor({ value, defaultValue, onChange, onOp, disabled = false, registry, data }) {
|
|
1186
1365
|
const initial = react.useMemo(() => defaultValue ?? emptyDoc("untitled"), [defaultValue]);
|
|
1187
|
-
const
|
|
1188
|
-
const
|
|
1366
|
+
const local = useEditor(initial);
|
|
1367
|
+
const controlled = value !== void 0;
|
|
1368
|
+
const localDoc = useLatestRef(local.state.doc);
|
|
1369
|
+
const lastNotified = react.useRef(local.state.doc);
|
|
1370
|
+
const onOpRef = useLatestRef(onOp);
|
|
1371
|
+
const [drafts] = react.useState(() => new InspectorDrafts(value ?? initial));
|
|
1372
|
+
react.useSyncExternalStore(drafts.subscribe, drafts.snapshot, drafts.snapshot);
|
|
1189
1373
|
const onChangeRef = useLatestRef(onChange);
|
|
1190
1374
|
react.useEffect(() => {
|
|
1191
|
-
if (
|
|
1192
|
-
|
|
1193
|
-
|
|
1375
|
+
if (controlled || lastNotified.current === local.state.doc) return;
|
|
1376
|
+
lastNotified.current = local.state.doc;
|
|
1377
|
+
onChangeRef.current?.(local.state.doc);
|
|
1378
|
+
}, [controlled, local.state.doc, onChangeRef]);
|
|
1379
|
+
const apply = (op) => {
|
|
1380
|
+
if (disabled) return false;
|
|
1381
|
+
const source = value ?? localDoc.current;
|
|
1382
|
+
const next = reduce(source, op);
|
|
1383
|
+
if (next === source) return false;
|
|
1384
|
+
if (!controlled) {
|
|
1385
|
+
localDoc.current = next;
|
|
1386
|
+
local.apply(op);
|
|
1194
1387
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1388
|
+
onOpRef.current?.(op);
|
|
1389
|
+
if (controlled) onChangeRef.current?.(next);
|
|
1390
|
+
return true;
|
|
1391
|
+
};
|
|
1392
|
+
react.useEffect(() => {
|
|
1393
|
+
if (controlled) drafts.configure(value, disabled, apply);
|
|
1394
|
+
});
|
|
1395
|
+
react.useEffect(() => () => drafts.dispose(), [drafts]);
|
|
1396
|
+
const structuralDisabled = disabled || controlled && drafts.busy;
|
|
1397
|
+
const ed = {
|
|
1398
|
+
...local,
|
|
1399
|
+
state: { ...local.state, doc: value ?? local.state.doc },
|
|
1400
|
+
apply: (op) => {
|
|
1401
|
+
if (!structuralDisabled) apply(op);
|
|
1402
|
+
},
|
|
1403
|
+
// Snapshot history belongs to the local document. Replaying it into a
|
|
1404
|
+
// server-owned value could overwrite another writer's accepted work.
|
|
1405
|
+
undo: () => {
|
|
1406
|
+
if (!controlled && !disabled) local.undo();
|
|
1407
|
+
},
|
|
1408
|
+
redo: () => {
|
|
1409
|
+
if (!controlled && !disabled) local.redo();
|
|
1410
|
+
},
|
|
1411
|
+
replace: (next) => {
|
|
1412
|
+
if (!controlled && !disabled) local.replace(next);
|
|
1413
|
+
},
|
|
1414
|
+
canUndo: !controlled && !disabled && local.canUndo,
|
|
1415
|
+
canRedo: !controlled && !disabled && local.canRedo
|
|
1416
|
+
};
|
|
1197
1417
|
const shell = {
|
|
1198
1418
|
display: "grid",
|
|
1199
1419
|
gridTemplateColumns: "220px 1fr 300px",
|
|
@@ -1205,9 +1425,9 @@ function Editor({ defaultValue, onChange, registry, data }) {
|
|
|
1205
1425
|
borderRadius: 12,
|
|
1206
1426
|
overflow: "hidden"
|
|
1207
1427
|
};
|
|
1208
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fancy-cms-editor", style: shell, children: [
|
|
1428
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fancy-cms-editor", style: shell, "aria-busy": structuralDisabled || void 0, children: [
|
|
1209
1429
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: CHROME_CSS }),
|
|
1210
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRight: "1px solid var(--fcms-border)", display: "flex", flexDirection: "column", minHeight: 0 }, children: [
|
|
1430
|
+
/* @__PURE__ */ jsxRuntime.jsx("fieldset", { disabled: structuralDisabled, "aria-label": "Page structure controls", style: { display: "contents", border: 0, padding: 0, margin: 0 }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRight: "1px solid var(--fcms-border)", display: "flex", flexDirection: "column", minHeight: 0 }, children: [
|
|
1211
1431
|
/* @__PURE__ */ jsxRuntime.jsx(Toolbar, { ed }),
|
|
1212
1432
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1213
1433
|
LayersPanel,
|
|
@@ -1218,9 +1438,22 @@ function Editor({ defaultValue, onChange, registry, data }) {
|
|
|
1218
1438
|
onMove: (id, parent, order) => ed.apply({ t: "move_node", id, parent, order })
|
|
1219
1439
|
}
|
|
1220
1440
|
)
|
|
1221
|
-
] }),
|
|
1441
|
+
] }) }),
|
|
1222
1442
|
/* @__PURE__ */ jsxRuntime.jsx(Canvas, { doc: ed.state.doc, selection: ed.state.selection, onSelect: ed.select, apply: ed.apply, registry, data }),
|
|
1223
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1443
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderLeft: "1px solid var(--fcms-border)", minHeight: 0, overflow: "auto" }, children: [
|
|
1444
|
+
controlled && drafts.conflicts.map((conflict) => /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", "data-cms-draft-conflict": conflict.key, style: { padding: 12, fontFamily: "system-ui,sans-serif", fontSize: 13 }, children: [
|
|
1445
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
1446
|
+
conflict.label,
|
|
1447
|
+
": ",
|
|
1448
|
+
conflict.message
|
|
1449
|
+
] }),
|
|
1450
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { "data-cms-retained-draft": "", style: { whiteSpace: "pre-wrap", overflowWrap: "anywhere" }, children: drafts.value(conflict.key, "") }),
|
|
1451
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled, onClick: () => drafts.resolve(conflict.key, false), children: "Use server value" }),
|
|
1452
|
+
" ",
|
|
1453
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled: disabled || conflict.missing, onClick: () => drafts.resolve(conflict.key, true), children: "Keep draft" })
|
|
1454
|
+
] }, conflict.key)),
|
|
1455
|
+
/* @__PURE__ */ jsxRuntime.jsx("fieldset", { disabled: !controlled && disabled, "aria-label": "Page property controls", style: { border: 0, padding: 0, margin: 0, minWidth: 0, height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(Inspector, { doc: ed.state.doc, selection: ed.state.selection, apply: ed.apply, drafts: controlled ? drafts : void 0 }) })
|
|
1456
|
+
] })
|
|
1224
1457
|
] });
|
|
1225
1458
|
}
|
|
1226
1459
|
function Toolbar({ ed }) {
|