feat: support customizing tooltip style (#856)

This commit is contained in:
Lucas.Xu 2024-08-06 17:14:06 +08:00 • committed by GitHub
commit 4c4cc415d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 195 additions and 162 deletions

View file

@ -74,6 +74,13 @@ class _DesktopEditorState extends State<DesktopEditor> {
...textDirectionItems, ...textDirectionItems,
...alignmentItems, ...alignmentItems,
], ],
tooltipBuilder: (context, message, child) {
return Tooltip(
message: message,
preferBelow: false,
child: child,
);
},
editorState: editorState, editorState: editorState,
textDirection: widget.textDirection, textDirection: widget.textDirection,
editorScrollController: editorScrollController, editorScrollController: editorScrollController,

View file

@ -31,6 +31,7 @@ class FloatingToolbar extends StatefulWidget {
required this.textDirection, required this.textDirection,
required this.child, required this.child,
this.style = const FloatingToolbarStyle(), this.style = const FloatingToolbarStyle(),
this.tooltipBuilder,
}); });
final List<ToolbarItem> items; final List<ToolbarItem> items;
@ -39,6 +40,7 @@ class FloatingToolbar extends StatefulWidget {
final TextDirection? textDirection; final TextDirection? textDirection;
final Widget child; final Widget child;
final FloatingToolbarStyle style; final FloatingToolbarStyle style;
final ToolbarTooltipBuilder? tooltipBuilder;
@override @override
State<FloatingToolbar> createState() => _FloatingToolbarState(); State<FloatingToolbar> createState() => _FloatingToolbarState();
@ -192,6 +194,7 @@ class _FloatingToolbarState extends State<FloatingToolbar>
toolbarElevation: widget.style.toolbarElevation, toolbarElevation: widget.style.toolbarElevation,
toolbarShadowColor: widget.style.toolbarShadowColor, toolbarShadowColor: widget.style.toolbarShadowColor,
textDirection: widget.textDirection ?? Directionality.of(context), textDirection: widget.textDirection ?? Directionality.of(context),
tooltipBuilder: widget.tooltipBuilder,
); );
return _toolbarWidget!; return _toolbarWidget!;
} }

View file

@ -10,6 +10,12 @@ const floatingToolbarContainerKey =
@visibleForTesting @visibleForTesting
const floatingToolbarItemPrefixKey = 'appflowy_editor_floating_toolbar_item'; const floatingToolbarItemPrefixKey = 'appflowy_editor_floating_toolbar_item';
typedef ToolbarTooltipBuilder = Widget Function(
BuildContext context,
String message,
Widget child,
);
class FloatingToolbarWidget extends StatefulWidget { class FloatingToolbarWidget extends StatefulWidget {
const FloatingToolbarWidget({ const FloatingToolbarWidget({
super.key, super.key,
@ -21,6 +27,7 @@ class FloatingToolbarWidget extends StatefulWidget {
required this.items, required this.items,
required this.editorState, required this.editorState,
required this.textDirection, required this.textDirection,
this.tooltipBuilder,
}); });
final List<ToolbarItem> items; final List<ToolbarItem> items;
@ -31,6 +38,7 @@ class FloatingToolbarWidget extends StatefulWidget {
final Color? toolbarShadowColor; final Color? toolbarShadowColor;
final EditorState editorState; final EditorState editorState;
final TextDirection textDirection; final TextDirection textDirection;
final ToolbarTooltipBuilder? tooltipBuilder;
@override @override
State<FloatingToolbarWidget> createState() => _FloatingToolbarWidgetState(); State<FloatingToolbarWidget> createState() => _FloatingToolbarWidgetState();
@ -57,21 +65,22 @@ class _FloatingToolbarWidgetState extends State<FloatingToolbarWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
textDirection: widget.textDirection, textDirection: widget.textDirection,
children: activeItems children: activeItems.mapIndexed(
.mapIndexed( (index, item) {
(index, item) => Center( return Center(
key: Key( key: Key(
'${floatingToolbarItemPrefixKey}_${item.id}_$index', '${floatingToolbarItemPrefixKey}_${item.id}_$index',
),
child: item.builder!(
context,
widget.editorState,
widget.toolbarActiveColor,
widget.toolbarIconColor,
),
), ),
) child: item.builder!(
.toList(growable: false), context,
widget.editorState,
widget.toolbarActiveColor,
widget.toolbarIconColor,
widget.tooltipBuilder,
),
);
},
).toList(growable: false),
), ),
), ),
), ),

