extend ClideTappable with press/longpress, retrofit button + rail

ClideTappable builder now receives (context, hovered, pressed).
Optional onLongPress and onPressChanged callbacks. ClideButton
is now a StatelessWidget wrapping ClideTappable. ClideIconRail
refactored — _RailButton uses ClideTappable with tooltip.
ClideTooltip positions smart (above when near screen bottom).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 11:21:05 +02:00
co-authored by Claude Opus 4.6
parent c9870bb044
commit fbd5f1ae04
5 changed files with 129 additions and 139 deletions
+31 -6
View File
@@ -1,16 +1,23 @@
import 'package:clide/widgets/src/clide_tooltip.dart';
import 'package:flutter/widgets.dart';
class ClideTappable extends StatefulWidget {
const ClideTappable({
super.key,
required this.onTap,
required this.builder,
this.onTap,
this.onLongPress,
this.onPressChanged,
this.cursor = SystemMouseCursors.click,
this.tooltip,
});
final VoidCallback onTap;
final Widget Function(BuildContext context, bool hovered) builder;
final Widget Function(BuildContext context, bool hovered, bool pressed) builder;
final VoidCallback? onTap;
final VoidCallback? onLongPress;
final ValueChanged<bool>? onPressChanged;
final MouseCursor cursor;
final String? tooltip;
@override
State<ClideTappable> createState() => _ClideTappableState();
@@ -18,18 +25,36 @@ class ClideTappable extends StatefulWidget {
class _ClideTappableState extends State<ClideTappable> {
bool _hover = false;
bool _pressed = false;
void _setPressed(bool v) {
if (_pressed == v) return;
setState(() => _pressed = v);
widget.onPressChanged?.call(v);
}
@override
Widget build(BuildContext context) {
return MouseRegion(
Widget child = MouseRegion(
cursor: widget.cursor,
onEnter: (_) => setState(() => _hover = true),
onExit: (_) => setState(() => _hover = false),
onExit: (_) {
setState(() => _hover = false);
_setPressed(false);
},
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: widget.onTap,
child: widget.builder(context, _hover),
onLongPress: widget.onLongPress,
onTapDown: (_) => _setPressed(true),
onTapUp: (_) => _setPressed(false),
onTapCancel: () => _setPressed(false),
child: widget.builder(context, _hover, _pressed),
),
);
if (widget.tooltip != null) {
child = ClideTooltip(message: widget.tooltip!, child: child);
}
return child;
}
}