@bemedev/mind-flow 1.3.0 → 1.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Flow.d.ts","sourceRoot":"","sources":["../../src/ui/Flow.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAG9D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAChD,OAAO,SAAS,CAAC,CAAC,CAAC,KAClB,GAAG,CAAC,OAkCN,CAAC"}
1
+ {"version":3,"file":"Flow.d.ts","sourceRoot":"","sources":["../../src/ui/Flow.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAChD,OAAO,SAAS,CAAC,CAAC,CAAC,KAClB,GAAG,CAAC,OAeN,CAAC"}
@@ -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,OA+DN,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,OA6DN,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"}
@@ -15,8 +15,8 @@ export type FlowPanels = {
15
15
  * Configuration options and callback handlers for the {@linkcode FlowChart}
16
16
  * component.
17
17
  *
18
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
19
- * {@linkcode NodeData}.
18
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
19
+ * extending type {@linkcode NodeData}.
20
20
  */
21
21
  export type FlowProps<D extends NodeData = NodeData> = {
22
22
  /** Optional delay in milliseconds before mounting the flowchart canvas. */
@@ -64,24 +64,24 @@ export type FlowProps<D extends NodeData = NodeData> = {
64
64
  /**
65
65
  * Type alias extracting the non-undefined flowchart configuration object.
66
66
  *
67
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
68
- * {@linkcode NodeData}.
67
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
68
+ * extending type {@linkcode NodeData}.
69
69
  */
70
70
  export type ConfigFrom<D extends NodeData = NodeData> = NotUndefined<FlowProps<D>['config']>;
71
71
  /**
72
72
  * Type alias extracting the non-undefined list of nodes from flowchart
73
73
  * configuration.
74
74
  *
75
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
76
- * {@linkcode NodeData}.
75
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
76
+ * extending type {@linkcode NodeData}.
77
77
  */
78
78
  export type NodesFrom<D extends NodeData> = NotUndefined<ConfigFrom<D>['nodes']>;
79
79
  /**
80
80
  * Type alias extracting the non-undefined list of edges from flowchart
81
81
  * configuration.
82
82
  *
83
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
84
- * {@linkcode NodeData}.
83
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
84
+ * extending type {@linkcode NodeData}.
85
85
  */
86
86
  export type EdgesFrom<D extends NodeData> = NotUndefined<ConfigFrom<D>['edges']>;
87
87
  //# sourceMappingURL=FlowChart.types.d.ts.map
@@ -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,OA+NN,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":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,CAAC,UAAU,CAkBxC,CAAC"}
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.0",
3
+ "version": "1.4.1",
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.2.0",
68
+ "@bemedev/dev-utils": "^1.5.0",
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.3.0",
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:server && pnpm run build:client && pnpm run build:css",
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",
package/src/ui/Flow.tsx CHANGED
@@ -1,33 +1,27 @@
1
- import { createSignal, onMount, Show, type JSX } from 'solid-js';
2
- import {} from 'solid-js/web';
1
+ import { type JSX } from 'solid-js';
3
2
 
4
3
  import type { NodeData } from '../services/main.machine.typings';
5
4
  import { FlowChart } from './components/FlowChart';
6
5
  import { Provider } from './components/FlowChart.context';
7
6
  import type { FlowProps } from './components/FlowChart.types';
8
- import { LoadingFallback } from './globals/components/organisms/LoadingFallback';
9
7
 
10
8
  /**
11
9
  * Root Flow component wrapping the {@linkcode FlowChart} inside the flow context
12
10
  * provider.
13
11
  *
14
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
15
- * {@linkcode NodeData}.
12
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
13
+ * extending type {@linkcode NodeData}.
16
14
  *
17
15
  * @param props - Flow chart configuration and callbacks of type
18
16
  * {@linkcode FlowProps}.
19
17
  *
20
18
  * @returns The rendered Solid component.
21
19
  *
22
- * @see {@linkcode Provider}, {@linkcode FlowChart}
20
+ * @see {@linkcode Provider}
23
21
  */
24
22
  export const Flow = <D extends NodeData = NodeData>(
25
23
  props: FlowProps<D>,
26
24
  ): JSX.Element => {
27
- const [isMounted, setIsMounted] = createSignal(false);
28
-
29
- // onMount never runs on the server, only in the browser
30
- onMount(() => setTimeout(() => setIsMounted(true), props.delay));
31
25
  return (
32
26
  <div
33
27
  style={{
@@ -37,24 +31,9 @@ export const Flow = <D extends NodeData = NodeData>(
37
31
 
38
32
  class='relative flex h-full w-full rounded-lg border-2 border-gray-600 bg-white bg-size-[30px_30px]'
39
33
  >
40
- <Show
41
- when={isMounted()}
42
- keyed
43
- fallback={
44
- <div class='relative flex flex-1 items-center justify-center'>
45
- <LoadingFallback
46
- message='Chart is loading...'
47
- interval={35}
48
- rewind
49
- rewindDelay={1_000}
50
- />
51
- </div>
52
- }
53
- >
54
- <Provider>
55
- <FlowChart {...props} />
56
- </Provider>
57
- </Show>
34
+ <Provider>
35
+ <FlowChart {...props} />
36
+ </Provider>
58
37
  </div>
59
38
  );
60
39
  };
@@ -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={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 hasNewEdge = createState(service, { selector: s => !!s.context.newEdge });
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
- createEffect(() => {
51
- if (!hasNewEdge()) return;
52
-
53
- const handlePointerMove = (e: MouseEvent | PointerEvent) => {
54
- service.send({
55
- type: 'MOVE_NEW_EDGE',
56
- payload: { x: e.clientX, y: e.clientY },
57
- });
58
- };
59
-
60
- const handlePointerUp = (e: MouseEvent | PointerEvent) => {
61
- const from = service.state.context.newEdge?.from;
62
- if (from) {
63
- const el = document.elementFromPoint(e.clientX, e.clientY);
64
- const inputHandle = el?.closest('[data-handle-type="input"]');
65
- const targetId = inputHandle?.getAttribute('data-node-id');
66
- if (targetId && targetId !== from) {
67
- service.send({ type: 'ADD_EDGE', payload: { from, to: targetId } });
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
- service.send('CLEAR_NEW_EDGE');
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: hasNewEdge() ? 'inherit' : 'crosshair' }}
128
+ style={{ cursor: fromSignal() ? 'inherit' : 'crosshair' }}
87
129
  >
88
130
  <NodesBoard panels={props.panels} component={props.component} />
89
131
  </div>
@@ -19,8 +19,8 @@ export type FlowPanels = {
19
19
  * Configuration options and callback handlers for the {@linkcode FlowChart}
20
20
  * component.
21
21
  *
22
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
23
- * {@linkcode NodeData}.
22
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
23
+ * extending type {@linkcode NodeData}.
24
24
  */
25
25
  export type FlowProps<D extends NodeData = NodeData> = {
26
26
  /** Optional delay in milliseconds before mounting the flowchart canvas. */
@@ -66,8 +66,8 @@ export type FlowProps<D extends NodeData = NodeData> = {
66
66
  /**
67
67
  * Type alias extracting the non-undefined flowchart configuration object.
68
68
  *
69
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
70
- * {@linkcode NodeData}.
69
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
70
+ * extending type {@linkcode NodeData}.
71
71
  */
72
72
  export type ConfigFrom<D extends NodeData = NodeData> = NotUndefined<
73
73
  FlowProps<D>['config']
@@ -77,8 +77,8 @@ export type ConfigFrom<D extends NodeData = NodeData> = NotUndefined<
77
77
  * Type alias extracting the non-undefined list of nodes from flowchart
78
78
  * configuration.
79
79
  *
80
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
81
- * {@linkcode NodeData}.
80
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
81
+ * extending type {@linkcode NodeData}.
82
82
  */
83
83
  export type NodesFrom<D extends NodeData> = NotUndefined<ConfigFrom<D>['nodes']>;
84
84
 
@@ -86,7 +86,7 @@ export type NodesFrom<D extends NodeData> = NotUndefined<ConfigFrom<D>['nodes']>
86
86
  * Type alias extracting the non-undefined list of edges from flowchart
87
87
  * configuration.
88
88
  *
89
- * @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
90
- * {@linkcode NodeData}.
89
+ * @template | Type {@linkcode NodeData} `D` - Custom node data dictionary type
90
+ * extending type {@linkcode NodeData}.
91
91
  */
92
92
  export type EdgesFrom<D extends NodeData> = NotUndefined<ConfigFrom<D>['edges']>;
@@ -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
- data-handle-type='output'
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
- <Show when={props.topLeft} keyed>
17
- {Panel => <div class='absolute top-4 left-4 z-50'>{<Panel />}</div>}
18
- </Show>
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
  };