@kubuild/editor 0.1.0 → 0.1.3

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 CHANGED
@@ -88,12 +88,13 @@ module.exports = __toCommonJS(index_exports);
88
88
 
89
89
  // src/editor.tsx
90
90
  var import_react19 = __toESM(require("react"), 1);
91
- var import_components6 = require("@kubuild/components");
91
+ var import_components7 = require("@kubuild/components");
92
92
  var import_core12 = require("@kubuild/core");
93
93
 
94
94
  // src/store.ts
95
95
  var import_zustand = require("zustand");
96
96
  var import_core = require("@kubuild/core");
97
+ var import_components = require("@kubuild/components");
97
98
  function formatCommandError(err) {
98
99
  if (err && typeof err === "object" && Array.isArray(err.issues)) {
99
100
  const issues = err.issues;
@@ -118,7 +119,11 @@ function buildDefaultChildren(specs, existingIds, registry) {
118
119
  const def = registry.get(spec.type);
119
120
  const nodeProps = (0, import_core.deepClone)(spec.props ?? def?.defaultProps ?? {});
120
121
  const nodeStyles = spec.styles ?? def?.defaultStyles;
121
- const childNodes = buildDefaultChildren(spec.children ?? def?.defaultChildren, existingIds, registry);
122
+ const childNodes = buildDefaultChildren(
123
+ spec.children ?? def?.defaultChildren,
124
+ existingIds,
125
+ registry
126
+ );
122
127
  const node = {
123
128
  id,
124
129
  type: spec.type,
@@ -138,6 +143,7 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
138
143
  document: historyManager.document,
139
144
  selectedNodeId: null,
140
145
  hoveredNodeId: null,
146
+ dragPayload: null,
141
147
  viewport: "desktop",
142
148
  isDirty: false,
143
149
  canUndo: false,
@@ -147,6 +153,7 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
147
153
  variableCatalog: [],
148
154
  navigatorMode: "floating",
149
155
  tableSpreadsheetMode: "floating",
156
+ setDragPayload: (payload) => set({ dragPayload: payload }),
150
157
  setVariableCatalog: (catalog) => set({ variableCatalog: catalog }),
151
158
  setNavigatorMode: (mode) => set({ navigatorMode: mode }),
152
159
  toggleNavigator: () => set((state) => ({
@@ -163,6 +170,7 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
163
170
  isDirty: false,
164
171
  selectedNodeId: null,
165
172
  hoveredNodeId: null,
173
+ dragPayload: null,
166
174
  clipboard: null,
167
175
  canUndo: false,
168
176
  canRedo: false
@@ -181,12 +189,15 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
181
189
  });
182
190
  onChangeHandler?.(result.document);
183
191
  },
184
- insertComponent: (type, registry, parentId) => {
192
+ insertComponent: (type, registry, parentId, index) => {
185
193
  const state = get();
186
194
  const targetParentId = parentId ?? state.selectedNodeId ?? state.document.document.id;
187
195
  const parentNode = (0, import_core.findNodeById)(state.document.document, targetParentId);
188
196
  if (!parentNode) {
189
- return { success: false, error: `Insertion target "${targetParentId}" was not found in the document.` };
197
+ return {
198
+ success: false,
199
+ error: `Insertion target "${targetParentId}" was not found in the document.`
200
+ };
190
201
  }
191
202
  const definition = registry.get(type);
192
203
  if (!definition) {
@@ -203,7 +214,10 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
203
214
  return { success: false, error: propResult.join(" ") };
204
215
  }
205
216
  if (propResult === false) {
206
- return { success: false, error: `Default props for "${definition.label}" failed validation.` };
217
+ return {
218
+ success: false,
219
+ error: `Default props for "${definition.label}" failed validation.`
220
+ };
207
221
  }
208
222
  }
209
223
  const existingIds = (0, import_core.collectNodeIdSet)(state.document.document);
@@ -217,10 +231,49 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
217
231
  ...definition.defaultStyles ? { styles: (0, import_core.deepClone)(definition.defaultStyles) } : {},
218
232
  ...children ? { children } : {}
219
233
  };
220
- get().dispatch((doc) => (0, import_core.insertNode)(doc, { parentId: targetParentId, node }));
234
+ get().dispatch((doc) => (0, import_core.insertNode)(doc, { parentId: targetParentId, node, index }));
221
235
  get().selectNode(nodeId);
222
236
  return { success: true, nodeId };
223
237
  },
238
+ insertBlock: (blockOrId, parentId, index) => {
239
+ const state = get();
240
+ const targetParentId = parentId ?? state.selectedNodeId ?? state.document.document.id;
241
+ let blockDef;
242
+ if (typeof blockOrId === "string") {
243
+ blockDef = import_components.STARTER_BLOCKS.find((b) => b.id === blockOrId);
244
+ } else {
245
+ blockDef = blockOrId;
246
+ }
247
+ if (!blockDef) {
248
+ return { success: false, error: "Block definition not found." };
249
+ }
250
+ const existingIds = (0, import_core.collectNodeIdSet)(state.document.document);
251
+ let counter = 1;
252
+ const generateId = (prefix = "node") => {
253
+ let id = `${prefix}-${Date.now().toString(36)}-${counter++}`;
254
+ while (existingIds.has(id)) {
255
+ id = `${prefix}-${Date.now().toString(36)}-${counter++}`;
256
+ }
257
+ existingIds.add(id);
258
+ return id;
259
+ };
260
+ const nodeTree = blockDef.createNodeTree(generateId);
261
+ try {
262
+ get().dispatch((doc) => (0, import_core.insertNode)(doc, { parentId: targetParentId, node: nodeTree, index }));
263
+ get().selectNode(nodeTree.id);
264
+ return { success: true, nodeId: nodeTree.id };
265
+ } catch {
266
+ try {
267
+ get().dispatch(
268
+ (doc) => (0, import_core.insertNode)(doc, { parentId: state.document.document.id, node: nodeTree })
269
+ );
270
+ get().selectNode(nodeTree.id);
271
+ return { success: true, nodeId: nodeTree.id };
272
+ } catch (err) {
273
+ return { success: false, error: formatCommandError(err) };
274
+ }
275
+ }
276
+ },
224
277
  moveComponent: (nodeId, targetParentId, registry, index) => {
225
278
  const state = get();
226
279
  if (nodeId === state.document.document.id) {
@@ -232,10 +285,16 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
232
285
  }
233
286
  const targetParent = (0, import_core.findNodeById)(state.document.document, targetParentId);
234
287
  if (!targetParent) {
235
- return { success: false, error: `Move target "${targetParentId}" was not found in the document.` };
288
+ return {
289
+ success: false,
290
+ error: `Move target "${targetParentId}" was not found in the document.`
291
+ };
236
292
  }
237
293
  if ((0, import_core.isDescendantOf)(sourceLocation.node, targetParentId)) {
238
- return { success: false, error: "Cannot move a node into itself or one of its own descendants." };
294
+ return {
295
+ success: false,
296
+ error: "Cannot move a node into itself or one of its own descendants."
297
+ };
239
298
  }
240
299
  const policy = registry.canInsertChild(targetParent.type, sourceLocation.node.type);
241
300
  if (!policy.valid) {
@@ -372,10 +431,16 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
372
431
  }
373
432
  const targetParent = (0, import_core.findNodeById)(document2.document, targetParentId);
374
433
  if (!targetParent) {
375
- return { success: false, error: `Paste target "${targetParentId}" was not found in the document.` };
434
+ return {
435
+ success: false,
436
+ error: `Paste target "${targetParentId}" was not found in the document.`
437
+ };
376
438
  }
377
439
  if ((0, import_core.isDescendantOf)(clipboard, targetParentId)) {
378
- return { success: false, error: "Cannot paste a node into itself or one of its own descendants." };
440
+ return {
441
+ success: false,
442
+ error: "Cannot paste a node into itself or one of its own descendants."
443
+ };
379
444
  }
380
445
  const policy = registry.canInsertChild(targetParent.type, clipboard.type);
381
446
  if (!policy.valid) {
@@ -384,7 +449,9 @@ var useEditorStore = (0, import_zustand.create)((set, get) => ({
384
449
  const existingIds = (0, import_core.collectNodeIdSet)(document2.document);
385
450
  const { clonedNode } = (0, import_core.cloneTreeWithNewIds)(clipboard, void 0, existingIds);
386
451
  try {
387
- get().dispatch((doc) => (0, import_core.insertNode)(doc, { parentId: targetParentId, node: clonedNode, index }));
452
+ get().dispatch(
453
+ (doc) => (0, import_core.insertNode)(doc, { parentId: targetParentId, node: clonedNode, index })
454
+ );
388
455
  } catch (err) {
389
456
  return { success: false, error: formatCommandError(err) };
390
457
  }
@@ -549,7 +616,19 @@ var EditorCanvas = ({
549
616
  onDiagnostic,
550
617
  config
551
618
  }) => {
552
- const { document: storeDoc, selectedNodeId, hoveredNodeId, selectNode, hoverNode, updateNodeProps } = useEditorStore();
619
+ const {
620
+ document: storeDoc,
621
+ selectedNodeId,
622
+ hoveredNodeId,
623
+ dragPayload,
624
+ selectNode,
625
+ hoverNode,
626
+ updateNodeProps,
627
+ setDragPayload,
628
+ insertComponent,
629
+ insertBlock,
630
+ moveComponent
631
+ } = useEditorStore();
553
632
  const document2 = propDoc ?? storeDoc;
554
633
  const showFloatingBadges = config?.showFloatingBadges !== false;
555
634
  const containerRef = (0, import_react.useRef)(null);
@@ -626,7 +705,11 @@ var EditorCanvas = ({
626
705
  const direction = ARROW_DIRECTIONS[e.key];
627
706
  if (direction) {
628
707
  e.preventDefault();
629
- const target = (0, import_core3.getNavigationTarget)(state.document.document, state.selectedNodeId, direction);
708
+ const target = (0, import_core3.getNavigationTarget)(
709
+ state.document.document,
710
+ state.selectedNodeId,
711
+ direction
712
+ );
630
713
  if (target) state.selectNode(target);
631
714
  }
632
715
  };
@@ -653,24 +736,71 @@ var EditorCanvas = ({
653
736
  e.stopPropagation();
654
737
  e.dataTransfer.effectAllowed = "move";
655
738
  e.dataTransfer.setData("text/plain", nodeId);
739
+ e.dataTransfer.setData("application/kubuild-drag-type", "node");
740
+ e.dataTransfer.setData("application/kubuild-node-id", nodeId);
656
741
  setDraggingId(nodeId);
742
+ setDragPayload({ type: "node", nodeId });
657
743
  selectNode(nodeId);
658
744
  };
659
745
  const handleDragOver = (e) => {
660
- if (!draggingId) return;
746
+ const activePayload = dragPayload ?? (draggingId ? { type: "node", nodeId: draggingId } : null);
747
+ if (!activePayload) return;
661
748
  const container = containerRef.current;
662
- const hoveredEl = e.target.closest("[data-kubuild-node]");
663
- if (!container || !hoveredEl) return;
664
- const hoveredId = hoveredEl.getAttribute("data-kubuild-node");
665
- const draggedNode = hoveredId ? (0, import_core3.findNodeById)(document2.document, draggingId) : null;
666
- const hoveredNode = hoveredId ? (0, import_core3.findNodeById)(document2.document, hoveredId) : null;
667
- if (!hoveredId || !draggedNode || !hoveredNode || (0, import_core3.isDescendantOf)(draggedNode, hoveredId)) {
749
+ if (!container) return;
750
+ const containerRect = container.getBoundingClientRect();
751
+ const hoveredEl = e.target.closest(
752
+ "[data-kubuild-node]"
753
+ );
754
+ let incomingType = null;
755
+ if (activePayload.type === "node") {
756
+ const draggedNode = (0, import_core3.findNodeById)(document2.document, activePayload.nodeId);
757
+ incomingType = draggedNode?.type ?? null;
758
+ } else if (activePayload.type === "component") {
759
+ incomingType = activePayload.componentType;
760
+ } else if (activePayload.type === "block") {
761
+ incomingType = "section";
762
+ }
763
+ if (!incomingType) {
668
764
  setDropTarget(null);
669
765
  e.dataTransfer.dropEffect = "none";
670
766
  return;
671
767
  }
768
+ if (!hoveredEl) {
769
+ const rootNode = document2.document;
770
+ const policy2 = registry.canInsertChild(rootNode.type, incomingType);
771
+ if (!policy2.valid) {
772
+ setDropTarget(null);
773
+ e.dataTransfer.dropEffect = "none";
774
+ return;
775
+ }
776
+ e.preventDefault();
777
+ e.dataTransfer.dropEffect = activePayload.type === "node" ? "move" : "copy";
778
+ setDropTarget({
779
+ parentId: rootNode.id,
780
+ index: rootNode.children?.length ?? 0,
781
+ position: "inside",
782
+ rect: {
783
+ top: 0,
784
+ left: 0,
785
+ width: containerRect.width,
786
+ height: Math.max(containerRect.height, 200)
787
+ }
788
+ });
789
+ return;
790
+ }
791
+ const hoveredId = hoveredEl.getAttribute("data-kubuild-node");
792
+ if (!hoveredId) return;
793
+ if (activePayload.type === "node") {
794
+ const draggedNode = (0, import_core3.findNodeById)(document2.document, activePayload.nodeId);
795
+ if (!draggedNode || (0, import_core3.isDescendantOf)(draggedNode, hoveredId)) {
796
+ setDropTarget(null);
797
+ e.dataTransfer.dropEffect = "none";
798
+ return;
799
+ }
800
+ }
801
+ const hoveredNode = (0, import_core3.findNodeById)(document2.document, hoveredId);
802
+ if (!hoveredNode) return;
672
803
  const elRect = hoveredEl.getBoundingClientRect();
673
- const containerRect = container.getBoundingClientRect();
674
804
  const ratio = elRect.height > 0 ? (e.clientY - elRect.top) / elRect.height : 0.5;
675
805
  const hoveredDef = registry.get(hoveredNode.type);
676
806
  const canGoInside = !!hoveredDef?.acceptsChildren;
@@ -691,18 +821,21 @@ var EditorCanvas = ({
691
821
  targetType: location.parent.type
692
822
  };
693
823
  } else {
694
- setDropTarget(null);
695
- e.dataTransfer.dropEffect = "none";
696
- return;
824
+ candidate = {
825
+ parentId: document2.document.id,
826
+ index: document2.document.children?.length ?? 0,
827
+ position: "inside",
828
+ targetType: document2.document.type
829
+ };
697
830
  }
698
- const policy = registry.canInsertChild(candidate.targetType, draggedNode.type);
831
+ const policy = registry.canInsertChild(candidate.targetType, incomingType);
699
832
  if (!policy.valid) {
700
833
  setDropTarget(null);
701
834
  e.dataTransfer.dropEffect = "none";
702
835
  return;
703
836
  }
704
837
  e.preventDefault();
705
- e.dataTransfer.dropEffect = "move";
838
+ e.dataTransfer.dropEffect = activePayload.type === "node" ? "move" : "copy";
706
839
  setDropTarget({
707
840
  parentId: candidate.parentId,
708
841
  index: candidate.index,
@@ -717,15 +850,29 @@ var EditorCanvas = ({
717
850
  };
718
851
  const handleDrop = (e) => {
719
852
  e.preventDefault();
720
- if (draggingId && dropTarget) {
721
- useEditorStore.getState().moveComponent(draggingId, dropTarget.parentId, registry, dropTarget.index);
853
+ const activePayload = dragPayload ?? (draggingId ? { type: "node", nodeId: draggingId } : null);
854
+ if (activePayload && dropTarget) {
855
+ if (activePayload.type === "node") {
856
+ moveComponent(activePayload.nodeId, dropTarget.parentId, registry, dropTarget.index);
857
+ } else if (activePayload.type === "component") {
858
+ insertComponent(
859
+ activePayload.componentType,
860
+ registry,
861
+ dropTarget.parentId,
862
+ dropTarget.index
863
+ );
864
+ } else if (activePayload.type === "block") {
865
+ insertBlock(activePayload.blockId, dropTarget.parentId, dropTarget.index);
866
+ }
722
867
  }
723
868
  setDraggingId(null);
724
869
  setDropTarget(null);
870
+ setDragPayload(null);
725
871
  };
726
872
  const handleDragEnd = () => {
727
873
  setDraggingId(null);
728
874
  setDropTarget(null);
875
+ setDragPayload(null);
729
876
  };
730
877
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
731
878
  "div",
@@ -2077,21 +2224,32 @@ var EditorToolbar = ({
2077
2224
  type: "button",
2078
2225
  title: `Navigator / Element Tree (${navigatorMode !== "hidden" ? "Open" : "Hidden"})`,
2079
2226
  onClick: toggleNavigator,
2080
- className: `flex items-center gap-1 text-xs px-2.5 py-1 rounded border transition font-medium cursor-pointer ${navigatorMode !== "hidden" ? "border-blue-500 bg-blue-50 text-blue-700 shadow-xs" : "border-slate-200 bg-white hover:border-slate-300 text-slate-700"}`,
2227
+ className: `hidden sm:flex items-center gap-1 text-xs px-2.5 py-1 rounded border transition font-medium cursor-pointer ${navigatorMode !== "hidden" ? "border-blue-500 bg-blue-50 text-blue-700 shadow-xs" : "border-slate-200 bg-white hover:border-slate-300 text-slate-700"}`,
2081
2228
  children: [
2082
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2083
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "8", y1: "6", x2: "21", y2: "6" }),
2084
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "8", y1: "12", x2: "21", y2: "12" }),
2085
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "8", y1: "18", x2: "21", y2: "18" }),
2086
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }),
2087
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }),
2088
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })
2089
- ] }),
2229
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2230
+ "svg",
2231
+ {
2232
+ width: "13",
2233
+ height: "13",
2234
+ viewBox: "0 0 24 24",
2235
+ fill: "none",
2236
+ stroke: "currentColor",
2237
+ strokeWidth: "2",
2238
+ children: [
2239
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "8", y1: "6", x2: "21", y2: "6" }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "8", y1: "12", x2: "21", y2: "12" }),
2241
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "8", y1: "18", x2: "21", y2: "18" }),
2242
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }),
2243
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }),
2244
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })
2245
+ ]
2246
+ }
2247
+ ),
2090
2248
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Navigator" })
2091
2249
  ]
