@btst/stack 1.10.0 → 1.11.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.
Files changed (75) hide show
  1. package/dist/packages/ui/src/components/minimal-tiptap/utils.cjs +15 -11
  2. package/dist/packages/ui/src/components/minimal-tiptap/utils.mjs +15 -11
  3. package/dist/packages/ui/src/components/ui-builder/index.cjs +9 -7
  4. package/dist/packages/ui/src/components/ui-builder/index.mjs +9 -7
  5. package/dist/packages/ui/src/components/ui-builder/internal/canvas/auto-frame.cjs +6 -3
  6. package/dist/packages/ui/src/components/ui-builder/internal/canvas/auto-frame.mjs +6 -3
  7. package/dist/packages/ui/src/components/ui-builder/internal/components/add-component-popover.cjs +228 -48
  8. package/dist/packages/ui/src/components/ui-builder/internal/components/add-component-popover.mjs +228 -48
  9. package/dist/packages/ui/src/components/ui-builder/internal/components/element-selector.cjs +1 -1
  10. package/dist/packages/ui/src/components/ui-builder/internal/components/element-selector.mjs +1 -1
  11. package/dist/packages/ui/src/components/ui-builder/internal/components/error-fallback.cjs +4 -2
  12. package/dist/packages/ui/src/components/ui-builder/internal/components/error-fallback.mjs +4 -2
  13. package/dist/packages/ui/src/components/ui-builder/internal/components/multi-select.cjs +6 -3
  14. package/dist/packages/ui/src/components/ui-builder/internal/components/multi-select.mjs +6 -3
  15. package/dist/packages/ui/src/components/ui-builder/internal/dnd/draggable-new-component.cjs +67 -0
  16. package/dist/packages/ui/src/components/ui-builder/internal/dnd/draggable-new-component.mjs +62 -0
  17. package/dist/packages/ui/src/components/ui-builder/internal/dnd/drop-zone.cjs +181 -37
  18. package/dist/packages/ui/src/components/ui-builder/internal/dnd/drop-zone.mjs +181 -38
  19. package/dist/packages/ui/src/components/ui-builder/internal/editor-panel.cjs +1 -1
  20. package/dist/packages/ui/src/components/ui-builder/internal/editor-panel.mjs +1 -1
  21. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-group-control.cjs +1 -1
  22. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-group-control.mjs +1 -1
  23. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-item-control.cjs +9 -2
  24. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-item-control.mjs +9 -2
  25. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/iconname-field.cjs +3 -2
  26. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/iconname-field.mjs +3 -2
  27. package/dist/packages/ui/src/components/ui-builder/internal/layers-panel.cjs +1 -1
  28. package/dist/packages/ui/src/components/ui-builder/internal/layers-panel.mjs +1 -1
  29. package/dist/packages/ui/src/components/ui-builder/internal/props-panel.cjs +17 -5
  30. package/dist/packages/ui/src/components/ui-builder/internal/props-panel.mjs +17 -5
  31. package/dist/packages/ui/src/components/ui-builder/internal/utils/render-utils.cjs +70 -16
  32. package/dist/packages/ui/src/components/ui-builder/internal/utils/render-utils.mjs +73 -20
  33. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context-colission-utils.cjs +14 -9
  34. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context-colission-utils.mjs +14 -9
  35. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context.cjs +38 -10
  36. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context.mjs +35 -11
  37. package/dist/packages/ui/src/lib/ui-builder/context/dnd-contexts.cjs +1 -0
  38. package/dist/packages/ui/src/lib/ui-builder/context/dnd-contexts.mjs +1 -0
  39. package/dist/packages/ui/src/lib/ui-builder/context/drag-overlay.cjs +7 -4
  40. package/dist/packages/ui/src/lib/ui-builder/context/drag-overlay.mjs +7 -4
  41. package/dist/packages/ui/src/lib/ui-builder/hooks/use-auto-scroll.cjs +4 -4
  42. package/dist/packages/ui/src/lib/ui-builder/hooks/use-auto-scroll.mjs +4 -4
  43. package/dist/packages/ui/src/lib/ui-builder/hooks/use-dnd-event-handlers.cjs +53 -16
  44. package/dist/packages/ui/src/lib/ui-builder/hooks/use-dnd-event-handlers.mjs +53 -16
  45. package/dist/packages/ui/src/lib/ui-builder/hooks/use-drop-validation.cjs +23 -7
  46. package/dist/packages/ui/src/lib/ui-builder/hooks/use-drop-validation.mjs +23 -7
  47. package/dist/packages/ui/src/lib/ui-builder/registry/form-field-overrides.cjs +110 -11
  48. package/dist/packages/ui/src/lib/ui-builder/registry/form-field-overrides.mjs +111 -13
  49. package/dist/packages/ui/src/lib/ui-builder/store/editor-store.cjs +3 -2
  50. package/dist/packages/ui/src/lib/ui-builder/store/editor-store.mjs +3 -2
  51. package/dist/packages/ui/src/lib/ui-builder/store/layer-store.cjs +53 -7
  52. package/dist/packages/ui/src/lib/ui-builder/store/layer-store.mjs +54 -8
  53. package/dist/packages/ui/src/lib/ui-builder/store/layer-utils.cjs +4 -3
  54. package/dist/packages/ui/src/lib/ui-builder/store/layer-utils.mjs +4 -3
  55. package/dist/packages/ui/src/lib/ui-builder/utils/variable-resolver.cjs +12 -0
  56. package/dist/packages/ui/src/lib/ui-builder/utils/variable-resolver.mjs +12 -1
  57. package/dist/plugins/ui-builder/client/components/index.d.cts +1 -1
  58. package/dist/plugins/ui-builder/client/components/index.d.mts +1 -1
  59. package/dist/plugins/ui-builder/client/components/index.d.ts +1 -1
  60. package/dist/plugins/ui-builder/client/hooks/index.d.cts +2 -2
  61. package/dist/plugins/ui-builder/client/hooks/index.d.mts +2 -2
  62. package/dist/plugins/ui-builder/client/hooks/index.d.ts +2 -2
  63. package/dist/plugins/ui-builder/client/index.d.cts +17 -7
  64. package/dist/plugins/ui-builder/client/index.d.mts +17 -7
  65. package/dist/plugins/ui-builder/client/index.d.ts +17 -7
  66. package/dist/plugins/ui-builder/index.d.cts +2 -2
  67. package/dist/plugins/ui-builder/index.d.mts +2 -2
  68. package/dist/plugins/ui-builder/index.d.ts +2 -2
  69. package/dist/shared/{stack.BSM2cgoq.d.cts → stack.BYysGdHl.d.cts} +1 -1
  70. package/dist/shared/{stack.CqfZWfjJ.d.cts → stack.BdJFrdyt.d.cts} +8 -2
  71. package/dist/shared/{stack.e1FN86dE.d.mts → stack.ChVuHi5e.d.mts} +8 -2
  72. package/dist/shared/{stack.CLtOoAqF.d.mts → stack.DYCFcnkL.d.mts} +1 -1
  73. package/dist/shared/{stack.MMntCVZZ.d.ts → stack.EhM4pmtN.d.ts} +8 -2
  74. package/dist/shared/{stack.BD1m-4yB.d.ts → stack.kFbDspnF.d.ts} +1 -1
  75. package/package.json +1 -1
