feat: make the columns block same width width the editor (#7493)

* feat: make the columns block same width width the editor

* chore: turn off column debug mode

* feat: add block selection container in outline block

* feat: use ratio instead of width in simple columns

* fix: document rules

* fix: turn off debug mode

* fix: update the existing columns block data
This commit is contained in:
Lucas 2025-03-10 18:13:15 +08:00 committed by GitHub
parent 7b32a92290
commit c81f87dcdc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 223 additions and 107 deletions

View File

@ -104,6 +104,28 @@ class DocumentRules {
} else { } else {
// otherwise, delete the column // otherwise, delete the column
deleteColumnsTransaction.deleteNode(column); deleteColumnsTransaction.deleteNode(column);
final deletedColumnRatio =
column.attributes[SimpleColumnBlockKeys.ratio];
if (deletedColumnRatio != null) {
// update the ratio of the columns
final columnsNode = column.columnsParent;
if (columnsNode != null) {
final length = columnsNode.children.length;
for (final columnNode in columnsNode.children) {
final ratio =
columnNode.attributes[SimpleColumnBlockKeys.ratio] ??
1.0 / length;
if (ratio != null) {
deleteColumnsTransaction.updateNode(columnNode, {
...columnNode.attributes,
SimpleColumnBlockKeys.ratio:
ratio + deletedColumnRatio / (length - 1),
});
}
}
}
}
} }
} }
} }

View File

