فهرست منبع

feat: move divider plugin to appflowy editor plugins directory

Lucas.Xu 2 سال پیش
والد
کامیت
157f929ff9

+ 11 - 0
frontend/app_flowy/packages/appflowy_editor/example/lib/pages/simple_editor.dart

@@ -1,6 +1,7 @@
 import 'dart:convert';
 
 import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
 import 'package:flutter/material.dart';
 
 class SimpleEditor extends StatelessWidget {
@@ -30,10 +31,20 @@ class SimpleEditor extends StatelessWidget {
             ),
           );
           onEditorStateChange(editorState);
+
           return AppFlowyEditor(
             editorState: editorState,
             themeData: themeData,
             autoFocus: editorState.document.isEmpty,
+            customBuilders: {
+              kDividerType: DividerWidgetBuilder(),
+            },
+            shortcutEvents: [
+              insertDividerEvent,
+            ],
+            selectionMenuItems: [
+              dividerMenuItem,
+            ],
           );
         } else {
           return const Center(

+ 0 - 166
frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/horizontal_rule_node_widget.dart

@@ -1,166 +0,0 @@
-import 'dart:collection';
-
-import 'package:appflowy_editor/appflowy_editor.dart';
-import 'package:flutter/material.dart';
-
-ShortcutEvent insertHorizontalRule = ShortcutEvent(
-  key: 'Horizontal rule',
-  command: 'Minus',
-  handler: _insertHorzaontalRule,
-);
-
-ShortcutEventHandler _insertHorzaontalRule = (editorState, event) {
-  final selection = editorState.service.selectionService.currentSelection.value;
-  final textNodes = editorState.service.selectionService.currentSelectedNodes
-      .whereType<TextNode>();
-  if (textNodes.length != 1 || selection == null) {
-    return KeyEventResult.ignored;
-  }
-  final textNode = textNodes.first;
-  if (textNode.toPlainText() == '--') {
-    final transaction = editorState.transaction
-      ..deleteText(textNode, 0, 2)
-      ..insertNode(
-        textNode.path,
-        Node(
-          type: 'horizontal_rule',
-          children: LinkedList(),
-          attributes: {},
-        ),
-      )
-      ..afterSelection =
-          Selection.single(path: textNode.path.next, startOffset: 0);
-    editorState.apply(transaction);
-    return KeyEventResult.handled;
-  }
-  return KeyEventResult.ignored;
-};
-
-SelectionMenuItem horizontalRuleMenuItem = SelectionMenuItem(
-  name: () => 'Horizontal rule',
-  icon: (_, __) => const Icon(
-    Icons.horizontal_rule,
-    color: Colors.black,
-    size: 18.0,
-  ),
-  keywords: ['horizontal rule'],
-  handler: (editorState, _, __) {
-    final selection =
-        editorState.service.selectionService.currentSelection.value;
-    final textNodes = editorState.service.selectionService.currentSelectedNodes
-        .whereType<TextNode>();
-    if (selection == null || textNodes.isEmpty) {
-      return;
-    }
-    final textNode = textNodes.first;
-    if (textNode.toPlainText().isEmpty) {
-      final transaction = editorState.transaction
-        ..insertNode(
-          textNode.path,
-          Node(
-            type: 'horizontal_rule',
-            children: LinkedList(),
-            attributes: {},
-          ),
-        )
-        ..afterSelection =
-            Selection.single(path: textNode.path.next, startOffset: 0);
-      editorState.apply(transaction);
-    } else {
-      final transaction = editorState.transaction
-        ..insertNode(
-          selection.end.path.next,
-          TextNode(
-            children: LinkedList(),
-            attributes: {
-              'subtype': 'horizontal_rule',
-            },
-            delta: Delta()..insert('---'),
-          ),
-        )
-        ..afterSelection = selection;
-      editorState.apply(transaction);
-    }
-  },
-);
-
-class HorizontalRuleWidgetBuilder extends NodeWidgetBuilder<Node> {
-  @override
-  Widget build(NodeWidgetContext<Node> context) {
-    return _HorizontalRuleWidget(
-      key: context.node.key,
-      node: context.node,
-      editorState: context.editorState,
-    );
-  }
-
-  @override
-  NodeValidator<Node> get nodeValidator => (node) {
-        return true;
-      };
-}
-
-class _HorizontalRuleWidget extends StatefulWidget {
-  const _HorizontalRuleWidget({
-    Key? key,
-    required this.node,
-    required this.editorState,
-  }) : super(key: key);
-
-  final Node node;
-  final EditorState editorState;
-
-  @override
-  State<_HorizontalRuleWidget> createState() => __HorizontalRuleWidgetState();
-}
-
-class __HorizontalRuleWidgetState extends State<_HorizontalRuleWidget>
-    with SelectableMixin {
-  RenderBox get _renderBox => context.findRenderObject() as RenderBox;
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      padding: const EdgeInsets.symmetric(vertical: 10),
-      child: Container(
-        height: 1,
-        color: Colors.grey,
-      ),
-    );
-  }
-
-  @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.borderLine;
-
-  @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);
-}

+ 2 - 0
frontend/app_flowy/packages/appflowy_editor/example/pubspec.yaml

@@ -45,6 +45,8 @@ dependencies:
   universal_html: ^2.0.8
   highlight: ^0.7.0
   flutter_math_fork: ^0.6.3+1
+  appflowy_editor_plugins:
+    path: ../../../packages/appflowy_editor_plugins
 
 dev_dependencies:
   flutter_test:

+ 2 - 5
frontend/app_flowy/packages/appflowy_editor_plugins/lib/appflowy_editor_plugins.dart