@@ -13,37 +13,59 @@ const useDndEventHandlers = require('../hooks/use-dnd-event-handlers.cjs');
13
13
  const useDropValidation = require('../hooks/use-drop-validation.cjs');
14
14
  const useKeyboardShortcutsDnd = require('../hooks/use-keyboard-shortcuts-dnd.cjs');
15
15
 
16
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
17
+
18
+ const React__default = /*#__PURE__*/_interopDefaultCompat(React);
19
+
16
20
  const DndContextProvider = ({ children }) => {
17
21
  const [activeLayerId, setActiveLayerId] = React.useState(null);
22
+ const [newComponentType, setNewComponentType] = React.useState(null);
18
23
  const [componentDragging, setComponentDragging] = React.useState(false);
19
24
  const { handleParentMouseMove, handleIframeMouseMove, stopAutoScroll } = useAutoScroll.useAutoScroll();
20
25
  const sensors = useDndSensors.useDndSensors();
26
+ const clearDragState = React.useCallback(() => {
27
+ setActiveLayerId(null);
28
+ setNewComponentType(null);
29
+ }, []);
30
+ const canDropOnLayerRef = React__default.useRef(() => false);
21
31
  const { handleDragStart, handleDragEnd, handleDragCancel, isLayerDescendantOf } = useDndEventHandlers.useDndEventHandlers({
22
32
  stopAutoScroll,
23
- setActiveLayerId
33
+ setActiveLayerId,
34
+ setNewComponentType,
35
+ clearDragState,
36
+ canDropOnLayer: (layerId) => canDropOnLayerRef.current(layerId)
24
37
  });
25
- const { canDropOnLayer } = useDropValidation.useDropValidation(activeLayerId, isLayerDescendantOf);
26
- useKeyboardShortcutsDnd.useKeyboardShortcutsDnd(activeLayerId, handleDragCancel);
38
+ const { canDropOnLayer } = useDropValidation.useDropValidation(activeLayerId, isLayerDescendantOf, newComponentType);
39
+ React__default.useEffect(() => {
40
+ canDropOnLayerRef.current = canDropOnLayer;
41
+ }, [canDropOnLayer]);
42
+ const handleKeyboardCancel = React.useCallback(() => {
43
+ handleDragCancel();
44
+ clearDragState();
45
+ }, [handleDragCancel, clearDragState]);
46
+ useKeyboardShortcutsDnd.useKeyboardShortcutsDnd(activeLayerId || newComponentType, handleKeyboardCancel);
27
47
  const collisionDetection = dndContextColissionUtils.createTransformAwareCollisionDetection();
28
48
  const contextValue = React.useMemo(() => ({
29
- isDragging: !!activeLayerId,
49
+ isDragging: !!activeLayerId || !!newComponentType,
30
50
  activeLayerId,
51
+ newComponentType,
31
52
  canDropOnLayer
32
- }), [activeLayerId, canDropOnLayer]);
53
+ }), [activeLayerId, newComponentType, canDropOnLayer]);
33
54
  const componentDragContextValue = React.useMemo(() => ({
34
55
  isDragging: componentDragging,
35
56
  setDragging: setComponentDragging
36
57
  }), [componentDragging]);
