Skip to content

Commit f0a357b

Browse files
XazinLucasXu0
andauthored
feat: shrinkWrap option for AppFlowyEditor (#20)
* feat: shrinkWrap option for AppFlowyEditor Relates: #19 * test: add autoFocus tests for editor service * chore: Update lib/src/core/transform/operation.dart Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
1 parent 4e8b8bc commit f0a357b

File tree

6 files changed

+74
-13
lines changed

6 files changed

+74
-13
lines changed

lib/src/core/transform/operation.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,28 +235,30 @@ class UpdateTextOperation extends Operation {
235235

236236
// TODO(Lucas.Xu): refactor this part
237237
Path transformPath(Path preInsertPath, Path b, [int delta = 1]) {
238-
if (preInsertPath.length > b.length) {
239-
return b;
240-
}
241-
if (preInsertPath.isEmpty || b.isEmpty) {
238+
if (preInsertPath.length > b.length || preInsertPath.isEmpty || b.isEmpty) {
242239
return b;
243240
}
241+
244242
// check the prefix
245243
for (var i = 0; i < preInsertPath.length - 1; i++) {
246244
if (preInsertPath[i] != b[i]) {
247245
return b;
248246
}
249247
}
248+
250249
final prefix = preInsertPath.sublist(0, preInsertPath.length - 1);
251250
final suffix = b.sublist(preInsertPath.length);
251+
252252
final preInsertLast = preInsertPath.last;
253253
final bAtIndex = b[preInsertPath.length - 1];
254254
if (preInsertLast <= bAtIndex) {
255255
prefix.add(bAtIndex + delta);
256256
} else {
257257
prefix.add(bAtIndex);
258258
}
259+
259260
prefix.addAll(suffix);
261+
260262
return prefix;
261263
}
262264

lib/src/service/editor_service.dart

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class AppFlowyEditor extends StatefulWidget {
3434
this.autoFocus = false,
3535
this.focusedSelection,
3636
this.customActionMenuBuilder,
37+
this.shrinkWrap = false,
3738
ThemeData? themeData,
3839
}) : super(key: key) {
3940
this.themeData = themeData ??
@@ -55,17 +56,21 @@ class AppFlowyEditor extends StatefulWidget {
5556

5657
final List<ToolbarItem> toolbarItems;
5758

58-
late final ThemeData themeData;
59-
6059
final bool editable;
6160

6261
/// Set the value to true to focus the editor on the start of the document.
6362
final bool autoFocus;
63+
6464
final Selection? focusedSelection;
6565

6666
final Positioned Function(BuildContext context, List<ActionMenuItem> items)?
6767
customActionMenuBuilder;
6868

69+
/// If false the Editor is inside an [AppFlowyScroll]
70+
final bool shrinkWrap;
71+
72+
late final ThemeData themeData;
73+
6974
@override
7075
State<AppFlowyEditor> createState() => _AppFlowyEditorState();
7176
}
@@ -116,6 +121,7 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
116121
@override
117122
Widget build(BuildContext context) {
118123
services ??= _buildServices(context);
124+
119125
return Overlay(
120126
initialEntries: [
121127
OverlayEntry(
@@ -125,11 +131,21 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
125131
);
126132
}
127133

134+
Widget _buildScroll({required Widget child}) {
135+
if (widget.shrinkWrap) {
136+
return child;
137+
}
138+
139+
return AppFlowyScroll(
140+
key: editorState.service.scrollServiceKey,
141+
child: child,
142+
);
143+
}
144+
128145
Widget _buildServices(BuildContext context) {
129146
return Theme(
130147
data: widget.themeData,
131-
child: AppFlowyScroll(
132-
key: editorState.service.scrollServiceKey,
148+
child: _buildScroll(
133149
child: Container(
134150
color: editorStyle.backgroundColor,
135151
padding: editorStyle.padding!,

lib/src/service/selection_service.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
337337
// try to select the word.
338338
final selection = currentSelection.value;
339339
if (selection == null ||
340-
(selection.isCollapsed == true &&
341-
currentSelectedNodes.first is TextNode)) {
340+
(selection.isCollapsed && currentSelectedNodes.first is TextNode)) {
342341
_onDoubleTapDown(details);
343342
}
344343

test/infra/test_editor.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class EditorWidgetTester {
2626

2727
Future<EditorWidgetTester> startTesting({
2828
Locale locale = const Locale('en'),
29+
bool shrinkWrap = false,
30+
bool autoFocus = false,
2931
}) async {
3032
final app = MaterialApp(
3133
localizationsDelegates: const [
@@ -39,6 +41,8 @@ class EditorWidgetTester {
3941
home: Scaffold(
4042
body: AppFlowyEditor(
4143
editorState: _editorState,
44+
shrinkWrap: shrinkWrap,
45+
autoFocus: autoFocus,
4246
),
4347
),
4448
);

test/render/rich_text/toolbar_rich_text_test.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,7 @@ void main() async {
238238
node.allSatisfyInSelection(
239239
code,
240240
BuiltInAttributeKey.code,
241-
(value) {
242-
return value == true;
243-
},
241+
(value) => value == true,
244242
),
245243
true,
246244
);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import 'package:appflowy_editor/appflowy_editor.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
4+
import '../infra/test_editor.dart';
5+
6+
void main() {
7+
group('AppFlowyEditor tests', () {
8+
testWidgets('shrinkWrap is false', (tester) async {
9+
final editor = tester.editor;
10+
await editor.startTesting();
11+
12+
expect(find.byType(AppFlowyScroll), findsOneWidget);
13+
});
14+
15+
testWidgets('shrinkWrap is true', (tester) async {
16+
final editor = tester.editor;
17+
await editor.startTesting(shrinkWrap: true);
18+
19+
expect(find.byType(AppFlowyScroll), findsNothing);
20+
});
21+
22+
testWidgets('without autoFocus', (tester) async {
23+
final editor = tester.editor..insertTextNode('Hello');
24+
await editor.startTesting(shrinkWrap: true, autoFocus: false);
25+
26+
final selectedNodes =
27+
editor.editorState.service.selectionService.currentSelectedNodes;
28+
29+
expect(selectedNodes.isEmpty, true);
30+
});
31+
32+
testWidgets('with autoFocus', (tester) async {
33+
final editor = tester.editor..insertTextNode('Hello');
34+
await editor.startTesting(shrinkWrap: true, autoFocus: true);
35+
36+
final selectedNodes =
37+
editor.editorState.service.selectionService.currentSelectedNodes;
38+
39+
expect(selectedNodes.isEmpty, false);
40+
});
41+
});
42+
}

0 commit comments

Comments
 (0)