@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/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-B2kVZJA0.cjs';
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-BQSictH3.js';
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-BVMSHUQF.js';
2
- export { Canvas, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor } from './chunk-BVMSHUQF.js';
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 s = node.style.base;
1016
- const setStyle = (patch) => apply({ t: "set_style", id: node.id, breakpoint: "base", patch });
1017
- const setProp = (key, value) => apply({ t: "set_node_props", id: node.id, patch: { [key]: value } });
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
- value: typeof node.props.content === "string" ? node.props.content : "",
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
- value: typeof node.props.src === "string" ? node.props.src : "",
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
- value: s.background ?? "",
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
- value: s.color ?? "",
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
- value: s.fontSize?.value ?? "",
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
- value: s.padding?.value ?? "",
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
- value: s.opacity ?? "",
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 ed = useEditor(initial);
1188
- const first = react.useRef(true);
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 (first.current) {
1192
- first.current = false;
1193
- return;
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
- onChangeRef.current?.(ed.state.doc);
1196
- }, [ed.state.doc, onChangeRef]);
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.jsx("div", { style: { borderLeft: "1px solid var(--fcms-border)", minHeight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(Inspector, { doc: ed.state.doc, selection: ed.state.selection, apply: ed.apply }) })
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 }) {