View file

@ -28,19 +28,24 @@ class _AlignmentToolbarItem extends ToolbarItem {
id: 'editor.$id', id: 'editor.$id',
group: 6, group: 6,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (
context,
editorState,
highlightColor,
iconColor,
tooltipBuilder,
) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.every( final isHighlight = nodes.every(
(n) => n.attributes[blockComponentAlign] == align, (n) => n.attributes[blockComponentAlign] == align,
); );
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/$name', iconName: 'toolbar/$name',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: getTooltipText(id),
onPressed: () => editorState.updateNode( onPressed: () => editorState.updateNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -51,6 +56,16 @@ class _AlignmentToolbarItem extends ToolbarItem {
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
getTooltipText(id),
child,
);
}
return child;
}, },
); );
} }

View file

@ -4,16 +4,15 @@ final ToolbarItem bulletedListItem = ToolbarItem(
id: 'editor.bulleted_list', id: 'editor.bulleted_list',
group: 3, group: 3,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'bulleted_list'; final isHighlight = node.type == 'bulleted_list';
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/bulleted_list', iconName: 'toolbar/bulleted_list',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.bulletedList,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -21,5 +20,15 @@ final ToolbarItem bulletedListItem = ToolbarItem(
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.bulletedList,
child,
);
}
return child;
}, },
); );

View file

@ -5,7 +5,7 @@ ToolbarItem buildHighlightColorItem({List<ColorOption>? colorOptions}) {
id: 'editor.highlightColor', id: 'editor.highlightColor',
group: 4, group: 4,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
String? highlightColorHex; String? highlightColorHex;
final selection = editorState.selection!; final selection = editorState.selection!;
@ -16,12 +16,12 @@ ToolbarItem buildHighlightColorItem({List<ColorOption>? colorOptions}) {
return highlightColorHex != null; return highlightColorHex != null;
}); });
}); });
return SVGIconItemWidget(
final child = SVGIconItemWidget(
iconName: 'toolbar/highlight_color', iconName: 'toolbar/highlight_color',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.highlightColor,
onPressed: () { onPressed: () {
bool showClearButton = false; bool showClearButton = false;
nodes.allSatisfyInSelection(selection, (delta) { nodes.allSatisfyInSelection(selection, (delta) {
@ -47,6 +47,16 @@ ToolbarItem buildHighlightColorItem({List<ColorOption>? colorOptions}) {
); );
}, },
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.highlightColor,
child,
);
}
return child;
}, },
); );
} }

View file

@ -7,7 +7,7 @@ ToolbarItem buildTextColorItem({
id: 'editor.textColor', id: 'editor.textColor',
group: 4, group: 4,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
String? textColorHex; String? textColorHex;
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
@ -17,12 +17,12 @@ ToolbarItem buildTextColorItem({
return (textColorHex != null); return (textColorHex != null);
}); });
}); });
return SVGIconItemWidget(
final child = SVGIconItemWidget(
iconName: 'toolbar/text_color', iconName: 'toolbar/text_color',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.textColor,
onPressed: () { onPressed: () {
bool showClearButton = false; bool showClearButton = false;
nodes.allSatisfyInSelection( nodes.allSatisfyInSelection(
@ -51,6 +51,16 @@ ToolbarItem buildTextColorItem({
); );
}, },
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.textColor,
child,
);
}
return child;
}, },
); );
} }

View file

@ -32,7 +32,13 @@ class _FormatToolbarItem extends ToolbarItem {
id: 'editor.$id', id: 'editor.$id',
group: 2, group: 2,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (
context,
editorState,
highlightColor,
iconColor,
tooltipBuilder,
) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.allSatisfyInSelection(selection, (delta) { final isHighlight = nodes.allSatisfyInSelection(selection, (delta) {
@ -40,14 +46,24 @@ class _FormatToolbarItem extends ToolbarItem {
(attributes) => attributes[name] == true, (attributes) => attributes[name] == true,
); );
}); });
return SVGIconItemWidget(
final child = SVGIconItemWidget(
iconName: 'toolbar/$name', iconName: 'toolbar/$name',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: getTooltipText(id),
onPressed: () => editorState.toggleAttribute(name), onPressed: () => editorState.toggleAttribute(name),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
getTooltipText(id),
child,
);
}
return child;
}, },
); );
} }