2092
2250
  }
2093
2251
  ),
2094
- showNavigatorToggle && (showClipboard || showHistory || showCodeViewer || showExportImport) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-4 w-px bg-slate-200 mx-1" }),
2252
+ showNavigatorToggle && (showClipboard || showHistory || showCodeViewer || showExportImport) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hidden sm:block h-4 w-px bg-slate-200 mx-1" }),
2095
2253
  (showClipboard || showHistory) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1", children: [
2096
2254
  showClipboard && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2097
2255
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -2166,21 +2324,21 @@ var EditorToolbar = ({
2166
2324
  )
2167
2325
  ] })
2168
2326
  ] }),
2169
- (showClipboard || showHistory) && (showCodeViewer || showExportImport) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-4 w-px bg-slate-200 mx-1" }),
2327
+ (showClipboard || showHistory) && (showCodeViewer || showExportImport) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hidden sm:block h-4 w-px bg-slate-200 mx-1" }),
2170
2328
  showCodeViewer && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2171
2329
  "button",
2172
2330
  {
2173
2331
  type: "button",
2174
2332
  title: "View Semantic HTML & CSS (< >)",
2175
2333
  onClick: () => setIsCodeViewerModalOpen(true),
2176
- className: "flex items-center gap-1.5 text-xs px-2.5 py-1 rounded border border-slate-200 bg-white hover:border-blue-500 hover:text-blue-600 font-medium text-slate-700 transition",
2334
+ className: "flex items-center gap-1.5 text-xs px-2 sm:px-2.5 py-1 rounded border border-slate-200 bg-white hover:border-blue-500 hover:text-blue-600 font-medium text-slate-700 transition",
2177
2335
  children: [
2178
2336
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-mono text-[11px] font-bold text-blue-600", children: "<>" }),
2179
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "View Code" })
2337
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hidden sm:inline", children: "View Code" })
2180
2338
  ]
