Skip to content

Commit

Permalink
Finish tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
Pante committed Aug 30, 2024
1 parent 8943c7e commit 8bdd8e3
Show file tree
Hide file tree
Showing 24 changed files with 753 additions and 41 deletions.
80 changes: 80 additions & 0 deletions docs/pages/docs/tooltip.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Callout } from "nextra/components";
import { Tabs } from 'nextra/components';
import { Widget } from "../../components/widget";
import LinkBadge from "../../components/link-badge/link-badge";
import LinkBadgeGroup from "../../components/link-badge/link-badge-group";

# Tooltip
A tooltip displays information related to a widget when focused, hovered over on desktop, and long pressed on Android,
Fuchsia and iOS.

<LinkBadgeGroup>
<LinkBadge label="API Reference" href="https://pub.dev/documentation/forui/latest/forui.widgets.tooltip/forui.widgets.tooltip-library.html"/>
</LinkBadgeGroup>

<Callout type="info">
The examples will behave differently on desktop and mobile.
</Callout>

<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='tooltip' height={300}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FTooltip(
tipBuilder: (context, style, _) => const Text('Add to library'),
child: IntrinsicWidth(
child: FButton(
style: FButtonStyle.outline,
onPress: () {},
label: Text('Long press/Hover'),
),
),
),
```
</Tabs.Tab>
</Tabs>

## Usage

### `FTooltip(...)`

```dart
FTooltip(
controller: _controller, // FTooltipController
tipAnchor: Alignment.bottomCenter,
childAnchor: Alignment.topCenter,
shift: FPortalFollowerShift.flip,
tipBuilder: (context, style, _) => const Text('Tooltip'),
child: const Placeholder(),
);
```

## Examples

### Horizontal Alignment

You can change how the tooltip is aligned to the button.

<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='tooltip' query={{axis: 'horizontal'}} height={300}/>
</Tabs.Tab>
<Tabs.Tab>
```dart {2-3}
FTooltip(
tipAnchor: Alignment.topLeft,
childAnchor: Alignment.topRight,
tipBuilder: (context, style, _) => const Text('Add to library'),
child: IntrinsicWidth(
child: FButton(
style: FButtonStyle.outline,
onPress: () {},
label: Text('Long press/Hover'),
),
),
);
```
</Tabs.Tab>
</Tabs>
4 changes: 4 additions & 0 deletions forui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

* Add `FPopover`.

* Add `FTooltip`.

### Changes

* **Breaking:** Change `FAlertIconStyle.height` to `FAlertIconStyle.size`.
Expand Down Expand Up @@ -55,6 +57,8 @@
* **Breaking:** Flattened `FStyle.formFieldStyle` - use `FStyle.enabledFormFieldStyle`, `FStyle.disabledFormFieldStyle`,
and`FStyle.errorFormFieldStyle`.

* Improve platform detection for web when initializing platform-specific variables.

### Fixes

* Fix `FResizable` not rendering properly in an expanded widget when its crossAxisExtent is null.
Expand Down
1 change: 1 addition & 0 deletions forui/lib/forui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ export 'widgets/scaffold.dart';
export 'widgets/switch.dart';
export 'widgets/tabs.dart';
export 'widgets/text_field.dart';
export 'widgets/tooltip.dart';
6 changes: 6 additions & 0 deletions forui/lib/src/foundation/platform.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';

@internal
/// The platforms that are primarily touch enabled. It isn't 100% accurate but it is a good approximation.
const touchPlatforms = { TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.fuchsia };
9 changes: 7 additions & 2 deletions forui/lib/src/theme/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ class FTheme extends StatelessWidget {
data: data,
child: Directionality(
textDirection: textDirection ?? Directionality.of(context),
child: Overlay(
// TODO: temporary until we create FApp.
child: Overlay.maybeOf(context) == null ? Overlay( // TODO: temporary until we create FApp.
initialEntries: [
OverlayEntry(
builder: (context) => DefaultTextStyle(
Expand All @@ -116,6 +115,12 @@ class FTheme extends StatelessWidget {
),
),
],
) : DefaultTextStyle(
style: data.typography.base.copyWith(
fontFamily: data.typography.defaultFontFamily,
color: data.colorScheme.foreground,
),
child: child,
),
),
);
Expand Down
10 changes: 10 additions & 0 deletions forui/lib/src/theme/theme_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ final class FThemeData with Diagnosticable {
/// The text field style.
final FTextFieldStyle textFieldStyle;

/// The tooltip style.
final FTooltipStyle tooltipStyle;

/// The scaffold style.
final FScaffoldStyle scaffoldStyle;

Expand Down Expand Up @@ -107,6 +110,7 @@ final class FThemeData with Diagnosticable {
required this.resizableStyle,
required this.tabsStyle,
required this.textFieldStyle,
required this.tooltipStyle,
required this.scaffoldStyle,
required this.dividerStyles,
required this.switchStyle,
Expand Down Expand Up @@ -141,6 +145,7 @@ final class FThemeData with Diagnosticable {
resizableStyle: FResizableStyle.inherit(colorScheme: colorScheme),
tabsStyle: FTabsStyle.inherit(colorScheme: colorScheme, typography: typography, style: style),
textFieldStyle: FTextFieldStyle.inherit(colorScheme: colorScheme, typography: typography, style: style),
tooltipStyle: FTooltipStyle.inherit(colorScheme: colorScheme, typography: typography, style: style),
scaffoldStyle: FScaffoldStyle.inherit(colorScheme: colorScheme, style: style),
dividerStyles: FDividerStyles.inherit(colorScheme: colorScheme, style: style),
switchStyle: FSwitchStyle.inherit(colorScheme: colorScheme),
Expand Down Expand Up @@ -210,6 +215,7 @@ final class FThemeData with Diagnosticable {
FResizableStyle? resizableStyle,
FTabsStyle? tabsStyle,
FTextFieldStyle? textFieldStyle,
FTooltipStyle? tooltipStyle,
FScaffoldStyle? scaffoldStyle,
FDividerStyles? dividerStyles,
FSwitchStyle? switchStyle,
Expand All @@ -235,6 +241,7 @@ final class FThemeData with Diagnosticable {
resizableStyle: resizableStyle ?? this.resizableStyle,
tabsStyle: tabsStyle ?? this.tabsStyle,
textFieldStyle: textFieldStyle ?? this.textFieldStyle,
tooltipStyle: tooltipStyle ?? this.tooltipStyle,
scaffoldStyle: scaffoldStyle ?? this.scaffoldStyle,
switchStyle: switchStyle ?? this.switchStyle,
);
Expand Down Expand Up @@ -263,6 +270,7 @@ final class FThemeData with Diagnosticable {
..add(DiagnosticsProperty('resizableStyle', resizableStyle))
..add(DiagnosticsProperty('tabsStyle', tabsStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('textFieldStyle', textFieldStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('tooltipStyle', tooltipStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('scaffoldStyle', scaffoldStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('switchStyle', switchStyle, level: DiagnosticLevel.debug));
}
Expand Down Expand Up @@ -292,6 +300,7 @@ final class FThemeData with Diagnosticable {
resizableStyle == other.resizableStyle &&
tabsStyle == other.tabsStyle &&
textFieldStyle == other.textFieldStyle &&
tooltipStyle == other.tooltipStyle &&
scaffoldStyle == other.scaffoldStyle &&
switchStyle == other.switchStyle;

Expand All @@ -317,6 +326,7 @@ final class FThemeData with Diagnosticable {
resizableStyle.hashCode ^
tabsStyle.hashCode ^
textFieldStyle.hashCode ^
tooltipStyle.hashCode ^
scaffoldStyle.hashCode ^
switchStyle.hashCode;
}
4 changes: 2 additions & 2 deletions forui/lib/src/widgets/calendar/calendar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ class FCalendar extends StatelessWidget {
/// The start date. It is truncated to the nearest date.
///
/// ## Contract
/// Throws [AssertionError] if [end] <= [start]
/// Throws [AssertionError] if [end] <= [start].
final DateTime start;

/// The end date. It is truncated to the nearest date.
///
/// ## Contract
/// Throws [AssertionError] if [end] <= [start]
/// Throws [AssertionError] if [end] <= [start].
final DateTime end;

/// The current date. It is truncated to the nearest date. Defaults to the [DateTime.now].
Expand Down
8 changes: 4 additions & 4 deletions forui/lib/src/widgets/popover.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:forui/src/foundation/platform.dart';

import 'package:meta/meta.dart';

Expand Down Expand Up @@ -69,10 +70,9 @@ final class FPopoverController extends ChangeNotifier {
/// * [FPopoverController] for controlling a popover.
/// * [FPopoverStyle] for customizing a popover's appearance.
class FPopover extends StatefulWidget {
static ({Alignment follower, Alignment target}) get _platform => switch (defaultTargetPlatform) {
TargetPlatform.android || TargetPlatform.iOS => (follower: Alignment.bottomCenter, target: Alignment.topCenter),
_ => (follower: Alignment.topCenter, target: Alignment.bottomCenter),
};
static ({Alignment follower, Alignment target}) get _platform => touchPlatforms.contains(defaultTargetPlatform)
? (follower: Alignment.bottomCenter, target: Alignment.topCenter)
: (follower: Alignment.topCenter, target: Alignment.bottomCenter);

/// The controller that shows and hides the follower. It initially hides the follower.
final FPopoverController controller;
Expand Down
4 changes: 2 additions & 2 deletions forui/lib/src/widgets/resizable/resizable.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:forui/src/foundation/platform.dart';

import 'package:meta/meta.dart';
import 'package:sugar/sugar.dart';
Expand Down Expand Up @@ -84,8 +85,7 @@ class FResizable extends StatefulWidget {
'The hitRegionExtent should be positive, but is $hitRegionExtent.',
),
controller = controller ?? FResizableController.cascade(),
hitRegionExtent = hitRegionExtent ??
(defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS ? 60 : 10);
hitRegionExtent = hitRegionExtent ?? (touchPlatforms.contains(defaultTargetPlatform) ? 60 : 10);

@override
State<StatefulWidget> createState() => _FResizableState();
Expand Down
Loading

0 comments on commit 8bdd8e3

Please sign in to comment.