@bemedev/mind-flow 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.cjs.js +1 -1
- package/lib/index.es.js +358 -357
- package/lib/output.css +1 -1
- package/lib/server.cjs.js +113 -80
- package/lib/server.es.js +113 -80
- package/lib/ui/components/EditPanel.d.ts.map +1 -1
- package/lib/ui/components/FlowChart.d.ts.map +1 -1
- package/lib/ui/components/NodeComponent.d.ts.map +1 -1
- package/lib/ui/components/Panels.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/ui/components/EditPanel.tsx +6 -1
- package/src/ui/components/FlowChart.tsx +65 -23
- package/src/ui/components/NodeComponent.tsx +3 -6
- package/src/ui/components/Panels.tsx +38 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditPanel.d.ts","sourceRoot":"","sources":["../../../src/ui/components/EditPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAQ,MAAM,UAAU,CAAC;AAE1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAK/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACrD,OAAO,cAAc,CAAC,CAAC,CAAC,KACvB,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"EditPanel.d.ts","sourceRoot":"","sources":["../../../src/ui/components/EditPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAQ,MAAM,UAAU,CAAC;AAE1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAK/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACrD,OAAO,cAAc,CAAC,CAAC,CAAC,KACvB,GAAG,CAAC,OAoEN,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowChart.d.ts","sourceRoot":"","sources":["../../../src/ui/components/FlowChart.tsx"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,GAAG,EAAsB,MAAM,UAAU,CAAC;AAGtE,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAG1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAIpC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACrD,OAAO,SAAS,CAAC,CAAC,CAAC,KAClB,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"FlowChart.d.ts","sourceRoot":"","sources":["../../../src/ui/components/FlowChart.tsx"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,GAAG,EAAsB,MAAM,UAAU,CAAC;AAGtE,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAG1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAIpC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACrD,OAAO,SAAS,CAAC,CAAC,CAAC,KAClB,GAAG,CAAC,OAuGN,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeComponent.d.ts","sourceRoot":"","sources":["../../../src/ui/components/NodeComponent.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAO,KAAK,GAAG,EAAQ,MAAM,UAAU,CAAC;AAQ/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAK/D,uEAAuE;AACvE,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IAC9D,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,iEAAiE;IACjE,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACzD,OAAO,kBAAkB,CAAC,CAAC,CAAC,KAC3B,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"NodeComponent.d.ts","sourceRoot":"","sources":["../../../src/ui/components/NodeComponent.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAO,KAAK,GAAG,EAAQ,MAAM,UAAU,CAAC;AAQ/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAK/D,uEAAuE;AACvE,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IAC9D,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,iEAAiE;IACjE,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACzD,OAAO,kBAAkB,CAAC,CAAC,CAAC,KAC3B,GAAG,CAAC,OA4NN,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Panels.d.ts","sourceRoot":"","sources":["../../../src/ui/components/Panels.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Panels.d.ts","sourceRoot":"","sources":["../../../src/ui/components/Panels.tsx"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAGhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiCpD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,CAAC,UAAU,CAQxC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bemedev/mind-flow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Flow Chart UI library for Solid.js applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"diagram",
|
|
@@ -65,13 +65,13 @@
|
|
|
65
65
|
"@bemedev/app": "^2.5.0",
|
|
66
66
|
"@bemedev/app-cli": "^2.5.0",
|
|
67
67
|
"@bemedev/app-solidjs": "^2.5.1",
|
|
68
|
-
"@bemedev/dev-utils": "^1.
|
|
68
|
+
"@bemedev/dev-utils": "^1.3.1",
|
|
69
69
|
"@rollup/plugin-babel": "^7.1.0",
|
|
70
70
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
71
71
|
"@size-limit/file": "^13.0.3",
|
|
72
72
|
"@tailwindcss/cli": "^4.3.3",
|
|
73
73
|
"@tailwindcss/vite": "^4.3.3",
|
|
74
|
-
"@types/node": "^26.
|
|
74
|
+
"@types/node": "^26.4.0",
|
|
75
75
|
"@vitest/coverage-v8": "^4.1.11",
|
|
76
76
|
"glob": "^13.0.6",
|
|
77
77
|
"globals": "^17.11.0",
|
|
@@ -113,7 +113,8 @@
|
|
|
113
113
|
"node": ">=22"
|
|
114
114
|
},
|
|
115
115
|
"scripts": {
|
|
116
|
-
"build": "pnpm rm:lib && pnpm run build:
|
|
116
|
+
"build": "pnpm rm:lib && pnpm run build:dev",
|
|
117
|
+
"build:dev": "pnpm run build:server && pnpm run build:client && pnpm run build:css",
|
|
117
118
|
"build:client": "vite build",
|
|
118
119
|
"build:server": "vite build --mode server",
|
|
119
120
|
"build:css": "pnpx @tailwindcss/cli -i ./input.css -o ../lib/output.css --minify --cwd ./src",
|
|
@@ -25,6 +25,7 @@ export const EditPanel = <D extends NodeData = NodeData>(
|
|
|
25
25
|
props: EditPanelProps<D>,
|
|
26
26
|
): JSX.Element => {
|
|
27
27
|
void clickOutside;
|
|
28
|
+
// const editing
|
|
28
29
|
const hooks = useHook<D>(props.timeout);
|
|
29
30
|
const classList = () =>
|
|
30
31
|
props.classList instanceof Function ? props.classList(hooks) : props.classList;
|
|
@@ -36,7 +37,11 @@ export const EditPanel = <D extends NodeData = NodeData>(
|
|
|
36
37
|
class={cn(
|
|
37
38
|
`w-80 cursor-default rounded-2xl border border-gray-200 bg-white/95 p-4 shadow-xl backdrop-blur-md transition-all ${props.class ?? ''}`,
|
|
38
39
|
)}
|
|
39
|
-
classList={
|
|
40
|
+
classList={{
|
|
41
|
+
...classList(),
|
|
42
|
+
'pointer-events-none! -z-10': !hooks.editing(),
|
|
43
|
+
'pointer-events-all! z-50': !!hooks.editing(),
|
|
44
|
+
}}
|
|
40
45
|
style={props.style}
|
|
41
46
|
onMouseDown={e => e.stopPropagation()}
|
|
42
47
|
use:clickOutside={hooks.close}
|
|
@@ -32,7 +32,9 @@ export const FlowChart = <D extends NodeData = NodeData>(
|
|
|
32
32
|
const primaryNodes = props.config?.nodes ?? DEFAULT_NODES;
|
|
33
33
|
const primaryEdges = props.config?.edges;
|
|
34
34
|
const service = useFlow();
|
|
35
|
-
const
|
|
35
|
+
const fromSignal = createState(service, {
|
|
36
|
+
selector: s => s.context.newEdge?.from,
|
|
37
|
+
});
|
|
36
38
|
onCleanup(service.pause);
|
|
37
39
|
|
|
38
40
|
onMount(() => {
|
|
@@ -47,33 +49,73 @@ export const FlowChart = <D extends NodeData = NodeData>(
|
|
|
47
49
|
});
|
|
48
50
|
});
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
52
|
+
let added = false;
|
|
53
|
+
|
|
54
|
+
// Track the currently enlarged handle during edge drag
|
|
55
|
+
let activeHandle: HTMLElement | null = null;
|
|
56
|
+
|
|
57
|
+
const clearActiveHandle = () => {
|
|
58
|
+
if (activeHandle) {
|
|
59
|
+
activeHandle.classList.remove('scale-150');
|
|
60
|
+
activeHandle = null;
|
|
61
|
+
added = false;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const handlePointerMove = (e: MouseEvent | PointerEvent) => {
|
|
66
|
+
service.send({ type: 'MOVE_NEW_EDGE', payload: { x: e.clientX, y: e.clientY } });
|
|
67
|
+
|
|
68
|
+
const elements = document.elementsFromPoint(e.clientX, e.clientY);
|
|
69
|
+
const inputHandle = elements
|
|
70
|
+
.map(el => el.closest<HTMLElement>('.rounded-full[data-handle-type="input"]'))
|
|
71
|
+
.find((handle): handle is HTMLElement =>
|
|
72
|
+
Boolean(handle && handle.id !== 'inputs'),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// If cursor moved away from previous handle, reset its scale
|
|
76
|
+
if (activeHandle && activeHandle !== inputHandle) {
|
|
77
|
+
clearActiveHandle();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// If cursor entered a valid target handle, enlarge it
|
|
81
|
+
if (inputHandle) {
|
|
82
|
+
if (activeHandle !== inputHandle) {
|
|
83
|
+
inputHandle.classList.add('scale-150');
|
|
84
|
+
activeHandle = inputHandle;
|
|
85
|
+
added = true;
|
|
69
86
|
}
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const createHandlePointerUp = (from: string) => (e: MouseEvent | PointerEvent) => {
|
|
91
|
+
const elements = document.elementsFromPoint(e.clientX, e.clientY);
|
|
92
|
+
const inputHandle = elements
|
|
93
|
+
.map(el => el.closest<HTMLElement>('.rounded-full[data-handle-type="input"]'))
|
|
94
|
+
.find((handle): handle is HTMLElement =>
|
|
95
|
+
Boolean(handle && handle.id !== 'inputs'),
|
|
96
|
+
);
|
|
97
|
+
const to = inputHandle?.getAttribute('data-node-id');
|
|
98
|
+
|
|
99
|
+
if (inputHandle && to) {
|
|
100
|
+
service.send({ type: 'ADD_EDGE', payload: { from, to } });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Cleanup on release
|
|
104
|
+
clearActiveHandle();
|
|
105
|
+
service.send('CLEAR_NEW_EDGE');
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
createEffect(() => {
|
|
109
|
+
const from = fromSignal();
|
|
110
|
+
if (!from || added) return;
|
|
72
111
|
|
|
112
|
+
const handlePointerUp = createHandlePointerUp(from);
|
|
73
113
|
window.addEventListener('pointermove', handlePointerMove);
|
|
74
114
|
window.addEventListener('pointerup', handlePointerUp);
|
|
75
115
|
|
|
76
116
|
onCleanup(() => {
|
|
117
|
+
// Cleanup on effect disposal
|
|
118
|
+
clearActiveHandle();
|
|
77
119
|
window.removeEventListener('pointermove', handlePointerMove);
|
|
78
120
|
window.removeEventListener('pointerup', handlePointerUp);
|
|
79
121
|
});
|
|
@@ -83,7 +125,7 @@ export const FlowChart = <D extends NodeData = NodeData>(
|
|
|
83
125
|
<div class='relative h-full w-full'>
|
|
84
126
|
<div
|
|
85
127
|
class='h-full w-full'
|
|
86
|
-
style={{ cursor:
|
|
128
|
+
style={{ cursor: fromSignal() ? 'inherit' : 'crosshair' }}
|
|
87
129
|
>
|
|
88
130
|
<NodesBoard panels={props.panels} component={props.component} />
|
|
89
131
|
</div>
|
|
@@ -200,8 +200,6 @@ export const NodeComponent = <D extends NodeData = NodeData>(
|
|
|
200
200
|
|
|
201
201
|
<div
|
|
202
202
|
id='inputs'
|
|
203
|
-
data-handle-type='input'
|
|
204
|
-
data-node-id={props.id}
|
|
205
203
|
class='pointer-events-none absolute top-0 z-10 flex cursor-default flex-col'
|
|
206
204
|
style={{ left: `-${HANDLE_CONTAINER_OFFSET_X}px` }}
|
|
207
205
|
>
|
|
@@ -211,7 +209,7 @@ export const NodeComponent = <D extends NodeData = NodeData>(
|
|
|
211
209
|
onMouseDown={event => event.stopPropagation()}
|
|
212
210
|
onPointerDown={e => e.stopPropagation()}
|
|
213
211
|
|
|
214
|
-
class='cursor-default rounded-full bg-[#e38b29] shadow-md transition-transform'
|
|
212
|
+
class='cursor-default rounded-full bg-[#e38b29] shadow-md transition-transform duration-150 ease-in-out hover:scale-150'
|
|
215
213
|
|
|
216
214
|
style={{
|
|
217
215
|
width: `${HANDLE_SIZE}px`,
|
|
@@ -233,8 +231,7 @@ export const NodeComponent = <D extends NodeData = NodeData>(
|
|
|
233
231
|
</div>
|
|
234
232
|
<div
|
|
235
233
|
id='outputs'
|
|
236
|
-
|
|
237
|
-
data-node-id={props.id}
|
|
234
|
+
|
|
238
235
|
style={{ right: `-${HANDLE_CONTAINER_OFFSET_X}px` }}
|
|
239
236
|
|
|
240
237
|
class='pointer-events-none absolute top-0 z-10 flex flex-col'
|
|
@@ -242,7 +239,7 @@ export const NodeComponent = <D extends NodeData = NodeData>(
|
|
|
242
239
|
<div
|
|
243
240
|
data-handle-type='output'
|
|
244
241
|
data-node-id={props.id}
|
|
245
|
-
class='cursor-crosshair rounded-full bg-[#e38b29] shadow-md transition-transform'
|
|
242
|
+
class='cursor-crosshair rounded-full bg-[#e38b29] shadow-md transition-transform duration-150 ease-in-out hover:scale-150'
|
|
246
243
|
style={{
|
|
247
244
|
width: `${HANDLE_SIZE}px`,
|
|
248
245
|
height: `${HANDLE_SIZE}px`,
|
|
@@ -1,7 +1,40 @@
|
|
|
1
|
+
import { isDefined } from '@bemedev/app/bemedev';
|
|
1
2
|
import { Show, type Component } from 'solid-js';
|
|
2
3
|
|
|
4
|
+
import { cn } from '../utils';
|
|
3
5
|
import type { FlowPanels } from './FlowChart.types';
|
|
4
6
|
|
|
7
|
+
/** Properties for the internal {@linkcode Panel} wrapper component. */
|
|
8
|
+
type PanelProps = {
|
|
9
|
+
/** Optional component to render inside the panel container. */
|
|
10
|
+
children?: Component;
|
|
11
|
+
/** CSS class names for positioning and layout. */
|
|
12
|
+
class: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Overlay slot component rendering an optional panel component with z-index
|
|
17
|
+
* positioning.
|
|
18
|
+
*
|
|
19
|
+
* @param props - Panel properties of type {@linkcode PanelProps}.
|
|
20
|
+
*
|
|
21
|
+
* @returns The rendered panel container element or fallback.
|
|
22
|
+
*
|
|
23
|
+
* @see {@linkcode cn}
|
|
24
|
+
*/
|
|
25
|
+
const Panel: Component<PanelProps> = props => {
|
|
26
|
+
const exists = isDefined(props.children);
|
|
27
|
+
return (
|
|
28
|
+
<Show when={props.children} keyed>
|
|
29
|
+
{Children => (
|
|
30
|
+
<div class={cn(props.class)} classList={{ 'z-50': exists }}>
|
|
31
|
+
<Children />
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
</Show>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
5
38
|
/**
|
|
6
39
|
* Overlay container rendering custom panel slots positioned around the flowchart
|
|
7
40
|
* canvas.
|
|
@@ -12,20 +45,10 @@ import type { FlowPanels } from './FlowChart.types';
|
|
|
12
45
|
*/
|
|
13
46
|
export const Panels: Component<FlowPanels> = props => {
|
|
14
47
|
return (
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{/* Top-Right Panel */}
|
|
21
|
-
<Show when={props.topRight} keyed>
|
|
22
|
-
{Panel => <div class='absolute top-4 right-4 z-50'>{<Panel />}</div>}
|
|
23
|
-
</Show>
|
|
24
|
-
|
|
25
|
-
{/* Bottom-Left Panel */}
|
|
26
|
-
<Show when={props.bottomLeft} keyed>
|
|
27
|
-
{Panel => <div class='absolute bottom-4 left-4 z-50'>{<Panel />}</div>}
|
|
28
|
-
</Show>
|
|
29
|
-
</>
|
|
48
|
+
<div class='pointer-events-none absolute inset-0'>
|
|
49
|
+
<Panel children={props.topLeft} class='absolute top-4 left-4' />
|
|
50
|
+
<Panel children={props.topRight} class='absolute top-4 right-4' />
|
|
51
|
+
<Panel children={props.bottomLeft} class='absolute bottom-4 left-4' />
|
|
52
|
+
</div>
|
|
30
53
|
);
|
|
31
54
|
};
|