View file

@ -12,18 +12,23 @@ class _HeadingToolbarItem extends ToolbarItem {
id: 'editor.h$level', id: 'editor.h$level',
group: 1, group: 1,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (
context,
editorState,
highlightColor,
iconColor,
tooltipBuilder,
) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = final isHighlight =
node.type == 'heading' && node.attributes['level'] == level; node.type == 'heading' && node.attributes['level'] == level;
final delta = (node.delta ?? Delta()).toJson(); final delta = (node.delta ?? Delta()).toJson();
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/h$level', iconName: 'toolbar/h$level',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: levelToTooltips(level),
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -41,6 +46,16 @@ class _HeadingToolbarItem extends ToolbarItem {
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
levelToTooltips(level),
child,
);
}
return child;
}, },
); );

View file

@ -11,7 +11,6 @@ class SVGIconItemWidget extends StatelessWidget {
required this.isHighlight, required this.isHighlight,
required this.highlightColor, required this.highlightColor,
this.iconColor, this.iconColor,
this.tooltip,
this.onPressed, this.onPressed,
}); });
@ -22,7 +21,6 @@ class SVGIconItemWidget extends StatelessWidget {
final bool isHighlight; final bool isHighlight;
final Color highlightColor; final Color highlightColor;
final Color? iconColor; final Color? iconColor;
final String? tooltip;
final VoidCallback? onPressed; final VoidCallback? onPressed;
@override @override
@ -49,15 +47,7 @@ class SVGIconItemWidget extends StatelessWidget {
), ),
); );
} }
if (tooltip != null) {
child = Tooltip(
textAlign: TextAlign.center,
preferBelow: false,
message: tooltip,
waitDuration: const Duration(milliseconds: 500),
child: child,
);
}
return SizedBox( return SizedBox(
width: size.width, width: size.width,
height: size.height, height: size.height,

View file

@ -11,7 +11,7 @@ final linkItem = ToolbarItem(
id: 'editor.link', id: 'editor.link',
group: 4, group: 4,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHref = nodes.allSatisfyInSelection(selection, (delta) { final isHref = nodes.allSatisfyInSelection(selection, (delta) {
@ -20,16 +20,25 @@ final linkItem = ToolbarItem(
); );
}); });
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/link', iconName: 'toolbar/link',
isHighlight: isHref, isHighlight: isHref,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.link,
onPressed: () { onPressed: () {
showLinkMenu(context, editorState, selection, isHref); showLinkMenu(context, editorState, selection, isHref);
}, },
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.link,
child,
);
}
return child;
}, },
); );

View file

@ -4,16 +4,15 @@ final ToolbarItem numberedListItem = ToolbarItem(
id: 'editor.numbered_list', id: 'editor.numbered_list',
group: 3, group: 3,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'numbered_list'; final isHighlight = node.type == 'numbered_list';
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/numbered_list', iconName: 'toolbar/numbered_list',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.numberedList,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -21,5 +20,15 @@ final ToolbarItem numberedListItem = ToolbarItem(
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.numberedList,
child,
);
}
return child;
}, },
); );

View file

@ -4,17 +4,16 @@ final ToolbarItem paragraphItem = ToolbarItem(
id: 'editor.paragraph', id: 'editor.paragraph',
group: 1, group: 1,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'paragraph'; final isHighlight = node.type == 'paragraph';
final delta = (node.delta ?? Delta()).toJson(); final delta = (node.delta ?? Delta()).toJson();
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/text', iconName: 'toolbar/text',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.text,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -29,5 +28,15 @@ final ToolbarItem paragraphItem = ToolbarItem(
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.text,
child,
);
}
return child;
}, },
); );

View file