2181
2339
  }
2182
2340
  ),
2183
- showExportImport && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2341
+ showExportImport && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1", children: [
2184
2342
  showCodeViewer && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-4 w-px bg-slate-200 mx-1" }),
2185
2343
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2186
2344
  "button",
@@ -2188,7 +2346,7 @@ var EditorToolbar = ({
2188
2346
  type: "button",
2189
2347
  title: "Import .stora Package",
2190
2348
  onClick: () => setIsImportModalOpen(true),
2191
- className: "text-xs px-2.5 py-1 rounded border border-slate-200 bg-white hover:border-blue-500 hover:text-blue-600 font-medium text-slate-700 transition",
2349
+ className: "text-xs px-2 sm:px-2.5 py-1 rounded border border-slate-200 bg-white hover:border-blue-500 hover:text-blue-600 font-medium text-slate-700 transition",
2192
2350
  children: "Import"
2193
2351
  }
2194
2352
  ),
@@ -2199,8 +2357,8 @@ var EditorToolbar = ({
2199
2357
  title: "Export .stora Archive",
2200
2358
  disabled: isExporting,
2201
2359
  onClick: handleExportStora,
2202
- className: "text-xs px-2.5 py-1 rounded border border-blue-600 bg-blue-600 hover:bg-blue-500 text-white font-medium disabled:opacity-50 transition shadow-sm",
2203
- children: isExporting ? "Exporting..." : "Export .stora"
2360
+ className: "text-xs px-2 sm:px-2.5 py-1 rounded border border-blue-600 bg-blue-600 hover:bg-blue-500 text-white font-medium disabled:opacity-50 transition shadow-xs",
2361
+ children: isExporting ? "..." : "Export"
2204
2362
  }
2205
2363
  ),
2206
2364
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -2209,7 +2367,7 @@ var EditorToolbar = ({
2209
2367
  type: "button",
2210
2368
  title: "Download page.json",
2211
2369
  onClick: handleExportJson,
2212
- className: "text-xs px-2 py-1 rounded border border-slate-200 bg-white hover:border-slate-400 text-slate-600 transition",
2370
+ className: "hidden md:inline-block text-xs px-2 py-1 rounded border border-slate-200 bg-white hover:border-slate-400 text-slate-600 transition",
2213
2371
  children: "JSON"
2214
2372
  }
2215
2373
  )
