@bemedev/mind-flow 0.3.0 → 0.3.2
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/lib/index.cjs.js +1 -1
- package/lib/index.es.js +244 -268
- package/lib/server.cjs.js +153 -189
- package/lib/server.es.js +153 -189
- package/lib/services/main.machine.d.ts +994 -14
- package/lib/services/main.machine.d.ts.map +1 -1
- package/lib/ui/components/EdgeComponent.d.ts.map +1 -1
- package/lib/ui/components/FlowChart.context.d.ts +994 -14
- package/lib/ui/components/FlowChart.context.d.ts.map +1 -1
- package/lib/ui/components/NodeComponent.d.ts.map +1 -1
- package/lib/ui/components/NodesBoard.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/services/main.machine.ts +148 -41
- package/src/ui/components/EdgeComponent.tsx +46 -56
- package/src/ui/components/FlowChart.context.ts +2 -131
- package/src/ui/components/FlowChart.tsx +10 -10
- package/src/ui/components/NodeComponent.tsx +13 -14
- package/src/ui/components/NodesBoard.tsx +32 -49
|
@@ -39,12 +39,14 @@ type Props = {
|
|
|
39
39
|
*/
|
|
40
40
|
export const NodeComponent: Component<Props> = props => {
|
|
41
41
|
const service = useFlow();
|
|
42
|
+
const newEdge = createState(service, { selector: s => s.context.newEdge });
|
|
43
|
+
const draggable = createDraggable(props.id);
|
|
44
|
+
void draggable;
|
|
42
45
|
|
|
43
46
|
const node = createState(service, {
|
|
44
47
|
selector: ({ context }) => {
|
|
45
48
|
const list = toArray.typed(context.data?.nodes);
|
|
46
|
-
const item = list.find(n => n.id === props.id)
|
|
47
|
-
if (!item) return undefined;
|
|
49
|
+
const item = list.find(n => n.id === props.id)!;
|
|
48
50
|
return {
|
|
49
51
|
x: item.position.x,
|
|
50
52
|
y: item.position.y,
|
|
@@ -56,10 +58,8 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
56
58
|
equals: dequal,
|
|
57
59
|
});
|
|
58
60
|
|
|
59
|
-
const newEdge = createState(service, { selector: s => s.context.newEdge });
|
|
60
|
-
|
|
61
61
|
const selected = createState(service, {
|
|
62
|
-
selector:
|
|
62
|
+
selector: ({ context }) => context.selected === props.id,
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
const hasParent = createState(service, {
|
|
@@ -70,9 +70,6 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
70
70
|
},
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
const draggable = createDraggable(props.id);
|
|
74
|
-
void draggable;
|
|
75
|
-
|
|
76
73
|
return (
|
|
77
74
|
<div
|
|
78
75
|
classList={{
|
|
@@ -81,7 +78,7 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
81
78
|
'border border-[#e6d4be] z-[1]': !selected(),
|
|
82
79
|
}}
|
|
83
80
|
|
|
84
|
-
style={{ top: `${node()
|
|
81
|
+
style={{ top: `${node().y}px`, left: `${node().x}px` }}
|
|
85
82
|
class='min-w-48'
|
|
86
83
|
use:draggable={{ skipTransform: true }}
|
|
87
84
|
id={props.id}
|
|
@@ -122,6 +119,7 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
122
119
|
<Show when={hasParent()}>
|
|
123
120
|
<svg
|
|
124
121
|
class='cursor-pointer overflow-visible rounded-full bg-green-500 p-0.5 text-center font-bold hover:bg-green-600'
|
|
122
|
+
|
|
125
123
|
style={{
|
|
126
124
|
'pointer-events': 'all',
|
|
127
125
|
'fill-rule': 'evenodd',
|
|
@@ -145,6 +143,7 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
145
143
|
</g>
|
|
146
144
|
</svg>
|
|
147
145
|
</Show>
|
|
146
|
+
|
|
148
147
|
<svg
|
|
149
148
|
class='flex cursor-pointer items-center justify-center rounded-lg bg-blue-500 p-0.5 text-center font-bold text-white hover:bg-blue-600'
|
|
150
149
|
onClick={() => service.send({ type: 'ADD_CHILD', payload: props.id })}
|
|
@@ -162,7 +161,7 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
162
161
|
</svg>
|
|
163
162
|
</div>
|
|
164
163
|
|
|
165
|
-
<Show when={node()
|
|
164
|
+
<Show when={node().label} keyed>
|
|
166
165
|
{label => (
|
|
167
166
|
<span class='min-w-max border-b border-[#f0f0f0] p-3 whitespace-nowrap text-red-600 select-none'>
|
|
168
167
|
{label}
|
|
@@ -170,13 +169,13 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
170
169
|
)}
|
|
171
170
|
</Show>
|
|
172
171
|
|
|
173
|
-
<Show when={node()
|
|
172
|
+
<Show when={node().content} keyed>
|
|
174
173
|
{content => <div class='p-3 select-none'>{content}</div>}
|
|
175
174
|
</Show>
|
|
176
175
|
|
|
177
|
-
<Show when={node()
|
|
176
|
+
<Show when={node().input || hasParent()}>
|
|
178
177
|
<div
|
|
179
|
-
id='
|
|
178
|
+
id='inputs'
|
|
180
179
|
class='pointer-events-none absolute top-0 z-10 flex cursor-default flex-col'
|
|
181
180
|
style={{ left: `-${HANDLE_CONTAINER_OFFSET_X}px` }}
|
|
182
181
|
>
|
|
@@ -206,7 +205,7 @@ export const NodeComponent: Component<Props> = props => {
|
|
|
206
205
|
</div>
|
|
207
206
|
</Show>
|
|
208
207
|
<div
|
|
209
|
-
id='
|
|
208
|
+
id='outputs'
|
|
210
209
|
class='pointer-events-none absolute top-0 z-10 flex flex-col'
|
|
211
210
|
style={{ right: `-${HANDLE_CONTAINER_OFFSET_X}px` }}
|
|
212
211
|
>
|
|
@@ -34,7 +34,6 @@ export const NodesBoard: Component = () => {
|
|
|
34
34
|
let containerRef: HTMLDivElement;
|
|
35
35
|
const [isPanning, setIsPanning] = createSignal(false);
|
|
36
36
|
const [transform, setTransform] = createSignal({ x: 0, y: 0 });
|
|
37
|
-
const [id, setId] = createSignal<string | number>('');
|
|
38
37
|
const [ref, setRef] = createSignal<HTMLDivElement | undefined>();
|
|
39
38
|
let percentX = 0;
|
|
40
39
|
let percentY = 0;
|
|
@@ -107,15 +106,6 @@ export const NodesBoard: Component = () => {
|
|
|
107
106
|
|
|
108
107
|
const selectedId = createState(service, { selector: s => s.context?.selected });
|
|
109
108
|
|
|
110
|
-
/**
|
|
111
|
-
* Determines whether the given element ID matches the currently selected entity.
|
|
112
|
-
*
|
|
113
|
-
* @param id - The node or edge identifier to check.
|
|
114
|
-
*
|
|
115
|
-
* @returns `true` if the item is currently selected, otherwise `false`.
|
|
116
|
-
*/
|
|
117
|
-
const selected = (id: string | number) => selectedId() === id;
|
|
118
|
-
|
|
119
109
|
const nodeIds = createState(service, {
|
|
120
110
|
selector: ({ context }) => {
|
|
121
111
|
const list = toArray.typed(context.data?.nodes);
|
|
@@ -149,44 +139,38 @@ export const NodesBoard: Component = () => {
|
|
|
149
139
|
>
|
|
150
140
|
<DragDropProvider
|
|
151
141
|
onDragMove={({ draggable: { transform: _transform, node, id } }) => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
`translate3d(${deltaX}px, ${deltaY}px, 0)`,
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
service.send({ type: 'MOVE_IMMEDIATE', payload: { id: `${id}`, x, y } });
|
|
184
|
-
setTransform({ x: deltaX * currentZoom, y: deltaY * currentZoom });
|
|
185
|
-
}
|
|
142
|
+
const grandParent = node.parentElement?.parentElement;
|
|
143
|
+
const currentZoom = zoom();
|
|
144
|
+
const minX = 0;
|
|
145
|
+
const maxX = grandParent
|
|
146
|
+
? Math.max(0, grandParent.clientWidth / currentZoom - node.offsetWidth)
|
|
147
|
+
: Infinity;
|
|
148
|
+
const minY = 0;
|
|
149
|
+
const maxY = grandParent
|
|
150
|
+
? Math.max(0, grandParent.clientHeight / currentZoom - node.offsetHeight)
|
|
151
|
+
: Infinity;
|
|
152
|
+
|
|
153
|
+
const targetX = node.offsetLeft + _transform.x / currentZoom;
|
|
154
|
+
const targetY = node.offsetTop + _transform.y / currentZoom;
|
|
155
|
+
|
|
156
|
+
const x = Math.min(Math.max(targetX, minX), maxX);
|
|
157
|
+
const y = Math.min(Math.max(targetY, minY), maxY);
|
|
158
|
+
|
|
159
|
+
const deltaX = x - node.offsetLeft;
|
|
160
|
+
const deltaY = y - node.offsetTop;
|
|
161
|
+
|
|
162
|
+
// Directly update the draggable node's CSS transform adjusted for zoom:
|
|
163
|
+
node.style.setProperty(
|
|
164
|
+
'transform',
|
|
165
|
+
`translate3d(${deltaX}px, ${deltaY}px, 0)`,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
service.send({ type: 'MOVE_IMMEDIATE', payload: { id: `${id}`, x, y } });
|
|
169
|
+
setTransform({ x: deltaX * currentZoom, y: deltaY * currentZoom });
|
|
186
170
|
}}
|
|
187
171
|
|
|
188
172
|
onDragEnd={({ draggable: { node, id } }) => {
|
|
189
|
-
if (!selected(id)) return;
|
|
173
|
+
// if (!selected(id)) return;
|
|
190
174
|
|
|
191
175
|
const grandParent = node.parentElement?.parentElement;
|
|
192
176
|
const currentZoom = zoom();
|
|
@@ -227,11 +211,12 @@ export const NodesBoard: Component = () => {
|
|
|
227
211
|
class='relative cursor-crosshair overflow-hidden'
|
|
228
212
|
classList={{ 'cursor-grabbing': isPanning() }}
|
|
229
213
|
style={{ height: cHeight(), width: cWidth() }}
|
|
230
|
-
onScroll={() => {}}
|
|
214
|
+
// onScroll={() => {}}
|
|
231
215
|
|
|
232
216
|
onMouseDown={e => {
|
|
233
217
|
if (newEdge() || e.button !== 0) return;
|
|
234
218
|
service.send('DESELECT');
|
|
219
|
+
setIsPanning(true);
|
|
235
220
|
|
|
236
221
|
// #region Props
|
|
237
222
|
const startX = e.clientX;
|
|
@@ -240,8 +225,6 @@ export const NodesBoard: Component = () => {
|
|
|
240
225
|
const startScrollTop = containerRef.scrollTop;
|
|
241
226
|
// #endregion
|
|
242
227
|
|
|
243
|
-
setIsPanning(true);
|
|
244
|
-
|
|
245
228
|
const handleMouseMove = (moveEvent: MouseEvent) => {
|
|
246
229
|
const dx = moveEvent.clientX - startX;
|
|
247
230
|
const dy = moveEvent.clientY - startY;
|
|
@@ -325,7 +308,7 @@ export const NodesBoard: Component = () => {
|
|
|
325
308
|
</svg>
|
|
326
309
|
</button>
|
|
327
310
|
</div>
|
|
328
|
-
<Show when={!
|
|
311
|
+
<Show when={!selectedId()}>
|
|
329
312
|
<DragOverlay children='' />
|
|
330
313
|
</Show>
|
|
331
314
|
</DragDropProvider>
|