Browse Source

Merge pull request #1045 from AppFlowy-IO/feat/wrap-appflowy-style-popover

Nathan.fooo 2 years ago
parent
commit
4f34068f51
26 changed files with 291 additions and 308 deletions
  1. 26 26
      frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_setting.dart
  2. 20 3
      frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_toolbar.dart
  3. 3 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_cell.dart
  4. 8 13
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_editor.dart
  5. 12 14
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart
  6. 16 18
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart
  7. 6 10
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/url_cell/cell_editor.dart
  8. 5 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/url_cell/url_cell.dart
  9. 10 12
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_editor.dart
  10. 2 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_list.dart
  11. 3 6
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_option_editor.dart
  12. 7 9
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/grid_header.dart
  13. 20 23
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart
  14. 1 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/multi_select.dart
  15. 10 12
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart
  16. 18 20
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart
  17. 1 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/single_select.dart
  18. 29 18
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/row/row_detail.dart
  19. 15 23
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_group.dart
  20. 7 9
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_property.dart
  21. 12 17
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_toolbar.dart
  22. 9 9
      frontend/app_flowy/packages/appflowy_popover/lib/popover.dart
  23. 1 1
      frontend/app_flowy/packages/flowy_infra_ui/lib/flowy_infra_ui.dart
  24. 48 0
      frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/appflowy_stype_popover.dart
  25. 0 59
      frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_popover.dart
  26. 2 0
      frontend/app_flowy/packages/flowy_infra_ui/pubspec.yaml

+ 26 - 26
frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_setting.dart

@@ -2,11 +2,12 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
 import 'package:app_flowy/plugins/board/application/toolbar/board_setting_bloc.dart';
 import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
 import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