@ -7,7 +7,7 @@ final ToolbarItem placeholderItem = ToolbarItem(
id: placeholderItemId, id: placeholderItemId,
group: -1, group: -1,
isActive: (editorState) => true, isActive: (editorState) => true,
builder: (_, __, ___, ____) { builder: (_, __, ___, ____, _____) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
child: Container( child: Container(

View file

@ -4,16 +4,15 @@ final ToolbarItem quoteItem = ToolbarItem(
id: 'editor.quote', id: 'editor.quote',
group: 3, group: 3,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (context, editorState, highlightColor, iconColor, tooltipBuilder) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'quote'; final isHighlight = node.type == 'quote';
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/quote', iconName: 'toolbar/quote',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: AppFlowyEditorL10n.current.quote,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -21,5 +20,15 @@ final ToolbarItem quoteItem = ToolbarItem(
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
AppFlowyEditorL10n.current.quote,
child,
);
}
return child;
}, },
); );

View file

@ -28,18 +28,23 @@ class _TextDirectionToolbarItem extends ToolbarItem {
id: 'editor.$id', id: 'editor.$id',
group: 7, group: 7,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, iconColor) { builder: (
context,
editorState,
highlightColor,
iconColor,
tooltipBuilder,
) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.every( final isHighlight = nodes.every(
(n) => n.attributes[blockComponentTextDirection] == name, (n) => n.attributes[blockComponentTextDirection] == name,
); );
return SVGIconItemWidget( final child = SVGIconItemWidget(
iconName: 'toolbar/$iconName', iconName: 'toolbar/$iconName',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor, iconColor: iconColor,
tooltip: getTooltipText(id),
onPressed: () => editorState.updateNode( onPressed: () => editorState.updateNode(
selection, selection,
(node) => node.copyWith( (node) => node.copyWith(
@ -50,6 +55,16 @@ class _TextDirectionToolbarItem extends ToolbarItem {
), ),
), ),
); );
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
getTooltipText(id),
child,
);
}
return child;
}, },
); );
} }

View file

@ -31,6 +31,7 @@ class ToolbarItem {
EditorState editorState, EditorState editorState,
Color highlightColor, Color highlightColor,
Color? iconColor, Color? iconColor,
ToolbarTooltipBuilder? tooltipBuilder,
)? builder; )? builder;
// deprecated // deprecated

View file

@ -1,103 +0,0 @@
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_item.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_item_widget.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
mixin ToolbarMixin<T extends StatefulWidget> on State<T> {
void hide();
}
class ToolbarWidget extends StatefulWidget {
const ToolbarWidget({
super.key,
required this.editorState,
required this.layerLink,
required this.offset,
required this.highlightColor,
this.iconColor,
required this.items,
this.alignment = Alignment.topLeft,
});
final EditorState editorState;
final LayerLink layerLink;
final Offset offset;
final Color highlightColor;
final Color? iconColor;
final List<ToolbarItem> items;
final Alignment alignment;
@override
State<ToolbarWidget> createState() => _ToolbarWidgetState();
}
class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
OverlayEntry? _listToolbarOverlay;
@override
Widget build(BuildContext context) {
return Positioned(
top: widget.offset.dx,
left: widget.offset.dy,
child: CompositedTransformFollower(
link: widget.layerLink,
showWhenUnlinked: true,
offset: widget.offset,
followerAnchor: widget.alignment,
child: _buildToolbar(context, widget.highlightColor, widget.iconColor),
),
);
}
@override
void hide() {
_listToolbarOverlay?.remove();
_listToolbarOverlay = null;
}
Widget _buildToolbar(
BuildContext context,
Color highlightColor,
Color? iconColor,
) {
return Material(
borderRadius: BorderRadius.circular(8.0),
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(
height: 32.0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: widget.items
.map(
(item) => Center(
child: item.builder?.call(
context,
widget.editorState,
highlightColor,
iconColor,
) ??
item.itemBuilder?.call(context, widget.editorState) ??
ToolbarItemWidget(
item: item,
isHighlight: item.highlightCallback
?.call(widget.editorState) ??
false,
onPressed: () {
item.handler?.call(widget.editorState, context);
widget.editorState.service.keyboardService
?.enable();
},
),
),
)
.toList(growable: false),
),
),
),
);
}
}