Skip to content

Commit e1be3de

Browse files
committed
fix: hit testing outside the bounds of resizer and group-annotation
1 parent 1b344f6 commit e1be3de

File tree

3 files changed

+51
-46
lines changed

3 files changed

+51
-46
lines changed

packages/vyuh_node_flow/lib/annotations/group_annotation_widget.dart

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import '../graph/cursor_theme.dart';
55
import '../graph/node_flow_controller.dart';
66
import '../graph/node_flow_theme.dart';
77
import '../shared/resizer_widget.dart';
8+
import '../shared/unbounded_widgets.dart';
89
import 'group_annotation.dart';
910

1011
/// Widget that renders a group annotation with resize handles when selected.
@@ -57,52 +58,57 @@ class GroupAnnotationWidget extends StatelessWidget {
5758
isInteractive: group.isInteractive,
5859
);
5960

61+
// Use UnboundedStack to allow hit testing on resize handles
62+
// that extend outside the annotation bounds
6063
return Positioned(
6164
left: position.dx,
6265
top: position.dy,
63-
child: MouseRegion(
64-
cursor: cursor,
65-
child: GestureDetector(
66-
behavior: HitTestBehavior.opaque,
67-
onDoubleTap: onDoubleTap,
68-
onSecondaryTapUp: onContextMenu != null
69-
? (details) => onContextMenu!(details.globalPosition)
70-
: null,
71-
onPanStart: (_) => controller.startAnnotationDrag(group.id),
72-
onPanUpdate: (details) =>
73-
controller.moveAnnotationDrag(details.delta),
74-
onPanEnd: (_) => controller.endAnnotationDrag(),
75-
child: SizedBox(
76-
width: groupSize.width,
77-
height: groupSize.height,
78-
child: isSelected && group.isResizable
79-
? ResizerWidget(
80-
handleSize: theme.resizerTheme.handleSize,
81-
color: theme.resizerTheme.color,
82-
borderColor: theme.resizerTheme.borderColor,
83-
borderWidth: theme.resizerTheme.borderWidth,
84-
snapDistance: theme.resizerTheme.snapDistance,
85-
onResizeStart: (handle) => controller.annotations
86-
.startGroupResize(group.id, _toGroupHandle(handle)),
87-
onResizeUpdate: (delta) =>
88-
controller.annotations.updateGroupResize(delta),
89-
onResizeEnd: () =>
90-
controller.annotations.endGroupResize(),
91-
child: _GroupContent(
92-
group: group,
93-
controller: controller,
94-
isSelected: isSelected,
95-
isHighlighted: isHighlighted,
96-
),
97-
)
98-
: _GroupContent(
99-
group: group,
100-
controller: controller,
101-
isSelected: isSelected,
102-
isHighlighted: isHighlighted,
103-
),
66+
width: groupSize.width,
67+
height: groupSize.height,
68+
child: UnboundedStack(
69+
clipBehavior: Clip.none,
70+
children: [
71+
// The annotation content
72+
Positioned.fill(
73+
child: MouseRegion(
74+
cursor: cursor,
75+
child: GestureDetector(
76+
behavior: HitTestBehavior.opaque,
77+
onDoubleTap: onDoubleTap,
78+
onSecondaryTapUp: onContextMenu != null
79+
? (details) => onContextMenu!(details.globalPosition)
80+
: null,
81+
onPanStart: (_) => controller.startAnnotationDrag(group.id),
82+
onPanUpdate: (details) =>
83+
controller.moveAnnotationDrag(details.delta),
84+
onPanEnd: (_) => controller.endAnnotationDrag(),
85+
child: _GroupContent(
86+
group: group,
87+
controller: controller,
88+
isSelected: isSelected,
89+
isHighlighted: isHighlighted,
90+
),
91+
),
92+
),
10493
),
105-
),
94+
// Resize handles as overlay (only when selected and resizable)
95+
if (isSelected && group.isResizable)
96+
Positioned.fill(
97+
child: ResizerWidget(
98+
handleSize: theme.resizerTheme.handleSize,
99+
color: theme.resizerTheme.color,
100+
borderColor: theme.resizerTheme.borderColor,
101+
borderWidth: theme.resizerTheme.borderWidth,
102+
snapDistance: theme.resizerTheme.snapDistance,
103+
onResizeStart: (handle) => controller.annotations
104+
.startGroupResize(group.id, _toGroupHandle(handle)),
105+
onResizeUpdate: (delta) =>
106+
controller.annotations.updateGroupResize(delta),
107+
onResizeEnd: () => controller.annotations.endGroupResize(),
108+
child: const SizedBox.expand(),
109+
),
110+
),
111+
],
106112
),
107113
);
108114
},

packages/vyuh_node_flow/lib/graph/resizer_theme.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class ResizerTheme {
7272
///
7373
/// Uses white fill with blue border for visibility on light backgrounds.
7474
static const light = ResizerTheme(
75-
handleSize: 10.0,
75+
handleSize: 8.0,
7676
color: Colors.white,
7777
borderColor: Colors.blue,
7878
borderWidth: 1.0,
@@ -83,7 +83,7 @@ class ResizerTheme {
8383
///
8484
/// Uses dark fill with lighter blue border for visibility on dark backgrounds.
8585
static const dark = ResizerTheme(
86-
handleSize: 10.0,
86+
handleSize: 8.0,
8787
color: Color(0xFF1E1E1E),
8888
borderColor: Color(0xFF64B5F6),
8989
// Colors.blue[300]

packages/vyuh_node_flow/lib/shared/resizer_widget.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ class ResizerWidget extends StatelessWidget {
242242
required this.onResizeStart,
243243
required this.onResizeUpdate,
244244
required this.onResizeEnd,
245-
this.handleSize = 10.0,
245+
this.handleSize = 8.0,
246246
this.color = Colors.white,
247247
this.borderColor = Colors.blue,
248248
this.borderWidth = 1.0,
@@ -351,7 +351,6 @@ class ResizerWidget extends StatelessWidget {
351351
decoration: BoxDecoration(
352352
color: color,
353353
border: Border.all(color: borderColor, width: borderWidth),
354-
borderRadius: BorderRadius.circular(2),
355354
),
356355
),
357356
),

0 commit comments

Comments
 (0)