diff --git a/README.md b/README.md index 43c7fbb..4f869dc 100644 --- a/README.md +++ b/README.md @@ -221,9 +221,9 @@ SuperTooltip( ) ``` -### AnimationConfiguration - Animation Timing - -Control animation behavior: +### AnimationConfiguration - Animation Timing + +Control animation behavior: ```dart SuperTooltip( @@ -235,10 +235,35 @@ SuperTooltip( exitDuration: Duration(milliseconds: 100), // Hover exit delay ), // ... -) -``` - -## 🎯 Common Use Cases +) +``` + +### Overlay Selection + +Control which `Overlay` receives the tooltip entries: + +```dart +SuperTooltip( + useRootOverlay: true, // default: insert into the app's root Overlay + content: const Text( + 'I use the global overlay by default.', + style: TextStyle(color: Colors.white), + ), + child: const Icon(Icons.layers), +) +``` + +- `useRootOverlay: true` - Insert into the root/global `Overlay` and keep the tooltip above subsequently presented routes +- `useRootOverlay: false` - Insert into the nearest local `Overlay` and follow the local route layering +- Default is `true`, so existing usages may change layering behavior after upgrading + +Use `false` when the tooltip must stay scoped to a nested `Overlay`, such as a +custom overlay region, embedded navigator, or other locally managed floating +content. In route-based surfaces like dialogs or bottom sheets, `false` allows +newly presented routes to naturally cover the tooltip instead of forcing the +tooltip to the global top layer. + +## 🎯 Common Use Cases ### Auto-Positioning Tooltip @@ -455,17 +480,18 @@ SuperTooltip( ) ``` -### Touch-Through Areas - -Allow touches to pass through specific areas: - -```dart -SuperTooltip( - controller: _controller, - touchThroughArea: Rect.fromLTWH(100, 100, 200, 100), - touchThroughAreaShape: ClipAreaShape.rectangle, - touchThroughAreaCornerRadius: 10.0, - barrierConfig: const BarrierConfiguration(show: true), +### Touch-Through Areas + +Allow touches to pass through specific areas. The builder receives the target +child's global rect and returns the final pass-through rect: + +```dart +SuperTooltip( + controller: _controller, + touchThroughAreaBuilder: (area) => area.inflate(12), + touchThroughAreaShape: ClipAreaShape.rectangle, + touchThroughAreaCornerRadius: 10.0, + barrierConfig: const BarrierConfiguration(show: true), content: const Text("Tutorial step 1"), child: const Icon(Icons.lightbulb), ) diff --git a/lib/src/super_tooltip.dart b/lib/src/super_tooltip.dart index 360d3f9..e0e278a 100644 --- a/lib/src/super_tooltip.dart +++ b/lib/src/super_tooltip.dart @@ -15,6 +15,7 @@ import 'super_tooltip_style.dart'; import 'utils.dart'; typedef DecorationBuilder = Decoration Function(Offset target); +typedef TouchThroughAreaBuilder = Rect? Function(Rect area); /// A powerful and customizable tooltip widget for Flutter. /// @@ -40,6 +41,7 @@ class SuperTooltip extends StatefulWidget { Key? key, required this.content, this.controller, + this.useRootOverlay = true, this.child, this.style = const TooltipStyle(), this.arrowConfig = const ArrowConfiguration(), @@ -55,7 +57,7 @@ class SuperTooltip extends StatefulWidget { maxWidth: double.infinity, ), this.decorationBuilder, - this.touchThroughArea, + this.touchThroughAreaBuilder, this.touchThroughAreaShape = ClipAreaShape.oval, this.touchThroughAreaCornerRadius = 5.0, this.overlayDimensions = const EdgeInsets.all(10), @@ -71,6 +73,12 @@ class SuperTooltip extends StatefulWidget { /// Controller to manage the tooltip's visibility and state. final SuperTooltipController? controller; + /// Whether to insert tooltip entries into the root [Overlay]. + /// + /// When true, the tooltip is shown in the app's root overlay instead of the + /// nearest local overlay. + final bool useRootOverlay; + /// The target widget to which the tooltip is attached. final Widget? child; @@ -101,8 +109,9 @@ class SuperTooltip extends StatefulWidget { /// Custom decoration builder for advanced styling. final DecorationBuilder? decorationBuilder; - /// Rectangular area that allows touch events to pass through the barrier. - final Rect? touchThroughArea; + /// Builder that receives the target child's global rect and returns the + /// touch-through area for the barrier. + final TouchThroughAreaBuilder? touchThroughAreaBuilder; /// Shape of the touch-through area. final ClipAreaShape touchThroughAreaShape; @@ -144,6 +153,7 @@ class SuperTooltip extends StatefulWidget { class _SuperTooltipState extends State with SingleTickerProviderStateMixin { final LayerLink _layerLink = LayerLink(); + final OverlayPortalController _portalController = OverlayPortalController(); late AnimationController _animationController; late SuperTooltipController _controller; bool _ownsController = false; @@ -152,8 +162,6 @@ class _SuperTooltipState extends State OverlayEntry? _barrierEntry; OverlayEntry? _blurEntry; - TooltipDirection _resolvedDirection = TooltipDirection.down; - Timer? _showTimer; Timer? _hideTimer; Timer? _showDurationTimer; @@ -248,7 +256,7 @@ class _SuperTooltipState extends State @override void dispose() { _cancelAllTimers(); - _removeAllOverlayEntries(); + _removeAllTooltipPresentations(); _controller.removeListener(_onControllerChanged); if (_ownsController) { _controller.dispose(); @@ -263,7 +271,7 @@ class _SuperTooltipState extends State _showDurationTimer?.cancel(); } - void _removeAllOverlayEntries() { + void _removeAllTooltipPresentations() { if (_tooltipEntry != null) { _removeEntries(); } @@ -271,7 +279,7 @@ class _SuperTooltipState extends State @override Widget build(BuildContext context) { - return MouseRegion( + final anchoredChild = MouseRegion( cursor: widget.mouseCursor ?? SystemMouseCursors.basic, hitTestBehavior: HitTestBehavior.translucent, onEnter: _handleMouseEnter, @@ -285,6 +293,16 @@ class _SuperTooltipState extends State ), ), ); + + if (widget.useRootOverlay) { + return anchoredChild; + } + + return OverlayPortal( + controller: _portalController, + overlayChildBuilder: _buildPortalOverlayChild, + child: anchoredChild, + ); } void _handleMouseEnter(PointerEnterEvent event) { @@ -335,10 +353,18 @@ class _SuperTooltipState extends State Future _showTooltip() async { widget.onShow?.call(); - if (_tooltipEntry != null) return; + if (widget.useRootOverlay) { + if (_tooltipEntry != null) return; + } else if (_portalController.isShowing) { + return; + } _showTimer?.cancel(); - _createOverlayEntries(); + if (widget.useRootOverlay) { + _createOverlayEntries(); + } else { + _portalController.show(); + } await _animationController.forward().whenComplete(_controller.complete); @@ -357,79 +383,193 @@ class _SuperTooltipState extends State _showDurationTimer?.cancel(); await _animationController.reverse().whenComplete(_controller.complete); - _removeEntries(); + if (widget.useRootOverlay) { + _removeEntries(); + } else if (_portalController.isShowing) { + _portalController.hide(); + } } void _createOverlayEntries() { - final overlayState = Overlay.of(context); - final renderBox = context.findRenderObject() as RenderBox; - final overlay = overlayState.context.findRenderObject() as RenderBox?; + final overlayState = Overlay.of(context, rootOverlay: true); + final presentationData = _computePresentationData( + context, + rootOverlay: true, + ); + if (presentationData == null) { + return; + } + final animation = _buildTooltipAnimation(); - final size = renderBox.size; - final target = renderBox.localToGlobal(size.center(Offset.zero)); + _barrierEntry = _shouldShowBarrier + ? _createBarrierEntry(animation, presentationData.touchThroughArea) + : null; + + _blurEntry = widget.barrierConfig.showBlur + ? _createBlurEntry(animation) + : null; + + _tooltipEntry = _createTooltipEntry( + animation: animation, + presentationData: presentationData, + ); + + overlayState.insertAll([ + if (widget.barrierConfig.showBlur) _blurEntry!, + if (_shouldShowBarrier) _barrierEntry!, + _tooltipEntry!, + ]); + } + + OverlayEntry _createBarrierEntry( + Animation animation, + Rect? clipRect, + ) { + return OverlayEntry( + builder: (context) => _buildBarrierLayer(animation, clipRect), + ); + } - final animation = CurvedAnimation( + OverlayEntry _createBlurEntry(Animation animation) { + return OverlayEntry(builder: (context) => _buildBlurLayer(animation)); + } + + OverlayEntry _createTooltipEntry({ + required Animation animation, + required _OverlayPresentationData presentationData, + }) { + return OverlayEntry( + builder: (context) => + _buildTooltipLayer(animation: animation, data: presentationData), + ); + } + + Animation _buildTooltipAnimation() { + return CurvedAnimation( parent: _animationController, curve: Curves.fastOutSlowIn, ); + } - final offsetToTarget = Offset( - -target.dx + size.width / 2, - -target.dy + size.height / 2, + Widget _buildPortalOverlayChild(BuildContext context) { + final presentationData = _computePresentationData( + context, + rootOverlay: false, ); + if (presentationData == null) { + return const SizedBox.shrink(); + } - final backgroundColor = - widget.style.backgroundColor ?? Theme.of(context).cardColor; + final animation = _buildTooltipAnimation(); - final positionData = _calculatePosition(target, overlay); - _resolvedDirection = positionData.direction; + return Stack( + fit: StackFit.expand, + children: [ + if (widget.barrierConfig.showBlur) _buildBlurLayer(animation), + if (_shouldShowBarrier) + _buildBarrierLayer(animation, presentationData.touchThroughArea), + _buildTooltipLayer(animation: animation, data: presentationData), + ], + ); + } - _barrierEntry = _shouldShowBarrier ? _createBarrierEntry(animation) : null; + _OverlayPresentationData? _computePresentationData( + BuildContext overlayContext, { + required bool rootOverlay, + }) { + final renderBox = context.findRenderObject() as RenderBox?; + if (renderBox == null || !renderBox.hasSize) { + return null; + } - _blurEntry = widget.barrierConfig.showBlur - ? _createBlurEntry(animation) - : null; + final overlayState = Overlay.of(overlayContext, rootOverlay: rootOverlay); + final overlay = overlayState.context.findRenderObject() as RenderBox?; + final size = renderBox.size; + final childGlobalRect = _globalRectForRenderBox(renderBox); + final centerTarget = renderBox.localToGlobal(size.center(Offset.zero)); + final backgroundColor = + widget.style.backgroundColor ?? Theme.of(context).cardColor; + final touchThroughArea = _resolveTouchThroughArea( + childGlobalRect: childGlobalRect, + overlay: overlay, + ); + final initialPositionData = _calculatePosition(centerTarget, overlay); + var anchorDirection = initialPositionData.direction; + var anchorOffset = SuperUtils.tooltipAnchorPoint( + childSize: size, + direction: anchorDirection, + ); + var target = renderBox.localToGlobal(anchorOffset); + var positionData = _calculatePosition(target, overlay); + + if (positionData.direction != anchorDirection) { + anchorDirection = positionData.direction; + anchorOffset = SuperUtils.tooltipAnchorPoint( + childSize: size, + direction: anchorDirection, + ); + target = renderBox.localToGlobal(anchorOffset); + positionData = _calculatePosition(target, overlay); + } - _tooltipEntry = _createTooltipEntry( - animation: animation, - offsetToTarget: offsetToTarget, + final offsetToTarget = Offset( + -target.dx + anchorOffset.dx, + -target.dy + anchorOffset.dy, + ); + + return _OverlayPresentationData( target: target, + offsetToTarget: offsetToTarget, backgroundColor: backgroundColor, overlay: overlay, positionData: positionData, + touchThroughArea: touchThroughArea, ); + } - overlayState.insertAll([ - if (widget.barrierConfig.showBlur) _blurEntry!, - if (_shouldShowBarrier) _barrierEntry!, - _tooltipEntry!, - ]); + Rect _globalRectForRenderBox(RenderBox renderBox) { + final topLeft = renderBox.localToGlobal(Offset.zero); + return topLeft & renderBox.size; } - OverlayEntry _createBarrierEntry(Animation animation) { - return OverlayEntry( - builder: (context) => FadeTransition( - opacity: animation, - child: GestureDetector( - onTap: widget.interactionConfig.hideOnBarrierTap - ? _controller.hideTooltip - : null, - onVerticalDragUpdate: widget.interactionConfig.hideOnScroll - ? (_) => _controller.hideTooltip() - : null, - onHorizontalDragUpdate: widget.interactionConfig.hideOnScroll - ? (_) => _controller.hideTooltip() - : null, - child: Container( - key: SuperTooltip.barrierKey, - decoration: ShapeDecoration( - shape: ShapeOverlay( - clipAreaCornerRadius: widget.touchThroughAreaCornerRadius, - clipAreaShape: widget.touchThroughAreaShape, - clipRect: widget.touchThroughArea, - barrierColor: _effectiveBarrierColor, - overlayDimensions: widget.overlayDimensions, - ), + Rect? _resolveTouchThroughArea({ + required Rect childGlobalRect, + required RenderBox? overlay, + }) { + final globalRect = widget.touchThroughAreaBuilder?.call(childGlobalRect); + if (globalRect == null) { + return null; + } + if (overlay == null) { + return globalRect; + } + + final overlayOrigin = overlay.localToGlobal(Offset.zero); + return globalRect.shift(-overlayOrigin); + } + + Widget _buildBarrierLayer(Animation animation, Rect? clipRect) { + return FadeTransition( + opacity: animation, + child: GestureDetector( + onTap: widget.interactionConfig.hideOnBarrierTap + ? _controller.hideTooltip + : null, + onVerticalDragUpdate: widget.interactionConfig.hideOnScroll + ? (_) => _controller.hideTooltip() + : null, + onHorizontalDragUpdate: widget.interactionConfig.hideOnScroll + ? (_) => _controller.hideTooltip() + : null, + child: Container( + key: SuperTooltip.barrierKey, + decoration: ShapeDecoration( + shape: ShapeOverlay( + clipAreaCornerRadius: widget.touchThroughAreaCornerRadius, + clipAreaShape: widget.touchThroughAreaShape, + clipRect: clipRect, + barrierColor: _effectiveBarrierColor, + overlayDimensions: widget.overlayDimensions, ), ), ), @@ -437,62 +577,59 @@ class _SuperTooltipState extends State ); } - OverlayEntry _createBlurEntry(Animation animation) { - return OverlayEntry( - builder: (context) => FadeTransition( - opacity: animation, - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: widget.barrierConfig.sigmaX, - sigmaY: widget.barrierConfig.sigmaY, - ), - child: Container(width: double.infinity, height: double.infinity), + Widget _buildBlurLayer(Animation animation) { + return FadeTransition( + opacity: animation, + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: widget.barrierConfig.sigmaX, + sigmaY: widget.barrierConfig.sigmaY, ), + child: Container(width: double.infinity, height: double.infinity), ), ); } - OverlayEntry _createTooltipEntry({ + Widget _buildTooltipLayer({ required Animation animation, - required Offset offsetToTarget, - required Offset target, - required Color backgroundColor, - required RenderBox? overlay, - required _PositionData positionData, + required _OverlayPresentationData data, }) { - return OverlayEntry( - builder: (context) => IgnorePointer( - ignoring: widget.interactionConfig.clickThrough, - child: FadeTransition( - opacity: animation, - child: Center( - child: CompositedTransformFollower( - link: _layerLink, - showWhenUnlinked: false, - offset: offsetToTarget, - child: CustomSingleChildLayout( - delegate: SuperToolTipPositionDelegate( - preferredDirection: positionData.direction, - constraints: positionData.constraints, - top: positionData.top, - bottom: positionData.bottom, - left: positionData.left, - right: positionData.right, - target: target, - overlay: overlay, - margin: widget.positionConfig.minimumOutsideMargin, - snapsFarAwayHorizontally: - widget.positionConfig.snapsFarAwayHorizontally, - snapsFarAwayVertically: - widget.positionConfig.snapsFarAwayVertically, - ), - child: Stack( - fit: StackFit.passthrough, - children: [ - _buildTooltipBubble(target, backgroundColor, positionData), - _buildCloseButton(), - ], - ), + return IgnorePointer( + ignoring: widget.interactionConfig.clickThrough, + child: FadeTransition( + opacity: animation, + child: Center( + child: CompositedTransformFollower( + link: _layerLink, + showWhenUnlinked: false, + offset: data.offsetToTarget, + child: CustomSingleChildLayout( + delegate: SuperToolTipPositionDelegate( + preferredDirection: data.positionData.direction, + constraints: data.positionData.constraints, + top: data.positionData.top, + bottom: data.positionData.bottom, + left: data.positionData.left, + right: data.positionData.right, + target: data.target, + overlay: data.overlay, + margin: widget.positionConfig.minimumOutsideMargin, + snapsFarAwayHorizontally: + widget.positionConfig.snapsFarAwayHorizontally, + snapsFarAwayVertically: + widget.positionConfig.snapsFarAwayVertically, + ), + child: Stack( + fit: StackFit.passthrough, + children: [ + _buildTooltipBubble( + target: data.target, + backgroundColor: data.backgroundColor, + positionData: data.positionData, + resolvedDirection: data.positionData.direction, + ), + _buildCloseButton(data.positionData.direction), + ], ), ), ), @@ -501,11 +638,12 @@ class _SuperTooltipState extends State ); } - Widget _buildTooltipBubble( - Offset target, - Color backgroundColor, - _PositionData positionData, - ) { + Widget _buildTooltipBubble({ + required Offset target, + required Color backgroundColor, + required _PositionData positionData, + required TooltipDirection resolvedDirection, + }) { return Material( color: Colors.transparent, child: GestureDetector( @@ -525,7 +663,7 @@ class _SuperTooltipState extends State arrowLength: widget.arrowConfig.length, arrowTipDistance: widget.arrowConfig.tipDistance, closeButtonSize: _effectiveCloseButtonSize, - preferredDirection: _resolvedDirection, + preferredDirection: resolvedDirection, closeButtonType: widget.closeButtonConfig.type, showCloseButton: widget.closeButtonConfig.show, ), @@ -536,20 +674,27 @@ class _SuperTooltipState extends State ), decoration: widget.decorationBuilder?.call(target) ?? - _buildDefaultDecoration(backgroundColor, target, positionData), + _buildDefaultDecoration( + backgroundColor: backgroundColor, + target: target, + positionData: positionData, + resolvedDirection: resolvedDirection, + ), child: widget.content, ), ), ); } - Decoration _buildDefaultDecoration( - Color backgroundColor, - Offset target, - _PositionData positionData, - ) { + Decoration _buildDefaultDecoration({ + required Color backgroundColor, + required Offset target, + required _PositionData positionData, + required TooltipDirection resolvedDirection, + }) { return ShapeDecoration( - color: backgroundColor, + gradient: widget.style.gradient, + color: widget.style.gradient == null ? backgroundColor : null, shadows: widget.style.hasShadow ? widget.style.boxShadows ?? [ @@ -570,7 +715,7 @@ class _SuperTooltipState extends State borderWidth: widget.style.borderWidth, bottom: positionData.bottom, left: positionData.left, - preferredDirection: _resolvedDirection, + preferredDirection: resolvedDirection, right: positionData.right, target: target, top: positionData.top, @@ -579,12 +724,12 @@ class _SuperTooltipState extends State ); } - Widget _buildCloseButton() { + Widget _buildCloseButton(TooltipDirection resolvedDirection) { if (!widget.closeButtonConfig.show) { return const SizedBox.shrink(); } - final buttonPosition = _calculateCloseButtonPosition(); + final buttonPosition = _calculateCloseButtonPosition(resolvedDirection); return Positioned( right: buttonPosition.right, @@ -606,10 +751,12 @@ class _SuperTooltipState extends State ); } - ({double right, double top}) _calculateCloseButtonPosition() { + ({double right, double top}) _calculateCloseButtonPosition( + TooltipDirection resolvedDirection, + ) { final isInside = widget.closeButtonConfig.type == CloseButtonType.inside; - switch (_resolvedDirection) { + switch (resolvedDirection) { case TooltipDirection.left: return ( right: @@ -788,6 +935,24 @@ class _SuperTooltipState extends State } } +class _OverlayPresentationData { + const _OverlayPresentationData({ + required this.target, + required this.offsetToTarget, + required this.backgroundColor, + required this.overlay, + required this.positionData, + required this.touchThroughArea, + }); + + final Offset target; + final Offset offsetToTarget; + final Color backgroundColor; + final RenderBox? overlay; + final _PositionData positionData; + final Rect? touchThroughArea; +} + /// Internal class to hold position calculation results class _PositionData { const _PositionData({ diff --git a/lib/src/super_tooltip_configuration.dart b/lib/src/super_tooltip_configuration.dart index cee2074..2de465f 100644 --- a/lib/src/super_tooltip_configuration.dart +++ b/lib/src/super_tooltip_configuration.dart @@ -5,10 +5,10 @@ import 'package:super_tooltip/src/enums.dart'; @immutable class ArrowConfiguration { const ArrowConfiguration( - {this.length = 20.0, - this.baseWidth = 20.0, + {this.length = 8.0, + this.baseWidth = 16.0, this.tipRadius = 0.0, - this.tipDistance = 2.0}); + this.tipDistance = 4.0}); final double length; final double baseWidth; @@ -107,7 +107,6 @@ class PositionConfiguration { this.bottom, this.left, this.minimumOutsideMargin = 20.0, - this.verticalOffset = 0.0, }); final TooltipDirection preferredDirection; @@ -119,7 +118,6 @@ class PositionConfiguration { final double? bottom; final double? left; final double minimumOutsideMargin; - final double verticalOffset; PositionConfiguration copyWith({ TooltipDirection? preferredDirection, @@ -131,7 +129,6 @@ class PositionConfiguration { double? bottom, double? left, double? minimumOutsideMargin, - double? verticalOffset, }) { return PositionConfiguration( preferredDirection: preferredDirection ?? this.preferredDirection, @@ -146,7 +143,6 @@ class PositionConfiguration { bottom: bottom ?? this.bottom, left: left ?? this.left, minimumOutsideMargin: minimumOutsideMargin ?? this.minimumOutsideMargin, - verticalOffset: verticalOffset ?? this.verticalOffset, ); } } diff --git a/lib/src/super_tooltip_position_delegate.dart b/lib/src/super_tooltip_position_delegate.dart index 4297c0c..c732156 100644 --- a/lib/src/super_tooltip_position_delegate.dart +++ b/lib/src/super_tooltip_position_delegate.dart @@ -15,17 +15,14 @@ class SuperToolTipPositionDelegate extends SingleChildLayoutDelegate { required this.left, required this.right, required this.target, - // @required this.verticalOffset, required this.overlay, }); - // assert(verticalOffset != null); final bool snapsFarAwayVertically; final bool snapsFarAwayHorizontally; // TD: Make this EdgeInsets final double margin; final Offset target; - // final double verticalOffset; final RenderBox? overlay; final BoxConstraints constraints; diff --git a/lib/src/super_tooltip_style.dart b/lib/src/super_tooltip_style.dart index b9ddca5..7ef3f95 100644 --- a/lib/src/super_tooltip_style.dart +++ b/lib/src/super_tooltip_style.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; class TooltipStyle { const TooltipStyle({ this.backgroundColor, + this.gradient, this.borderColor = Colors.black, this.borderWidth = 0.0, this.borderRadius = 10.0, @@ -18,6 +19,7 @@ class TooltipStyle { }); final Color? backgroundColor; + final Gradient? gradient; final Color borderColor; final double borderWidth; final double borderRadius; @@ -32,6 +34,7 @@ class TooltipStyle { TooltipStyle copyWith({ Color? backgroundColor, + Gradient? gradient, Color? borderColor, double? borderWidth, double? borderRadius, @@ -46,6 +49,7 @@ class TooltipStyle { }) { return TooltipStyle( backgroundColor: backgroundColor ?? this.backgroundColor, + gradient: gradient ?? this.gradient, borderColor: borderColor ?? this.borderColor, borderWidth: borderWidth ?? this.borderWidth, borderRadius: borderRadius ?? this.borderRadius, diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 80a6e6d..9bbc265 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -4,6 +4,24 @@ import 'package:flutter/material.dart'; import 'enums.dart'; class SuperUtils { + static Offset tooltipAnchorPoint({ + required Size childSize, + required TooltipDirection direction, + }) { + switch (direction) { + case TooltipDirection.up: + return Offset(childSize.width / 2, 0.0); + case TooltipDirection.down: + return Offset(childSize.width / 2, childSize.height); + case TooltipDirection.left: + return Offset(0.0, childSize.height / 2); + case TooltipDirection.right: + return Offset(childSize.width, childSize.height / 2); + case TooltipDirection.auto: + return childSize.center(Offset.zero); + } + } + static EdgeInsets getTooltipMargin({ required CloseButtonType? closeButtonType, required double? closeButtonSize, @@ -15,8 +33,8 @@ class SuperUtils { final top = !showCloseButton ? 0.0 : (closeButtonType == CloseButtonType.outside) - ? closeButtonSize! + 12 - : 0.0; + ? closeButtonSize! + 12 + : 0.0; switch (preferredDirection) { case TooltipDirection.down: @@ -24,7 +42,9 @@ class SuperUtils { case TooltipDirection.up: return EdgeInsets.only( - bottom: arrowTipDistance + arrowLength, top: top); + bottom: arrowTipDistance + arrowLength, + top: top, + ); case TooltipDirection.left: return EdgeInsets.only(right: arrowTipDistance + arrowLength, top: top); @@ -45,8 +65,8 @@ class SuperUtils { final top = !showCloseButton ? 0.0 : (closeButtonType == CloseButtonType.inside) - ? closeButtonSize! - : 0.0; + ? closeButtonSize! + : 0.0; return EdgeInsets.only(top: top); }