Bläddra i källkod

feat: add bulleted-list and number-list

Lucas.Xu 2 år sedan
förälder
incheckning
51bc965029

+ 12 - 9
frontend/app_flowy/packages/flowy_editor/example/assets/example.json

@@ -111,8 +111,8 @@
           { "insert": " and just typing." }
           { "insert": " and just typing." }
         ],
         ],
         "attributes": {
         "attributes": {
-          "list": "todo",
-          "todo": true
+          "subtype": "checkbox",
+          "checkbox": true
         }
         }
       },
       },
       {
       {
@@ -130,8 +130,8 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
-          "list": "todo",
-          "todo": true
+          "subtype": "checkbox",
+          "checkbox": true
         }
         }
       },
       },
       {
       {
@@ -146,8 +146,8 @@
           { "insert": "." }
           { "insert": "." }
         ],
         ],
         "attributes": {
         "attributes": {
-          "list": "todo",
-          "todo": true
+          "subtype": "checkbox",
+          "checkbox": true
         }
         }
       },
       },
       {
       {
@@ -170,7 +170,7 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
-          "list": "bullet"
+          "subtype": "bullet-list"
         }
         }
       },
       },
       {
       {
@@ -181,7 +181,7 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
-          "list": "bullet"
+          "subtype": "bullet-list"
         }
         }
       },
       },
       {
       {
@@ -192,7 +192,7 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
-          "list": "bullet"
+          "subtype": "bullet-list"
         }
         }
       },
       },
       {
       {
@@ -225,6 +225,7 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
+          "subtype": "number-list",
           "number": 1
           "number": 1
         }
         }
       },
       },
@@ -236,6 +237,7 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
+          "subtype": "number-list",
           "number": 2
           "number": 2
         }
         }
       },
       },
@@ -247,6 +249,7 @@
           }
           }
         ],
         ],
         "attributes": {
         "attributes": {
+          "subtype": "number-list",
           "number": 3
           "number": 3
         }
         }
       }
       }

+ 6 - 0
frontend/app_flowy/packages/flowy_editor/lib/editor_state.dart

@@ -1,7 +1,9 @@
 import 'dart:async';
 import 'dart:async';
+import 'package:flowy_editor/render/rich_text/bulleted_list_text.dart';
 import 'package:flowy_editor/render/rich_text/checkbox_text.dart';
 import 'package:flowy_editor/render/rich_text/checkbox_text.dart';
 import 'package:flowy_editor/render/rich_text/flowy_rich_text.dart';
 import 'package:flowy_editor/render/rich_text/flowy_rich_text.dart';
 import 'package:flowy_editor/render/rich_text/heading_text.dart';
 import 'package:flowy_editor/render/rich_text/heading_text.dart';
+import 'package:flowy_editor/render/rich_text/number_list_text.dart';
 import 'package:flowy_editor/service/service.dart';
 import 'package:flowy_editor/service/service.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 
 
@@ -47,6 +49,10 @@ class EditorState {
     renderPlugins.register('text', RichTextNodeWidgetBuilder.create);
     renderPlugins.register('text', RichTextNodeWidgetBuilder.create);
     renderPlugins.register('text/checkbox', CheckboxNodeWidgetBuilder.create);
     renderPlugins.register('text/checkbox', CheckboxNodeWidgetBuilder.create);
     renderPlugins.register('text/heading', HeadingTextNodeWidgetBuilder.create);
     renderPlugins.register('text/heading', HeadingTextNodeWidgetBuilder.create);
+    renderPlugins.register(
+        'text/bullet-list', BulletedListTextNodeWidgetBuilder.create);
+    renderPlugins.register(
+        'text/number-list', NumberListTextNodeWidgetBuilder.create);
     undoManager.state = this;
     undoManager.state = this;
   }
   }
 
 

+ 73 - 0
frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart

@@ -0,0 +1,73 @@
+import 'package:flowy_editor/document/node.dart';
+import 'package:flowy_editor/editor_state.dart';
+import 'package:flowy_editor/infra/flowy_svg.dart';
+import 'package:flowy_editor/render/node_widget_builder.dart';
+import 'package:flowy_editor/render/rich_text/default_selectable.dart';
+import 'package:flowy_editor/render/rich_text/flowy_rich_text.dart';
+import 'package:flowy_editor/render/selection/selectable.dart';
+import 'package:flutter/material.dart';
+
+class BulletedListTextNodeWidgetBuilder extends NodeWidgetBuilder {
+  BulletedListTextNodeWidgetBuilder.create({
+    required super.editorState,
+    required super.node,
+    required super.key,
+  }) : super.create();
+
+  @override
+  Widget build(BuildContext context) {
+    return BulletedListTextNodeWidget(
+      key: key,
+      textNode: node as TextNode,
+      editorState: editorState,
+    );
+  }
+}
+
+class BulletedListTextNodeWidget extends StatefulWidget {
+  const BulletedListTextNodeWidget({
+    Key? key,
+    required this.textNode,
+    required this.editorState,
+  }) : super(key: key);
+
+  final TextNode textNode;
+  final EditorState editorState;
+
+  @override
+  State<BulletedListTextNodeWidget> createState() =>
+      _BulletedListTextNodeWidgetState();
+}
+
+// customize
+
+class _BulletedListTextNodeWidgetState extends State<BulletedListTextNodeWidget>
+    with Selectable, DefaultSelectable {
+  final _richTextKey = GlobalKey(debugLabel: 'heading_text');
+  final leftPadding = 20.0;
+
+  @override
+  Selectable<StatefulWidget> get forward =>
+      _richTextKey.currentState as Selectable;
+
+  @override
+  Offset get baseOffset {
+    return Offset(leftPadding, 0);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        const FlowySvg(
+          name: 'point',
+        ),
+        FlowyRichText(
+          key: _richTextKey,
+          textNode: widget.textNode,
+          editorState: widget.editorState,
+        ),
+      ],
+    );
+  }
+}