@@ -1,7 +1,4 @@
 library appflowy_editor_plugins;
 
-/// A Calculator.
-class Calculator {
-  /// Returns [value] plus 1.
-  int addOne(int value) => value + 1;
-}
+export 'src/divider/divider_node_widget.dart';
+export 'src/divider/divider_shortcut_event.dart';

+ 84 - 0
frontend/app_flowy/packages/appflowy_editor_plugins/lib/src/divider/divider_node_widget.dart

@@ -0,0 +1,84 @@
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:flutter/material.dart';
+
+const String kDividerType = 'divider';
+
+class DividerWidgetBuilder extends NodeWidgetBuilder<Node> {
+  @override
+  Widget build(NodeWidgetContext<Node> context) {
+    return _DividerWidget(
+      key: context.node.key,
+      node: context.node,
+      editorState: context.editorState,
+    );
+  }
+
+  @override
+  NodeValidator<Node> get nodeValidator => (node) {
+        return true;
+      };
+}
+
+class _DividerWidget extends StatefulWidget {
+  const _DividerWidget({
+    Key? key,
+    required this.node,
+    required this.editorState,
+  }) : super(key: key);
+
+  final Node node;
+  final EditorState editorState;
+
+  @override
+  State<_DividerWidget> createState() => _DividerWidgetState();
+}
+
+class _DividerWidgetState extends State<_DividerWidget> with SelectableMixin {
+  RenderBox get _renderBox => context.findRenderObject() as RenderBox;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 10),
+      child: Container(
+        height: 1,
+        color: Colors.grey,
+      ),
+    );
+  }
+
+  @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.borderLine;
+
+  @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);
+}

+ 72 - 0
frontend/app_flowy/packages/appflowy_editor_plugins/lib/src/divider/divider_shortcut_event.dart

@@ -0,0 +1,72 @@
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:appflowy_editor_plugins/src/divider/divider_node_widget.dart';
+import 'package:flutter/material.dart';
+
+// insert divider into a document by typing three minuses.
+// ---
+ShortcutEvent insertDividerEvent = ShortcutEvent(
+  key: 'Divider',
+  command: 'Minus',
+  handler: _insertDividerHandler,
+);
+
+ShortcutEventHandler _insertDividerHandler = (editorState, event) {
+  final selection = editorState.service.selectionService.currentSelection.value;
+  final textNodes = editorState.service.selectionService.currentSelectedNodes
+      .whereType<TextNode>();
+  if (textNodes.length != 1 || selection == null) {
+    return KeyEventResult.ignored;
+  }
+  final textNode = textNodes.first;
+  if (textNode.toPlainText() != '--') {
+    return KeyEventResult.ignored;
+  }
+  final transaction = editorState.transaction
+    ..deleteText(textNode, 0, 2) // remove the existing minuses.
+    ..insertNode(textNode.path, Node(type: kDividerType)) // insert the divder
+    ..afterSelection = Selection.single(
+      // update selection to the next text node.
+      path: textNode.path.next,
+      startOffset: 0,
+    );
+  editorState.apply(transaction);
+  return KeyEventResult.handled;
+};
+
+SelectionMenuItem dividerMenuItem = SelectionMenuItem(
+  name: () => 'Divider',
+  icon: (editorState, onSelected) => Icon(
+    Icons.horizontal_rule,
+    color: onSelected
+        ? editorState.editorStyle.selectionMenuItemSelectedIconColor
+        : editorState.editorStyle.selectionMenuItemIconColor,
+    size: 18.0,
+  ),
+  keywords: ['horizontal rule', 'divider'],
+  handler: (editorState, _, __) {
+    final selection =
+        editorState.service.selectionService.currentSelection.value;
+    final textNodes = editorState.service.selectionService.currentSelectedNodes
+        .whereType<TextNode>();
+    if (textNodes.length != 1 || selection == null) {
+      return;
+    }
+    final textNode = textNodes.first;
+    // insert the divider at current path if the text node is empty.
+    if (textNode.toPlainText().isEmpty) {
+      final transaction = editorState.transaction
+        ..insertNode(textNode.path, Node(type: kDividerType))
+        ..afterSelection = Selection.single(
+          path: textNode.path.next,
+          startOffset: 0,
+        );
+      editorState.apply(transaction);
+    } else {
+      // insert the divider at the path next to current path if the text node is not empty.
+      final transaction = editorState.transaction
+        ..insertNode(selection.end.path.next, Node(type: kDividerType))
+        ..afterSelection = selection;
+      editorState.apply(transaction);
+    }
+  },
+);

+ 5 - 1
frontend/app_flowy/packages/appflowy_editor_plugins/pubspec.yaml

@@ -1,7 +1,9 @@
 name: appflowy_editor_plugins
 description: A new Flutter package project.
 version: 0.0.1
-homepage:
+homepage: https://github.com/AppFlowy-IO/AppFlowy
+
+publish_to: none
 
 environment:
   sdk: ">=2.17.6 <3.0.0"
@@ -10,6 +12,8 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
+  appflowy_editor: 
+    path: ../appflowy_editor
 
 dev_dependencies:
   flutter_test:

+ 0 - 11
frontend/app_flowy/packages/appflowy_editor_plugins/test/appflowy_editor_plugins_test.dart

@@ -1,12 +1 @@
-import 'package:flutter_test/flutter_test.dart';
 
-import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
-
-void main() {
-  test('adds one to input values', () {
-    final calculator = Calculator();
-    expect(calculator.addOne(2), 3);
-    expect(calculator.addOne(-7), -6);
-    expect(calculator.addOne(0), 1);
-  });
-}