mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: reafactor add block menu (#4563)
This commit is contained in:
parent
caede19267
commit
a143a030a9
@ -0,0 +1,153 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TypeOptionMenuItemValue<T> {
|
||||
const TypeOptionMenuItemValue({
|
||||
required this.value,
|
||||
required this.icon,
|
||||
required this.text,
|
||||
required this.backgroundColor,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final T value;
|
||||
final FlowySvgData icon;
|
||||
final String text;
|
||||
final Color backgroundColor;
|
||||
final void Function(BuildContext context, T value) onTap;
|
||||
}
|
||||
|
||||
class TypeOptionMenu<T> extends StatelessWidget {
|
||||
const TypeOptionMenu({
|
||||
super.key,
|
||||
required this.values,
|
||||
this.width = 94,
|
||||
this.iconWidth = 72,
|
||||
this.scaleFactor = 1.0,
|
||||
this.maxAxisSpacing = 18,
|
||||
this.crossAxisCount = 3,
|
||||
});
|
||||
|
||||
final List<TypeOptionMenuItemValue<T>> values;
|
||||
|
||||
final double iconWidth;
|
||||
final double width;
|
||||
final double scaleFactor;
|
||||
final double maxAxisSpacing;
|
||||
final int crossAxisCount;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _GridView(
|
||||
crossAxisCount: crossAxisCount,
|
||||
mainAxisSpacing: maxAxisSpacing * scaleFactor,
|
||||
itemWidth: width * scaleFactor,
|
||||
children: values
|
||||
.map(
|
||||
(value) => _TypeOptionMenuItem<T>(
|
||||
value: value,
|
||||
width: width,
|
||||
iconWidth: iconWidth,
|
||||
scaleFactor: scaleFactor,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TypeOptionMenuItem<T> extends StatelessWidget {
|
||||
const _TypeOptionMenuItem({
|
||||
required this.value,
|
||||
this.width = 94,
|
||||
this.iconWidth = 72,
|
||||
this.scaleFactor = 1.0,
|
||||
});
|
||||
|
||||
final TypeOptionMenuItemValue<T> value;
|
||||
final double iconWidth;
|
||||
final double width;
|
||||
final double scaleFactor;
|
||||
|
||||
double get scaledIconWidth => iconWidth * scaleFactor;
|
||||
double get scaledWidth => width * scaleFactor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => value.onTap(context, value.value),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
height: scaledIconWidth,
|
||||
width: scaledIconWidth,
|
||||
decoration: ShapeDecoration(
|
||||
color: value.backgroundColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(24 * scaleFactor),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.all(21 * scaleFactor),
|
||||
child: FlowySvg(
|
||||
value.icon,
|
||||
),
|
||||
),
|
||||
const VSpace(6),
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: scaledWidth,
|
||||
),
|
||||
child: FlowyText(
|
||||
value.text,
|
||||
fontSize: 14.0,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _GridView extends StatelessWidget {
|
||||
const _GridView({
|
||||
required this.children,
|
||||
required this.crossAxisCount,
|
||||
required this.mainAxisSpacing,
|
||||
required this.itemWidth,
|
||||
});
|
||||
|
||||
final List<Widget> children;
|
||||
final int crossAxisCount;
|
||||
final double mainAxisSpacing;
|
||||
final double itemWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (var i = 0; i < children.length; i += crossAxisCount)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: mainAxisSpacing),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
for (var j = 0; j < crossAxisCount; j++)
|
||||
i + j < children.length
|
||||
? SizedBox(
|
||||
width: itemWidth,
|
||||
child: children[i + j],
|
||||
)
|
||||
: HSpace(itemWidth),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -26,6 +26,11 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
Color? barrierColor,
|
||||
double? elevation,
|
||||
bool showDoneButton = false,
|
||||
bool enableDraggableScrollable = false,
|
||||
// only used when enableDraggableScrollable is true
|
||||
double minChildSize = 0.5,
|
||||
double maxChildSize = 0.8,
|
||||
double initialChildSize = 0.51,
|
||||
}) async {
|
||||
assert(() {
|
||||
if (showCloseButton || title.isNotEmpty) assert(showHeader);
|
||||
@ -57,7 +62,7 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
builder: (context) {
|
||||
final List<Widget> children = [];
|
||||
|
||||
final child = builder(context);
|
||||
final Widget child = builder(context);
|
||||
|
||||
// if the children is only one, we don't need to wrap it with a column
|
||||
if (!showDragHandle &&
|
||||
@ -92,6 +97,29 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
|
||||
// ----- header area -----
|
||||
|
||||
if (enableDraggableScrollable) {
|
||||
return DraggableScrollableSheet(
|
||||
expand: false,
|
||||
snap: true,
|
||||
initialChildSize: initialChildSize,
|
||||
minChildSize: minChildSize,
|
||||
maxChildSize: maxChildSize,
|
||||
builder: (context, scrollController) {
|
||||
return Column(
|
||||
children: [
|
||||
...children,
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// ----- content area -----
|
||||
if (resizeToAvoidBottomInset) {
|
||||
children.add(
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/type_option_menu_item.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||
@ -11,7 +12,6 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.da
|
||||
import 'package:appflowy/startup/tasks/app_widget.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@ -64,16 +64,15 @@ Future<bool?> showAddBlockMenu(
|
||||
context,
|
||||
showHeader: true,
|
||||
showDragHandle: true,
|
||||
showDoneButton: true,
|
||||
showCloseButton: true,
|
||||
title: LocaleKeys.button_add.tr(),
|
||||
barrierColor: Colors.transparent,
|
||||
backgroundColor: theme.toolbarMenuBackgroundColor,
|
||||
elevation: 20,
|
||||
title: LocaleKeys.button_add.tr(),
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
|
||||
enableDraggableScrollable: true,
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
padding: EdgeInsets.all(16 * context.scale),
|
||||
child: _AddBlockMenu(
|
||||
selection: selection,
|
||||
editorState: editorState,
|
||||
@ -92,127 +91,87 @@ class _AddBlockMenu extends StatelessWidget {
|
||||
final Selection selection;
|
||||
final EditorState editorState;
|
||||
|
||||
late final _menuItemData = [
|
||||
// paragraph
|
||||
_AddBlockMenuItemData(
|
||||
blockType: ParagraphBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFBAC9FF),
|
||||
text: LocaleKeys.editor_text.tr(),
|
||||
icon: FlowySvgs.m_add_block_paragraph_s,
|
||||
onTap: () => _insertBlock(paragraphNode()),
|
||||
),
|
||||
|
||||
late final List<TypeOptionMenuItemValue<String>> typeOptionMenuItemValue = [
|
||||
// heading 1 - 3
|
||||
_AddBlockMenuItemData(
|
||||
blockType: HeadingBlockKeys.type,
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFBAC9FF),
|
||||
text: LocaleKeys.editor_heading1.tr(),
|
||||
icon: FlowySvgs.m_add_block_h1_s,
|
||||
onTap: () => _insertBlock(headingNode(level: 1)),
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 1)),
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: HeadingBlockKeys.type,
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFBAC9FF),
|
||||
text: LocaleKeys.editor_heading2.tr(),
|
||||
icon: FlowySvgs.m_add_block_h2_s,
|
||||
onTap: () => _insertBlock(headingNode(level: 2)),
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 2)),
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: HeadingBlockKeys.type,
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFBAC9FF),
|
||||
text: LocaleKeys.editor_heading3.tr(),
|
||||
icon: FlowySvgs.m_add_block_h3_s,
|
||||
onTap: () => _insertBlock(headingNode(level: 3)),
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 3)),
|
||||
),
|
||||
|
||||
// paragraph
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFBAC9FF),
|
||||
text: LocaleKeys.editor_text.tr(),
|
||||
icon: FlowySvgs.m_add_block_paragraph_s,
|
||||
onTap: (_, __) => _insertBlock(paragraphNode()),
|
||||
),
|
||||
|
||||
// checkbox
|
||||
_AddBlockMenuItemData(
|
||||
blockType: TodoListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFF91EAF5),
|
||||
TypeOptionMenuItemValue(
|
||||
value: TodoListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFF98F4CD),
|
||||
text: LocaleKeys.editor_checkbox.tr(),
|
||||
icon: FlowySvgs.m_add_block_checkbox_s,
|
||||
onTap: () => _insertBlock(todoListNode(checked: false)),
|
||||
onTap: (_, __) => _insertBlock(todoListNode(checked: false)),
|
||||
),
|
||||
|
||||
// list: bulleted, numbered, toggle
|
||||
_AddBlockMenuItemData(
|
||||
blockType: BulletedListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFFB9EF),
|
||||
text: LocaleKeys.editor_bulletedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_bulleted_list_s,
|
||||
onTap: () => _insertBlock(bulletedListNode()),
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: NumberedListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFFB9EF),
|
||||
text: LocaleKeys.editor_numberedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_numbered_list_s,
|
||||
onTap: () => _insertBlock(numberedListNode()),
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: ToggleListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFFB9EF),
|
||||
text: LocaleKeys.editor_toggleListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_toggle_s,
|
||||
onTap: () => _insertBlock(toggleListBlockNode()),
|
||||
),
|
||||
|
||||
// callout, code, math equation, quote
|
||||
_AddBlockMenuItemData(
|
||||
blockType: CalloutBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFCABDFF),
|
||||
text: LocaleKeys.document_plugins_callout.tr(),
|
||||
icon: FlowySvgs.m_add_block_callout_s,
|
||||
onTap: () => _insertBlock(calloutNode()),
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: CodeBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFCABDFF),
|
||||
text: LocaleKeys.editor_codeBlockShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_code_s,
|
||||
onTap: () => _insertBlock(codeBlockNode()),
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: MathEquationBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFCABDFF),
|
||||
text: LocaleKeys.editor_mathEquationShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_formula_s,
|
||||
onTap: () {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertMathEquation(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
_AddBlockMenuItemData(
|
||||
blockType: QuoteBlockKeys.type,
|
||||
// quote
|
||||
TypeOptionMenuItemValue(
|
||||
value: QuoteBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFDEDA7),
|
||||
text: LocaleKeys.editor_quote.tr(),
|
||||
icon: FlowySvgs.m_add_block_quote_s,
|
||||
onTap: () => _insertBlock(quoteNode()),
|
||||
onTap: (_, __) => _insertBlock(quoteNode()),
|
||||
),
|
||||
|
||||
// divider
|
||||
_AddBlockMenuItemData(
|
||||
blockType: DividerBlockKeys.type,
|
||||
backgroundColor: const Color(0xFF98F4CD),
|
||||
text: LocaleKeys.editor_divider.tr(),
|
||||
icon: FlowySvgs.m_add_block_divider_s,
|
||||
onTap: () {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertDivider(selection);
|
||||
});
|
||||
},
|
||||
// bulleted list, numbered list, toggle list
|
||||
TypeOptionMenuItemValue(
|
||||
value: BulletedListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFFB9EF),
|
||||
text: LocaleKeys.editor_bulletedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_bulleted_list_s,
|
||||
onTap: (_, __) => _insertBlock(bulletedListNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: NumberedListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFFB9EF),
|
||||
text: LocaleKeys.editor_numberedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_numbered_list_s,
|
||||
onTap: (_, __) => _insertBlock(numberedListNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFFFB9EF),
|
||||
text: LocaleKeys.editor_toggleListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_toggle_s,
|
||||
onTap: (_, __) => _insertBlock(toggleListBlockNode()),
|
||||
),
|
||||
|
||||
// image
|
||||
_AddBlockMenuItemData(
|
||||
blockType: DividerBlockKeys.type,
|
||||
TypeOptionMenuItemValue(
|
||||
value: DividerBlockKeys.type,
|
||||
backgroundColor: const Color(0xFF98F4CD),
|
||||
text: LocaleKeys.editor_image.tr(),
|
||||
icon: FlowySvgs.m_toolbar_imae_lg,
|
||||
onTap: () async {
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final imagePlaceholderKey = GlobalKey<ImagePlaceholderState>();
|
||||
@ -222,22 +181,62 @@ class _AddBlockMenu extends StatelessWidget {
|
||||
),
|
||||
|
||||
// date
|
||||
_AddBlockMenuItemData(
|
||||
blockType: ParagraphBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFF49898),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: const Color(0xFF91EAF5),
|
||||
text: LocaleKeys.editor_date.tr(),
|
||||
icon: FlowySvgs.date_s,
|
||||
onTap: () => _insertBlock(dateMentionNode()),
|
||||
onTap: (_, __) => _insertBlock(dateMentionNode()),
|
||||
),
|
||||
|
||||
// divider
|
||||
TypeOptionMenuItemValue(
|
||||
value: DividerBlockKeys.type,
|
||||
backgroundColor: const Color(0xFF98F4CD),
|
||||
text: LocaleKeys.editor_divider.tr(),
|
||||
icon: FlowySvgs.m_add_block_divider_s,
|
||||
onTap: (_, __) {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertDivider(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// callout, code, math equation
|
||||
TypeOptionMenuItemValue(
|
||||
value: CalloutBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFCABDFF),
|
||||
text: LocaleKeys.document_plugins_callout.tr(),
|
||||
icon: FlowySvgs.m_add_block_callout_s,
|
||||
onTap: (_, __) => _insertBlock(calloutNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: CodeBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFCABDFF),
|
||||
text: LocaleKeys.editor_codeBlockShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_code_s,
|
||||
onTap: (_, __) => _insertBlock(codeBlockNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: MathEquationBlockKeys.type,
|
||||
backgroundColor: const Color(0xFFCABDFF),
|
||||
text: LocaleKeys.editor_mathEquationShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_formula_s,
|
||||
onTap: (_, __) {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertMathEquation(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _GridView(
|
||||
mainAxisSpacing: 20 * context.scale,
|
||||
itemWidth: 68.0 * context.scale,
|
||||
crossAxisCount: 4,
|
||||
children: _menuItemData.map((e) => _AddBlockMenuItem(data: e)).toList(),
|
||||
return TypeOptionMenu<String>(
|
||||
values: typeOptionMenuItemValue,
|
||||
scaleFactor: context.scale,
|
||||
);
|
||||
}
|
||||
|
||||
@ -252,102 +251,6 @@ class _AddBlockMenu extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _AddBlockMenuItemData {
|
||||
const _AddBlockMenuItemData({
|
||||
required this.blockType,
|
||||
required this.backgroundColor,
|
||||
required this.text,
|
||||
required this.icon,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final String blockType;
|
||||
final Color backgroundColor;
|
||||
final String text;
|
||||
final FlowySvgData icon;
|
||||
final VoidCallback onTap;
|
||||
}
|
||||
|
||||
class _AddBlockMenuItem extends StatelessWidget {
|
||||
const _AddBlockMenuItem({
|
||||
required this.data,
|
||||
});
|
||||
|
||||
final _AddBlockMenuItemData data;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: data.onTap,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 68.0 * context.scale,
|
||||
width: 68.0 * context.scale,
|
||||
decoration: ShapeDecoration(
|
||||
color: data.backgroundColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.all(20 * context.scale),
|
||||
child: FlowySvg(
|
||||
data.icon,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const VSpace(4),
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 68.0 * context.scale,
|
||||
),
|
||||
child: FlowyText(
|
||||
data.text,
|
||||
fontSize: 12.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _GridView extends StatelessWidget {
|
||||
const _GridView({
|
||||
required this.children,
|
||||
required this.crossAxisCount,
|
||||
required this.mainAxisSpacing,
|
||||
required this.itemWidth,
|
||||
});
|
||||
|
||||
final List<Widget> children;
|
||||
final int crossAxisCount;
|
||||
final double mainAxisSpacing;
|
||||
final double itemWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (var i = 0; i < children.length; i += crossAxisCount)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: mainAxisSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
for (var j = 0; j < crossAxisCount; j++)
|
||||
i + j < children.length ? children[i + j] : HSpace(itemWidth),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension on EditorState {
|
||||
Future<void> insertBlockAfterCurrentSelection(
|
||||
Selection selection,
|
||||
|
Loading…
Reference in New Issue
Block a user