+import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_group.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_property.dart';
+import 'package:appflowy_popover/popover.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
@@ -141,10 +142,12 @@ extension _GridSettingExtension on BoardSettingAction {
 }
 
 class BoardSettingListPopover extends StatefulWidget {
+  final PopoverController popoverController;
   final BoardSettingContext settingContext;
 
   const BoardSettingListPopover({
     Key? key,
+    required this.popoverController,
     required this.settingContext,
   }) : super(key: key);
 
@@ -153,36 +156,33 @@ class BoardSettingListPopover extends StatefulWidget {
 }
 
 class _BoardSettingListPopoverState extends State<BoardSettingListPopover> {
-  bool _showGridPropertyList = false;
+  BoardSettingAction? _action;
 
   @override
   Widget build(BuildContext context) {
-    if (_showGridPropertyList) {
-      return OverlayContainer(
-        constraints: BoxConstraints.loose(const Size(260, 400)),
-        child: GridPropertyList(
-          gridId: widget.settingContext.viewId,
-          fieldController: widget.settingContext.fieldController,
-        ),
-      );
+    if (_action != null) {
+      switch (_action!) {
+        case BoardSettingAction.groups:
+          return GridGroupList(
+            viewId: widget.settingContext.viewId,
+            fieldController: widget.settingContext.fieldController,
+            onDismissed: () {
+              widget.popoverController.close();
+            },
+          );
+        case BoardSettingAction.properties:
+          return GridPropertyList(
+            gridId: widget.settingContext.viewId,
+            fieldController: widget.settingContext.fieldController,
+          );
+      }
     }
 
-    return OverlayContainer(
-      constraints: BoxConstraints.loose(const Size(140, 400)),
-      child: BoardSettingList(
-        settingContext: widget.settingContext,
-        onAction: (action, settingContext) {
-          switch (action) {
-            case BoardSettingAction.groups:
-              break;
-            case BoardSettingAction.properties:
-              setState(() {
-                _showGridPropertyList = true;
-              });
-              break;
-          }
-        },
-      ),
+    return BoardSettingList(
+      settingContext: widget.settingContext,
+      onAction: (action, settingContext) {
+        setState(() => _action = action);
+      },
     );
   }
 }

+ 20 - 3
frontend/app_flowy/lib/plugins/board/presentation/toolbar/board_toolbar.dart

@@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
 import 'package:appflowy_popover/popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/icon_button.dart';
 import 'package:flutter/widgets.dart';
 import 'package:provider/provider.dart';
@@ -40,15 +41,30 @@ class BoardToolbar extends StatelessWidget {
   }
 }
 
-class _SettingButton extends StatelessWidget {
+class _SettingButton extends StatefulWidget {
   final BoardSettingContext settingContext;
   const _SettingButton({required this.settingContext, Key? key})
       : super(key: key);
 
+  @override
+  State<_SettingButton> createState() => _SettingButtonState();
+}
+
+class _SettingButtonState extends State<_SettingButton> {
+  late PopoverController popoverController;
+
+  @override
+  void initState() {
+    popoverController = PopoverController();
+    super.initState();
+  }
+
   @override
   Widget build(BuildContext context) {
     final theme = context.read<AppTheme>();
-    return Popover(
+    return AppFlowyStylePopover(
+      controller: popoverController,
+      constraints: BoxConstraints.loose(const Size(260, 400)),
       triggerActions: PopoverTriggerActionFlags.click,
       child: FlowyIconButton(
         hoverColor: theme.hover,
@@ -61,7 +77,8 @@ class _SettingButton extends StatelessWidget {
       ),
       popupBuilder: (BuildContext popoverContext) {
         return BoardSettingListPopover(
-          settingContext: settingContext,
+          settingContext: widget.settingContext,
+          popoverController: popoverController,
         );
       },
     );

+ 3 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_cell.dart

@@ -1,3 +1,4 @@
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -62,10 +63,11 @@ class _DateCellState extends GridCellState<GridDateCell> {
       value: _cellBloc,
       child: BlocBuilder<DateCellBloc, DateCellState>(
         builder: (context, state) {
-          return Popover(
+          return AppFlowyStylePopover(
             controller: _popover,
             offset: const Offset(0, 20),
             direction: PopoverDirection.bottomWithLeftAligned,
+            constraints: BoxConstraints.loose(const Size(320, 500)),
             child: SizedBox.expand(
               child: GestureDetector(
                 behavior: HitTestBehavior.opaque,

+ 8 - 13
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_editor.dart

@@ -64,12 +64,9 @@ class _DateCellEditor extends State<DateCellEditor> {
       return Container();
     }
 
-    return OverlayContainer(
-      constraints: BoxConstraints.loose(const Size(320, 500)),
-      child: _CellCalendarWidget(
-        cellContext: widget.cellController,
-        dateTypeOptionPB: _dateTypeOptionPB!,
-      ),
+    return _CellCalendarWidget(
+      cellContext: widget.cellController,
+      dateTypeOptionPB: _dateTypeOptionPB!,
     );
   }
 }
@@ -302,10 +299,11 @@ class _DateTypeOptionButton extends StatelessWidget {
     return BlocSelector<DateCalBloc, DateCalState, DateTypeOptionPB>(
       selector: (state) => state.dateTypeOptionPB,
       builder: (context, dateTypeOptionPB) {
-        return Popover(
+        return AppFlowyStylePopover(
           triggerActions:
               PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
           offset: const Offset(20, 0),
+          constraints: BoxConstraints.loose(const Size(140, 100)),
           child: FlowyButton(
             text: FlowyText.medium(title, fontSize: 12),
             hoverColor: theme.hover,
@@ -313,12 +311,9 @@ class _DateTypeOptionButton extends StatelessWidget {
             rightIcon: svgWidget("grid/more", color: theme.iconColor),
           ),
           popupBuilder: (BuildContext popContext) {
-            return OverlayContainer(
-              constraints: BoxConstraints.loose(const Size(140, 100)),
-              child: _CalDateTimeSetting(
-                dateTypeOptionPB: dateTypeOptionPB,
-                onEvent: (event) => context.read<DateCalBloc>().add(event),
-              ),
+            return _CalDateTimeSetting(
+              dateTypeOptionPB: dateTypeOptionPB,
+              onEvent: (event) => context.read<DateCalBloc>().add(event),
             );
           },
         );

+ 12 - 14
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart

@@ -3,7 +3,7 @@ import 'package:app_flowy/plugins/grid/application/prelude.dart';
 import 'package:appflowy_popover/popover.dart';
 
 import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 // ignore: unused_import
 import 'package:flowy_sdk/log.dart';
@@ -194,8 +194,10 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
       alignment: AlignmentDirectional.center,
       fit: StackFit.expand,
       children: [
-        Popover(
+        AppFlowyStylePopover(
           controller: _popover,
+          constraints: BoxConstraints.loose(
+              Size(SelectOptionCellEditor.editorPanelWidth, 300)),
           offset: const Offset(0, 20),
           direction: PopoverDirection.bottomWithLeftAligned,
           // triggerActions: PopoverTriggerActionFlags.c,
@@ -203,18 +205,14 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
             WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
               widget.onFocus?.call(true);
             });
-            return OverlayContainer(
-              constraints: BoxConstraints.loose(
-                  Size(SelectOptionCellEditor.editorPanelWidth, 300)),
-              child: SizedBox(
-                width: SelectOptionCellEditor.editorPanelWidth,
-                child: SelectOptionCellEditor(
-                  cellController: widget.cellControllerBuilder.build()
-                      as GridSelectOptionCellController,
-                  onDismissed: () {
-                    widget.onFocus?.call(false);
-                  },
-                ),
+            return SizedBox(
+              width: SelectOptionCellEditor.editorPanelWidth,
+              child: SelectOptionCellEditor(
+                cellController: widget.cellControllerBuilder.build()
+                    as GridSelectOptionCellController,
+                onDismissed: () {
+                  widget.onFocus?.call(false);
+                },
               ),
             );
           },

+ 16 - 18
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart

@@ -251,9 +251,10 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-    return Popover(
+    return AppFlowyStylePopover(
       controller: _popoverController,
       offset: const Offset(20, 0),
+      constraints: BoxConstraints.loose(const Size(200, 300)),
       child: SizedBox(
         height: GridSize.typeOptionItemHeight,
         child: Row(
@@ -286,23 +287,20 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
         ),
       ),
       popupBuilder: (BuildContext popoverContext) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(200, 300)),
-          child: SelectOptionTypeOptionEditor(
-            option: widget.option,
-            onDeleted: () {
-              context
-                  .read<SelectOptionCellEditorBloc>()
-                  .add(SelectOptionEditorEvent.deleteOption(widget.option));
-            },
-            onUpdated: (updatedOption) {
-              context
-                  .read<SelectOptionCellEditorBloc>()
-                  .add(SelectOptionEditorEvent.updateOption(updatedOption));
-            },
-            key: ValueKey(widget.option
-                .id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
-          ),
+        return SelectOptionTypeOptionEditor(
+          option: widget.option,
+          onDeleted: () {
+            context
+                .read<SelectOptionCellEditorBloc>()
+                .add(SelectOptionEditorEvent.deleteOption(widget.option));
+          },
+          onUpdated: (updatedOption) {
+            context
+                .read<SelectOptionCellEditorBloc>()
+                .add(SelectOptionEditorEvent.updateOption(updatedOption));
+          },
+          key: ValueKey(widget.option
+              .id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
         );
       },
     );

+ 6 - 10
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/url_cell/cell_editor.dart

@@ -1,6 +1,5 @@
 import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
 import 'package:app_flowy/plugins/grid/application/cell/url_cell_editor_bloc.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/material.dart';
 import 'dart:async';
 
@@ -79,15 +78,12 @@ class URLEditorPopover extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return OverlayContainer(
-      constraints: BoxConstraints.loose(const Size(300, 160)),
-      child: SizedBox(
-        width: 200,
-        child: Padding(
-          padding: const EdgeInsets.all(6),
-          child: URLCellEditor(
-            cellController: cellController,
-          ),
+    return SizedBox(
+      width: 200,
+      child: Padding(
+        padding: const EdgeInsets.all(6),
+        child: URLCellEditor(
+          cellController: cellController,
         ),
       ),
     );

+ 5 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/url_cell/url_cell.dart

@@ -6,6 +6,7 @@ import 'package:appflowy_popover/popover.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -129,8 +130,9 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
             ),
           );
 
-          return Popover(
+          return AppFlowyStylePopover(
             controller: _popoverController,
+            constraints: BoxConstraints.loose(const Size(300, 160)),
             direction: PopoverDirection.bottomWithLeftAligned,
             offset: const Offset(0, 20),
             child: SizedBox.expand(
@@ -214,7 +216,8 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-    return Popover(
+    return AppFlowyStylePopover(
+      constraints: BoxConstraints.loose(const Size(300, 160)),
       controller: _popoverController,
       direction: PopoverDirection.bottomWithLeftAligned,
       triggerActions: PopoverTriggerActionFlags.click,

+ 10 - 12
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_editor.dart

@@ -163,22 +163,20 @@ class _DeleteFieldButton extends StatelessWidget {
   }
 
   Widget _wrapPopover(Widget widget) {
-    return Popover(
+    return AppFlowyStylePopover(
       triggerActions: PopoverTriggerActionFlags.click,
+      constraints: BoxConstraints.loose(const Size(400, 240)),
       mutex: popoverMutex,
       direction: PopoverDirection.center,
       popupBuilder: (popupContext) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(400, 240)),
-          child: PopoverAlertView(
-            title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
-            cancel: () => popoverMutex.state?.close(),
-            confirm: () {
-              onDeleted?.call();
-              popoverMutex.state?.close();
-            },
-            popoverMutex: popoverMutex,
-          ),
+        return PopoverAlertView(
+          title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
+          cancel: () => popoverMutex.state?.close(),
+          confirm: () {
+            onDeleted?.call();
+            popoverMutex.state?.close();
+          },
+          popoverMutex: popoverMutex,
         );
       },
       child: widget,

+ 2 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_list.dart

@@ -1,3 +1,4 @@
+import 'package:appflowy_popover/popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -25,7 +26,7 @@ class FieldTypeList extends StatelessWidget with FlowyOverlayDelegate {
         fieldType: fieldType,
         onSelectField: (fieldType) {
           onSelectField(fieldType);
-          FlowyOverlay.of(context).remove(FieldTypeList.identifier());
+          PopoverContainer.of(context).closeAll();
         },
       );
     }).toList();

+ 3 - 6
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_option_editor.dart

@@ -64,18 +64,15 @@ class FieldTypeOptionEditor extends StatelessWidget {
     final theme = context.watch<AppTheme>();
     return SizedBox(
       height: GridSize.typeOptionItemHeight,
-      child: Popover(
+      child: AppFlowyStylePopover(
+        constraints: BoxConstraints.loose(const Size(460, 440)),
         triggerActions: PopoverTriggerActionFlags.click,
         mutex: popoverMutex,
         offset: const Offset(20, 0),
         popupBuilder: (context) {
-          final list = FieldTypeList(onSelectField: (newFieldType) {
+          return FieldTypeList(onSelectField: (newFieldType) {
             dataController.switchToField(newFieldType);
           });
-          return OverlayContainer(
-            constraints: BoxConstraints.loose(const Size(460, 440)),
-            child: list,
-          );
         },
         child: FlowyButton(
           text: FlowyText.medium(field.fieldType.title(), fontSize: 12),

+ 7 - 9
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/grid_header.dart

@@ -7,7 +7,7 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:appflowy_popover/popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
@@ -176,9 +176,10 @@ class CreateFieldButton extends StatelessWidget {
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
 
-    return Popover(
+    return AppFlowyStylePopover(
       triggerActions: PopoverTriggerActionFlags.click,
       direction: PopoverDirection.bottomWithRightAligned,
+      constraints: BoxConstraints.loose(const Size(240, 200)),
       child: FlowyButton(
         text: FlowyText.medium(
           LocaleKeys.grid_field_newColumn.tr(),
@@ -192,13 +193,10 @@ class CreateFieldButton extends StatelessWidget {
         ),
       ),
       popupBuilder: (BuildContext popover) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(240, 200)),
-          child: FieldEditor(
-            gridId: gridId,
-            fieldName: "",
-            typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
-          ),
+        return FieldEditor(
+          gridId: gridId,
+          fieldName: "",
+          typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
         );
       },
     );

+ 20 - 23
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart

@@ -62,23 +62,21 @@ class DateTypeOptionWidget extends TypeOptionWidget {
   }
 
   Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) {
-    return Popover(
+    return AppFlowyStylePopover(
       mutex: popoverMutex,
       triggerActions:
           PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
       offset: const Offset(20, 0),
+      constraints: BoxConstraints.loose(const Size(460, 440)),
       popupBuilder: (popoverContext) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(460, 440)),
-          child: DateFormatList(
-            selectedFormat: dataFormat,
-            onSelected: (format) {
-              context
-                  .read<DateTypeOptionBloc>()
-                  .add(DateTypeOptionEvent.didSelectDateFormat(format));
-              PopoverContainerState.of(popoverContext).closeAll();
-            },
-          ),
+        return DateFormatList(
+          selectedFormat: dataFormat,
+          onSelected: (format) {
+            context
+                .read<DateTypeOptionBloc>()
+                .add(DateTypeOptionEvent.didSelectDateFormat(format));
+            PopoverContainer.of(popoverContext).closeAll();
+          },
         );
       },
       child: const DateFormatButton(),
@@ -86,22 +84,21 @@ class DateTypeOptionWidget extends TypeOptionWidget {
   }
 
   Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) {
-    return Popover(
+    return AppFlowyStylePopover(
       mutex: popoverMutex,
       triggerActions:
           PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
       offset: const Offset(20, 0),
+      constraints: BoxConstraints.loose(const Size(460, 440)),
       popupBuilder: (BuildContext popoverContext) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(460, 440)),
-          child: TimeFormatList(
-              selectedFormat: timeFormat,
-              onSelected: (format) {
-                context
-                    .read<DateTypeOptionBloc>()
-                    .add(DateTypeOptionEvent.didSelectTimeFormat(format));
-                PopoverContainerState.of(popoverContext).closeAll();
-              }),
+        return TimeFormatList(
+          selectedFormat: timeFormat,
+          onSelected: (format) {
+            context
+                .read<DateTypeOptionBloc>()
+                .add(DateTypeOptionEvent.didSelectTimeFormat(format));
+            PopoverContainer.of(popoverContext).closeAll();
+          },
         );
       },
       child: TimeFormatButton(timeFormat: timeFormat),

+ 1 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/multi_select.dart

@@ -41,7 +41,7 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
     return SelectOptionTypeOptionWidget(
       options: selectOptionAction.typeOption.options,
       beginEdit: () {
-        PopoverContainerState.of(context).closeAll();
+        PopoverContainer.of(context).closeAll();
       },
       popoverMutex: popoverMutex,
       typeOptionAction: selectOptionAction,

+ 10 - 12
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart

@@ -55,11 +55,12 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
           listener: (context, state) =>
               typeOptionContext.typeOption = state.typeOption,
           builder: (context, state) {
-            return Popover(
+            return AppFlowyStylePopover(
               mutex: popoverMutex,
               triggerActions: PopoverTriggerActionFlags.hover |
                   PopoverTriggerActionFlags.click,
               offset: const Offset(20, 0),
+              constraints: BoxConstraints.loose(const Size(460, 440)),
               child: FlowyButton(
                 margin: GridSize.typeOptionContentInsets,
                 hoverColor: theme.hover,
@@ -76,17 +77,14 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
                 ),
               ),
               popupBuilder: (BuildContext popoverContext) {
-                return OverlayContainer(
-                  constraints: BoxConstraints.loose(const Size(460, 440)),
-                  child: NumberFormatList(
-                    onSelected: (format) {
-                      context
-                          .read<NumberTypeOptionBloc>()
-                          .add(NumberTypeOptionEvent.didSelectFormat(format));
-                      PopoverContainerState.of(popoverContext).closeAll();
-                    },
-                    selectedFormat: state.typeOption.format,
-                  ),
+                return NumberFormatList(
+                  onSelected: (format) {
+                    context
+                        .read<NumberTypeOptionBloc>()
+                        .add(NumberTypeOptionEvent.didSelectFormat(format));
+                    PopoverContainer.of(popoverContext).closeAll();
+                  },
+                  selectedFormat: state.typeOption.format,
                 );
               },
             );

+ 18 - 20
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart

@@ -2,7 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/type_option/select_opti
 import 'package:appflowy_popover/popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
@@ -180,10 +180,11 @@ class _OptionCellState extends State<_OptionCell> {
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
 
-    return Popover(
+    return AppFlowyStylePopover(
       controller: _popoverController,
       mutex: widget.popoverMutex,
       offset: const Offset(20, 0),
+      constraints: BoxConstraints.loose(const Size(460, 440)),
       child: SizedBox(
         height: GridSize.typeOptionItemHeight,
         child: SelectOptionTagCell(
@@ -200,24 +201,21 @@ class _OptionCellState extends State<_OptionCell> {
         ),
       ),
       popupBuilder: (BuildContext popoverContext) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(460, 440)),
-          child: SelectOptionTypeOptionEditor(
-            option: widget.option,
-            onDeleted: () {
-              context
-                  .read<SelectOptionTypeOptionBloc>()
-                  .add(SelectOptionTypeOptionEvent.deleteOption(widget.option));
-              PopoverContainerState.of(popoverContext).closeAll();
-            },
-            onUpdated: (updatedOption) {
-              context
-                  .read<SelectOptionTypeOptionBloc>()
-                  .add(SelectOptionTypeOptionEvent.updateOption(updatedOption));
-              PopoverContainerState.of(popoverContext).closeAll();
-            },
-            key: ValueKey(widget.option.id),
-          ),
+        return SelectOptionTypeOptionEditor(
+          option: widget.option,
+          onDeleted: () {
+            context
+                .read<SelectOptionTypeOptionBloc>()
+                .add(SelectOptionTypeOptionEvent.deleteOption(widget.option));
+            PopoverContainer.of(popoverContext).closeAll();
+          },
+          onUpdated: (updatedOption) {
+            context
+                .read<SelectOptionTypeOptionBloc>()
+                .add(SelectOptionTypeOptionEvent.updateOption(updatedOption));
+            PopoverContainer.of(popoverContext).closeAll();
+          },
+          key: ValueKey(widget.option.id),
         );
       },
     );

+ 1 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/single_select.dart

@@ -40,7 +40,7 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
     return SelectOptionTypeOptionWidget(
       options: selectOptionAction.typeOption.options,
       beginEdit: () {
-        PopoverContainerState.of(context).closeAll();
+        PopoverContainer.of(context).closeAll();
       },
       popoverMutex: popoverMutex,
       typeOptionAction: selectOptionAction,

+ 29 - 18
frontend/app_flowy/lib/plugins/grid/presentation/widgets/row/row_detail.dart

@@ -146,18 +146,15 @@ class _PropertyList extends StatelessWidget {
                 });
               },
               onOpened: (controller) {
-                return OverlayContainer(
-                  constraints: BoxConstraints.loose(const Size(240, 200)),
-                  child: FieldEditor(
-                    gridId: viewId,
-                    typeOptionLoader: NewFieldTypeOptionLoader(gridId: viewId),
-                    onDeleted: (fieldId) {
-                      controller.close();
-                      context
-                          .read<RowDetailBloc>()
-                          .add(RowDetailEvent.deleteField(fieldId));
-                    },
-                  ),
+                return FieldEditor(
+                  gridId: viewId,
+                  typeOptionLoader: NewFieldTypeOptionLoader(gridId: viewId),
+                  onDeleted: (fieldId) {
+                    controller.close();
+                    context
+                        .read<RowDetailBloc>()
+                        .add(RowDetailEvent.deleteField(fieldId));
+                  },
                 );
               },
             ),
@@ -168,28 +165,41 @@ class _PropertyList extends StatelessWidget {
   }
 }
 
-class _CreateFieldButton extends StatelessWidget {
+class _CreateFieldButton extends StatefulWidget {
   final String viewId;
   final Widget Function(PopoverController) onOpened;
   final VoidCallback onClosed;
-  final PopoverController popoverController = PopoverController();
 
-  _CreateFieldButton({
+  const _CreateFieldButton({
     required this.viewId,
     required this.onOpened,
     required this.onClosed,
     Key? key,
   }) : super(key: key);
 
+  @override
+  State<_CreateFieldButton> createState() => _CreateFieldButtonState();
+}
+
+class _CreateFieldButtonState extends State<_CreateFieldButton> {
+  late PopoverController popoverController;
+
+  @override
+  void initState() {
+    popoverController = PopoverController();
+    super.initState();
+  }
+
   @override
   Widget build(BuildContext context) {
     final theme = context.read<AppTheme>();
 
-    return Popover(
+    return AppFlowyStylePopover(
+      constraints: BoxConstraints.loose(const Size(240, 200)),
       controller: popoverController,
       triggerActions: PopoverTriggerActionFlags.click,
       direction: PopoverDirection.topWithLeftAligned,
-      onClose: onClosed,
+      onClose: widget.onClosed,
       child: Container(
         height: 40,
         decoration: _makeBoxDecoration(context),
@@ -203,7 +213,8 @@ class _CreateFieldButton extends StatelessWidget {
           leftIcon: svgWidget("home/add"),
         ),
       ),
-      popupBuilder: (BuildContext context) => onOpened(popoverController),
+      popupBuilder: (BuildContext context) =>
+          widget.onOpened(popoverController),
     );
   }
 

+ 15 - 23
frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_group.dart

@@ -3,7 +3,6 @@ import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/header/field_type_extension.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
@@ -15,9 +14,11 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 class GridGroupList extends StatelessWidget {
   final String viewId;
   final GridFieldController fieldController;
+  final VoidCallback onDismissed;
   const GridGroupList({
     required this.viewId,
     required this.fieldController,
+    required this.onDismissed,
     Key? key,
   }) : super(key: key);
 
@@ -33,6 +34,7 @@ class GridGroupList extends StatelessWidget {
           final cells = state.fieldContexts.map((fieldContext) {
             Widget cell = _GridGroupCell(
               fieldContext: fieldContext,
+              onSelected: () => onDismissed(),
               key: ValueKey(fieldContext.id),
             );
 
@@ -56,29 +58,16 @@ class GridGroupList extends StatelessWidget {
       ),
     );
   }
-
-  void show(BuildContext context) {
-    FlowyOverlay.of(context).insertWithAnchor(
-      widget: OverlayContainer(
-        constraints: BoxConstraints.loose(const Size(260, 400)),
-        child: this,
-      ),
-      identifier: identifier(),
-      anchorContext: context,
-      anchorDirection: AnchorDirection.bottomRight,
-      style: FlowyOverlayStyle(blur: false),
-    );
-  }
-
-  static String identifier() {
-    return (GridGroupList).toString();
-  }
 }
 
 class _GridGroupCell extends StatelessWidget {
+  final VoidCallback onSelected;
   final GridFieldContext fieldContext;
-  const _GridGroupCell({required this.fieldContext, Key? key})
-      : super(key: key);
+  const _GridGroupCell({
+    required this.fieldContext,
+    required this.onSelected,
+    Key? key,
+  }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
@@ -97,8 +86,10 @@ class _GridGroupCell extends StatelessWidget {
       child: FlowyButton(
         text: FlowyText.medium(fieldContext.name, fontSize: 12),
         hoverColor: theme.hover,
-        leftIcon: svgWidget(fieldContext.fieldType.iconName(),
-            color: theme.iconColor),
+        leftIcon: svgWidget(
+          fieldContext.fieldType.iconName(),
+          color: theme.iconColor,
+        ),
         rightIcon: rightIcon,
         onTap: () {
           context.read<GridGroupBloc>().add(
@@ -107,7 +98,8 @@ class _GridGroupCell extends StatelessWidget {
                   fieldContext.fieldType,
                 ),
               );
-          FlowyOverlay.of(context).remove(GridGroupList.identifier());
+          onSelected();
+          // FlowyOverlay.of(context).remove(GridGroupList.identifier());
         },
       ),
     );

+ 7 - 9
frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_property.dart

@@ -116,10 +116,11 @@ class _GridPropertyCell extends StatelessWidget {
   }
 
   Widget _editFieldButton(AppTheme theme, BuildContext context) {
-    return Popover(
+    return AppFlowyStylePopover(
       mutex: popoverMutex,
       triggerActions: PopoverTriggerActionFlags.click,
       offset: const Offset(20, 0),
+      constraints: BoxConstraints.loose(const Size(240, 200)),
       child: FlowyButton(
         text: FlowyText.medium(fieldContext.name, fontSize: 12),
         hoverColor: theme.hover,
@@ -127,14 +128,11 @@ class _GridPropertyCell extends StatelessWidget {
             color: theme.iconColor),
       ),
       popupBuilder: (BuildContext context) {
-        return OverlayContainer(
-          constraints: BoxConstraints.loose(const Size(240, 200)),
-          child: FieldEditor(
-            gridId: gridId,
-            fieldName: fieldContext.name,
-            typeOptionLoader: FieldTypeOptionLoader(
-                gridId: gridId, field: fieldContext.field),
-          ),
+        return FieldEditor(
+          gridId: gridId,
+          fieldName: fieldContext.name,
+          typeOptionLoader:
+              FieldTypeOptionLoader(gridId: gridId, field: fieldContext.field),
         );
       },
     );

+ 12 - 17
frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_toolbar.dart

@@ -53,7 +53,8 @@ class _SettingButton extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-    return Popover(
+    return AppFlowyStylePopover(
+      constraints: BoxConstraints.loose(const Size(260, 400)),
       triggerActions: PopoverTriggerActionFlags.click,
       offset: const Offset(0, 10),
       child: FlowyIconButton(
@@ -87,25 +88,19 @@ class _GridSettingListPopoverState extends State<_GridSettingListPopover> {
   @override
   Widget build(BuildContext context) {
     if (_action == GridSettingAction.properties) {
-      return OverlayContainer(
-        constraints: BoxConstraints.loose(const Size(260, 400)),
-        child: GridPropertyList(
-          gridId: widget.settingContext.gridId,
-          fieldController: widget.settingContext.fieldController,
-        ),
+      return GridPropertyList(
+        gridId: widget.settingContext.gridId,
+        fieldController: widget.settingContext.fieldController,
       );
     }
 
-    return OverlayContainer(
-      constraints: BoxConstraints.loose(const Size(140, 400)),
-      child: GridSettingList(
-        settingContext: widget.settingContext,
-        onAction: (action, settingContext) {
-          setState(() {
-            _action = action;
-          });
-        },
-      ),
+    return GridSettingList(
+      settingContext: widget.settingContext,
+      onAction: (action, settingContext) {
+        setState(() {
+          _action = action;
+        });
+      },
     );
   }
 }

+ 9 - 9
frontend/app_flowy/packages/appflowy_popover/lib/popover.dart

@@ -284,6 +284,15 @@ class PopoverContainer extends StatefulWidget {
 
   @override
   State<StatefulWidget> createState() => PopoverContainerState();
+
+  static PopoverContainerState of(BuildContext context) {
+    if (context is StatefulElement && context.state is PopoverContainerState) {
+      return context.state as PopoverContainerState;
+    }
+    final PopoverContainerState? result =
+        context.findAncestorStateOfType<PopoverContainerState>();
+    return result!;
+  }
 }
 
 class PopoverContainerState extends State<PopoverContainer> {
@@ -302,13 +311,4 @@ class PopoverContainerState extends State<PopoverContainer> {
   close() => widget.onClose();
 
   closeAll() => widget.onCloseAll();
-
-  static PopoverContainerState of(BuildContext context) {
-    if (context is StatefulElement && context.state is PopoverContainerState) {
-      return context.state as PopoverContainerState;
-    }
-    final PopoverContainerState? result =
-        context.findAncestorStateOfType<PopoverContainerState>();
-    return result!;
-  }
 }

+ 1 - 1
frontend/app_flowy/packages/flowy_infra_ui/lib/flowy_infra_ui.dart

@@ -9,4 +9,4 @@ export 'src/flowy_overlay/flowy_overlay.dart';
 export 'src/flowy_overlay/list_overlay.dart';
 export 'src/flowy_overlay/option_overlay.dart';
 export 'src/flowy_overlay/flowy_dialog.dart';
-export 'src/flowy_overlay/flowy_popover.dart';
+export 'src/flowy_overlay/appflowy_stype_popover.dart';

+ 48 - 0
frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/appflowy_stype_popover.dart

@@ -0,0 +1,48 @@
+import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
+import 'package:appflowy_popover/popover.dart';
+import 'package:flutter/material.dart';
+
+class AppFlowyStylePopover extends StatelessWidget {
+  final Widget child;
+  final PopoverController? controller;
+  final Widget Function(BuildContext context) popupBuilder;
+  final PopoverDirection direction;
+  final int triggerActions;
+  final BoxConstraints? constraints;
+  final void Function()? onClose;
+  final PopoverMutex? mutex;
+  final Offset? offset;
+
+  const AppFlowyStylePopover({
+    Key? key,
+    required this.child,
+    required this.popupBuilder,
+    this.direction = PopoverDirection.rightWithTopAligned,
+    this.onClose,
+    this.constraints,
+    this.mutex,
+    this.triggerActions = 0,
+    this.offset,
+    this.controller,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Popover(
+      controller: controller,
+      onClose: onClose,
+      direction: direction,
+      mutex: mutex,
+      triggerActions: triggerActions,
+      popupBuilder: (context) {
+        final child = popupBuilder(context);
+        debugPrint('$child popover');
+        return OverlayContainer(
+          constraints: constraints,
+          child: popupBuilder(context),
+        );
+      },
+      child: child,
+    );
+  }
+}

+ 0 - 59
frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_popover.dart

@@ -1,59 +0,0 @@
-import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
-import 'package:flowy_infra_ui/style_widget/decoration.dart';
-import 'package:flowy_infra/theme.dart';
-import 'package:provider/provider.dart';
-import 'package:flutter/material.dart';
-import './flowy_popover_layout.dart';
-
-const _overlayContainerPadding = EdgeInsets.all(12);
-
-class FlowyPopover extends StatefulWidget {
-  final Widget Function(BuildContext context) builder;
-  final ShapeBorder? shape;
-  final Rect anchorRect;
-  final AnchorDirection? anchorDirection;
-  final EdgeInsets padding;
-  final BoxConstraints? constraints;
-
-  const FlowyPopover({
-    Key? key,
-    required this.builder,
-    required this.anchorRect,
-    this.shape,
-    this.padding = _overlayContainerPadding,
-    this.anchorDirection,
-    this.constraints,
-  }) : super(key: key);
-
-  @override
-  State<FlowyPopover> createState() => _FlowyPopoverState();
-}
-
-class _FlowyPopoverState extends State<FlowyPopover> {
-  final preRenderKey = GlobalKey();
-  Size? size;
-
-  @override
-  Widget build(BuildContext context) {
-    final theme =
-        context.watch<AppTheme?>() ?? AppTheme.fromType(ThemeType.light);
-    return Material(
-        type: MaterialType.transparency,
-        child: CustomSingleChildLayout(
-            delegate: PopoverLayoutDelegate(
-              anchorRect: widget.anchorRect,
-              anchorDirection:
-                  widget.anchorDirection ?? AnchorDirection.rightWithTopAligned,
-              overlapBehaviour: OverlapBehaviour.stretch,
-            ),
-            child: Container(
-              padding: widget.padding,
-              constraints: widget.constraints ??
-                  BoxConstraints.loose(const Size(280, 400)),
-              decoration: FlowyDecoration.decoration(
-                  theme.surface, theme.shadowColor.withOpacity(0.15)),
-              key: preRenderKey,
-              child: widget.builder(context),
-            )));
-  }
-}

+ 2 - 0
frontend/app_flowy/packages/flowy_infra_ui/pubspec.yaml

@@ -27,6 +27,8 @@ dependencies:
     path: flowy_infra_ui_platform_interface
   flowy_infra_ui_web:
     path: flowy_infra_ui_web
+  appflowy_popover:
+    path: ../appflowy_popover
 
   # Flowy packages
   flowy_infra: