[infra_ui][overlay] Implement option overlay

This commit is contained in:
Jaylen Bian 2021-08-09 10:49:16 +08:00
parent 051240a2fb
commit 82e6856f75
3 changed files with 101 additions and 0 deletions

View File

@ -6,3 +6,5 @@ export 'src/keyboard/keyboard_visibility_detector.dart';
// Overlay
export 'src/flowy_overlay/flowy_overlay.dart';
export 'src/flowy_overlay/list_overlay.dart';
export 'src/flowy_overlay/option_overlay.dart';

View File

@ -6,3 +6,5 @@ export 'src/keyboard/keyboard_visibility_detector.dart';
// Overlay
export 'src/flowy_overlay/flowy_overlay.dart';
export 'src/flowy_overlay/list_overlay.dart';
export 'src/flowy_overlay/option_overlay.dart';

View File

@ -0,0 +1,97 @@
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flutter/material.dart';
class OptionItem {
const OptionItem(this.icon, this.title);
final Icon? icon;
final String title;
}
class OptionOverlay<T> extends StatelessWidget {
const OptionOverlay({
Key? key,
required this.items,
this.onHover,
this.onTap,
}) : super(key: key);
final List<T> items;
final IndexedValueCallback<T>? onHover;
final IndexedValueCallback<T>? onTap;
static void showWithAnchor<T>(
BuildContext context, {
required String identifier,
required List<T> items,
IndexedValueCallback<T>? onHover,
IndexedValueCallback<T>? onTap,
required BuildContext anchorContext,
AnchorDirection? anchorDirection,
FlowyOverlayDelegate? delegate,
OverlapBehaviour? overlapBehaviour,
}) {
FlowyOverlay.of(context).insertWithAnchor(
widget: OptionOverlay(
items: items,
onHover: onHover,
onTap: onTap,
),
identifier: identifier,
anchorContext: anchorContext,
anchorDirection: anchorDirection,
delegate: delegate,
overlapBehaviour: overlapBehaviour,
);
}
@override
Widget build(BuildContext context) {
final List<_OptionListItem> listItems = items.map((e) => _OptionListItem(e)).toList();
return ListOverlay(
itemBuilder: (context, index) {
return MouseRegion(
cursor: SystemMouseCursors.click,
onHover: onHover != null ? (_) => onHover!(items[index], index) : null,
child: GestureDetector(
onTap: onTap != null ? () => onTap!(items[index], index) : null,
child: listItems[index],
),
);
},
itemCount: listItems.length,
);
}
}
class _OptionListItem<T> extends StatelessWidget {
const _OptionListItem(
this.value, {
Key? key,
}) : super(key: key);
final T value;
@override
Widget build(BuildContext context) {
if (T == String || T == OptionItem) {
var children = <Widget>[];
if (value is String) {
children = [
Text(value as String),
];
} else if (value is OptionItem) {
final optionItem = value as OptionItem;
children = [
if (optionItem.icon != null) optionItem.icon!,
Text(optionItem.title),
];
}
return Column(
mainAxisSize: MainAxisSize.min,
children: children,
);
}
throw UnimplementedError('The type $T is not supported by option list.');
}
}