feat: add simple columns block in editor (#1038)
* feat: add simple columns block in editor * feat: add divider between column block * fix: add fallback logic in calculate selection function * feat: add column width resizer * feat: integrate columns block in editor on desktop
This commit is contained in:
parent
1df3cb1a1f
commit
c1e9d15572
2 changed files with 562 additions and 29 deletions
|
|
@ -136,6 +136,10 @@ class _DesktopEditorState extends State<DesktopEditor> {
|
|||
Map<String, BlockComponentBuilder> _buildBlockComponentBuilders() {
|
||||
final map = {
|
||||
...standardBlockComponentBuilderMap,
|
||||
|
||||
// columns block
|
||||
ColumnBlockKeys.type: ColumnBlockComponentBuilder(),
|
||||
ColumnsBlockKeys.type: ColumnsBlockComponentBuilder(),
|
||||
};
|
||||
// customize the image block component to show a menu
|
||||
map[ImageBlockKeys.type] = ImageBlockComponentBuilder(
|
||||
|
|
@ -165,7 +169,13 @@ class _DesktopEditorState extends State<DesktopEditor> {
|
|||
// customize the padding
|
||||
map.forEach((key, value) {
|
||||
value.configuration = value.configuration.copyWith(
|
||||
padding: (_) => const EdgeInsets.symmetric(vertical: 8.0),
|
||||
padding: (node) {
|
||||
if (node.type == ColumnsBlockKeys.type ||
|
||||
node.type == ColumnBlockKeys.type) {
|
||||
return EdgeInsets.zero;
|
||||
}
|
||||
return const EdgeInsets.symmetric(vertical: 8.0);
|
||||
},
|
||||
blockSelectionAreaMargin: (_) => const EdgeInsets.symmetric(
|
||||
vertical: 1.0,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -287,29 +287,49 @@ class _DragToReorderActionState extends State<DragToReorderAction> {
|
|||
final (verticalPosition, horizontalPosition, _) = position;
|
||||
Path newPath = targetNode.path;
|
||||
|
||||
// Determine the new path based on drop position
|
||||
// For VerticalPosition.top, we keep the target node's path
|
||||
if (verticalPosition == VerticalPosition.bottom) {
|
||||
newPath = horizontalPosition == HorizontalPosition.left
|
||||
? newPath.next // Insert after target node
|
||||
: newPath.child(0); // Insert as first child of target node
|
||||
}
|
||||
|
||||
// Check if the drop should be ignored
|
||||
if (_shouldIgnoreDrop(node, newPath)) {
|
||||
debugPrint(
|
||||
'Drop ignored: node($node, ${node.path}), path($acceptedPath)',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final realNode = widget.blockComponentContext.node;
|
||||
debugPrint('Moving node($realNode, ${realNode.path}) to path($newPath)');
|
||||
|
||||
// Perform the node move operation
|
||||
final transaction = editorState.transaction;
|
||||
transaction.moveNode(newPath, realNode);
|
||||
await editorState.apply(transaction);
|
||||
// if the horizontal position is right, we need to create a column block
|
||||
if (horizontalPosition == HorizontalPosition.right) {
|
||||
final node = columnsNode(
|
||||
children: [
|
||||
columnNode(
|
||||
children: [targetNode.deepCopy()],
|
||||
),
|
||||
columnNode(
|
||||
children: [realNode.deepCopy()],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
final transaction = editorState.transaction;
|
||||
transaction.insertNode(newPath, node);
|
||||
transaction.deleteNode(targetNode);
|
||||
transaction.deleteNode(realNode);
|
||||
await editorState.apply(transaction);
|
||||
} else {
|
||||
// Determine the new path based on drop position
|
||||
// For VerticalPosition.top, we keep the target node's path
|
||||
if (verticalPosition == VerticalPosition.bottom) {
|
||||
newPath = horizontalPosition == HorizontalPosition.left
|
||||
? newPath.next // Insert after target node
|
||||
: newPath.child(0); // Insert as first child of target node
|
||||
}
|
||||
|
||||
// Check if the drop should be ignored
|
||||
if (_shouldIgnoreDrop(node, newPath)) {
|
||||
debugPrint(
|
||||
'Drop ignored: node($node, ${node.path}), path($acceptedPath)',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform the node move operation
|
||||
final transaction = editorState.transaction;
|
||||
transaction.moveNode(newPath, realNode);
|
||||
await editorState.apply(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildFeedback() {
|
||||
|
|
@ -387,7 +407,7 @@ Widget _buildDropArea(
|
|||
color: Colors.red,
|
||||
);
|
||||
|
||||
if (horizontalPosition == HorizontalPosition.right) {
|
||||
if (horizontalPosition == HorizontalPosition.center) {
|
||||
const breakWidth = 22.0;
|
||||
const padding = 8.0;
|
||||
child = Row(
|
||||
|
|
@ -406,6 +426,16 @@ Widget _buildDropArea(
|
|||
),
|
||||
],
|
||||
);
|
||||
} else if (horizontalPosition == HorizontalPosition.right) {
|
||||
return Positioned(
|
||||
top: globalBlockRect.top,
|
||||
height: globalBlockRect.height,
|
||||
left: globalBlockRect.right - 2,
|
||||
child: Container(
|
||||
width: 2,
|
||||
color: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
|
|
@ -452,9 +482,10 @@ Widget _buildDropArea(
|
|||
// Horizontal position
|
||||
if (dragOffset.dx < globalBlockRect.left + 44) {
|
||||
horizontalPosition = HorizontalPosition.left;
|
||||
} else {
|
||||
// ignore the middle here, it's not used in this example
|
||||
} else if (dragOffset.dx > globalBlockRect.right / 3.0 * 2.0) {
|
||||
horizontalPosition = HorizontalPosition.right;
|
||||
} else {
|
||||
horizontalPosition = HorizontalPosition.center;
|
||||
}
|
||||
|
||||
// Vertical position
|
||||
|
|
|
|||
Loading…
Reference in a new issue