@@ -2242,16 +2400,16 @@ var EditorToolbar = ({
2242
2400
 
2243
2401
  // src/inspector-panel.tsx
2244
2402
  var import_react13 = require("react");
2245
- var import_components3 = require("@kubuild/components");
2403
+ var import_components4 = require("@kubuild/components");
2246
2404
  var import_core8 = require("@kubuild/core");
2247
2405
  var import_schema5 = require("@kubuild/schema");
2248
2406
 
2249
2407
  // src/variable-picker.tsx
2250
2408
  var import_schema2 = require("@kubuild/schema");
2251
- var import_components = require("@kubuild/components");
2409
+ var import_components2 = require("@kubuild/components");
2252
2410
  var import_jsx_runtime7 = require("react/jsx-runtime");
2253
2411
  function getCompatibleCatalogEntries(field, catalog) {
2254
- const expectedType = (0, import_components.primitiveTypeForField)(field);
2412
+ const expectedType = (0, import_components2.primitiveTypeForField)(field);
2255
2413
  if (!expectedType || !catalog) {
2256
2414
  return [];
2257
2415
  }
@@ -3050,15 +3208,18 @@ var TableSpreadsheetEditor = ({
3050
3208
  setIsImportModalOpen(false);
3051
3209
  setCsvInputText("");
3052
3210
  };
3053
- const [pos, setPos] = (0, import_react7.useState)({ x: 260, y: 120 });
3211
+ const [pos, setPos] = (0, import_react7.useState)(() => ({
3212
+ x: typeof window !== "undefined" ? Math.max(10, Math.min(window.innerWidth - 400, 20)) : 20,
3213
+ y: 120
3214
+ }));
3054
3215
  const [isDragging, setIsDragging] = (0, import_react7.useState)(false);
3055
3216
  const dragStartRef = (0, import_react7.useRef)({
3056
3217
  startX: 0,
3057
3218
  startY: 0,
3058
- posX: 260,
3219
+ posX: 20,
3059
3220
  posY: 120
3060
3221
  });
3061
- const handleHeaderMouseDown = (e) => {
3222
+ const handleHeaderPointerDown = (e) => {
3062
3223
  if (e.target.closest("button, input, select, textarea")) return;
3063
3224
  setIsDragging(true);
3064
3225
  dragStartRef.current = {
@@ -3070,22 +3231,26 @@ var TableSpreadsheetEditor = ({
3070
3231
  };
3071
3232
  (0, import_react7.useEffect)(() => {
3072
3233
  if (!isDragging) return;
3073
- const handleMouseMove = (e) => {
3234
+ const handlePointerMove = (e) => {
3074
3235
  const dx = e.clientX - dragStartRef.current.startX;
3075
3236
  const dy = e.clientY - dragStartRef.current.startY;
3237
+ const maxX = Math.max(8, window.innerWidth - 320);
3238
+ const maxY = Math.max(8, window.innerHeight - 100);
3076
3239
  setPos({
3077
- x: Math.max(10, Math.min(window.innerWidth - 350, dragStartRef.current.posX + dx)),
3078
- y: Math.max(10, Math.min(window.innerHeight - 150, dragStartRef.current.posY + dy))
3240
+ x: Math.max(8, Math.min(maxX, dragStartRef.current.posX + dx)),
3241
+ y: Math.max(8, Math.min(maxY, dragStartRef.current.posY + dy))
3079
3242
  });
3080
3243
  };
3081
- const handleMouseUp = () => {
3244
+ const handlePointerUp = () => {
3082
3245
  setIsDragging(false);
3083
3246
  };
3084
- window.addEventListener("mousemove", handleMouseMove);
3085
- window.addEventListener("mouseup", handleMouseUp);
3247
+ window.addEventListener("pointermove", handlePointerMove);
3248
+ window.addEventListener("pointerup", handlePointerUp);
3249
+ window.addEventListener("pointercancel", handlePointerUp);
3086
3250
  return () => {
3087
- window.removeEventListener("mousemove", handleMouseMove);
3088
- window.removeEventListener("mouseup", handleMouseUp);
3251
+ window.removeEventListener("pointermove", handlePointerMove);
3252
+ window.removeEventListener("pointerup", handlePointerUp);
3253
+ window.removeEventListener("pointercancel", handlePointerUp);
3089
3254
  };
3090
3255
  }, [isDragging]);
3091
3256
  if (!tableNode) return null;
@@ -3639,9 +3804,9 @@ var TableSpreadsheetEditor = ({
3639
3804
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3640
3805
  "div",
3641
3806
  {
3642
- style: { left: `${pos.x}px`, top: `${pos.y}px` },
3643
- onMouseDown: handleHeaderMouseDown,
3644
- className: `fixed z-40 min-w-[380px] max-w-[620px] bg-white/95 backdrop-blur-md rounded-xl shadow-2xl border border-slate-300 flex flex-col max-h-[460px] overflow-hidden ${className}`,
3807
+ style: { left: `${pos.x}px`, top: `${pos.y}px`, touchAction: "none" },
3808
+ onPointerDown: handleHeaderPointerDown,
3809
+ className: `fixed z-40 min-w-[320px] sm:min-w-[380px] max-w-[620px] bg-white/95 backdrop-blur-md rounded-xl shadow-2xl border border-slate-300 flex flex-col max-h-[460px] overflow-hidden cursor-grab active:cursor-grabbing touch-none ${className}`,
3645
3810
  children: content
3646
3811
  }
3647
3812
  )
@@ -5456,7 +5621,7 @@ var StyleManagerAccordion = ({
5456
5621
 
5457
5622
  // src/traits-panel.tsx
5458
5623
  var import_react12 = require("react");
5459
- var import_components2 = require("@kubuild/components");
5624
+ var import_components3 = require("@kubuild/components");
5460
5625
  var import_core7 = require("@kubuild/core");
5461
5626
  var import_lucide_react5 = require("lucide-react");
5462
5627
  var import_jsx_runtime16 = require("react/jsx-runtime");
@@ -5779,7 +5944,7 @@ var TraitsPanel = ({
5779
5944
  grouped.set(key, list);
5780
5945
  }
5781
5946
  const orderedGroups = [
5782
- ...import_components2.TRAIT_GROUP_ORDER.filter((g) => grouped.has(g)),
5947
+ ...import_components3.TRAIT_GROUP_ORDER.filter((g) => grouped.has(g)),
5783
5948
  ...grouped.has(void 0) ? [void 0] : []
5784
5949
  ];
5785
5950
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: `flex flex-col gap-4 ${className ?? "p-3"} text-sm text-slate-900`, children: orderedGroups.map((group) => {
@@ -5787,7 +5952,7 @@ var TraitsPanel = ({
5787
5952
  const traitNames = new Set(groupTraits.map((t) => t.name));
5788
5953
  const isLinkGroup = group === "link" && traitNames.has("href");
5789
5954
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
5790
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2", children: group ? import_components2.TRAIT_GROUP_LABELS[group] : "Other" }),
5955
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2", children: group ? import_components3.TRAIT_GROUP_LABELS[group] : "Other" }),
5791
5956
  isLinkGroup ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5792
5957
  LinkTraitControl,
5793
5958
  {
@@ -6601,7 +6766,7 @@ var InspectorPanel = ({
6601
6766
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
6602
6767
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "block text-xs font-medium text-slate-600 mb-1", children: field.label }),
6603
6768
  !bound && renderPropControl(field),
6604
- (0, import_components3.isBindableField)(field) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6769
+ (0, import_components4.isBindableField)(field) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6605
6770
  VariableBindingControl,
6606
6771
  {
6607
6772
  field,
@@ -6703,16 +6868,19 @@ var LayersPanel = ({ registry, className }) => {
6703
6868
  const [expandedIds, setExpandedIds] = (0, import_react14.useState)(() => /* @__PURE__ */ new Set([document2.document.id]));
6704
6869
  const [draggingId, setDraggingId] = (0, import_react14.useState)(null);
6705
6870
  const [dropCandidate, setDropCandidate] = (0, import_react14.useState)(null);
6706
- const [pos, setPos] = (0, import_react14.useState)({ x: 280, y: 70 });
6871
+ const [pos, setPos] = (0, import_react14.useState)(() => ({
6872
+ x: typeof window !== "undefined" ? Math.max(12, Math.min(window.innerWidth - 300, 24)) : 24,
6873
+ y: 70
6874
+ }));
6707
6875
  const [isDraggingWindow, setIsDraggingWindow] = (0, import_react14.useState)(false);
6708
6876
  const dragStartRef = (0, import_react14.useRef)({
6709
6877
  startX: 0,
6710
6878
  startY: 0,
6711
- posX: 280,
6879
+ posX: 24,
6712
6880
  posY: 70
6713
6881
  });
6714
- const handleHeaderMouseDown = (e) => {
6715
- if (e.target.closest("button")) return;
6882
+ const handleHeaderPointerDown = (e) => {
6883
+ if (e.target.closest("button, input, select, textarea")) return;
6716
6884
  setIsDraggingWindow(true);
6717
6885
  dragStartRef.current = {
6718
6886
  startX: e.clientX,
@@ -6723,22 +6891,26 @@ var LayersPanel = ({ registry, className }) => {
6723
6891
  };
6724
6892
  (0, import_react14.useEffect)(() => {
6725
6893
  if (!isDraggingWindow) return;
6726
- const handleMouseMove = (e) => {
6894
+ const handlePointerMove = (e) => {
6727
6895
  const dx = e.clientX - dragStartRef.current.startX;
6728
6896
  const dy = e.clientY - dragStartRef.current.startY;
6897
+ const maxX = Math.max(8, window.innerWidth - 296);
6898
+ const maxY = Math.max(8, window.innerHeight - 100);
6729
6899
  setPos({
6730
- x: Math.max(10, Math.min(window.innerWidth - 280, dragStartRef.current.posX + dx)),
6731
- y: Math.max(10, Math.min(window.innerHeight - 120, dragStartRef.current.posY + dy))
6900
+ x: Math.max(8, Math.min(maxX, dragStartRef.current.posX + dx)),
6901
+ y: Math.max(8, Math.min(maxY, dragStartRef.current.posY + dy))
6732
6902
  });
6733
6903
  };
6734
- const handleMouseUp = () => {
6904
+ const handlePointerUp = () => {
6735
6905
  setIsDraggingWindow(false);
6736
6906
  };
6737
- window.addEventListener("mousemove", handleMouseMove);
6738
- window.addEventListener("mouseup", handleMouseUp);
6907
+ window.addEventListener("pointermove", handlePointerMove);
6908
+ window.addEventListener("pointerup", handlePointerUp);
6909
+ window.addEventListener("pointercancel", handlePointerUp);
6739
6910
  return () => {
6740
- window.removeEventListener("mousemove", handleMouseMove);
6741
- window.removeEventListener("mouseup", handleMouseUp);
6911
+ window.removeEventListener("pointermove", handlePointerMove);
6912
+ window.removeEventListener("pointerup", handlePointerUp);
6913
+ window.removeEventListener("pointercancel", handlePointerUp);
6742
6914
  };
6743
6915
  }, [isDraggingWindow]);
6744
6916
  (0, import_react14.useEffect)(() => {
@@ -6889,8 +7061,9 @@ var LayersPanel = ({ registry, className }) => {
6889
7061
  const header = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
6890
7062
  "div",
6891
7063
  {
6892
- onMouseDown: isFloating ? handleHeaderMouseDown : void 0,
6893
- className: `flex items-center justify-between px-3 py-2 border-b border-slate-200/90 select-none ${isFloating ? "cursor-grab active:cursor-grabbing bg-slate-50/90 rounded-t-xl" : "bg-slate-50"}`,
7064
+ onPointerDown: isFloating ? handleHeaderPointerDown : void 0,
7065
+ style: { touchAction: isFloating ? "none" : "auto" },
7066
+ className: `flex items-center justify-between px-3 py-2 border-b border-slate-200/90 select-none ${isFloating ? "cursor-grab active:cursor-grabbing bg-slate-50/90 rounded-t-xl touch-none" : "bg-slate-50"}`,
6894
7067
  children: [
6895
7068
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1.5 font-semibold text-xs text-slate-700", children: [
6896
7069
  isFloating && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react7.GripVertical, { className: "w-3 h-3 text-slate-400 mr-0.5", "aria-hidden": "true" }),
@@ -6949,11 +7122,11 @@ var LayersPanel = ({ registry, className }) => {
6949
7122
 
6950
7123
  // src/breadcrumbs.tsx
6951
7124
  var import_react15 = __toESM(require("react"), 1);
6952
- var import_components4 = require("@kubuild/components");
7125
+ var import_components5 = require("@kubuild/components");
6953
7126
  var import_core10 = require("@kubuild/core");
6954
7127
  var import_jsx_runtime19 = require("react/jsx-runtime");
6955
7128
  var HierarchyBreadcrumbs = ({
6956
- registry = (0, import_components4.createDefaultComponentRegistry)(),
7129
+ registry = (0, import_components5.createDefaultComponentRegistry)(),
6957
7130
  document: propDoc,
6958
7131
  selectedNodeId: propSelectedNodeId,
6959
7132
  className
@@ -7019,7 +7192,15 @@ var import_lucide_react9 = require("lucide-react");
7019
7192
  // src/component-panel.tsx
7020
7193
  var import_react16 = require("react");
7021
7194
  var import_jsx_runtime20 = require("react/jsx-runtime");
7022
- var CATEGORY_ORDER = ["layout", "typography", "media", "form", "interactive", "data", "custom"];
7195
+ var CATEGORY_ORDER = [
7196
+ "layout",
7197
+ "typography",
7198
+ "media",
7199
+ "form",
7200
+ "interactive",
7201
+ "data",
7202
+ "custom"
7203
+ ];
7023
7204
  var CATEGORY_LABELS = {
7024
7205
  layout: "Layout",
7025
7206
  typography: "Typography",
@@ -7031,6 +7212,7 @@ var CATEGORY_LABELS = {
7031
7212
  };
7032
7213
  var ComponentPanel = ({ registry, className }) => {
7033
7214
  const insertComponent = useEditorStore((s) => s.insertComponent);
7215
+ const setDragPayload = useEditorStore((s) => s.setDragPayload);
7034
7216
  const [error, setError] = (0, import_react16.useState)(null);
7035
7217
  const groups = CATEGORY_ORDER.map((category) => ({
7036
7218
  category,
@@ -7040,6 +7222,16 @@ var ComponentPanel = ({ registry, className }) => {
7040
7222
  const result = insertComponent(definition.type, registry);
7041
7223
  setError(result.success ? null : result.error ?? `Could not insert "${definition.label}".`);
7042
7224
  };
7225
+ const handleDragStart = (e, definition) => {
7226
+ e.dataTransfer.effectAllowed = "copy";
7227
+ e.dataTransfer.setData("text/plain", `component:${definition.type}`);
7228
+ e.dataTransfer.setData("application/kubuild-drag-type", "component");
7229
+ e.dataTransfer.setData("application/kubuild-component-type", definition.type);
7230
+ setDragPayload({ type: "component", componentType: definition.type });
7231
+ };
7232
+ const handleDragEnd = () => {
7233
+ setDragPayload(null);
7234
+ };
7043
7235
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: `flex flex-col gap-4 p-3 overflow-y-auto h-full min-h-0 ${className || ""}`, children: [
7044
7236
  error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7045
7237
  "div",
@@ -7055,12 +7247,16 @@ var ComponentPanel = ({ registry, className }) => {
7055
7247
  "button",
7056
7248
  {
7057
7249
  type: "button",
7250
+ draggable: true,
7251
+ onDragStart: (e) => handleDragStart(e, definition),
7252
+ onDragEnd: handleDragEnd,
7058
7253
  onClick: () => handleInsert(definition),
7059
- title: definition.description || definition.label,
7060
- className: "flex flex-col items-center justify-center p-2.5 min-h-[74px] rounded-lg border border-slate-200 bg-white hover:border-blue-400 hover:bg-blue-50/50 hover:shadow text-slate-700 transition group cursor-pointer text-center",
7254
+ "data-testid": `component-item-${definition.type}`,
7255
+ title: definition.description || `Click to insert or drag to canvas: ${definition.label}`,
7256
+ className: "flex flex-col items-center justify-center p-2.5 min-h-[74px] rounded-lg border border-slate-200 bg-white hover:border-blue-400 hover:bg-blue-50/50 hover:shadow text-slate-700 transition group cursor-grab active:cursor-grabbing text-center select-none",
7061
7257
  children: [
7062
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "mb-1.5 text-slate-500 group-hover:text-blue-600 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ComponentIcon, { iconOrType: definition.icon ?? definition.type, size: 22 }) }),
7063
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] font-medium text-slate-700 group-hover:text-blue-600 text-center leading-tight break-words w-full select-none", children: definition.label })
7258
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "mb-1.5 text-slate-500 group-hover:text-blue-600 transition-colors pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ComponentIcon, { iconOrType: definition.icon ?? definition.type, size: 22 }) }),
7259
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] font-medium text-slate-700 group-hover:text-blue-600 text-center leading-tight break-words w-full pointer-events-none", children: definition.label })
7064
7260
  ]
7065
7261
  },
7066
7262
  definition.type
@@ -7071,7 +7267,7 @@ var ComponentPanel = ({ registry, className }) => {
7071
7267
 
7072
7268
  // src/blocks-panel.tsx
7073
7269
  var import_react17 = require("react");
7074
- var import_components5 = require("@kubuild/components");
7270
+ var import_components6 = require("@kubuild/components");
7075
7271
  var import_core11 = require("@kubuild/core");
7076
7272
  var import_lucide_react8 = require("lucide-react");
7077
7273
  var import_jsx_runtime21 = require("react/jsx-runtime");
@@ -7137,7 +7333,7 @@ var BlockThumbnail = ({ block }) => {
7137
7333
  }
7138
7334
  };
7139
7335
  var BlocksPanel = ({
7140
- blocks = import_components5.STARTER_BLOCKS,
7336
+ blocks = import_components6.STARTER_BLOCKS,
7141
7337
  className,
7142
7338
  onInsertBlock
7143
7339
  }) => {
@@ -7181,6 +7377,17 @@ var BlocksPanel = ({
7181
7377
  selectNode(nodeTree.id);
7182
7378
  }
7183
7379
  };
7380
+ const setDragPayload = useEditorStore((s) => s.setDragPayload);
7381
+ const handleDragStart = (e, block) => {
7382
+ e.dataTransfer.effectAllowed = "copy";
7383
+ e.dataTransfer.setData("text/plain", `block:${block.id}`);
7384
+ e.dataTransfer.setData("application/kubuild-drag-type", "block");
7385
+ e.dataTransfer.setData("application/kubuild-block-id", block.id);
7386
+ setDragPayload({ type: "block", blockId: block.id });
7387
+ };
7388
+ const handleDragEnd = () => {
7389
+ setDragPayload(null);
7390
+ };
7184
7391
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7185
7392
  "div",
7186
7393
  {
@@ -7211,13 +7418,17 @@ var BlocksPanel = ({
7211
7418
  "button",
7212
7419
  {
7213
7420
  type: "button",
7421
+ draggable: true,
7422
+ onDragStart: (e) => handleDragStart(e, block),
7423
+ onDragEnd: handleDragEnd,
7214
7424
  "data-testid": "block-card",
7215
7425
  "data-block-id": block.id,
7216
7426
  onClick: () => handleInsert(block),
7217
- className: "flex flex-col justify-between p-2 rounded-lg border border-slate-200 bg-white hover:border-blue-400 hover:shadow-md hover:bg-blue-50/20 transition-all text-left group cursor-pointer",
7427
+ title: block.description || `Click to insert or drag to canvas: ${block.name}`,
7428
+ className: "flex flex-col justify-between p-2 rounded-lg border border-slate-200 bg-white hover:border-blue-400 hover:shadow-md hover:bg-blue-50/20 transition-all text-left group cursor-grab active:cursor-grabbing select-none",
7218
7429
  children: [
7219
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mb-2 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BlockThumbnail, { block }) }),
7220
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "w-full", children: [
7430
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mb-2 w-full pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BlockThumbnail, { block }) }),
7431
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "w-full pointer-events-none", children: [
7221
7432
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex items-center justify-between gap-1 mb-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[11px] font-semibold text-slate-800 group-hover:text-blue-600 truncate", children: block.name }) }),
7222
7433
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-block text-[9px] uppercase tracking-wider font-semibold text-slate-400 bg-slate-100 px-1 py-0.2 rounded", children: block.category })
7223
7434
  ] })
@@ -7367,10 +7578,11 @@ function resolveEditorConfig(config) {
7367
7578
  }
7368
7579
 
7369
7580
  // src/editor.tsx
7581
+ var import_lucide_react10 = require("lucide-react");
7370
7582
  var import_jsx_runtime23 = require("react/jsx-runtime");
7371
7583
  var KubuildEditor = ({
7372
7584
  initialDocument,
7373
- registry = (0, import_components6.createDefaultComponentRegistry)(),
7585
+ registry = (0, import_components7.createDefaultComponentRegistry)(),
7374
7586
  context,
7375
7587
  variableCatalog,
7376
7588
  onChange,
@@ -7388,9 +7600,16 @@ var KubuildEditor = ({
7388
7600
  selectedNodeId,
7389
7601
  navigatorMode,
7390
7602
  tableSpreadsheetMode,
7391
- setTableSpreadsheetMode
7603
+ setTableSpreadsheetMode,
7604
+ undo,
7605
+ redo,
7606
+ canUndo,
7607
+ canRedo
7392
7608
  } = useEditorStore();
7393
7609
  const lastLoadedDocRef = import_react19.default.useRef(void 0);
7610
+ const [isMobileSidebarOpen, setIsMobileSidebarOpen] = (0, import_react19.useState)(false);
7611
+ const [isMobileInspectorOpen, setIsMobileInspectorOpen] = (0, import_react19.useState)(false);
7612
+ const [isMobileLayersOpen, setIsMobileLayersOpen] = (0, import_react19.useState)(false);
7394
7613
  const activeTable = (0, import_react19.useMemo)(
7395
7614
  () => findActiveTableNode(document2.document, selectedNodeId),
7396
7615
  [document2.document, selectedNodeId]
@@ -7419,65 +7638,245 @@ var KubuildEditor = ({
7419
7638
  }, [context, sampleVariables]);
7420
7639
  const viewportWidthMap = {
7421
7640
  desktop: "w-full max-w-6xl",
7422
- tablet: "w-[768px]",
7423
- mobile: "w-[375px]"
7641
+ tablet: "w-full max-w-[768px] sm:w-[768px]",
7642
+ mobile: "w-full max-w-[375px] sm:w-[375px]"
7643
+ };
7644
+ const viewportIcons = {
7645
+ desktop: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Monitor, { className: "w-3.5 h-3.5" }),
7646
+ tablet: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Tablet, { className: "w-3.5 h-3.5" }),
7647
+ mobile: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Smartphone, { className: "w-3.5 h-3.5" })
7424
7648
  };
7425
7649
  const resolvedConfig = (0, import_react19.useMemo)(() => resolveEditorConfig(config), [config]);
7426
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `flex flex-col h-full bg-slate-100 text-slate-900 relative ${className || ""}`, children: [
7427
- navigatorMode === "floating" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LayersPanel, { registry }),
7428
- activeTable && tableSpreadsheetMode === "floating" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7429
- TableSpreadsheetEditor,
7430
- {
7431
- registry,
7432
- tableNode: activeTable,
7433
- mode: "floating",
7434
- onToggleMode: () => setTableSpreadsheetMode("docked"),
7435
- onClose: () => setTableSpreadsheetMode("hidden")
7436
- }
7437
- ),
7438
- resolvedConfig.toolbar.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between px-4 py-2 bg-white border-b border-slate-200", children: [
7439
- resolvedConfig.toolbar.showTitle ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
7440
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-800 text-sm", children: "KUBUILD Editor" }),
7441
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-xs bg-slate-100 text-slate-600 px-2 py-0.5 rounded border", children: document2.metadata?.title || "Untitled" })
7442
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", {}),
7443
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EditorToolbar, { registry, config: resolvedConfig.toolbar }),
7444
- resolvedConfig.toolbar.showViewportSwitcher && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex items-center gap-1 bg-slate-100 p-1 rounded-md text-xs", children: ["desktop", "tablet", "mobile"].map((vp) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7445
- "button",
7446
- {
7447
- type: "button",
7448
- onClick: () => setViewport(vp),
7449
- className: `px-3 py-1 rounded capitalize font-medium transition ${viewport === vp ? "bg-white text-blue-600 shadow-sm" : "text-slate-600 hover:text-slate-900"}`,
7450
- children: vp
7451
- },
7452
- vp
7453
- )) }),
7454
- resolvedConfig.toolbar.showSelectionStatus && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-xs text-slate-500", children: selectedNodeId ? `Selected: #${selectedNodeId}` : "No element selected" })
7455
- ] }),
7456
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-1 overflow-hidden min-h-0", children: [
7457
- resolvedConfig.sidebar.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-80 shrink-0 bg-white border-r border-slate-200 overflow-hidden flex flex-col min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LeftSidebar, { registry, config: resolvedConfig.sidebar }) }),
7458
- navigatorMode === "docked" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-60 shrink-0 bg-white border-r border-slate-200 overflow-hidden flex flex-col min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LayersPanel, { registry }) }),
7459
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex-1 overflow-hidden flex flex-col min-h-0 h-full", children: [
7460
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-auto p-8 flex justify-center items-start min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7461
- "div",
7650
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7651
+ "div",
7652
+ {
7653
+ className: `flex flex-col h-full bg-slate-100 text-slate-900 relative overflow-hidden ${className || ""}`,
7654
+ children: [
7655
+ navigatorMode === "floating" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LayersPanel, { registry }),
7656
+ activeTable && tableSpreadsheetMode === "floating" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7657
+ TableSpreadsheetEditor,
7462
7658
  {
7463
- className: `${viewportWidthMap[viewport]} bg-white shadow-md rounded-lg overflow-hidden transition-all duration-200 min-h-[600px] border border-slate-200`,
7464
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7465
- EditorCanvas,
7659
+ registry,
7660
+ tableNode: activeTable,
7661
+ mode: "floating",
7662
+ onToggleMode: () => setTableSpreadsheetMode("docked"),
7663
+ onClose: () => setTableSpreadsheetMode("hidden")
7664
+ }
7665
+ ),
7666
+ isMobileSidebarOpen && resolvedConfig.sidebar.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "fixed inset-0 z-50 flex lg:hidden animate-in fade-in duration-200", children: [
7667
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7668
+ "div",
7669
+ {
7670
+ className: "fixed inset-0 bg-slate-950/50 backdrop-blur-xs transition-opacity",
7671
+ onClick: () => setIsMobileSidebarOpen(false)
7672
+ }
7673
+ ),
7674
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "relative w-80 max-w-[85vw] bg-white h-full shadow-2xl flex flex-col z-10 animate-in slide-in-from-left duration-200", children: [
7675
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between px-3.5 py-2.5 border-b border-slate-200 bg-slate-50", children: [
7676
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
7677
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Boxes, { className: "w-4 h-4 text-blue-600" }),
7678
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-bold text-xs text-slate-800", children: "Add Components & Blocks" })
7679
+ ] }),
7680
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7681
+ "button",
7682
+ {
7683
+ type: "button",
7684
+ onClick: () => setIsMobileSidebarOpen(false),
7685
+ className: "p-1 rounded-md text-slate-400 hover:text-slate-700 hover:bg-slate-200 transition",
7686
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.X, { className: "w-4 h-4" })
7687
+ }
7688
+ )
7689
+ ] }),
7690
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-hidden min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LeftSidebar, { registry, config: resolvedConfig.sidebar }) })
7691
+ ] })
7692
+ ] }),
7693
+ isMobileInspectorOpen && resolvedConfig.inspector.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "fixed inset-0 z-50 flex justify-end lg:hidden animate-in fade-in duration-200", children: [
7694
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7695
+ "div",
7696
+ {
7697
+ className: "fixed inset-0 bg-slate-950/50 backdrop-blur-xs transition-opacity",
7698
+ onClick: () => setIsMobileInspectorOpen(false)
7699
+ }
7700
+ ),
7701
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "relative w-84 max-w-[90vw] sm:max-w-md bg-white h-full shadow-2xl flex flex-col z-10 animate-in slide-in-from-right duration-200", children: [
7702
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between px-3.5 py-2.5 border-b border-slate-200 bg-slate-50", children: [
7703
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
7704
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Sliders, { className: "w-4 h-4 text-blue-600" }),
7705
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-bold text-xs text-slate-800", children: selectedNodeId ? `Inspector (#${selectedNodeId})` : "Inspector & Properties" })
7706
+ ] }),
7707
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7708
+ "button",
7709
+ {
7710
+ type: "button",
7711
+ onClick: () => setIsMobileInspectorOpen(false),
7712
+ className: "p-1 rounded-md text-slate-400 hover:text-slate-700 hover:bg-slate-200 transition",
7713
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.X, { className: "w-4 h-4" })
7714
+ }
7715
+ )
7716
+ ] }),
7717
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-hidden min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InspectorPanel, { registry, config: resolvedConfig.inspector }) })
7718
+ ] })
7719
+ ] }),
7720
+ isMobileLayersOpen && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "fixed inset-0 z-50 flex lg:hidden animate-in fade-in duration-200", children: [
7721
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7722
+ "div",
7723
+ {
7724
+ className: "fixed inset-0 bg-slate-950/50 backdrop-blur-xs transition-opacity",
7725
+ onClick: () => setIsMobileLayersOpen(false)
7726
+ }
7727
+ ),
7728
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "relative w-72 max-w-[85vw] bg-white h-full shadow-2xl flex flex-col z-10 animate-in slide-in-from-left duration-200", children: [
7729
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between px-3.5 py-2.5 border-b border-slate-200 bg-slate-50", children: [
7730
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
7731
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Layers, { className: "w-4 h-4 text-blue-600" }),
7732
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-bold text-xs text-slate-800", children: "Element Tree / Layers" })
7733
+ ] }),
7734
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7735
+ "button",
7736
+ {
7737
+ type: "button",
7738
+ onClick: () => setIsMobileLayersOpen(false),
7739
+ className: "p-1 rounded-md text-slate-400 hover:text-slate-700 hover:bg-slate-200 transition",
7740
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.X, { className: "w-4 h-4" })
7741
+ }
7742
+ )
7743
+ ] }),
7744
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-hidden min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LayersPanel, { registry }) })
7745
+ ] })
7746
+ ] }),
7747
+ resolvedConfig.toolbar.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between px-3 py-1.5 sm:px-4 sm:py-2 bg-white border-b border-slate-200 gap-2 overflow-x-auto min-h-[44px]", children: [
7748
+ resolvedConfig.toolbar.showTitle ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
7749
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-bold text-slate-800 text-xs sm:text-sm tracking-tight", children: "KUBUILD Editor" }),
7750
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-[11px] bg-slate-100 text-slate-600 px-1.5 py-0.5 rounded border max-w-[120px] sm:max-w-[200px] truncate font-medium", children: document2.metadata?.title || "Untitled" })
7751
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", {}),
7752
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
7753
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EditorToolbar, { registry, config: resolvedConfig.toolbar }),
7754
+ resolvedConfig.toolbar.showViewportSwitcher && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex items-center gap-0.5 bg-slate-100 p-0.5 sm:p-1 rounded-md text-xs border border-slate-200/80", children: ["desktop", "tablet", "mobile"].map((vp) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7755
+ "button",
7756
+ {
7757
+ type: "button",
7758
+ onClick: () => setViewport(vp),
7759
+ title: `Switch to ${vp} preview`,
7760
+ className: `px-2 py-1 sm:px-2.5 sm:py-1 rounded capitalize font-medium transition flex items-center gap-1 text-[11px] sm:text-xs ${viewport === vp ? "bg-white text-blue-600 shadow-xs font-semibold" : "text-slate-600 hover:text-slate-900"}`,
7761
+ children: [
7762
+ viewportIcons[vp],
7763
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "hidden md:inline", children: vp })
7764
+ ]
7765
+ },
7766
+ vp
7767
+ )) })
7768
+ ] }),
7769
+ resolvedConfig.toolbar.showSelectionStatus && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "hidden xl:block text-xs text-slate-500 shrink-0 font-mono", children: selectedNodeId ? `Selected: #${selectedNodeId}` : "No element selected" })
7770
+ ] }),
7771
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-1 overflow-hidden min-h-0 relative", children: [
7772
+ resolvedConfig.sidebar.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "hidden lg:flex w-80 shrink-0 bg-white border-r border-slate-200 overflow-hidden flex-col min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LeftSidebar, { registry, config: resolvedConfig.sidebar }) }),
7773
+ navigatorMode === "docked" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "hidden lg:flex w-60 shrink-0 bg-white border-r border-slate-200 overflow-hidden flex-col min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LayersPanel, { registry }) }),
7774
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex-1 overflow-hidden flex flex-col min-h-0 h-full bg-slate-100/90 relative", children: [
7775
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-auto p-2 sm:p-4 md:p-8 flex justify-center items-start min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7776
+ "div",
7466
7777
  {
7467
- registry,
7468
- context: previewContext,
7469
- viewport,
7470
- onDiagnostic,
7471
- config: resolvedConfig.canvas
7778
+ className: `${viewportWidthMap[viewport]} bg-white shadow-md rounded-lg overflow-hidden transition-all duration-200 min-h-[500px] border border-slate-200`,
7779
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7780
+ EditorCanvas,
7781
+ {
7782
+ registry,
7783
+ context: previewContext,
7784
+ viewport,
7785
+ onDiagnostic,
7786
+ config: resolvedConfig.canvas
7787
+ }
7788
+ )
7789
+ }
7790
+ ) }),
7791
+ selectedNodeId && !isMobileInspectorOpen && resolvedConfig.inspector.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "lg:hidden fixed bottom-14 left-1/2 -translate-x-1/2 z-30 animate-in fade-in slide-in-from-bottom-2", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7792
+ "button",
7793
+ {
7794
+ type: "button",
7795
+ onClick: () => setIsMobileInspectorOpen(true),
7796
+ className: "flex items-center gap-2 bg-blue-600 hover:bg-blue-500 text-white text-xs font-semibold px-4 py-2 rounded-full shadow-xl border border-blue-400/40 active:scale-95 transition",
7797
+ children: [
7798
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Sliders, { className: "w-3.5 h-3.5" }),
7799
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { children: [
7800
+ "Edit Element (#",
7801
+ selectedNodeId,
7802
+ ")"
7803
+ ] })
7804
+ ]
7805
+ }
7806
+ ) }),
7807
+ resolvedConfig.canvas.showBreadcrumbs && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(HierarchyBreadcrumbs, { registry })
7808
+ ] }),
7809
+ resolvedConfig.inspector.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "hidden lg:flex w-72 shrink-0 bg-white border-l border-slate-200 overflow-hidden flex-col min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InspectorPanel, { registry, config: resolvedConfig.inspector }) })
7810
+ ] }),
7811
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex lg:hidden items-center justify-around bg-white border-t border-slate-200 px-2 py-1.5 z-20 shrink-0 shadow-lg select-none min-h-[48px]", children: [
7812
+ resolvedConfig.sidebar.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7813
+ "button",
7814
+ {
7815
+ type: "button",
7816
+ onClick: () => setIsMobileSidebarOpen(true),
7817
+ className: "flex flex-col items-center justify-center gap-0.5 px-3 py-1 rounded-md text-slate-600 hover:text-blue-600 hover:bg-slate-50 active:bg-slate-100 transition",
7818
+ children: [
7819
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Plus, { className: "w-4 h-4 text-blue-600" }),
7820
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-[10px] font-medium", children: "Add" })
7821
+ ]
7822
+ }
7823
+ ),
7824
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7825
+ "button",
7826
+ {
7827
+ type: "button",
7828
+ onClick: () => setIsMobileLayersOpen(true),
7829
+ className: "flex flex-col items-center justify-center gap-0.5 px-3 py-1 rounded-md text-slate-600 hover:text-blue-600 hover:bg-slate-50 active:bg-slate-100 transition",
7830
+ children: [
7831
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Layers, { className: "w-4 h-4" }),
7832
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-[10px] font-medium", children: "Layers" })
7833
+ ]
7834
+ }
7835
+ ),
7836
+ resolvedConfig.inspector.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7837
+ "button",
7838
+ {
7839
+ type: "button",
7840
+ onClick: () => setIsMobileInspectorOpen(true),
7841
+ className: `flex flex-col items-center justify-center gap-0.5 px-3 py-1 rounded-md transition relative ${selectedNodeId ? "text-blue-600 font-semibold" : "text-slate-600 hover:text-blue-600 hover:bg-slate-50"}`,
7842
+ children: [
7843
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "relative", children: [
7844
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Sliders, { className: "w-4 h-4" }),
7845
+ selectedNodeId && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 rounded-full bg-blue-600 ring-2 ring-white" })
7846
+ ] }),
7847
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-[10px]", children: selectedNodeId ? "Inspect *" : "Inspect" })
7848
+ ]
7849
+ }
7850
+ ),
7851
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "h-5 w-px bg-slate-200 mx-0.5" }),
7852
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1", children: [
7853
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7854
+ "button",
7855
+ {
7856
+ type: "button",
7857
+ disabled: !canUndo,
7858
+ onClick: undo,
7859
+ title: "Undo",
7860
+ className: "p-2 rounded text-slate-600 hover:text-blue-600 disabled:opacity-30 disabled:hover:text-slate-600 transition",
7861
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Undo2, { className: "w-4 h-4" })
7862
+ }
7863
+ ),
7864
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7865
+ "button",
7866
+ {
7867
+ type: "button",
7868
+ disabled: !canRedo,
7869
+ onClick: redo,
7870
+ title: "Redo",
7871
+ className: "p-2 rounded text-slate-600 hover:text-blue-600 disabled:opacity-30 disabled:hover:text-slate-600 transition",
7872
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react10.Redo2, { className: "w-4 h-4" })
7472
7873
  }
7473
7874
  )
7474
- }
7475
- ) }),
7476
- resolvedConfig.canvas.showBreadcrumbs && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(HierarchyBreadcrumbs, { registry })
7477
- ] }),
7478
- resolvedConfig.inspector.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-72 shrink-0 bg-white border-l border-slate-200 overflow-hidden flex flex-col min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InspectorPanel, { registry, config: resolvedConfig.inspector }) })
7479
- ] })
7480
- ] });
7875
+ ] })
7876
+ ] })
7877
+ ]
7878
+ }
7879
+ );
7481
7880
  };
7482
7881
  // Annotate the CommonJS export names for ESM import in node:
7483
7882
  0 && (module.exports = {