diff --git a/example/lib/pages/markdown/markdown_code_block_parser.dart b/example/lib/pages/markdown/markdown_code_block_parser.dart index 10b472498..76ed6da80 100644 --- a/example/lib/pages/markdown/markdown_code_block_parser.dart +++ b/example/lib/pages/markdown/markdown_code_block_parser.dart @@ -8,9 +8,10 @@ class MarkdownCodeBlockParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/editor/block_component/table_block_component/table_action_handler.dart b/lib/src/editor/block_component/table_block_component/table_action_handler.dart index 0a83a2cee..d8b4d13e8 100644 --- a/lib/src/editor/block_component/table_block_component/table_action_handler.dart +++ b/lib/src/editor/block_component/table_block_component/table_action_handler.dart @@ -1,7 +1,8 @@ -import 'package:flutter/material.dart'; +import 'dart:math' as math; + import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/src/editor/block_component/table_block_component/table_action_menu.dart'; -import 'dart:math' as math; +import 'package:flutter/material.dart'; class TableActionHandler extends StatefulWidget { const TableActionHandler({ diff --git a/lib/src/editor/block_component/table_block_component/table_block_component.dart b/lib/src/editor/block_component/table_block_component/table_block_component.dart index d781927ae..8a304b874 100644 --- a/lib/src/editor/block_component/table_block_component/table_block_component.dart +++ b/lib/src/editor/block_component/table_block_component/table_block_component.dart @@ -36,7 +36,7 @@ class TableStyle { final Color borderHoverColor; const TableStyle({ - this.colWidth = 80, + this.colWidth = 160, this.rowHeight = 40, this.colMinimumWidth = 40, this.borderWidth = 2, @@ -50,7 +50,7 @@ class TableStyle { class TableDefaults { const TableDefaults._(); - static double colWidth = 80.0; + static double colWidth = 160.0; static double rowHeight = 40.0; diff --git a/lib/src/editor/block_component/table_block_component/table_col.dart b/lib/src/editor/block_component/table_block_component/table_col.dart index 4610d4e2a..7e2cfdde9 100644 --- a/lib/src/editor/block_component/table_block_component/table_col.dart +++ b/lib/src/editor/block_component/table_block_component/table_col.dart @@ -133,7 +133,11 @@ class _TableColState extends State { } final transaction = widget.editorState.transaction; - widget.tableNode.updateRowHeight(row, transaction: transaction); + widget.tableNode.updateRowHeight( + row, + editorState: widget.editorState, + transaction: transaction, + ); if (transaction.operations.isNotEmpty) { transaction.afterSelection = transaction.beforeSelection; widget.editorState.apply(transaction); diff --git a/lib/src/editor/block_component/table_block_component/table_col_border.dart b/lib/src/editor/block_component/table_block_component/table_col_border.dart index 8952c85c5..41e48f333 100644 --- a/lib/src/editor/block_component/table_block_component/table_col_border.dart +++ b/lib/src/editor/block_component/table_block_component/table_col_border.dart @@ -64,14 +64,17 @@ class _TableColBorderState extends State { }, onHorizontalDragUpdate: (DragUpdateDetails details) { final colWidth = widget.tableNode.getColWidth(widget.colIdx); - widget.tableNode - .setColWidth(widget.colIdx, colWidth + details.delta.dx); + widget.tableNode.setColWidth( + widget.colIdx, + colWidth + details.delta.dx, + ); }, child: Container( key: _borderKey, width: widget.tableNode.config.borderWidth, - height: context - .select((Node n) => n.attributes[TableBlockKeys.colsHeight]), + height: context.select( + (Node n) => n.attributes[TableBlockKeys.colsHeight], + ), color: _borderHovering || _borderDragging ? widget.borderHoverColor : widget.borderColor, @@ -83,8 +86,9 @@ class _TableColBorderState extends State { Container buildFixedBorder(BuildContext context) { return Container( width: widget.tableNode.config.borderWidth, - height: - context.select((Node n) => n.attributes[TableBlockKeys.colsHeight]), + height: context.select( + (Node n) => n.attributes[TableBlockKeys.colsHeight], + ), color: Colors.grey, ); } diff --git a/lib/src/editor/block_component/table_block_component/table_node.dart b/lib/src/editor/block_component/table_block_component/table_node.dart index 26729a8b4..7b133c91c 100644 --- a/lib/src/editor/block_component/table_block_component/table_node.dart +++ b/lib/src/editor/block_component/table_block_component/table_node.dart @@ -168,6 +168,7 @@ class TableNode { void updateRowHeight( int row, { + EditorState? editorState, Transaction? transaction, }) { // The extra 8 is because of paragraph padding @@ -192,6 +193,9 @@ class TableNode { if (node.attributes[TableBlockKeys.colsHeight] != colsHeight) { if (transaction != null) { transaction.updateNode(node, {TableBlockKeys.colsHeight: colsHeight}); + if (editorState != null && editorState.editable != true) { + node.updateAttributes({TableBlockKeys.colsHeight: colsHeight}); + } } else { node.updateAttributes({TableBlockKeys.colsHeight: colsHeight}); } diff --git a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart index 59fbc60b6..e98d81502 100644 --- a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart @@ -47,7 +47,6 @@ class DocumentMarkdownDecoder extends Converter { nodes = parser.transform( mdNode, markdownElementParsers, - MarkdownListType.unknown, ); if (nodes.isNotEmpty) { diff --git a/lib/src/plugins/markdown/decoder/parser/custom_markdown_node_parser.dart b/lib/src/plugins/markdown/decoder/parser/custom_markdown_node_parser.dart index 22872fad9..8b29e1e6f 100644 --- a/lib/src/plugins/markdown/decoder/parser/custom_markdown_node_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/custom_markdown_node_parser.dart @@ -6,7 +6,8 @@ abstract class CustomMarkdownParser { List transform( md.Node element, - List parsers, - MarkdownListType listType, - ); + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }); } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart index e9366fef4..bdb4dbdfb 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart @@ -7,9 +7,10 @@ class MarkdownBlockQuoteParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_divider_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_divider_parser.dart index 8657ef66d..9bce8efa1 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_divider_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_divider_parser.dart @@ -7,9 +7,10 @@ class MarkdownDividerParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart index 395668d47..fdb6fd3c0 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart @@ -9,9 +9,10 @@ class MarkdownHeadingParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_image_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_image_parser.dart index 99443a83e..e70588879 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_image_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_image_parser.dart @@ -7,9 +7,10 @@ class MarkdownImageParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_item_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_item_parser.dart index 6850c12bc..87d6ccef4 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_item_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_item_parser.dart @@ -8,9 +8,10 @@ class MarkdownOrderedListItemParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } @@ -25,7 +26,7 @@ class MarkdownOrderedListItemParserV2 extends CustomMarkdownParser { int sliceIndex = -1; if (element.children != null) { for (final child in element.children!.reversed) { - if (child is md.Element) { + if (child is md.Element && (child.tag == 'ol' || child.tag == 'ul')) { ec.add(child); } else { break; @@ -42,6 +43,7 @@ class MarkdownOrderedListItemParserV2 extends CustomMarkdownParser { return [ numberedListNode( + number: startNumber, delta: deltaDecoder.convertNodes( deltaNodes, ), @@ -49,6 +51,7 @@ class MarkdownOrderedListItemParserV2 extends CustomMarkdownParser { ec.reversed.toList(), parsers, listType: MarkdownListType.ordered, + startNumber: startNumber, ), ), ]; diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_parser.dart index a8feced17..c080bcd9a 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_ordered_list_parser.dart @@ -7,9 +7,10 @@ class MarkdownOrderedListParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } @@ -18,11 +19,14 @@ class MarkdownOrderedListParserV2 extends CustomMarkdownParser { return []; } + final startNumber = element.attributes['start']; + // flatten the list return parseElementChildren( element.children, parsers, listType: MarkdownListType.ordered, + startNumber: startNumber != null ? int.tryParse(startNumber) : null, ); } } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart index 775cf972b..e5e62c14b 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart @@ -7,9 +7,10 @@ class MarkdownParagraphParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_parser_extension.dart b/lib/src/plugins/markdown/decoder/parser/markdown_parser_extension.dart index a2a020d3e..fb1a30d24 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_parser_extension.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_parser_extension.dart @@ -11,6 +11,8 @@ List parseElementChildren( List? elementChildren, List parsers, { MarkdownListType listType = MarkdownListType.unknown, + // in case of ordered list, the start number of the list items may not start from 1 + int? startNumber, }) { final List children = []; @@ -23,7 +25,8 @@ List parseElementChildren( final nodes = parser.transform( child, parsers, - listType, + listType: listType, + startNumber: startNumber, ); if (nodes.isNotEmpty) { diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_table_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_table_parser.dart index ba68f6a7b..eb0b1538b 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_table_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_table_parser.dart @@ -8,9 +8,10 @@ class MarkdownTableListParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart index 43d962d1c..3b353e70a 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart @@ -7,9 +7,10 @@ class MarkdownTodoListParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_item_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_item_parser.dart index 914ce2c12..68b2b3cef 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_item_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_item_parser.dart @@ -8,9 +8,10 @@ class MarkdownUnorderedListItemParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } @@ -25,7 +26,7 @@ class MarkdownUnorderedListItemParserV2 extends CustomMarkdownParser { int sliceIndex = -1; if (element.children != null) { for (final child in element.children!.reversed) { - if (child is md.Element) { + if (child is md.Element && (child.tag == 'ol' || child.tag == 'ul')) { ec.add(child); } else { break; diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_parser.dart index a0eeb17fc..12d991743 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_unordered_list_parser.dart @@ -7,9 +7,10 @@ class MarkdownUnorderedListParserV2 extends CustomMarkdownParser { @override List transform( md.Node element, - List parsers, - MarkdownListType listType, - ) { + List parsers, { + MarkdownListType listType = MarkdownListType.unknown, + int? startNumber, + }) { if (element is! md.Element) { return []; } diff --git a/test/new/block_component/table_block_component/table_view_test.dart b/test/new/block_component/table_block_component/table_view_test.dart index fd47c14ff..ac4194c6a 100644 --- a/test/new/block_component/table_block_component/table_view_test.dart +++ b/test/new/block_component/table_block_component/table_view_test.dart @@ -41,10 +41,10 @@ void main() async { tableNode.updateRowHeight(0, transaction: transaction); await editor.editorState.apply(transaction); - expect(tableNode.getRowHeight(0) != row0beforeHeight, true); + expect(tableNode.getRowHeight(0) != row0beforeHeight, false); expect(tableNode.getRowHeight(0), cell10.children.first.rect.height + 8); expect(tableNode.getRowHeight(1), row1beforeHeight); - expect(tableNode.getRowHeight(1) < tableNode.getRowHeight(0), true); + expect(tableNode.getRowHeight(1) < tableNode.getRowHeight(0), false); await editor.dispose(); }); @@ -75,7 +75,7 @@ void main() async { tableNode.updateRowHeight(0, transaction: transaction); await editor.editorState.apply(transaction); - expect(tableNode.getRowHeight(0) != row0beforeHeight, true); + expect(tableNode.getRowHeight(0) != row0beforeHeight, false); expect(tableNode.getRowHeight(0), cell10.children.first.rect.height + 8); transaction = editor.editorState.transaction; diff --git a/test/plugins/html/decoder/document_html_decoder_test.dart b/test/plugins/html/decoder/document_html_decoder_test.dart index 58c48c717..64263ac05 100644 --- a/test/plugins/html/decoder/document_html_decoder_test.dart +++ b/test/plugins/html/decoder/document_html_decoder_test.dart @@ -60,7 +60,7 @@ const htmlTablejson = { "colPosition": 0, "rowPosition": 0, "height": 40.0, - "width": 80.0, + "width": 160.0, }, }, { @@ -82,7 +82,7 @@ const htmlTablejson = { "colPosition": 1, "rowPosition": 0, "height": 40.0, - "width": 80.0, + "width": 160.0, }, }, { @@ -104,7 +104,7 @@ const htmlTablejson = { "colPosition": 0, "rowPosition": 1, "height": 40.0, - "width": 80.0, + "width": 160.0, }, }, { @@ -123,14 +123,14 @@ const htmlTablejson = { "colPosition": 1, "rowPosition": 1, "height": 40.0, - "width": 80.0, + "width": 160.0, }, } ], "data": { "rowsLen": 2, "colsLen": 2, - "colDefaultWidth": 80, + "colDefaultWidth": 160, "rowDefaultHeight": 40, "colMinimumWidth": 40, }, diff --git a/test/plugins/markdown/decoder/table_decoder_test.dart b/test/plugins/markdown/decoder/table_decoder_test.dart index f33358964..8aa74433c 100644 --- a/test/plugins/markdown/decoder/table_decoder_test.dart +++ b/test/plugins/markdown/decoder/table_decoder_test.dart @@ -36,7 +36,7 @@ void main() async { 'colPosition': 0, 'rowPosition': 0, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -55,7 +55,7 @@ void main() async { 'colPosition': 0, 'rowPosition': 1, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -74,7 +74,7 @@ void main() async { 'colPosition': 0, 'rowPosition': 2, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -93,7 +93,7 @@ void main() async { 'colPosition': 0, 'rowPosition': 3, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -112,7 +112,7 @@ void main() async { 'colPosition': 1, 'rowPosition': 0, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -131,7 +131,7 @@ void main() async { 'colPosition': 1, 'rowPosition': 1, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -150,7 +150,7 @@ void main() async { 'colPosition': 1, 'rowPosition': 2, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, }, { @@ -169,14 +169,14 @@ void main() async { 'colPosition': 1, 'rowPosition': 3, 'height': 40.0, - 'width': 80.0, + 'width': 160.0, }, } ], 'data': { 'colsLen': 2, 'rowsLen': 4, - 'colDefaultWidth': 80.0, + 'colDefaultWidth': 160.0, 'rowDefaultHeight': 40.0, 'colMinimumWidth': 40.0, }, diff --git a/test/plugins/markdown/markdown_customer_test.dart b/test/plugins/markdown/markdown_customer_test.dart new file mode 100644 index 000000000..cd137d053 --- /dev/null +++ b/test/plugins/markdown/markdown_customer_test.dart @@ -0,0 +1,118 @@ +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() async { + group('ordered list decoder', () { + test('customer issue - unordered list with links', () { + const markdown = ''' +- [The Straits Times](https://www.straitstimes.com/) +- [Channel News Asia](https://www.channelnewsasia.com/) +- [Today Online](https://www.todayonline.com/) +'''; + final result = markdownToDocument(markdown); + expect( + result.nodeAtPath([0])!.toJson(), + { + 'type': 'bulleted_list', + 'data': { + 'delta': [ + { + 'insert': 'The Straits Times', + 'attributes': {'href': 'https://www.straitstimes.com/'}, + }, + ], + }, + }, + ); + expect( + result.nodeAtPath([1])!.toJson(), + { + 'type': 'bulleted_list', + 'data': { + 'delta': [ + { + 'insert': 'Channel News Asia', + 'attributes': {'href': 'https://www.channelnewsasia.com/'}, + }, + ], + }, + }, + ); + expect( + result.nodeAtPath([2])!.toJson(), + { + 'type': 'bulleted_list', + 'data': { + 'delta': [ + { + 'insert': 'Today Online', + 'attributes': {'href': 'https://www.todayonline.com/'}, + }, + ], + }, + }, + ); + }); + + test('customer issue - ordered list with numbers', () { + const markdown = ''' +1. **Ensure Dependencies** + +Make sure you have the necessary packages in your `pubspec.yaml`. For example, if `FlowyText` and `AFThemeExtension` are from packages, list them under dependencies. + +2. **Import Statements** + +Add the necessary import statements at the top of your Dart file. + +3. **Class Definition** + +Here is the complete Dart file with the above steps: +'''; + final result = markdownToDocument(markdown); + expect( + result.nodeAtPath([0])!.toJson(), + { + 'type': 'numbered_list', + 'data': { + 'delta': [ + { + 'insert': 'Ensure Dependencies', + 'attributes': {'bold': true}, + }, + ], + }, + }, + ); + expect( + result.nodeAtPath([2])!.toJson(), + { + 'type': 'numbered_list', + 'data': { + 'number': 2, + 'delta': [ + { + 'insert': 'Import Statements', + 'attributes': {'bold': true}, + }, + ], + }, + }, + ); + expect( + result.nodeAtPath([4])!.toJson(), + { + 'type': 'numbered_list', + 'data': { + 'number': 3, + 'delta': [ + { + 'insert': 'Class Definition', + 'attributes': {'bold': true}, + }, + ], + }, + }, + ); + }); + }); +}