@ -89,7 +89,7 @@ class _DraggableOptionButtonState extends State<DraggableOptionButton> {
interceptor: (context, targetNode) { interceptor: (context, targetNode) {
// if the cursor node is in a columns block or a column block, // if the cursor node is in a columns block or a column block,
// we will return the node's parent instead to support dragging a node to the inside of a columns block or a column block. // we will return the node's parent instead to support dragging a node to the inside of a columns block or a column block.
final parentColumnNode = targetNode.parentColumn; final parentColumnNode = targetNode.columnParent;
if (parentColumnNode != null) { if (parentColumnNode != null) {
final position = getDragAreaPosition( final position = getDragAreaPosition(
context, context,
@ -147,7 +147,7 @@ class _DraggableOptionButtonState extends State<DraggableOptionButton> {
interceptor: (context, targetNode) { interceptor: (context, targetNode) {
// if the cursor node is in a columns block or a column block, // if the cursor node is in a columns block or a column block,
// we will return the node's parent instead to support dragging a node to the inside of a columns block or a column block. // we will return the node's parent instead to support dragging a node to the inside of a columns block or a column block.
final parentColumnNode = targetNode.parentColumn; final parentColumnNode = targetNode.columnParent;
if (parentColumnNode != null) { if (parentColumnNode != null) {
final position = getDragAreaPosition( final position = getDragAreaPosition(
context, context,

View File

@ -1,4 +1,3 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/columns/simple_columns_block_constant.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_editor/appflowy_editor.dart' import 'package:appflowy_editor/appflowy_editor.dart'
@ -60,38 +59,37 @@ Future<void> dragToMoveNode(
// 1. if the targetNode is a column block, it means we should create a column block to contain the node and insert the column node to the target node's parent // 1. if the targetNode is a column block, it means we should create a column block to contain the node and insert the column node to the target node's parent
// 2. if the targetNode is not a column block, it means we should create a columns block to contain the target node and the drag node // 2. if the targetNode is not a column block, it means we should create a columns block to contain the target node and the drag node
final transaction = editorState.transaction; final transaction = editorState.transaction;
final targetNodeParent = targetNode.parentColumnsBlock; final targetNodeParent = targetNode.columnsParent;
if (targetNodeParent != null) { if (targetNodeParent != null) {
final length = targetNodeParent.children.length; final length = targetNodeParent.children.length;
final ratios = targetNodeParent.children
.map(
(e) =>
e.attributes[SimpleColumnBlockKeys.ratio]?.toDouble() ??
1.0 / length,
)
.map((e) => e * length / (length + 1))
.toList();
final columnNode = simpleColumnNode( final columnNode = simpleColumnNode(
children: [node.deepCopy()], children: [node.deepCopy()],
width: (node.rect.width * 1 / (length + 1)).clamp( ratio: 1.0 / (length + 1),
SimpleColumnsBlockConstants.minimumColumnWidth,
double.infinity,
),
); );
for (final (index, column) in targetNodeParent.children.indexed) {
for (final column in targetNodeParent.children) {
final width =
column.attributes[SimpleColumnBlockKeys.width]?.toDouble() ??
SimpleColumnsBlockConstants.minimumColumnWidth;
transaction.updateNode(column, { transaction.updateNode(column, {
...column.attributes, ...column.attributes,
SimpleColumnBlockKeys.width: (width * length / (length + 1)).clamp( SimpleColumnBlockKeys.ratio: ratios[index],
SimpleColumnsBlockConstants.minimumColumnWidth,
double.infinity,
),
}); });
} }
transaction.insertNode(targetNode.path.next, columnNode); transaction.insertNode(targetNode.path.next, columnNode);
transaction.deleteNode(node); transaction.deleteNode(node);
} else { } else {
final width = targetNode.rect.width / 2 - 16;
final columnsNode = simpleColumnsNode( final columnsNode = simpleColumnsNode(
children: [ children: [
simpleColumnNode(children: [targetNode.deepCopy()], width: width), simpleColumnNode(children: [targetNode.deepCopy()], ratio: 0.5),
simpleColumnNode(children: [node.deepCopy()], width: width), simpleColumnNode(children: [node.deepCopy()], ratio: 0.5),
], ],
); );
@ -109,39 +107,37 @@ Future<void> dragToMoveNode(
// 1. if the target node is a column block, we should create a column block to contain the node and insert the column node to the target node's parent // 1. if the target node is a column block, we should create a column block to contain the node and insert the column node to the target node's parent
// 2. if the target node is not a column block, we should create a columns block to contain the target node and the drag node // 2. if the target node is not a column block, we should create a columns block to contain the target node and the drag node
final transaction = editorState.transaction; final transaction = editorState.transaction;
final targetNodeParent = targetNode.parentColumnsBlock; final targetNodeParent = targetNode.columnsParent;
if (targetNodeParent != null) { if (targetNodeParent != null) {
// find the previous sibling node of the target node // find the previous sibling node of the target node
final length = targetNodeParent.children.length; final length = targetNodeParent.children.length;
final ratios = targetNodeParent.children
.map(
(e) =>
e.attributes[SimpleColumnBlockKeys.ratio]?.toDouble() ??
1.0 / length,
)
.map((e) => e * length / (length + 1))
.toList();
final columnNode = simpleColumnNode( final columnNode = simpleColumnNode(
children: [node.deepCopy()], children: [node.deepCopy()],
width: (node.rect.width * 1 / (length + 1)).clamp( ratio: 1.0 / (length + 1),
SimpleColumnsBlockConstants.minimumColumnWidth,
double.infinity,
),
); );
for (final column in targetNodeParent.children) { for (final (index, column) in targetNodeParent.children.indexed) {
final width =
column.attributes[SimpleColumnBlockKeys.width]?.toDouble() ??
SimpleColumnsBlockConstants.minimumColumnWidth;
transaction.updateNode(column, { transaction.updateNode(column, {
...column.attributes, ...column.attributes,
SimpleColumnBlockKeys.width: (width * length / (length + 1)).clamp( SimpleColumnBlockKeys.ratio: ratios[index],
SimpleColumnsBlockConstants.minimumColumnWidth,
double.infinity,
),
}); });
} }
transaction.insertNode(targetNode.path.previous, columnNode); transaction.insertNode(targetNode.path.previous, columnNode);
transaction.deleteNode(node); transaction.deleteNode(node);
} else { } else {
final width = targetNode.rect.width / 2 - 16;
final columnsNode = simpleColumnsNode( final columnsNode = simpleColumnsNode(
children: [ children: [
simpleColumnNode(children: [node.deepCopy()], width: width), simpleColumnNode(children: [node.deepCopy()], ratio: 0.5),
simpleColumnNode(children: [targetNode.deepCopy()], width: width), simpleColumnNode(children: [targetNode.deepCopy()], ratio: 0.5),
], ],
); );

View File

@ -7,27 +7,62 @@ import 'package:provider/provider.dart';
Node simpleColumnNode({ Node simpleColumnNode({
List<Node>? children, List<Node>? children,
double? width, double? ratio,
}) { }) {
return Node( return Node(
type: SimpleColumnBlockKeys.type, type: SimpleColumnBlockKeys.type,
children: children ?? [paragraphNode()], children: children ?? [paragraphNode()],
attributes: { attributes: {
SimpleColumnBlockKeys.width: width, SimpleColumnBlockKeys.ratio: ratio,
}, },
); );
} }
extension SimpleColumnBlockAttributes on Node {
// get the next column node of the current column node
// if the current column node is the last column node, return null
Node? get nextColumn {
final index = path.last;
final parent = this.parent;
if (parent == null || index == parent.children.length - 1) {
return null;
}
return parent.children[index + 1];
}
// get the previous column node of the current column node
// if the current column node is the first column node, return null
Node? get previousColumn {
final index = path.last;
final parent = this.parent;
if (parent == null || index == 0) {
return null;
}
return parent.children[index - 1];
}
}
class SimpleColumnBlockKeys { class SimpleColumnBlockKeys {
const SimpleColumnBlockKeys._(); const SimpleColumnBlockKeys._();
static const String type = 'simple_column'; static const String type = 'simple_column';
/// @Deprecated Use [SimpleColumnBlockKeys.ratio] instead.
///
/// This field is no longer used since v0.6.9
@Deprecated('Use [SimpleColumnBlockKeys.ratio] instead.')
static const String width = 'width'; static const String width = 'width';
/// The ratio of the column width.
///
/// The value is a double number between 0 and 1.
static const String ratio = 'ratio';
} }
class SimpleColumnBlockComponentBuilder extends BlockComponentBuilder { class SimpleColumnBlockComponentBuilder extends BlockComponentBuilder {
SimpleColumnBlockComponentBuilder({super.configuration}); SimpleColumnBlockComponentBuilder({
super.configuration,
});
@override @override
BlockComponentWidget build(BlockComponentContext blockComponentContext) { BlockComponentWidget build(BlockComponentContext blockComponentContext) {
@ -74,16 +109,6 @@ class SimpleColumnBlockComponentState extends State<SimpleColumnBlockComponent>
late final EditorState editorState = context.read<EditorState>(); late final EditorState editorState = context.read<EditorState>();
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget child = Column( Widget child = Column(
@ -121,7 +146,7 @@ class SimpleColumnBlockComponentState extends State<SimpleColumnBlockComponent>
if (SimpleColumnsBlockConstants.enableDebugBorder) { if (SimpleColumnsBlockConstants.enableDebugBorder) {
child = Container( child = Container(
color: Colors.green.withValues( color: Colors.green.withValues(
alpha: 0.2, alpha: 0.3,
), ),
child: child, child: child,
); );

View File

@ -1,6 +1,5 @@
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart'; import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/drag_to_reorder/draggable_option_button.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/drag_to_reorder/draggable_option_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/columns/simple_columns_block_constant.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -26,6 +25,13 @@ class _SimpleColumnBlockWidthResizerState
ValueNotifier<bool> isHovering = ValueNotifier(false); ValueNotifier<bool> isHovering = ValueNotifier(false);
@override
void dispose() {
isHovering.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MouseRegion( return MouseRegion(
@ -78,25 +84,47 @@ class _SimpleColumnBlockWidthResizerState
// update the column width in memory // update the column width in memory
final columnNode = widget.columnNode; final columnNode = widget.columnNode;
final columnsNode = columnNode.columnsParent;
if (columnsNode == null) {
return;
}
final editorWidth = columnsNode.rect.width;
final rect = columnNode.rect; final rect = columnNode.rect;
final width = final width = rect.width;
columnNode.attributes[SimpleColumnBlockKeys.width] ?? rect.width; final originalRatio = columnNode.attributes[SimpleColumnBlockKeys.ratio];
final newWidth = width + details.delta.dx; final newWidth = width + details.delta.dx;
final transaction = widget.editorState.transaction; final transaction = widget.editorState.transaction;
final newRatio = newWidth / editorWidth;
transaction.updateNode(columnNode, { transaction.updateNode(columnNode, {
...columnNode.attributes, ...columnNode.attributes,
SimpleColumnBlockKeys.width: newWidth.clamp( SimpleColumnBlockKeys.ratio: newRatio,
SimpleColumnsBlockConstants.minimumColumnWidth,
double.infinity,
),
}); });
final columnsNode = columnNode.parent;
if (columnsNode != null) { if (newRatio < 0.1 && newRatio < originalRatio) {
return;
}
final nextColumn = columnNode.nextColumn;
if (nextColumn != null) {
final nextColumnRect = nextColumn.rect;
final nextColumnWidth = nextColumnRect.width;
final newNextColumnWidth = nextColumnWidth - details.delta.dx;
final newNextColumnRatio = newNextColumnWidth / editorWidth;
if (newNextColumnRatio < 0.1) {
return;
}
transaction.updateNode(nextColumn, {
...nextColumn.attributes,
SimpleColumnBlockKeys.ratio: newNextColumnRatio,
});
}
transaction.updateNode(columnsNode, { transaction.updateNode(columnsNode, {
...columnsNode.attributes, ...columnsNode.attributes,
ColumnsBlockKeys.columnCount: columnsNode.children.length, ColumnsBlockKeys.columnCount: columnsNode.children.length,
}); });
}
widget.editorState.apply( widget.editorState.apply(
transaction, transaction,
options: ApplyOptions(inMemoryUpdate: true), options: ApplyOptions(inMemoryUpdate: true),
@ -113,9 +141,15 @@ class _SimpleColumnBlockWidthResizerState
// apply the transaction again to make sure the width is updated // apply the transaction again to make sure the width is updated
final transaction = widget.editorState.transaction; final transaction = widget.editorState.transaction;
transaction.updateNode(widget.columnNode, { final columnsNode = widget.columnNode.columnsParent;
...widget.columnNode.attributes, if (columnsNode == null) {
return;
}
for (final columnNode in columnsNode.children) {
transaction.updateNode(columnNode, {
...columnNode.attributes,
}); });
}
widget.editorState.apply(transaction); widget.editorState.apply(transaction);
isDragging = false; isDragging = false;

View File

@ -3,7 +3,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
extension SimpleColumnNodeExtension on Node { extension SimpleColumnNodeExtension on Node {
/// Returns the parent [Node] of the current node if it is a [SimpleColumnsBlock]. /// Returns the parent [Node] of the current node if it is a [SimpleColumnsBlock].
Node? get parentColumnsBlock { Node? get columnsParent {
Node? currentNode = parent; Node? currentNode = parent;
while (currentNode != null) { while (currentNode != null) {
if (currentNode.type == SimpleColumnsBlockKeys.type) { if (currentNode.type == SimpleColumnsBlockKeys.type) {
@ -15,7 +15,7 @@ extension SimpleColumnNodeExtension on Node {
} }
/// Returns the parent [Node] of the current node if it is a [SimpleColumnBlock]. /// Returns the parent [Node] of the current node if it is a [SimpleColumnBlock].
Node? get parentColumn { Node? get columnParent {
Node? currentNode = parent; Node? currentNode = parent;
while (currentNode != null) { while (currentNode != null) {
if (currentNode.type == SimpleColumnBlockKeys.type) { if (currentNode.type == SimpleColumnBlockKeys.type) {
@ -27,8 +27,8 @@ extension SimpleColumnNodeExtension on Node {
} }
/// Returns whether the current node is in a [SimpleColumnsBlock]. /// Returns whether the current node is in a [SimpleColumnsBlock].
bool get isInColumnsBlock => parentColumnsBlock != null; bool get isInColumnsBlock => columnsParent != null;
/// Returns whether the current node is in a [SimpleColumnBlock]. /// Returns whether the current node is in a [SimpleColumnBlock].
bool get isInColumnBlock => parentColumn != null; bool get isInColumnBlock => columnParent != null;
} }

View File

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:appflowy/plugins/document/presentation/editor_plugins/columns/simple_columns_block_constant.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/columns/simple_columns_block_constant.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
@ -5,20 +7,19 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:universal_platform/universal_platform.dart';
// if the children is not provided, it will create two columns by default. // if the children is not provided, it will create two columns by default.
// if the columnCount is provided, it will create the specified number of columns. // if the columnCount is provided, it will create the specified number of columns.
Node simpleColumnsNode({ Node simpleColumnsNode({
List<Node>? children, List<Node>? children,
int? columnCount, int? columnCount,
double? width, double? ratio,
}) { }) {
columnCount ??= 2; columnCount ??= 2;
children ??= List.generate( children ??= List.generate(
columnCount, columnCount,
(index) => simpleColumnNode( (index) => simpleColumnNode(
width: width, ratio: ratio,
children: [paragraphNode()], children: [paragraphNode()],
), ),
); );
@ -91,6 +92,13 @@ class ColumnsBlockComponentState extends State<ColumnsBlockComponent>
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
@override
void initState() {
super.initState();
_updateColumnsBlock();
}
@override @override
void dispose() { void dispose() {
scrollController.dispose(); scrollController.dispose();
@ -100,23 +108,12 @@ class ColumnsBlockComponentState extends State<ColumnsBlockComponent>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget child = SingleChildScrollView( Widget child = Row(
scrollDirection: Axis.horizontal, mainAxisSize: MainAxisSize.min,
controller: scrollController,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildChildren(), children: _buildChildren(),
),
); );
if (UniversalPlatform.isDesktop) {
// only show the scrollbar on desktop
child = Scrollbar(
controller: scrollController,
child: child,
);
}
child = Align( child = Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: IntrinsicHeight( child: IntrinsicHeight(
@ -148,19 +145,18 @@ class ColumnsBlockComponentState extends State<ColumnsBlockComponent>
} }
List<Widget> _buildChildren() { List<Widget> _buildChildren() {
final length = node.children.length;
final children = <Widget>[]; final children = <Widget>[];
for (var i = 0; i < node.children.length; i++) { for (var i = 0; i < length; i++) {
final childNode = node.children[i]; final childNode = node.children[i];
final width = final double ratio =
childNode.attributes[SimpleColumnBlockKeys.width]?.toDouble() ?? childNode.attributes[SimpleColumnBlockKeys.ratio]?.toDouble() ??
SimpleColumnsBlockConstants.minimumColumnWidth; 1.0 / length;
Widget child = editorState.renderer.build(context, childNode); Widget child = editorState.renderer.build(context, childNode);
child = SizedBox( child = Expanded(
width: width.clamp( flex: (max(ratio, 0.1) * 10000).toInt(),
SimpleColumnsBlockConstants.minimumColumnWidth,
double.infinity,
),
child: child, child: child,
); );
@ -176,6 +172,26 @@ class ColumnsBlockComponentState extends State<ColumnsBlockComponent>
return children; return children;
} }
// Update the existing columns block data
// if the column ratio is not existing, it will be set to 1.0 / columnCount
void _updateColumnsBlock() {
final transaction = editorState.transaction;
final length = node.children.length;
for (int i = 0; i < length; i++) {
final childNode = node.children[i];
final ratio = childNode.attributes[SimpleColumnBlockKeys.ratio];
if (ratio == null) {
transaction.updateNode(childNode, {
...childNode.attributes,
SimpleColumnBlockKeys.ratio: 1.0 / length,
});
}
}
if (transaction.operations.isNotEmpty) {
editorState.apply(transaction);
}
}
@override @override
Position start() => Position(path: widget.node.path); Position start() => Position(path: widget.node.path);

View File

@ -227,6 +227,7 @@ class CustomImageBlockComponentState extends State<CustomImageBlockComponent>
delegate: this, delegate: this,
listenable: editorState.selectionNotifier, listenable: editorState.selectionNotifier,
blockColor: editorState.editorStyle.selectionColor, blockColor: editorState.editorStyle.selectionColor,
selectionAboveBlock: true,
supportTypes: const [BlockSelectionType.block], supportTypes: const [BlockSelectionType.block],
child: child, child: child,
); );
@ -313,7 +314,7 @@ class CustomImageBlockComponentState extends State<CustomImageBlockComponent>
}) { }) {
final imageBox = imageKey.currentContext?.findRenderObject(); final imageBox = imageKey.currentContext?.findRenderObject();
if (imageBox is RenderBox) { if (imageBox is RenderBox) {
return Offset.zero & imageBox.size; return padding.topLeft & imageBox.size;
} }
return Rect.zero; return Rect.zero;
} }

View File

@ -81,7 +81,9 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
with with
BlockComponentConfigurable, BlockComponentConfigurable,
BlockComponentTextDirectionMixin, BlockComponentTextDirectionMixin,
BlockComponentBackgroundColorMixin { BlockComponentBackgroundColorMixin,
DefaultSelectableMixin,
SelectableMixin {
// Change the value if the heading block type supports heading levels greater than '3' // Change the value if the heading block type supports heading levels greater than '3'
static const maxVisibleDepth = 6; static const maxVisibleDepth = 6;
@ -95,6 +97,17 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
late EditorState editorState = context.read<EditorState>(); late EditorState editorState = context.read<EditorState>();
late Stream<EditorTransactionValue> stream = editorState.transactionStream; late Stream<EditorTransactionValue> stream = editorState.transactionStream;
@override
GlobalKey<State<StatefulWidget>> blockComponentKey = GlobalKey(
debugLabel: OutlineBlockKeys.type,
);
@override
GlobalKey<State<StatefulWidget>> get containerKey => widget.node.key;
@override
GlobalKey<State<StatefulWidget>> get forwardKey => widget.node.key;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StreamBuilder( return StreamBuilder(
@ -102,6 +115,19 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
builder: (context, snapshot) { builder: (context, snapshot) {
Widget child = _buildOutlineBlock(); Widget child = _buildOutlineBlock();
child = BlockSelectionContainer(
node: node,
delegate: this,
listenable: editorState.selectionNotifier,
remoteSelection: editorState.remoteSelections,
blockColor: editorState.editorStyle.selectionColor,
selectionAboveBlock: true,
supportTypes: const [
BlockSelectionType.block,
],
child: child,
);
if (UniversalPlatform.isDesktopOrWeb) { if (UniversalPlatform.isDesktopOrWeb) {
if (widget.showActions && widget.actionBuilder != null) { if (widget.showActions && widget.actionBuilder != null) {
child = BlockComponentActionWrapper( child = BlockComponentActionWrapper(
@ -176,6 +202,7 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
} }
return Container( return Container(
key: blockComponentKey,
constraints: const BoxConstraints( constraints: const BoxConstraints(
minHeight: 40.0, minHeight: 40.0,
), ),

View File

@ -90,13 +90,8 @@ SelectionMenuItem fourColumnsSlashMenuItem = SelectionMenuItem.node(
); );
Node _buildColumnsNode(EditorState editorState, int columnCount) { Node _buildColumnsNode(EditorState editorState, int columnCount) {
final selection = editorState.selection; return simpleColumnsNode(
double? width; columnCount: columnCount,
if (selection != null) { ratio: 1.0 / columnCount,
final parentNode = editorState.getNodeAtPath(selection.start.path); );
if (parentNode != null) {
width = parentNode.rect.width / columnCount - 16;
}
}
return simpleColumnsNode(columnCount: columnCount, width: width);
} }