58
+ const isDragging = !!activeLayerId || !!newComponentType;
37
59
  React.useEffect(() => {
38
- if (activeLayerId) {
39
- const handleParentMove = (event) => handleParentMouseMove(event, activeLayerId);
60
+ if (isDragging) {
61
+ const handleParentMove = (event) => handleParentMouseMove(event, true);
40
62
  document.addEventListener("mousemove", handleParentMove);
41
63
  const iframeElements = dndUtils.getIframeElements();
42
64
  let iframeCleanup = null;
43
65
  if (iframeElements) {
44
66
  const { window: iframeWindow } = iframeElements;
45
67
  if (iframeWindow) {
46
- const handleIframeMove = (event) => handleIframeMouseMove(event, activeLayerId);
68
+ const handleIframeMove = (event) => handleIframeMouseMove(event, true);
47
69
  iframeWindow.addEventListener("mousemove", handleIframeMove);
48
70
  iframeCleanup = () => {
49
71
  try {
@@ -64,7 +86,7 @@ const DndContextProvider = ({ children }) => {
64
86
  } else {
65
87
  stopAutoScroll();
66
88
  }
67
- }, [activeLayerId, handleParentMouseMove, handleIframeMouseMove, stopAutoScroll]);
89
+ }, [isDragging, handleParentMouseMove, handleIframeMouseMove, stopAutoScroll]);
68
90
  React.useEffect(() => {
69
91
  return () => {
70
92
  stopAutoScroll();
@@ -80,7 +102,13 @@ const DndContextProvider = ({ children }) => {
80
102
  onDragCancel: handleDragCancel,
81
103
  children: [
82
104
  children,
83
- /* @__PURE__ */ jsxRuntime.jsx(dragOverlay.TransformAwareDragOverlay, { children: activeLayerId ? /* @__PURE__ */ jsxRuntime.jsx(dragOverlay.DragOverlayContent, { layerId: activeLayerId }) : null })
105
+ /* @__PURE__ */ jsxRuntime.jsx(dragOverlay.TransformAwareDragOverlay, { children: activeLayerId || newComponentType ? /* @__PURE__ */ jsxRuntime.jsx(
106
+ dragOverlay.DragOverlayContent,
107
+ {
108
+ layerId: activeLayerId || void 0,
109
+ componentType: newComponentType || void 0
110
+ }
111
+ ) : null })
84
112
  ]
85
113
  }
86
114
  ) }) });
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { useState, useMemo, useEffect } from 'react';
2
+ import React__default, { useState, useCallback, useMemo, useEffect } from 'react';
3
3
  import { DndContext } from '../../../../../../node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.mjs';
4
4
  import { createTransformAwareCollisionDetection } from './dnd-context-colission-utils.mjs';
5
5
  import { getIframeElements } from './dnd-utils.mjs';
@@ -14,35 +14,53 @@ import { useKeyboardShortcutsDnd } from '../hooks/use-keyboard-shortcuts-dnd.mjs
14
14
 
15
15
  const DndContextProvider = ({ children }) => {
16
16
  const [activeLayerId, setActiveLayerId] = useState(null);
17
+ const [newComponentType, setNewComponentType] = useState(null);
17
18
  const [componentDragging, setComponentDragging] = useState(false);
18
19
  const { handleParentMouseMove, handleIframeMouseMove, stopAutoScroll } = useAutoScroll();
19
20
  const sensors = useDndSensors();
21
+ const clearDragState = useCallback(() => {
22
+ setActiveLayerId(null);
23
+ setNewComponentType(null);
24
+ }, []);
25
+ const canDropOnLayerRef = React__default.useRef(() => false);
20
26
  const { handleDragStart, handleDragEnd, handleDragCancel, isLayerDescendantOf } = useDndEventHandlers({
21
27
  stopAutoScroll,
22
- setActiveLayerId
28
+ setActiveLayerId,
29
+ setNewComponentType,
30
+ clearDragState,
31
+ canDropOnLayer: (layerId) => canDropOnLayerRef.current(layerId)
23
32
  });
24
- const { canDropOnLayer } = useDropValidation(activeLayerId, isLayerDescendantOf);
25
- useKeyboardShortcutsDnd(activeLayerId, handleDragCancel);
33
+ const { canDropOnLayer } = useDropValidation(activeLayerId, isLayerDescendantOf, newComponentType);
34
+ React__default.useEffect(() => {
35
+ canDropOnLayerRef.current = canDropOnLayer;
36
+ }, [canDropOnLayer]);
37
+ const handleKeyboardCancel = useCallback(() => {
38
+ handleDragCancel();
39
+ clearDragState();
40
+ }, [handleDragCancel, clearDragState]);
41
+ useKeyboardShortcutsDnd(activeLayerId || newComponentType, handleKeyboardCancel);
26
42
  const collisionDetection = createTransformAwareCollisionDetection();
27
43
  const contextValue = useMemo(() => ({
28
- isDragging: !!activeLayerId,
44
+ isDragging: !!activeLayerId || !!newComponentType,
29
45
  activeLayerId,
46
+ newComponentType,
30
47
  canDropOnLayer
31
- }), [activeLayerId, canDropOnLayer]);
48
+ }), [activeLayerId, newComponentType, canDropOnLayer]);
32
49
  const componentDragContextValue = useMemo(() => ({
33
50
  isDragging: componentDragging,
34
51
  setDragging: setComponentDragging
35
52
  }), [componentDragging]);
