@principal-ai/principal-view-react 0.15.1 → 0.15.3
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/dist/components/GraphRenderer.d.ts +7 -0
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +154 -7
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/contexts/GraphEditContext.d.ts +2 -0
- package/dist/contexts/GraphEditContext.d.ts.map +1 -1
- package/dist/contexts/GraphEditContext.js.map +1 -1
- package/dist/hooks/useUndoRedo.d.ts +5 -0
- package/dist/hooks/useUndoRedo.d.ts.map +1 -1
- package/dist/hooks/useUndoRedo.js.map +1 -1
- package/dist/nodes/CustomNode.d.ts +1 -0
- package/dist/nodes/CustomNode.d.ts.map +1 -1
- package/dist/nodes/CustomNode.js +84 -6
- package/dist/nodes/CustomNode.js.map +1 -1
- package/package.json +1 -1
- package/src/components/GraphRenderer.tsx +187 -5
- package/src/contexts/GraphEditContext.tsx +2 -0
- package/src/hooks/useUndoRedo.ts +6 -0
- package/src/nodes/CustomNode.tsx +111 -4
package/src/nodes/CustomNode.tsx
CHANGED
|
@@ -28,6 +28,8 @@ export interface CustomNodeData extends Record<string, unknown> {
|
|
|
28
28
|
animationDuration?: number;
|
|
29
29
|
// Edit mode - shows larger connection handles
|
|
30
30
|
editable?: boolean;
|
|
31
|
+
// Pending text change (from inline editing, not yet saved)
|
|
32
|
+
pendingText?: string;
|
|
31
33
|
// Whether tooltips are enabled (defaults to true)
|
|
32
34
|
tooltipsEnabled?: boolean;
|
|
33
35
|
// Whether shift key is currently pressed (for tooltip control)
|
|
@@ -77,10 +79,13 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = (props) =>
|
|
|
77
79
|
|
|
78
80
|
// Fall through to legacy rendering for non-OTEL nodes
|
|
79
81
|
const { theme } = useTheme();
|
|
80
|
-
const { onNodeResizeEnd, onToggleNodeHidden, onHideUnconnectedNodes } = useGraphEdit();
|
|
82
|
+
const { onNodeResizeEnd, onNodeTextChange, onToggleNodeHidden, onHideUnconnectedNodes } = useGraphEdit();
|
|
81
83
|
const nodeId = useNodeId();
|
|
82
84
|
const [isHovered, setIsHovered] = useState(false);
|
|
85
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
86
|
+
const [editingText, setEditingText] = useState('');
|
|
83
87
|
const nodeRef = useRef<HTMLDivElement>(null);
|
|
88
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
84
89
|
const nodeProps = data;
|
|
85
90
|
const {
|
|
86
91
|
typeDefinition,
|
|
@@ -449,8 +454,8 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = (props) =>
|
|
|
449
454
|
// Use fillColor as the primary "color" for backwards compatibility
|
|
450
455
|
const color = fillColor;
|
|
451
456
|
|
|
452
|
-
// Get display name - use
|
|
453
|
-
const displayName = nodeProps.name;
|
|
457
|
+
// Get display name - use pending text if available, otherwise use name from props
|
|
458
|
+
const displayName = nodeProps.pendingText ?? nodeProps.name;
|
|
454
459
|
|
|
455
460
|
// Extract identifier based on node type (for display below the label)
|
|
456
461
|
// Supports: event.name, otel.spanPattern, otel.scope, otel.resourceMatch, boundary.direction
|
|
@@ -545,8 +550,58 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = (props) =>
|
|
|
545
550
|
|
|
546
551
|
const animationClass = getAnimationClass();
|
|
547
552
|
|
|
548
|
-
// Check if this is a group node
|
|
553
|
+
// Check if this is a group node or text node (canvas types that support inline editing)
|
|
549
554
|
const isGroup = nodeData.canvasType === 'group';
|
|
555
|
+
const isTextNode = nodeData.canvasType === 'text';
|
|
556
|
+
const isInlineEditable = (isGroup || isTextNode) && editable;
|
|
557
|
+
|
|
558
|
+
// Double-click handler for inline text editing
|
|
559
|
+
const lastClickTimeRef = useRef<number>(0);
|
|
560
|
+
const handleNodeDoubleClick = useCallback((event: React.MouseEvent) => {
|
|
561
|
+
if (!isInlineEditable || !nodeId || !onNodeTextChange) return;
|
|
562
|
+
|
|
563
|
+
event.stopPropagation();
|
|
564
|
+
event.preventDefault();
|
|
565
|
+
|
|
566
|
+
setEditingText(displayName || '');
|
|
567
|
+
setIsEditing(true);
|
|
568
|
+
|
|
569
|
+
// Focus the textarea after state update
|
|
570
|
+
setTimeout(() => {
|
|
571
|
+
textareaRef.current?.focus();
|
|
572
|
+
textareaRef.current?.select();
|
|
573
|
+
}, 0);
|
|
574
|
+
}, [isInlineEditable, nodeId, onNodeTextChange, displayName]);
|
|
575
|
+
|
|
576
|
+
// Single click tracking for double-click detection
|
|
577
|
+
const handleNodeClick = useCallback((event: React.MouseEvent) => {
|
|
578
|
+
const now = Date.now();
|
|
579
|
+
const timeSinceLastClick = now - lastClickTimeRef.current;
|
|
580
|
+
|
|
581
|
+
if (timeSinceLastClick < 300) {
|
|
582
|
+
// Double-click detected
|
|
583
|
+
handleNodeDoubleClick(event);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
lastClickTimeRef.current = now;
|
|
587
|
+
}, [handleNodeDoubleClick]);
|
|
588
|
+
|
|
589
|
+
// Save text changes
|
|
590
|
+
const handleSaveText = useCallback(() => {
|
|
591
|
+
if (!nodeId || !onNodeTextChange) return;
|
|
592
|
+
|
|
593
|
+
if (editingText !== displayName) {
|
|
594
|
+
onNodeTextChange(nodeId, editingText);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
setIsEditing(false);
|
|
598
|
+
}, [nodeId, onNodeTextChange, editingText, displayName]);
|
|
599
|
+
|
|
600
|
+
// Cancel text editing
|
|
601
|
+
const handleCancelEdit = useCallback(() => {
|
|
602
|
+
setIsEditing(false);
|
|
603
|
+
setEditingText('');
|
|
604
|
+
}, []);
|
|
550
605
|
|
|
551
606
|
// Shape-specific styles
|
|
552
607
|
const getShapeStyles = () => {
|
|
@@ -946,6 +1001,7 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = (props) =>
|
|
|
946
1001
|
ref={nodeRef}
|
|
947
1002
|
style={{ position: 'relative', width: '100%', height: '100%' }}
|
|
948
1003
|
onMouseDown={handleMouseDown}
|
|
1004
|
+
onClick={handleNodeClick}
|
|
949
1005
|
onMouseEnter={() => setIsHovered(true)}
|
|
950
1006
|
onMouseLeave={() => setIsHovered(false)}
|
|
951
1007
|
>
|
|
@@ -1018,6 +1074,57 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = (props) =>
|
|
|
1018
1074
|
)}
|
|
1019
1075
|
</div>
|
|
1020
1076
|
</div>
|
|
1077
|
+
{/* Inline text editor overlay */}
|
|
1078
|
+
{isEditing && isInlineEditable && (
|
|
1079
|
+
<div
|
|
1080
|
+
style={{
|
|
1081
|
+
position: 'absolute',
|
|
1082
|
+
top: 0,
|
|
1083
|
+
left: 0,
|
|
1084
|
+
width: '100%',
|
|
1085
|
+
height: '100%',
|
|
1086
|
+
zIndex: 1000,
|
|
1087
|
+
display: 'flex',
|
|
1088
|
+
flexDirection: 'column',
|
|
1089
|
+
padding: theme.space[1],
|
|
1090
|
+
boxSizing: 'border-box',
|
|
1091
|
+
}}
|
|
1092
|
+
onClick={(e) => e.stopPropagation()}
|
|
1093
|
+
>
|
|
1094
|
+
<textarea
|
|
1095
|
+
ref={textareaRef}
|
|
1096
|
+
value={editingText}
|
|
1097
|
+
onChange={(e) => setEditingText(e.target.value)}
|
|
1098
|
+
placeholder="Enter text..."
|
|
1099
|
+
style={{
|
|
1100
|
+
flex: 1,
|
|
1101
|
+
width: '100%',
|
|
1102
|
+
padding: theme.space[2],
|
|
1103
|
+
fontSize: theme.fontSizes[1],
|
|
1104
|
+
fontFamily: theme.fonts.body,
|
|
1105
|
+
color: theme.colors.text,
|
|
1106
|
+
backgroundColor: theme.colors.background,
|
|
1107
|
+
border: `3px solid ${theme.colors.primary}`,
|
|
1108
|
+
borderRadius: theme.radii[1],
|
|
1109
|
+
outline: 'none',
|
|
1110
|
+
resize: 'none',
|
|
1111
|
+
boxSizing: 'border-box',
|
|
1112
|
+
boxShadow: '0 8px 24px rgba(0, 0, 0, 0.3)',
|
|
1113
|
+
}}
|
|
1114
|
+
onKeyDown={(e) => {
|
|
1115
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
1116
|
+
e.preventDefault();
|
|
1117
|
+
handleSaveText();
|
|
1118
|
+
} else if (e.key === 'Escape') {
|
|
1119
|
+
e.preventDefault();
|
|
1120
|
+
handleCancelEdit();
|
|
1121
|
+
}
|
|
1122
|
+
}}
|
|
1123
|
+
onBlur={handleSaveText}
|
|
1124
|
+
/>
|
|
1125
|
+
</div>
|
|
1126
|
+
)}
|
|
1127
|
+
|
|
1021
1128
|
{tooltipsEnabled && (
|
|
1022
1129
|
<NodeTooltip
|
|
1023
1130
|
description={description}
|