-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added divider to work with * (#118)
* feat: Added divider to work with * * chore: Resolved the suggested changes * refactor: removed the check for star character * feat:added character variable to insert divider . * feat: support converting stars ** to divider --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
- Loading branch information
Showing
8 changed files
with
371 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
lib/src/editor/block_component/divider_block_component/divider_block_component.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import 'package:appflowy_editor/appflowy_editor.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
class DividerBlockKeys { | ||
const DividerBlockKeys._(); | ||
|
||
static const String type = 'divider'; | ||
} | ||
|
||
// creating a new callout node | ||
Node dividerNode() { | ||
return Node( | ||
type: DividerBlockKeys.type, | ||
); | ||
} | ||
|
||
class DividerBlockComponentBuilder extends BlockComponentBuilder { | ||
DividerBlockComponentBuilder({ | ||
this.configuration = const BlockComponentConfiguration(), | ||
this.lineColor = Colors.grey, | ||
}); | ||
|
||
@override | ||
final BlockComponentConfiguration configuration; | ||
|
||
final Color lineColor; | ||
|
||
@override | ||
BlockComponentWidget build(BlockComponentContext blockComponentContext) { | ||
final node = blockComponentContext.node; | ||
return DividerBlockComponentWidget( | ||
key: node.key, | ||
node: node, | ||
configuration: configuration, | ||
lineColor: lineColor, | ||
showActions: showActions(node), | ||
actionBuilder: (context, state) => actionBuilder( | ||
blockComponentContext, | ||
state, | ||
), | ||
); | ||
} | ||
|
||
@override | ||
bool validate(Node node) => node.children.isEmpty; | ||
} | ||
|
||
class DividerBlockComponentWidget extends BlockComponentStatefulWidget { | ||
const DividerBlockComponentWidget({ | ||
super.key, | ||
required super.node, | ||
super.showActions, | ||
super.actionBuilder, | ||
super.configuration = const BlockComponentConfiguration(), | ||
this.lineColor = Colors.grey, | ||
}); | ||
|
||
final Color lineColor; | ||
|
||
@override | ||
State<DividerBlockComponentWidget> createState() => | ||
_DividerBlockComponentWidgetState(); | ||
} | ||
|
||
class _DividerBlockComponentWidgetState | ||
extends State<DividerBlockComponentWidget> with SelectableMixin { | ||
RenderBox get _renderBox => context.findRenderObject() as RenderBox; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
Widget child = Container( | ||
height: 10, | ||
alignment: Alignment.center, | ||
child: Divider( | ||
color: widget.lineColor, | ||
thickness: 1, | ||
), | ||
); | ||
|
||
if (widget.showActions && widget.actionBuilder != null) { | ||
child = BlockComponentActionWrapper( | ||
node: widget.node, | ||
actionBuilder: widget.actionBuilder!, | ||
child: child, | ||
); | ||
} | ||
|
||
return child; | ||
} | ||
|
||
@override | ||
Position start() => Position(path: widget.node.path, offset: 0); | ||
|
||
@override | ||
Position end() => Position(path: widget.node.path, offset: 1); | ||
|
||
@override | ||
Position getPositionInOffset(Offset start) => end(); | ||
|
||
@override | ||
bool get shouldCursorBlink => false; | ||
|
||
@override | ||
CursorStyle get cursorStyle => CursorStyle.cover; | ||
|
||
@override | ||
Rect? getCursorRectInPosition(Position position) { | ||
final size = _renderBox.size; | ||
return Rect.fromLTWH(-size.width / 2.0, 0, size.width, size.height); | ||
} | ||
|
||
@override | ||
List<Rect> getRectsInSelection(Selection selection) => | ||
[Offset.zero & _renderBox.size]; | ||
|
||
@override | ||
Selection getSelectionInRange(Offset start, Offset end) => Selection.single( | ||
path: widget.node.path, | ||
startOffset: 0, | ||
endOffset: 1, | ||
); | ||
|
||
@override | ||
Offset localToGlobal(Offset offset) => _renderBox.localToGlobal(offset); | ||
} |
46 changes: 46 additions & 0 deletions
46
lib/src/editor/block_component/divider_block_component/divider_character_shortcut.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import 'package:appflowy_editor/appflowy_editor.dart'; | ||
|
||
/// insert divider into a document by typing three minuses(-). | ||
/// | ||
/// - support | ||
/// - desktop | ||
/// - web | ||
/// - mobile | ||
/// | ||
final CharacterShortcutEvent convertMinusesToDivider = CharacterShortcutEvent( | ||
key: 'convert minuses to a divider', | ||
character: '-', | ||
handler: (editorState) => _convertSyntaxToDivider(editorState, '--'), | ||
); | ||
|
||
final CharacterShortcutEvent convertStarsToDivider = CharacterShortcutEvent( | ||
key: 'convert starts to a divider', | ||
character: '*', | ||
handler: (editorState) => _convertSyntaxToDivider(editorState, '**'), | ||
); | ||
|
||
Future<bool> _convertSyntaxToDivider( | ||
EditorState editorState, | ||
String syntax, | ||
) async { | ||
final selection = editorState.selection; | ||
if (selection == null || !selection.isCollapsed) { | ||
return false; | ||
} | ||
final path = selection.end.path; | ||
final node = editorState.getNodeAtPath(path); | ||
final delta = node?.delta; | ||
if (node == null || delta == null) { | ||
return false; | ||
} | ||
if (delta.toPlainText() != syntax) { | ||
return false; | ||
} | ||
final transaction = editorState.transaction | ||
..insertNode(path, dividerNode()) | ||
..insertNode(path, paragraphNode()) | ||
..deleteNode(node) | ||
..afterSelection = Selection.collapse(path, 0); | ||
editorState.apply(transaction); | ||
return true; | ||
} |
31 changes: 31 additions & 0 deletions
31
lib/src/editor/block_component/divider_block_component/divider_menu_item.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import 'package:appflowy_editor/appflowy_editor.dart'; | ||
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_icon.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
SelectionMenuItem dividerMenuItem = SelectionMenuItem( | ||
name: 'Divider', | ||
icon: (editorState, isSelected, style) => SelectionMenuIconWidget( | ||
icon: Icons.horizontal_rule, | ||
isSelected: isSelected, | ||
style: style, | ||
), | ||
keywords: ['horizontal rule', 'divider'], | ||
handler: (editorState, _, __) { | ||
final selection = editorState.selection; | ||
if (selection == null || !selection.isCollapsed) { | ||
return; | ||
} | ||
final path = selection.end.path; | ||
final node = editorState.getNodeAtPath(path); | ||
final delta = node?.delta; | ||
if (node == null || delta == null) { | ||
return; | ||
} | ||
final insertedPath = delta.isEmpty ? path : path.next; | ||
final transaction = editorState.transaction | ||
..insertNode(insertedPath, dividerNode()) | ||
..insertNode(insertedPath, paragraphNode()) | ||
..afterSelection = Selection.collapse(insertedPath.next, 0); | ||
editorState.apply(transaction); | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import 'package:appflowy_editor/appflowy_editor.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
class SelectionMenuIconWidget extends StatelessWidget { | ||
SelectionMenuIconWidget({ | ||
super.key, | ||
this.name, | ||
this.icon, | ||
required this.isSelected, | ||
required this.style, | ||
}) { | ||
assert((name == null && icon != null) || ((name != null && icon == null))); | ||
} | ||
|
||
final String? name; | ||
final IconData? icon; | ||
final bool isSelected; | ||
final SelectionMenuStyle style; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (icon != null) { | ||
return Icon( | ||
icon, | ||
size: 18.0, | ||
color: isSelected | ||
? style.selectionMenuItemSelectedIconColor | ||
: style.selectionMenuItemIconColor, | ||
); | ||
} else if (name != null) { | ||
return FlowySvg( | ||
name: 'selection_menu/$name', | ||
width: 18.0, | ||
height: 18.0, | ||
color: isSelected | ||
? style.selectionMenuItemSelectedIconColor | ||
: style.selectionMenuItemIconColor, | ||
); | ||
} | ||
throw UnimplementedError(); | ||
} | ||
} |
Oops, something went wrong.