+ 3 - 3
frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart

@@ -68,15 +68,15 @@ class _FlowyRichTextState extends State<FlowyRichText> with Selectable {
     final attributes = _textNode.attributes;
     final attributes = _textNode.attributes;
     // TODO: use factory method ??
     // TODO: use factory method ??
     if (attributes.list == 'todo') {
     if (attributes.list == 'todo') {
-      return _buildTodoListRichText(context);
+      // return _buildTodoListRichText(context);
     } else if (attributes.list == 'bullet') {
     } else if (attributes.list == 'bullet') {
-      return _buildBulletedListRichText(context);
+      // return _buildBulletedListRichText(context);
     } else if (attributes.quote == true) {
     } else if (attributes.quote == true) {
       return _buildQuotedRichText(context);
       return _buildQuotedRichText(context);
     } else if (attributes.heading != null) {
     } else if (attributes.heading != null) {
       // return _buildHeadingRichText(context);
       // return _buildHeadingRichText(context);
     } else if (attributes.number != null) {
     } else if (attributes.number != null) {
-      return _buildNumberListRichText(context);
+      // return _buildNumberListRichText(context);
     }
     }
     return _buildRichText(context);
     return _buildRichText(context);
   }
   }

+ 0 - 3
frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart

@@ -1,13 +1,10 @@
 import 'package:flowy_editor/document/node.dart';
 import 'package:flowy_editor/document/node.dart';
 import 'package:flowy_editor/editor_state.dart';
 import 'package:flowy_editor/editor_state.dart';
-import 'package:flowy_editor/infra/flowy_svg.dart';
 import 'package:flowy_editor/render/node_widget_builder.dart';
 import 'package:flowy_editor/render/node_widget_builder.dart';
-import 'package:flowy_editor/render/render_plugins.dart';
 import 'package:flowy_editor/render/rich_text/default_selectable.dart';
 import 'package:flowy_editor/render/rich_text/default_selectable.dart';
 import 'package:flowy_editor/render/rich_text/flowy_rich_text.dart';
 import 'package:flowy_editor/render/rich_text/flowy_rich_text.dart';
 import 'package:flowy_editor/render/rich_text/rich_text_style.dart';
 import 'package:flowy_editor/render/rich_text/rich_text_style.dart';
 import 'package:flowy_editor/render/selection/selectable.dart';
 import 'package:flowy_editor/render/selection/selectable.dart';
-import 'package:flowy_editor/extensions/object_extensions.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 
 
 class HeadingTextNodeWidgetBuilder extends NodeWidgetBuilder {
 class HeadingTextNodeWidgetBuilder extends NodeWidgetBuilder {

+ 74 - 0
frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart

@@ -0,0 +1,74 @@
+import 'package:flowy_editor/document/node.dart';
+import 'package:flowy_editor/editor_state.dart';
+import 'package:flowy_editor/infra/flowy_svg.dart';
+import 'package:flowy_editor/render/node_widget_builder.dart';
+import 'package:flowy_editor/render/rich_text/default_selectable.dart';
+import 'package:flowy_editor/render/rich_text/flowy_rich_text.dart';
+import 'package:flowy_editor/render/rich_text/rich_text_style.dart';
+import 'package:flowy_editor/render/selection/selectable.dart';
+import 'package:flutter/material.dart';
+
+class NumberListTextNodeWidgetBuilder extends NodeWidgetBuilder {
+  NumberListTextNodeWidgetBuilder.create({
+    required super.editorState,
+    required super.node,
+    required super.key,
+  }) : super.create();
+
+  @override
+  Widget build(BuildContext context) {
+    return NumberListTextNodeWidget(
+      key: key,
+      textNode: node as TextNode,
+      editorState: editorState,
+    );
+  }
+}
+
+class NumberListTextNodeWidget extends StatefulWidget {
+  const NumberListTextNodeWidget({
+    Key? key,
+    required this.textNode,
+    required this.editorState,
+  }) : super(key: key);
+
+  final TextNode textNode;
+  final EditorState editorState;
+
+  @override
+  State<NumberListTextNodeWidget> createState() =>
+      _NumberListTextNodeWidgetState();
+}
+
+// customize
+
+class _NumberListTextNodeWidgetState extends State<NumberListTextNodeWidget>
+    with Selectable, DefaultSelectable {
+  final _richTextKey = GlobalKey(debugLabel: 'heading_text');
+  final leftPadding = 20.0;
+
+  @override
+  Selectable<StatefulWidget> get forward =>
+      _richTextKey.currentState as Selectable;
+
+  @override
+  Offset get baseOffset {
+    return Offset(leftPadding, 0);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        FlowySvg(
+          number: widget.textNode.attributes.number,
+        ),
+        FlowyRichText(
+          key: _richTextKey,
+          textNode: widget.textNode,
+          editorState: widget.editorState,
+        ),
+      ],
+    );
+  }
+}