@principal-ai/principal-view-react 0.6.9 → 0.6.11
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/README.md +2 -5
- package/dist/components/ConfigurationSelector.js +4 -2
- package/dist/components/ConfigurationSelector.js.map +1 -1
- package/dist/components/EdgeInfoPanel.d.ts.map +1 -1
- package/dist/components/EdgeInfoPanel.js +43 -13
- package/dist/components/EdgeInfoPanel.js.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +135 -82
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/NodeInfoPanel.d.ts.map +1 -1
- package/dist/components/NodeInfoPanel.js +143 -45
- package/dist/components/NodeInfoPanel.js.map +1 -1
- package/dist/edges/CustomEdge.d.ts.map +1 -1
- package/dist/edges/CustomEdge.js +2 -2
- package/dist/edges/CustomEdge.js.map +1 -1
- package/dist/edges/GenericEdge.d.ts.map +1 -1
- package/dist/edges/GenericEdge.js +2 -2
- package/dist/edges/GenericEdge.js.map +1 -1
- package/dist/hooks/usePathBasedEvents.d.ts +1 -1
- package/dist/hooks/usePathBasedEvents.d.ts.map +1 -1
- package/dist/hooks/usePathBasedEvents.js +9 -9
- package/dist/hooks/usePathBasedEvents.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/nodes/CustomNode.d.ts.map +1 -1
- package/dist/nodes/CustomNode.js +61 -44
- package/dist/nodes/CustomNode.js.map +1 -1
- package/dist/nodes/GenericNode.d.ts.map +1 -1
- package/dist/nodes/GenericNode.js.map +1 -1
- package/dist/utils/animationMapping.d.ts.map +1 -1
- package/dist/utils/animationMapping.js +12 -12
- package/dist/utils/animationMapping.js.map +1 -1
- package/dist/utils/graphConverter.d.ts.map +1 -1
- package/dist/utils/graphConverter.js +23 -17
- package/dist/utils/graphConverter.js.map +1 -1
- package/dist/utils/iconResolver.d.ts.map +1 -1
- package/dist/utils/iconResolver.js +1 -1
- package/dist/utils/iconResolver.js.map +1 -1
- package/package.json +2 -1
- package/src/components/ConfigurationSelector.tsx +5 -5
- package/src/components/EdgeInfoPanel.tsx +79 -37
- package/src/components/GraphRenderer.tsx +528 -364
- package/src/components/NodeInfoPanel.tsx +209 -86
- package/src/edges/CustomEdge.tsx +6 -4
- package/src/edges/GenericEdge.tsx +2 -6
- package/src/hooks/usePathBasedEvents.ts +54 -45
- package/src/index.ts +11 -2
- package/src/nodes/CustomNode.tsx +132 -106
- package/src/nodes/GenericNode.tsx +4 -3
- package/src/stories/AnimationWorkshop.stories.tsx +131 -12
- package/src/stories/CanvasNodeTypes.stories.tsx +898 -0
- package/src/stories/ColorPriority.stories.tsx +20 -10
- package/src/stories/EventDrivenAnimations.stories.tsx +8 -0
- package/src/stories/EventLog.stories.tsx +1 -1
- package/src/stories/GraphRenderer.stories.tsx +23 -10
- package/src/stories/IndustryThemes.stories.tsx +481 -0
- package/src/stories/MultiConfig.stories.tsx +8 -0
- package/src/stories/MultiDirectionalConnections.stories.tsx +8 -0
- package/src/stories/NodeFieldsAudit.stories.tsx +124 -37
- package/src/stories/NodeShapes.stories.tsx +73 -59
- package/src/utils/animationMapping.ts +19 -23
- package/src/utils/graphConverter.ts +35 -19
- package/src/utils/iconResolver.tsx +5 -1
|
@@ -10,14 +10,14 @@ import type {
|
|
|
10
10
|
ComponentActivityEvent,
|
|
11
11
|
ComponentActionEvent,
|
|
12
12
|
EdgeAnimationEvent,
|
|
13
|
-
PathBasedEvent
|
|
13
|
+
PathBasedEvent,
|
|
14
14
|
} from '@principal-ai/principal-view-core';
|
|
15
15
|
import {
|
|
16
16
|
logLevelToNodeAnimation,
|
|
17
17
|
actionToNodeAnimation,
|
|
18
18
|
actionToEdgeAnimation,
|
|
19
19
|
type NodeAnimation,
|
|
20
|
-
type EdgeAnimation
|
|
20
|
+
type EdgeAnimation,
|
|
21
21
|
} from '../utils/animationMapping';
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -52,53 +52,62 @@ export function usePathBasedEvents({
|
|
|
52
52
|
events,
|
|
53
53
|
callbacks,
|
|
54
54
|
onEventProcessed,
|
|
55
|
-
minLogLevel = 'info'
|
|
55
|
+
minLogLevel = 'info',
|
|
56
56
|
}: UsePathBasedEventsOptions): void {
|
|
57
57
|
const { onNodeAnimation, onEdgeAnimation } = callbacks;
|
|
58
58
|
|
|
59
59
|
// Process component activity events (Milestone 1)
|
|
60
|
-
const processActivityEvent = useCallback(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
const processActivityEvent = useCallback(
|
|
61
|
+
(event: ComponentActivityEvent) => {
|
|
62
|
+
// Map log level to animation
|
|
63
|
+
const animation = logLevelToNodeAnimation(event.level);
|
|
64
|
+
|
|
65
|
+
// Trigger node animation
|
|
66
|
+
onNodeAnimation(event.componentId, {
|
|
67
|
+
...animation,
|
|
68
|
+
timestamp: event.timestamp,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
onEventProcessed?.(event);
|
|
72
|
+
},
|
|
73
|
+
[onNodeAnimation, onEventProcessed]
|
|
74
|
+
);
|
|
72
75
|
|
|
73
76
|
// Process component action events (Milestone 2)
|
|
74
|
-
const processActionEvent = useCallback(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
const processActionEvent = useCallback(
|
|
78
|
+
(event: ComponentActionEvent) => {
|
|
79
|
+
// Map action/state to animation
|
|
80
|
+
const animation = actionToNodeAnimation(event.action, event.state);
|
|
81
|
+
|
|
82
|
+
// Trigger node animation
|
|
83
|
+
onNodeAnimation(event.componentId, {
|
|
84
|
+
...animation,
|
|
85
|
+
timestamp: event.timestamp,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
onEventProcessed?.(event);
|
|
89
|
+
},
|
|
90
|
+
[onNodeAnimation, onEventProcessed]
|
|
91
|
+
);
|
|
86
92
|
|
|
87
93
|
// Process edge animation events (Milestone 2)
|
|
88
|
-
const processEdgeAnimationEvent = useCallback(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
const processEdgeAnimationEvent = useCallback(
|
|
95
|
+
(event: EdgeAnimationEvent) => {
|
|
96
|
+
const animation = actionToEdgeAnimation(event.triggeredBy?.action || 'unknown', {
|
|
97
|
+
type: event.animation,
|
|
98
|
+
duration: event.duration,
|
|
99
|
+
direction: event.direction,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
onEdgeAnimation(event.edgeId, {
|
|
103
|
+
...animation,
|
|
104
|
+
timestamp: event.timestamp,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
onEventProcessed?.(event);
|
|
108
|
+
},
|
|
109
|
+
[onEdgeAnimation, onEventProcessed]
|
|
110
|
+
);
|
|
102
111
|
|
|
103
112
|
// Process events when they change
|
|
104
113
|
useEffect(() => {
|
|
@@ -149,7 +158,7 @@ export function processBatchEvents(
|
|
|
149
158
|
const animation = logLevelToNodeAnimation(event.level);
|
|
150
159
|
callbacks.onNodeAnimation(event.componentId, {
|
|
151
160
|
...animation,
|
|
152
|
-
timestamp: event.timestamp
|
|
161
|
+
timestamp: event.timestamp,
|
|
153
162
|
});
|
|
154
163
|
}
|
|
155
164
|
break;
|
|
@@ -159,7 +168,7 @@ export function processBatchEvents(
|
|
|
159
168
|
const animation = actionToNodeAnimation(event.action, event.state);
|
|
160
169
|
callbacks.onNodeAnimation(event.componentId, {
|
|
161
170
|
...animation,
|
|
162
|
-
timestamp: event.timestamp
|
|
171
|
+
timestamp: event.timestamp,
|
|
163
172
|
});
|
|
164
173
|
}
|
|
165
174
|
break;
|
|
@@ -169,11 +178,11 @@ export function processBatchEvents(
|
|
|
169
178
|
const animation = actionToEdgeAnimation(event.triggeredBy?.action || 'unknown', {
|
|
170
179
|
type: event.animation,
|
|
171
180
|
duration: event.duration,
|
|
172
|
-
direction: event.direction
|
|
181
|
+
direction: event.direction,
|
|
173
182
|
});
|
|
174
183
|
callbacks.onEdgeAnimation(event.edgeId, {
|
|
175
184
|
...animation,
|
|
176
|
-
timestamp: event.timestamp
|
|
185
|
+
timestamp: event.timestamp,
|
|
177
186
|
});
|
|
178
187
|
}
|
|
179
188
|
break;
|
package/src/index.ts
CHANGED
|
@@ -30,7 +30,12 @@ export type {
|
|
|
30
30
|
|
|
31
31
|
// Export components
|
|
32
32
|
export { GraphRenderer } from './components/GraphRenderer';
|
|
33
|
-
export type {
|
|
33
|
+
export type {
|
|
34
|
+
GraphRendererProps,
|
|
35
|
+
GraphRendererHandle,
|
|
36
|
+
NodePositionChange,
|
|
37
|
+
PendingChanges,
|
|
38
|
+
} from './components/GraphRenderer';
|
|
34
39
|
|
|
35
40
|
export { EventLog } from './components/EventLog';
|
|
36
41
|
export type { EventLogProps } from './components/EventLog';
|
|
@@ -61,7 +66,11 @@ export { CustomEdge } from './edges/CustomEdge';
|
|
|
61
66
|
export type { CustomEdgeData } from './edges/CustomEdge';
|
|
62
67
|
|
|
63
68
|
// Export utilities
|
|
64
|
-
export {
|
|
69
|
+
export {
|
|
70
|
+
convertToXYFlowNodes,
|
|
71
|
+
convertToXYFlowEdges,
|
|
72
|
+
autoLayoutNodes,
|
|
73
|
+
} from './utils/graphConverter';
|
|
65
74
|
export type { EdgeStateWithHandles } from './utils/graphConverter';
|
|
66
75
|
export { Icon, resolveIcon } from './utils/iconResolver';
|
|
67
76
|
export type { IconProps } from './utils/iconResolver';
|
package/src/nodes/CustomNode.tsx
CHANGED
|
@@ -37,9 +37,7 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
37
37
|
if (!typeDefinition) {
|
|
38
38
|
return (
|
|
39
39
|
<div style={{ padding: '10px', border: '2px solid red', borderRadius: '4px' }}>
|
|
40
|
-
<div style={{ fontSize: '12px', color: 'red' }}>
|
|
41
|
-
Error: Missing node type definition
|
|
42
|
-
</div>
|
|
40
|
+
<div style={{ fontSize: '12px', color: 'red' }}>Error: Missing node type definition</div>
|
|
43
41
|
</div>
|
|
44
42
|
);
|
|
45
43
|
}
|
|
@@ -49,8 +47,11 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
49
47
|
const nodeDataColor = nodeData.color as string | undefined;
|
|
50
48
|
const baseColor = nodeDataColor || typeDefinition.color || '#888';
|
|
51
49
|
// Check node's own states first (from pv.states), then fall back to type definition states
|
|
52
|
-
const nodeDataStates = nodeData.states as
|
|
53
|
-
|
|
50
|
+
const nodeDataStates = nodeData.states as
|
|
51
|
+
| Record<string, { color?: string; label?: string; icon?: string }>
|
|
52
|
+
| undefined;
|
|
53
|
+
const stateColor =
|
|
54
|
+
state && (nodeDataStates?.[state]?.color || typeDefinition.states?.[state]?.color);
|
|
54
55
|
const fillColor = stateColor || baseColor;
|
|
55
56
|
|
|
56
57
|
// Get stroke color - priority: node data stroke > type definition stroke > fill color
|
|
@@ -64,9 +65,10 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
64
65
|
const displayName = nodeProps.name;
|
|
65
66
|
|
|
66
67
|
// Icon priority: node data override > state icon (node data states first) > type definition icon
|
|
67
|
-
const icon =
|
|
68
|
-
|
|
69
|
-
|| typeDefinition.icon
|
|
68
|
+
const icon =
|
|
69
|
+
(nodeData.icon as string) ||
|
|
70
|
+
(state && (nodeDataStates?.[state]?.icon || typeDefinition.states?.[state]?.icon)) ||
|
|
71
|
+
typeDefinition.icon;
|
|
70
72
|
|
|
71
73
|
// Get animation class based on type
|
|
72
74
|
const getAnimationClass = () => {
|
|
@@ -86,11 +88,14 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
86
88
|
|
|
87
89
|
const animationClass = getAnimationClass();
|
|
88
90
|
|
|
91
|
+
// Check if this is a group node
|
|
92
|
+
const isGroup = nodeData.canvasType === 'group';
|
|
93
|
+
|
|
89
94
|
// Shape-specific styles
|
|
90
95
|
const getShapeStyles = () => {
|
|
91
96
|
const baseStyles = {
|
|
92
97
|
padding: '12px 16px',
|
|
93
|
-
backgroundColor: 'white',
|
|
98
|
+
backgroundColor: isGroup ? 'rgba(255, 255, 255, 0.7)' : 'white',
|
|
94
99
|
color: '#000',
|
|
95
100
|
border: `2px solid ${hasViolations ? '#D0021B' : strokeColor}`,
|
|
96
101
|
fontSize: '12px',
|
|
@@ -100,7 +105,7 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
100
105
|
display: 'flex',
|
|
101
106
|
flexDirection: 'column' as const,
|
|
102
107
|
alignItems: 'center',
|
|
103
|
-
justifyContent: 'center',
|
|
108
|
+
justifyContent: isGroup ? 'flex-start' : 'center',
|
|
104
109
|
gap: '4px',
|
|
105
110
|
boxShadow: selected ? `0 0 0 2px ${strokeColor}` : '0 2px 4px rgba(0,0,0,0.1)',
|
|
106
111
|
transition: 'all 0.2s ease',
|
|
@@ -156,47 +161,53 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
156
161
|
// Hexagon with gentle diagonals
|
|
157
162
|
const hexagonClipPath = 'polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)';
|
|
158
163
|
const hexagonBorderWidth = 2;
|
|
159
|
-
const hexagonBorderStyle: React.CSSProperties = isHexagon
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
const hexagonBorderStyle: React.CSSProperties = isHexagon
|
|
165
|
+
? {
|
|
166
|
+
position: 'relative',
|
|
167
|
+
clipPath: hexagonClipPath,
|
|
168
|
+
backgroundColor: hasViolations ? '#D0021B' : strokeColor,
|
|
169
|
+
width: typeDefinition.size?.width || 120,
|
|
170
|
+
height: typeDefinition.size?.height || 120,
|
|
171
|
+
boxShadow: selected ? `0 0 0 2px ${strokeColor}` : '0 2px 4px rgba(0,0,0,0.1)',
|
|
172
|
+
transition: 'all 0.2s ease',
|
|
173
|
+
}
|
|
174
|
+
: {};
|
|
168
175
|
|
|
169
176
|
// Hexagon inner fill styles (white background inset from border)
|
|
170
|
-
const hexagonInnerStyle: React.CSSProperties = isHexagon
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
177
|
+
const hexagonInnerStyle: React.CSSProperties = isHexagon
|
|
178
|
+
? {
|
|
179
|
+
position: 'absolute',
|
|
180
|
+
top: hexagonBorderWidth,
|
|
181
|
+
left: hexagonBorderWidth,
|
|
182
|
+
right: hexagonBorderWidth,
|
|
183
|
+
bottom: hexagonBorderWidth,
|
|
184
|
+
clipPath: hexagonClipPath,
|
|
185
|
+
backgroundColor: 'white',
|
|
186
|
+
color: '#000',
|
|
187
|
+
display: 'flex',
|
|
188
|
+
flexDirection: 'column',
|
|
189
|
+
alignItems: 'center',
|
|
190
|
+
justifyContent: 'center',
|
|
191
|
+
fontSize: '12px',
|
|
192
|
+
fontWeight: 500,
|
|
193
|
+
gap: '4px',
|
|
194
|
+
}
|
|
195
|
+
: {};
|
|
187
196
|
|
|
188
197
|
// Handle styles - larger and more visible in edit mode
|
|
189
|
-
const baseHandleStyle = editable
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
const baseHandleStyle = editable
|
|
199
|
+
? {
|
|
200
|
+
background: color,
|
|
201
|
+
width: 12,
|
|
202
|
+
height: 12,
|
|
203
|
+
border: '2px solid white',
|
|
204
|
+
boxShadow: '0 0 0 1px ' + color,
|
|
205
|
+
}
|
|
206
|
+
: {
|
|
207
|
+
background: color,
|
|
208
|
+
width: 8,
|
|
209
|
+
height: 8,
|
|
210
|
+
};
|
|
200
211
|
|
|
201
212
|
// Diamond handles need to be offset to reach the tips of the rotated shape
|
|
202
213
|
// A 45° rotated square has tips at ~41% beyond the original edges
|
|
@@ -235,51 +246,42 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
235
246
|
return (
|
|
236
247
|
<>
|
|
237
248
|
{/* Input handles - multiple connection points */}
|
|
238
|
-
<Handle
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
id="top"
|
|
242
|
-
style={getHandleStyle('top')}
|
|
243
|
-
/>
|
|
244
|
-
<Handle
|
|
245
|
-
type="target"
|
|
246
|
-
position={Position.Left}
|
|
247
|
-
id="left"
|
|
248
|
-
style={getHandleStyle('left')}
|
|
249
|
-
/>
|
|
250
|
-
<Handle
|
|
251
|
-
type="target"
|
|
252
|
-
position={Position.Right}
|
|
253
|
-
id="right"
|
|
254
|
-
style={getHandleStyle('right')}
|
|
255
|
-
/>
|
|
249
|
+
<Handle type="target" position={Position.Top} id="top" style={getHandleStyle('top')} />
|
|
250
|
+
<Handle type="target" position={Position.Left} id="left" style={getHandleStyle('left')} />
|
|
251
|
+
<Handle type="target" position={Position.Right} id="right" style={getHandleStyle('right')} />
|
|
256
252
|
|
|
257
253
|
{/* Hexagon needs a wrapper for proper border rendering */}
|
|
258
254
|
{isHexagon ? (
|
|
259
255
|
<div style={hexagonBorderStyle} className={animationClass}>
|
|
260
256
|
<div style={hexagonInnerStyle}>
|
|
261
|
-
{icon &&
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
257
|
+
{icon && (
|
|
258
|
+
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
259
|
+
{resolveIcon(icon, 20)}
|
|
260
|
+
</div>
|
|
261
|
+
)}
|
|
262
|
+
<div style={{ textAlign: 'center', wordBreak: 'break-word' }}>{displayName}</div>
|
|
265
263
|
{state && (
|
|
266
|
-
<div
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
264
|
+
<div
|
|
265
|
+
style={{
|
|
266
|
+
fontSize: '10px',
|
|
267
|
+
backgroundColor: color,
|
|
268
|
+
color: 'white',
|
|
269
|
+
padding: '2px 6px',
|
|
270
|
+
borderRadius: '4px',
|
|
271
|
+
textAlign: 'center',
|
|
272
|
+
}}
|
|
273
|
+
>
|
|
274
274
|
{nodeDataStates?.[state]?.label || typeDefinition.states?.[state]?.label || state}
|
|
275
275
|
</div>
|
|
276
276
|
)}
|
|
277
277
|
{hasViolations && (
|
|
278
|
-
<div
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
278
|
+
<div
|
|
279
|
+
style={{
|
|
280
|
+
fontSize: '10px',
|
|
281
|
+
color: '#D0021B',
|
|
282
|
+
fontWeight: 'bold',
|
|
283
|
+
}}
|
|
284
|
+
>
|
|
283
285
|
⚠️
|
|
284
286
|
</div>
|
|
285
287
|
)}
|
|
@@ -288,29 +290,58 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
288
290
|
) : (
|
|
289
291
|
<div style={getShapeStyles()} className={animationClass}>
|
|
290
292
|
{/* Inner content (rotated back if diamond) */}
|
|
291
|
-
<div
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
{
|
|
295
|
-
|
|
293
|
+
<div
|
|
294
|
+
style={{
|
|
295
|
+
...(isDiamond ? { transform: 'rotate(-45deg)' } : {}),
|
|
296
|
+
...(isGroup ? { width: '100%' } : {}),
|
|
297
|
+
}}
|
|
298
|
+
>
|
|
299
|
+
{/* Groups: icon and text inline, centered */}
|
|
300
|
+
{isGroup ? (
|
|
301
|
+
<div
|
|
302
|
+
style={{
|
|
303
|
+
display: 'flex',
|
|
304
|
+
alignItems: 'center',
|
|
305
|
+
justifyContent: 'center',
|
|
306
|
+
gap: '6px',
|
|
307
|
+
width: '100%',
|
|
308
|
+
}}
|
|
309
|
+
>
|
|
310
|
+
{icon && resolveIcon(icon, 18)}
|
|
311
|
+
<div style={{ wordBreak: 'break-word' }}>{displayName}</div>
|
|
312
|
+
</div>
|
|
313
|
+
) : (
|
|
314
|
+
<>
|
|
315
|
+
{icon && (
|
|
316
|
+
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
317
|
+
{resolveIcon(icon, 20)}
|
|
318
|
+
</div>
|
|
319
|
+
)}
|
|
320
|
+
<div style={{ textAlign: 'center', wordBreak: 'break-word' }}>{displayName}</div>
|
|
321
|
+
</>
|
|
322
|
+
)}
|
|
296
323
|
{state && (
|
|
297
|
-
<div
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
324
|
+
<div
|
|
325
|
+
style={{
|
|
326
|
+
fontSize: '10px',
|
|
327
|
+
backgroundColor: color,
|
|
328
|
+
color: 'white',
|
|
329
|
+
padding: '2px 6px',
|
|
330
|
+
borderRadius: '4px',
|
|
331
|
+
textAlign: 'center',
|
|
332
|
+
}}
|
|
333
|
+
>
|
|
305
334
|
{nodeDataStates?.[state]?.label || typeDefinition.states?.[state]?.label || state}
|
|
306
335
|
</div>
|
|
307
336
|
)}
|
|
308
337
|
{hasViolations && (
|
|
309
|
-
<div
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
338
|
+
<div
|
|
339
|
+
style={{
|
|
340
|
+
fontSize: '10px',
|
|
341
|
+
color: '#D0021B',
|
|
342
|
+
fontWeight: 'bold',
|
|
343
|
+
}}
|
|
344
|
+
>
|
|
314
345
|
⚠️
|
|
315
346
|
</div>
|
|
316
347
|
)}
|
|
@@ -325,12 +356,7 @@ export const CustomNode: React.FC<NodeProps<any>> = ({ data, selected }) => {
|
|
|
325
356
|
id="bottom"
|
|
326
357
|
style={getHandleStyle('bottom')}
|
|
327
358
|
/>
|
|
328
|
-
<Handle
|
|
329
|
-
type="source"
|
|
330
|
-
position={Position.Left}
|
|
331
|
-
id="left-out"
|
|
332
|
-
style={getHandleStyle('left')}
|
|
333
|
-
/>
|
|
359
|
+
<Handle type="source" position={Position.Left} id="left-out" style={getHandleStyle('left')} />
|
|
334
360
|
<Handle
|
|
335
361
|
type="source"
|
|
336
362
|
position={Position.Right}
|
|
@@ -29,9 +29,10 @@ export const GenericNode: React.FC<GenericNodeProps> = ({
|
|
|
29
29
|
hasViolations,
|
|
30
30
|
}) => {
|
|
31
31
|
// Get color based on state or default
|
|
32
|
-
const color =
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const color =
|
|
33
|
+
state && typeDefinition.states?.[state]?.color
|
|
34
|
+
? typeDefinition.states[state].color
|
|
35
|
+
: typeDefinition.color || '#888';
|
|
35
36
|
|
|
36
37
|
return (
|
|
37
38
|
<div
|