diff --git a/frontend/app_flowy/packages/appflowy_popover/README.md b/frontend/app_flowy/packages/appflowy_popover/README.md index 9d974e2253..11b608c860 100644 --- a/frontend/app_flowy/packages/appflowy_popover/README.md +++ b/frontend/app_flowy/packages/appflowy_popover/README.md @@ -1,38 +1,107 @@ - - # AppFlowy Popover A Popover can be used to display some content on top of another. -## Features +It can be used to display a dropdown menu. > A popover is a transient view that appears above other content onscreen when you tap a control or in an area. Typically, a popover includes an arrow pointing to the location from which it emerged. Popovers can be nonmodal or modal. A nonmodal popover is dismissed by tapping another part of the screen or a button on the popover. A modal popover is dismissed by tapping a Cancel or other button on the popover. Source: [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/views/popovers/). +## Features + - Basic popover style +- Follow the target automatically - Nested popover support -- Exclusive popover API +- Exclusive API + +![](./screenshot.png) ## Example ```dart Popover( + // Define how to trigger the popover triggerActions: PopoverTriggerActionFlags.click, child: TextButton(child: Text("Popover"), onPressed: () {}), + // Define the direction of the popover + direction: PopoverDirection.bottomWithLeftAligned, popupBuilder(BuildContext context) { return PopoverMenu(); }, ); ``` + +### Trigger the popover manually + +Sometimes, if you want to trigger the popover manually, you can use a `PopoverController`. + +```dart +class MyWidgetState extends State { + late PopoverController _popover; + + @override + void initState() { + _popover = PopoverController(); + super.initState(); + } + + // triggered by another widget + _onClick() { + _popover.show(); + } + + @override + Widget build(BuildContext context) { + return Popover( + controller: _popover, + ... + ) + } +} +``` + +### Make several popovers exclusive + +The popover has a mechanism to make sure there are only one popover is shown in a group of popovers. +It's called `PopoverMutex`. + +If you pass the same mutex object to the popovers, there will be only one popover is triggered. + +```dart +class MyWidgetState extends State { + final _popoverMutex = PopoverMutex(); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Popover( + mutex: _popoverMutex, + ... + ), + Popover( + mutex: _popoverMutex, + ... + ), + Popover( + mutex: _popoverMutex, + ... + ), + ] + ) + } +} +``` + +## API + +| Param | Description | Type | +| -------------- | ---------------------------------------------------------------- | --------------------------------------- | +| offset | The offset between the popover and the child | `Offset` | +| popupBuilder | The function used to build the popover | `Widget Function(BuildContext context)` | +| triggerActions | Define the actions about how to trigger the popover | `int` | +| mutex | If multiple popovers are exclusive, pass the same mutex to them. | `PopoverMutex` | +| direction | The direction where the popover should be placed | `PopoverDirection` | +| onClose | The callback will be called after the popover is closed | `void Function()` | +| child | The child to trigger the popover | `Widget` | diff --git a/frontend/app_flowy/packages/appflowy_popover/example/lib/example_button.dart b/frontend/app_flowy/packages/appflowy_popover/example/lib/example_button.dart index e2eee64067..357941dc7f 100644 --- a/frontend/app_flowy/packages/appflowy_popover/example/lib/example_button.dart +++ b/frontend/app_flowy/packages/appflowy_popover/example/lib/example_button.dart @@ -13,40 +13,61 @@ class _PopoverMenuState extends State { @override Widget build(BuildContext context) { - return Container( - width: 200, - height: 200, - decoration: const BoxDecoration(color: Colors.yellow), - child: ListView(children: [ - const Text("App"), - Popover( - triggerActions: - PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click, - mutex: popOverMutex, - offset: const Offset(10, 0), - popupBuilder: (BuildContext context) { - return const PopoverMenu(); - }, - child: TextButton( - onPressed: () {}, - child: const Text("First"), + return Material( + type: MaterialType.transparency, + child: Container( + width: 200, + height: 200, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(8)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 5, + blurRadius: 7, + offset: const Offset(0, 3), // changes position of shadow + ), + ], ), - ), - Popover( - triggerActions: - PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click, - mutex: popOverMutex, - offset: const Offset(10, 0), - popupBuilder: (BuildContext context) { - return const PopoverMenu(); - }, - child: TextButton( - onPressed: () {}, - child: const Text("Second"), - ), - ), - ]), - ); + child: ListView(children: [ + Container( + margin: const EdgeInsets.all(8), + child: const Text("Popover", + style: TextStyle( + fontSize: 14, + color: Colors.black, + fontStyle: null, + decoration: null)), + ), + Popover( + triggerActions: PopoverTriggerActionFlags.hover | + PopoverTriggerActionFlags.click, + mutex: popOverMutex, + offset: const Offset(10, 0), + popupBuilder: (BuildContext context) { + return const PopoverMenu(); + }, + child: TextButton( + onPressed: () {}, + child: const Text("First"), + ), + ), + Popover( + triggerActions: PopoverTriggerActionFlags.hover | + PopoverTriggerActionFlags.click, + mutex: popOverMutex, + offset: const Offset(10, 0), + popupBuilder: (BuildContext context) { + return const PopoverMenu(); + }, + child: TextButton( + onPressed: () {}, + child: const Text("Second"), + ), + ), + ]), + )); } } diff --git a/frontend/app_flowy/packages/appflowy_popover/screenshot.png b/frontend/app_flowy/packages/appflowy_popover/screenshot.png new file mode 100644 index 0000000000..556559d7a2 Binary files /dev/null and b/frontend/app_flowy/packages/appflowy_popover/screenshot.png differ