53
+ const isDragging = !!activeLayerId || !!newComponentType;
36
54
  useEffect(() => {
37
- if (activeLayerId) {
38
- const handleParentMove = (event) => handleParentMouseMove(event, activeLayerId);
55
+ if (isDragging) {
56
+ const handleParentMove = (event) => handleParentMouseMove(event, true);
39
57
  document.addEventListener("mousemove", handleParentMove);
40
58
  const iframeElements = getIframeElements();
41
59
  let iframeCleanup = null;
42
60
  if (iframeElements) {
43
61
  const { window: iframeWindow } = iframeElements;
44
62
  if (iframeWindow) {
45
- const handleIframeMove = (event) => handleIframeMouseMove(event, activeLayerId);
63
+ const handleIframeMove = (event) => handleIframeMouseMove(event, true);
46
64
  iframeWindow.addEventListener("mousemove", handleIframeMove);
47
65
  iframeCleanup = () => {
48
66
  try {
@@ -63,7 +81,7 @@ const DndContextProvider = ({ children }) => {
63
81
  } else {
64
82
  stopAutoScroll();
65
83
  }
66
- }, [activeLayerId, handleParentMouseMove, handleIframeMouseMove, stopAutoScroll]);
84
+ }, [isDragging, handleParentMouseMove, handleIframeMouseMove, stopAutoScroll]);
67
85
  useEffect(() => {
68
86
  return () => {
69
87
  stopAutoScroll();
@@ -79,7 +97,13 @@ const DndContextProvider = ({ children }) => {
79
97
  onDragCancel: handleDragCancel,
80
98
  children: [
81
99
  children,
82
- /* @__PURE__ */ jsx(TransformAwareDragOverlay, { children: activeLayerId ? /* @__PURE__ */ jsx(DragOverlayContent, { layerId: activeLayerId }) : null })
100
+ /* @__PURE__ */ jsx(TransformAwareDragOverlay, { children: activeLayerId || newComponentType ? /* @__PURE__ */ jsx(
101
+ DragOverlayContent,
102
+ {
103
+ layerId: activeLayerId || void 0,
104
+ componentType: newComponentType || void 0
105
+ }
106
+ ) : null })
83
107
  ]
84
108
  }
85
109
  ) }) });
@@ -5,6 +5,7 @@ const React = require('react');
5
5
  const DndContextStateContext = React.createContext({
6
6
  isDragging: false,
7
7
  activeLayerId: null,
8
+ newComponentType: null,
8
9
  canDropOnLayer: () => false
9
10
  });
10
11
  const ComponentDragContext = React.createContext({
@@ -3,6 +3,7 @@ import { createContext, useContext } from 'react';
3
3
  const DndContextStateContext = createContext({
4
4
  isDragging: false,
5
5
  activeLayerId: null,
6
+ newComponentType: null,
6
7
  canDropOnLayer: () => false
7
8
  });
8
9
  const ComponentDragContext = createContext({
@@ -34,10 +34,13 @@ const TransformAwareDragOverlay = ({ children }) => {
34
34
  mountNode
35
35
  );
36
36
  };
37
- const DragOverlayContent = ({ layerId }) => {
38
- const layer = layerStore.useLayerStore((state) => state.findLayerById(layerId));
39
- if (!layer) return null;
40
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-10 bg-white shadow-lg border border-gray-200 rounded px-2 py-1 text-sm font-medium opacity-60 text-nowrap min-w-fit", children: layer.name || layer.type });
37
+ const DragOverlayContent = ({ layerId, componentType }) => {
38
+ const layer = layerStore.useLayerStore((state) => layerId ? state.findLayerById(layerId) : null);
39
+ const displayName = layer?.name || layer?.type || componentType || "Component";
40
+ if (!layer && !componentType) {
41
+ return null;
42
+ }
43
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-10 bg-white dark:bg-gray-800 shadow-lg border-2 border-primary/50 rounded-lg px-3 py-2 text-sm font-medium opacity-90 text-nowrap min-w-fit pointer-events-none", children: displayName });
41
44
  };
42
45
 
43
46
  exports.DragOverlayContent = DragOverlayContent;
@@ -32,10 +32,13 @@ const TransformAwareDragOverlay = ({ children }) => {
32
32
  mountNode
33
33
  );
34
34
  };
35
- const DragOverlayContent = ({ layerId }) => {
36
- const layer = useLayerStore((state) => state.findLayerById(layerId));
37
- if (!layer) return null;
38
- return /* @__PURE__ */ jsx("div", { className: "mt-10 bg-white shadow-lg border border-gray-200 rounded px-2 py-1 text-sm font-medium opacity-60 text-nowrap min-w-fit", children: layer.name || layer.type });
35
+ const DragOverlayContent = ({ layerId, componentType }) => {
36
+ const layer = useLayerStore((state) => layerId ? state.findLayerById(layerId) : null);
37
+ const displayName = layer?.name || layer?.type || componentType || "Component";
38
+ if (!layer && !componentType) {
39
+ return null;
40
+ }
41
+ return /* @__PURE__ */ jsx("div", { className: "mt-10 bg-white dark:bg-gray-800 shadow-lg border-2 border-primary/50 rounded-lg px-3 py-2 text-sm font-medium opacity-90 text-nowrap min-w-fit pointer-events-none", children: displayName });
39
42
  };
40
43
 
41
44
  export { DragOverlayContent, TransformAwareDragOverlay };
@@ -83,15 +83,15 @@ const useAutoScroll = () => {
83
83
  }
84
84
  }
85
85
  }, []);
86
- const handleParentMouseMove = React.useCallback((event, activeLayerId) => {
87
- if (!activeLayerId) return;
86
+ const handleParentMouseMove = React.useCallback((event, isDragging) => {
87
+ if (!isDragging) return;
88
88
  mousePositionRef.current = { x: event.clientX, y: event.clientY };
89
89
  if (!animationFrameRef.current) {
90
90
  animationFrameRef.current = requestAnimationFrame(performAutoScroll);
91
91
  }
92
92
  }, [performAutoScroll]);
93
- const handleIframeMouseMove = React.useCallback((event, activeLayerId) => {
94
- if (!activeLayerId) return;
93
+ const handleIframeMouseMove = React.useCallback((event, isDragging) => {
94
+ if (!isDragging) return;
95
95
  const iframeElements = dndUtils.getIframeElements();
96
96
  if (!iframeElements) return;
97
97
  const { iframe } = iframeElements;
@@ -81,15 +81,15 @@ const useAutoScroll = () => {
81
81
  }
82
82
  }
83
83
  }, []);
84
- const handleParentMouseMove = useCallback((event, activeLayerId) => {
85
- if (!activeLayerId) return;
84
+ const handleParentMouseMove = useCallback((event, isDragging) => {
85
+ if (!isDragging) return;
86
86
  mousePositionRef.current = { x: event.clientX, y: event.clientY };
87
87
  if (!animationFrameRef.current) {
88
88
  animationFrameRef.current = requestAnimationFrame(performAutoScroll);
89
89
  }
90
90
  }, [performAutoScroll]);
91
- const handleIframeMouseMove = useCallback((event, activeLayerId) => {
92
- if (!activeLayerId) return;
91
+ const handleIframeMouseMove = useCallback((event, isDragging) => {
92
+ if (!isDragging) return;
93
93
  const iframeElements = getIframeElements();
94
94
  if (!iframeElements) return;
95
95
  const { iframe } = iframeElements;
@@ -4,8 +4,15 @@ const React = require('react');
4
4
  const layerStore = require('../store/layer-store.cjs');
5
5
  const layerUtils = require('../store/layer-utils.cjs');
6
6
 
7
- const useDndEventHandlers = ({ stopAutoScroll, setActiveLayerId }) => {
7
+ const useDndEventHandlers = ({
8
+ stopAutoScroll,
9
+ setActiveLayerId,
10
+ setNewComponentType,
11
+ clearDragState,
12
+ canDropOnLayer
13
+ }) => {
8
14
  const moveLayer = layerStore.useLayerStore((state) => state.moveLayer);
15
+ const addComponentLayer = layerStore.useLayerStore((state) => state.addComponentLayer);
9
16
  const pages = layerStore.useLayerStore((state) => state.pages);
10
17
  const isLayerDescendantOf = React.useCallback((childId, parentId) => {
11
18
  if (childId === parentId) return true;
@@ -16,34 +23,64 @@ const useDndEventHandlers = ({ stopAutoScroll, setActiveLayerId }) => {
16
23
  const { active } = event;
17
24
  if (active.data.current?.type === "layer") {
18
25
  setActiveLayerId(active.data.current.layerId);
19
- } else {
20
- console.log("Drag start: Non-layer drag detected", active.data.current?.type);
26
+ } else if (active.data.current?.type === "new-component") {
27
+ const componentType = active.data.current.componentType;
28
+ if (componentType && setNewComponentType) {
29
+ setNewComponentType(componentType);
30
+ }
21
31
  }
22
- }, [setActiveLayerId]);
32
+ }, [setActiveLayerId, setNewComponentType]);
23
33
  const handleDragEnd = React.useCallback((event) => {
24
34
  const { active, over } = event;
25
35
  stopAutoScroll();
26
- if (!over || !active.data.current?.layerId) {
27
- setActiveLayerId(null);
36
+ const activeData = active.data.current;
37
+ const overData = over?.data.current;
38
+ if (!over || !overData || overData.type !== "drop-zone") {
39
+ if (clearDragState) {
40
+ clearDragState();
41
+ } else {
42
+ setActiveLayerId(null);
43
+ }
28
44
  return;
29
45
  }
30
- const activeLayerId = active.data.current.layerId;
31
- const overData = over.data.current;
32
- if (overData?.type === "drop-zone") {
33
- const targetParentId = overData.parentId;
34
- const targetPosition = overData.position;
35
- if (isLayerDescendantOf(targetParentId, activeLayerId)) {
46
+ const targetParentId = overData.parentId;
47
+ const targetPosition = overData.position;
48
+ if (canDropOnLayer && !canDropOnLayer(targetParentId)) {
49
+ if (clearDragState) {
50
+ clearDragState();
51
+ } else {
36
52
  setActiveLayerId(null);
53
+ }
54
+ return;
55
+ }
56
+ if (activeData?.type === "layer" && activeData.layerId) {
57
+ const activeLayerId = activeData.layerId;
58
+ if (isLayerDescendantOf(targetParentId, activeLayerId)) {
59
+ if (clearDragState) {
60
+ clearDragState();
61
+ } else {
62
+ setActiveLayerId(null);
63
+ }
37
64
  return;
38
65
  }
39
66
  moveLayer(activeLayerId, targetParentId, targetPosition);
67
+ } else if (activeData?.type === "new-component" && activeData.componentType) {
68
+ addComponentLayer(activeData.componentType, targetParentId, targetPosition);
69
+ }
70
+ if (clearDragState) {
71
+ clearDragState();
72
+ } else {
73
+ setActiveLayerId(null);
40
74
  }
41
- setActiveLayerId(null);
42
- }, [moveLayer, isLayerDescendantOf, stopAutoScroll, setActiveLayerId]);
75
+ }, [moveLayer, addComponentLayer, isLayerDescendantOf, stopAutoScroll, setActiveLayerId, clearDragState, canDropOnLayer]);
43
76
  const handleDragCancel = React.useCallback(() => {
44
77
  stopAutoScroll();
45
- setActiveLayerId(null);
46
- }, [stopAutoScroll, setActiveLayerId]);
78
+ if (clearDragState) {
79
+ clearDragState();
80
+ } else {
81
+ setActiveLayerId(null);
82
+ }
83
+ }, [stopAutoScroll, setActiveLayerId, clearDragState]);
47
84
  return {
48
85
  handleDragStart,
49
86
  handleDragEnd,
@@ -2,8 +2,15 @@ import { useCallback } from 'react';
2
2
  import { useLayerStore } from '../store/layer-store.mjs';
3
3
  import { findAllParentLayersRecursive } from '../store/layer-utils.mjs';
4
4
 
5
- const useDndEventHandlers = ({ stopAutoScroll, setActiveLayerId }) => {
5
+ const useDndEventHandlers = ({
6
+ stopAutoScroll,
7
+ setActiveLayerId,
8
+ setNewComponentType,
9
+ clearDragState,
10
+ canDropOnLayer
11
+ }) => {
6
12
  const moveLayer = useLayerStore((state) => state.moveLayer);
13
+ const addComponentLayer = useLayerStore((state) => state.addComponentLayer);
7
14
  const pages = useLayerStore((state) => state.pages);
8
15
  const isLayerDescendantOf = useCallback((childId, parentId) => {
9
16
  if (childId === parentId) return true;
@@ -14,34 +21,64 @@ const useDndEventHandlers = ({ stopAutoScroll, setActiveLayerId }) => {
14
21
  const { active } = event;
15
22
  if (active.data.current?.type === "layer") {
16
23
  setActiveLayerId(active.data.current.layerId);
17
- } else {
18
- console.log("Drag start: Non-layer drag detected", active.data.current?.type);
24
+ } else if (active.data.current?.type === "new-component") {
25
+ const componentType = active.data.current.componentType;
26
+ if (componentType && setNewComponentType) {
27
+ setNewComponentType(componentType);
28
+ }
19
29
  }
20
- }, [setActiveLayerId]);
30
+ }, [setActiveLayerId, setNewComponentType]);
21
31
  const handleDragEnd = useCallback((event) => {
22
32
  const { active, over } = event;
23
33
  stopAutoScroll();
24
- if (!over || !active.data.current?.layerId) {
25
- setActiveLayerId(null);
34
+ const activeData = active.data.current;
35
+ const overData = over?.data.current;
36
+ if (!over || !overData || overData.type !== "drop-zone") {
37
+ if (clearDragState) {
38
+ clearDragState();
39
+ } else {
40
+ setActiveLayerId(null);
41
+ }
26
42
  return;
27
43
  }
28
- const activeLayerId = active.data.current.layerId;
29
- const overData = over.data.current;
30
- if (overData?.type === "drop-zone") {
31
- const targetParentId = overData.parentId;
32
- const targetPosition = overData.position;
33
- if (isLayerDescendantOf(targetParentId, activeLayerId)) {
44
+ const targetParentId = overData.parentId;
45
+ const targetPosition = overData.position;
46
+ if (canDropOnLayer && !canDropOnLayer(targetParentId)) {
47
+ if (clearDragState) {
48
+ clearDragState();
49
+ } else {
34
50
  setActiveLayerId(null);
51
+ }
52
+ return;
53
+ }
54
+ if (activeData?.type === "layer" && activeData.layerId) {
55
+ const activeLayerId = activeData.layerId;
56
+ if (isLayerDescendantOf(targetParentId, activeLayerId)) {
57
+ if (clearDragState) {
58
+ clearDragState();
59
+ } else {
60
+ setActiveLayerId(null);
61
+ }
35
62
  return;
36
63
  }
37
64
  moveLayer(activeLayerId, targetParentId, targetPosition);
65
+ } else if (activeData?.type === "new-component" && activeData.componentType) {
66
+ addComponentLayer(activeData.componentType, targetParentId, targetPosition);
67
+ }
68
+ if (clearDragState) {
69
+ clearDragState();
70
+ } else {
71
+ setActiveLayerId(null);
38
72
  }
39
- setActiveLayerId(null);
40
- }, [moveLayer, isLayerDescendantOf, stopAutoScroll, setActiveLayerId]);
73
+ }, [moveLayer, addComponentLayer, isLayerDescendantOf, stopAutoScroll, setActiveLayerId, clearDragState, canDropOnLayer]);
41
74
  const handleDragCancel = useCallback(() => {
42
75
  stopAutoScroll();
43
- setActiveLayerId(null);
44
- }, [stopAutoScroll, setActiveLayerId]);
76
+ if (clearDragState) {
77
+ clearDragState();
78
+ } else {
79
+ setActiveLayerId(null);
80
+ }
81
+ }, [stopAutoScroll, setActiveLayerId, clearDragState]);
45
82
  return {
46
83
  handleDragStart,
47
84
  handleDragEnd,
@@ -5,22 +5,38 @@ const layerStore = require('../store/layer-store.cjs');
5
5
  const editorStore = require('../store/editor-store.cjs');
6
6
  const layerUtils = require('../store/layer-utils.cjs');
7
7
 
8
- const useDropValidation = (activeLayerId, isLayerDescendantOf) => {
8
+ const useDropValidation = (activeLayerId, isLayerDescendantOf, newComponentType) => {
9
9
  const findLayerById = layerStore.useLayerStore((state) => state.findLayerById);
10
10
  const componentRegistry = editorStore.useEditorStore((state) => state.registry);
11
11
  const canDropOnLayer = React.useCallback((layerId) => {
12
+ if (!layerId) return false;
12
13
  const targetLayer = findLayerById(layerId);
13
14
  if (!targetLayer) return false;
14
- if (!activeLayerId) {
15
+ if (!activeLayerId && !newComponentType) {
15
16
  return layerUtils.canLayerAcceptChildren(targetLayer, componentRegistry);
16
17
  }
17
- if (isLayerDescendantOf(layerId, activeLayerId)) {
18
- return false;
18
+ if (newComponentType) {
19
+ const componentDef = componentRegistry[newComponentType];
20
+ if (componentDef?.childOf && !componentDef.childOf.includes(targetLayer.type)) {
21
+ return false;
22
+ }
23
+ return layerUtils.canLayerAcceptChildren(targetLayer, componentRegistry);
24
+ }
25
+ if (activeLayerId) {
26
+ if (isLayerDescendantOf(layerId, activeLayerId)) {
27
+ return false;
28
+ }
29
+ const draggedLayer = findLayerById(activeLayerId);
30
+ if (!draggedLayer) {
31
+ return layerUtils.canLayerAcceptChildren(targetLayer, componentRegistry);
32
+ }
33
+ const draggedDef = componentRegistry[draggedLayer.type];
34
+ if (draggedDef?.childOf && !draggedDef.childOf.includes(targetLayer.type)) {
35
+ return false;
36
+ }
19
37
  }
20
- const draggedLayer = findLayerById(activeLayerId);
21
- if (!draggedLayer) return false;
22
38
  return layerUtils.canLayerAcceptChildren(targetLayer, componentRegistry);
23
- }, [activeLayerId, isLayerDescendantOf, findLayerById, componentRegistry]);
39
+ }, [activeLayerId, newComponentType, isLayerDescendantOf, findLayerById, componentRegistry]);
24
40
  return { canDropOnLayer };
25
41
  };
26
42
 
@@ -3,22 +3,38 @@ import { useLayerStore } from '../store/layer-store.mjs';
3
3
  import { useEditorStore } from '../store/editor-store.mjs';
4
4
  import { canLayerAcceptChildren } from '../store/layer-utils.mjs';
5
5
 
6
- const useDropValidation = (activeLayerId, isLayerDescendantOf) => {
6
+ const useDropValidation = (activeLayerId, isLayerDescendantOf, newComponentType) => {
7
7
  const findLayerById = useLayerStore((state) => state.findLayerById);
8
8
  const componentRegistry = useEditorStore((state) => state.registry);
9
9
  const canDropOnLayer = useCallback((layerId) => {
10
+ if (!layerId) return false;
10
11
  const targetLayer = findLayerById(layerId);
11
12
  if (!targetLayer) return false;
12
- if (!activeLayerId) {
13
+ if (!activeLayerId && !newComponentType) {
13
14
  return canLayerAcceptChildren(targetLayer, componentRegistry);
14
15
  }
15
- if (isLayerDescendantOf(layerId, activeLayerId)) {
16
- return false;
16
+ if (newComponentType) {
17
+ const componentDef = componentRegistry[newComponentType];
18
+ if (componentDef?.childOf && !componentDef.childOf.includes(targetLayer.type)) {
19
+ return false;
20
+ }
21
+ return canLayerAcceptChildren(targetLayer, componentRegistry);
22
+ }
23
+ if (activeLayerId) {
24
+ if (isLayerDescendantOf(layerId, activeLayerId)) {
25
+ return false;
26
+ }
27
+ const draggedLayer = findLayerById(activeLayerId);
28
+ if (!draggedLayer) {
29
+ return canLayerAcceptChildren(targetLayer, componentRegistry);
30
+ }
31
+ const draggedDef = componentRegistry[draggedLayer.type];
32
+ if (draggedDef?.childOf && !draggedDef.childOf.includes(targetLayer.type)) {
33
+ return false;
34
+ }
17
35
  }
18
- const draggedLayer = findLayerById(activeLayerId);
19
- if (!draggedLayer) return false;
20
36
  return canLayerAcceptChildren(targetLayer, componentRegistry);
21
- }, [activeLayerId, isLayerDescendantOf, findLayerById, componentRegistry]);
37
+ }, [activeLayerId, newComponentType, isLayerDescendantOf, findLayerById, componentRegistry]);
22
38
  return { canDropOnLayer };
23
39
  };
24
40