Skip to content

Commit

Permalink
Merge branch 'fix/previous-node-text-direction-null' into feat/editor…
Browse files Browse the repository at this point in the history
…-state-update-node

* fix/previous-node-text-direction-null:
  feat: default text direction property (AppFlowy-IO#402)
  fix: fixed the cursor not moving to next line after inserting divider (AppFlowy-IO#371)
  chore: update theme colors for editor
  feat: refactor floating toolbar positioning logic
  fix: update resizable image width calculation with minimum width constraint
  chore: comment suggesting use of deprecated method (AppFlowy-IO#417)
  fix: replace matches on the same node (AppFlowy-IO#418)
  fix: rect of the divider block is incorrect (AppFlowy-IO#415)
  chore: bump version 1.2.4 (AppFlowy-IO#414)
  feat: migrate copy paste command from AppFlowy (AppFlowy-IO#413)
  feat: added support for custom parser for markdown to document (AppFlowy-IO#403)
  feat: improve CJK IME support
  feat: add support for context menu items to the editor
  fix: refactor _onSelectionChange method to update _showPlaceholder state more efficiently
  fix: typo (AppFlowy-IO#408)
  Fix selected nodes (AppFlowy-IO#407)
  fix: miss the nested node when copying (AppFlowy-IO#406)
  • Loading branch information
zoli committed Aug 28, 2023
2 parents 578537e + e93e030 commit ff471a8
Show file tree
Hide file tree
Showing 47 changed files with 884 additions and 374 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 1.2.4
* feat: improve CJK IME support by @LucasXu0 in ([#412](https://github.com/AppFlowy-IO/appflowy-editor/pull/412))
* feat: implement find dialog by @MayurSMahajan in ([#106](https://github.com/AppFlowy-IO/appflowy-editor/pull/106))
* feat: improve functionality for pasting from html by @LucasXu0 in ([#391](https://github.com/AppFlowy-IO/appflowy-editor/pull/391))
* feat: placeholder on paragraph when selected by @Xazin in ([#390](https://github.com/AppFlowy-IO/appflowy-editor/pull/390))
* feat: double hyphen to em dash by @Xazin in ([#395](https://github.com/AppFlowy-IO/appflowy-editor/pull/395))
* feat: skip whitespace between words while navigating with CTRL+ARROW keys by @johansutrisno in ([#363](https://github.com/AppFlowy-IO/appflowy-editor/pull/363))
* feat: add support for context menu items to the editor by @LucasXu0 in ([#410](https://github.com/AppFlowy-IO/appflowy-editor/pull/410))
* feat: add support for custom parser for markdown to document by @Mukund-Tandon in ([#403](https://github.com/AppFlowy-IO/appflowy-editor/pull/403))
* fix: miss the nested node when copying by @LucasXu0 in ([#406](https://github.com/AppFlowy-IO/appflowy-editor/pull/406))
* fix: refactor _onSelectionChange to update _showPlaceholder state more efficiently by @LucasXu0 in ([#409](https://github.com/AppFlowy-IO/appflowy-editor/pull/409))

## 1.2.3
* feat: add edit link menu on mobile by @hyj1204 in ([#320](https://github.com/AppFlowy-IO/appflowy-editor/pull/320))
* feat: html encode parser added by @alihassan143 in ([#314](https://github.com/AppFlowy-IO/appflowy-editor/pull/314))
Expand Down
6 changes: 3 additions & 3 deletions example/lib/pages/customize_theme_for_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class _CustomizeThemeForEditorState extends State<CustomizeThemeForEditor> {

Widget buildEditor(EditorState editorState) {
return Container(
color: Colors.black,
color: Colors.grey[900],
child: AppFlowyEditor(
editorState: editorState,
editorStyle: customizeEditorStyle(),
Expand Down Expand Up @@ -134,11 +134,11 @@ class _CustomizeThemeForEditorState extends State<CustomizeThemeForEditor> {
? const EdgeInsets.only(left: 100, right: 100, top: 20)
: const EdgeInsets.symmetric(horizontal: 20),
cursorColor: Colors.green,
selectionColor: Colors.green,
selectionColor: Colors.green.withOpacity(0.5),
textStyleConfiguration: TextStyleConfiguration(
text: const TextStyle(
fontSize: 18.0,
color: Colors.white54,
color: Colors.white,
),
bold: const TextStyle(
fontWeight: FontWeight.w900,
Expand Down
1 change: 1 addition & 0 deletions lib/appflowy_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export 'src/l10n/l10n.dart';
export 'src/plugins/plugins.dart';
export 'src/render/selection/selectable.dart';
export 'src/render/toolbar/toolbar_item.dart';
export 'src/service/context_menu/context_menu.dart';
export 'src/service/internal_key_event_handlers/copy_paste_handler.dart';
export 'src/service/shortcut_event/key_mapping.dart';
export 'src/service/shortcut_event/keybinding.dart';
2 changes: 0 additions & 2 deletions lib/src/core/location/selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ class Selection {
}) : start = Position(path: path, offset: startOffset),
end = Position(path: path, offset: endOffset ?? startOffset);

/// deprecated: use [Selection.collapse] instead.
/// Create a collapsed selection with [position].
///
Selection.collapsed(Position position)
: start = position,
end = position;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ mixin BlockComponentTextDirectionMixin {
}

/// Calculate the text direction of a node.
// If the textDirection attribute is not set we will use defaultTextDirection
// if set. If not will use layoutDirection.
// If the textDirection attribute is not set, we will use defaultTextDirection if
// it has a value (defaultTextDirection != null). If not will use layoutDirection.
// If the textDirection is ltr or rtl we will apply that.
// If the textDirection is auto we go by these priorities:
// 1. Determine the direction by first character with strong directionality
Expand All @@ -66,7 +66,8 @@ TextDirection calculateNodeDirection({
}) {
// if the block component has a text direction attribute which is not auto,
// use it
final value = node.attributes[blockComponentTextDirection] as String?;
final value = (node.attributes[blockComponentTextDirection] as String?) ??
defaultTextDirection;
if (value != null && value != blockComponentTextDirectionAuto) {
final direction = value.toTextDirection();
if (direction != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class _DividerBlockComponentWidgetState

@override
Rect getBlockRect() {
return getCursorRectInPosition(Position.invalid()) ?? Rect.zero;
return getRectsInSelection(Selection.invalid()).first;
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Future<bool> _convertSyntaxToDivider(
..insertNode(path, dividerNode())
..insertNode(path, paragraphNode())
..deleteNode(node)
..afterSelection = Selection.collapsed(Position(path: path));
..afterSelection = Selection.collapsed(Position(path: path.next));
editorState.apply(transaction);
return true;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import 'dart:io';

import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:file_picker/file_picker.dart' as fp;
import 'package:flutter/material.dart';

import '../../util/file_picker/file_picker_impl.dart';
import 'package:file_picker/file_picker.dart' as fp;

enum ImageFromFileStatus {
notSelected,
Expand Down Expand Up @@ -47,7 +48,7 @@ void showImageMenu(
builder: (context) => UploadImageMenu(
backgroundColor: menuService.style.selectionMenuBackgroundColor,
headerColor: menuService.style.selectionMenuItemTextColor,
width: MediaQuery.of(context).size.width * 0.4,
width: MediaQuery.of(context).size.width * 0.3,
onSubmitted: insertImage,
onUpload: insertImage,
),
Expand Down Expand Up @@ -103,8 +104,8 @@ class _UploadImageMenuState extends State<UploadImageMenu> {
Widget build(BuildContext context) {
return Container(
width: widget.width,
height: 300,
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 10.0),
height: 240,
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 5.0),
decoration: BoxDecoration(
color: widget.backgroundColor,
boxShadow: [
Expand All @@ -123,7 +124,8 @@ class _UploadImageMenuState extends State<UploadImageMenu> {
Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: 300,
width: 260,
height: 36,
child: TabBar(
tabs: const [
Tab(text: 'Upload Image'),
Expand Down Expand Up @@ -207,7 +209,7 @@ class _UploadImageMenuState extends State<UploadImageMenu> {
) {
return SizedBox(
width: 170,
height: 48,
height: 36,
child: TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(const Color(0xFF00BCF0)),
Expand Down Expand Up @@ -296,7 +298,7 @@ class _UploadImageMenuState extends State<UploadImageMenu> {
}
},
child: Container(
height: 80,
height: 60,
margin: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xff00BCF0)),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:math';

import 'package:flutter/material.dart';

Expand All @@ -25,6 +26,8 @@ class ResizableImage extends StatefulWidget {
State<ResizableImage> createState() => _ResizableImageState();
}

const _kImageBlockComponentMinWidth = 30.0;

class _ResizableImageState extends State<ResizableImage> {
late double imageWidth;

Expand All @@ -48,7 +51,7 @@ class _ResizableImageState extends State<ResizableImage> {
return Align(
alignment: widget.alignment,
child: SizedBox(
width: imageWidth - moveDistance,
width: max(_kImageBlockComponentMinWidth, imageWidth - moveDistance),
height: widget.height,
child: MouseRegion(
onEnter: (event) => setState(() {
Expand Down Expand Up @@ -180,7 +183,8 @@ class _ResizableImageState extends State<ResizableImage> {
}
},
onHorizontalDragEnd: (details) {
imageWidth = imageWidth - moveDistance;
imageWidth =
max(_kImageBlockComponentMinWidth, imageWidth - moveDistance);
initialOffset = 0;
moveDistance = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,12 @@ class _TextBlockComponentWidgetState extends State<TextBlockComponentWidget>
}

void _onSelectionChange() {
setState(() {
final selection = editorState.selection;
_showPlaceholder = selection != null &&
(selection.isSingle && selection.start.path.equals(node.path));
});
final selection = editorState.selection;
final showPlaceholder = selection != null &&
(selection.isSingle && selection.start.path.equals(node.path));
if (showPlaceholder != _showPlaceholder) {
setState(() => _showPlaceholder = showPlaceholder);
}
}

@override
Expand Down
13 changes: 12 additions & 1 deletion lib/src/editor/editor_component/service/editor.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/service/context_menu/built_in_context_menu_item.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:provider/provider.dart';

Expand All @@ -19,6 +20,7 @@ class AppFlowyEditor extends StatefulWidget {
Map<String, BlockComponentBuilder>? blockComponentBuilders,
List<CharacterShortcutEvent>? characterShortcutEvents,
List<CommandShortcutEvent>? commandShortcutEvents,
List<List<ContextMenuItem>>? contextMenuItems,
this.editable = true,
this.autoFocus = false,
this.focusedSelection,
Expand All @@ -33,7 +35,8 @@ class AppFlowyEditor extends StatefulWidget {
characterShortcutEvents =
characterShortcutEvents ?? standardCharacterShortcutEvents,
commandShortcutEvents =
commandShortcutEvents ?? standardCommandShortcutEvents;
commandShortcutEvents ?? standardCommandShortcutEvents,
contextMenuItems = contextMenuItems ?? standardContextMenuItems;

final EditorState editorState;

Expand Down Expand Up @@ -101,6 +104,13 @@ class AppFlowyEditor extends StatefulWidget {
/// ```
final List<CommandShortcutEvent> commandShortcutEvents;

/// The context menu items.
///
/// They will be shown when the user right click on the editor.
///
/// A divider will be added between each list.
final List<List<ContextMenuItem>> contextMenuItems;

/// Provide a scrollController to control the scroll behavior
/// if you need to custom the scroll behavior.
///
Expand Down Expand Up @@ -225,6 +235,7 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
key: editorState.service.selectionServiceKey,
cursorColor: widget.editorStyle.cursorColor,
selectionColor: widget.editorStyle.selectionColor,
contextMenuItems: widget.contextMenuItems,
child: KeyboardServiceWidget(
key: editorState.service.keyboardServiceKey,
characterShortcutEvents: widget.characterShortcutEvents,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@ import 'package:flutter/services.dart';

Future<void> onNonTextUpdate(
TextEditingDeltaNonTextUpdate nonTextUpdate,
EditorState editorState,
) async {
Log.input.debug('onNonTextUpdate: $nonTextUpdate');
// update the selection on Windows
//
// when typing characters with CJK IME on Windows, a non-text update is sent
// with the selection range.

if (PlatformExtension.isWindows) {
final selection = editorState.selection;
if (selection != null &&
nonTextUpdate.composing == TextRange.empty &&
nonTextUpdate.selection.isCollapsed) {
editorState.selection = Selection.collapsed(
Position(
path: selection.start.path,
offset: nonTextUpdate.selection.start,
),
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,6 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient {
_textInputConnection = TextInput.attach(
this,
configuration,
// TextInputConfiguration(
// enableDeltaModel: false,
// inputType: TextInputType.multiline,
// textCapitalization: TextCapitalization.sentences,
// inputAction: TextInputAction.newline,
// keyboardAppearance: Theme.of(context).brightness,
// ),
);
}

Expand Down Expand Up @@ -180,6 +173,10 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient {
composingTextRange = delta.composing;
}
}

if (PlatformExtension.isWindows && delta is TextEditingDeltaNonTextUpdate) {
composingTextRange = delta.composing;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ class KeyboardServiceWidgetState extends State<KeyboardServiceWidget>
editorState,
widget.characterShortcutEvents,
),
onNonTextUpdate: onNonTextUpdate,
onNonTextUpdate: (nonTextUpdate) async => await onNonTextUpdate(
nonTextUpdate,
editorState,
),
onPerformAction: (action) async => await onPerformAction(
action,
editorState,
Expand Down Expand Up @@ -189,14 +192,6 @@ class KeyboardServiceWidgetState extends State<KeyboardServiceWidget>
_attachTextInputService(selection);
_updateCaretPosition(selection);

// debounce the attachTextInputService function to avoid
// the text input service being attached too frequently.
// Debounce.debounce(
// 'attachTextInputService',
// const Duration(milliseconds: 200),
// () => _attachTextInputService(selection),
// );

if (editorState.selectionUpdateReason == SelectionUpdateReason.uiEvent) {
focusNode.requestFocus();
Log.editor.debug('keyboard service - request focus');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/service/context_menu/built_in_context_menu_item.dart';
import 'package:appflowy_editor/src/service/context_menu/context_menu.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;

import 'package:appflowy_editor/src/render/selection/cursor_widget.dart';
import 'package:appflowy_editor/src/render/selection/selection_widget.dart';
import 'package:appflowy_editor/src/service/selection/selection_gesture.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:provider/provider.dart';

class DesktopSelectionServiceWidget extends StatefulWidget {
const DesktopSelectionServiceWidget({
super.key,
this.cursorColor = const Color(0xFF00BCF0),
this.selectionColor = const Color.fromARGB(53, 111, 201, 231),
required this.contextMenuItems,
required this.child,
});

final Widget child;
final Color cursorColor;
final Color selectionColor;
final List<List<ContextMenuItem>> contextMenuItems;

@override
State<DesktopSelectionServiceWidget> createState() =>
Expand Down Expand Up @@ -530,6 +529,25 @@ class _DesktopSelectionServiceWidgetState
void _showContextMenu(TapDownDetails details) {
_clearContextMenu();

// only shows around the selection area.
if (selectionRects.isEmpty) {
return;
}

final isHitSelectionAreas = currentSelection.value?.isCollapsed == true ||
selectionRects.any((element) {
const threshold = 20;
final scaledArea = Rect.fromCenter(
center: element.center,
width: element.width + threshold,
height: element.height + threshold,
);
return scaledArea.contains(details.globalPosition);
});
if (!isHitSelectionAreas) {
return;
}

// For now, only support the text node.
if (!currentSelectedNodes.every((element) => element.delta != null)) {
return;
Expand All @@ -542,7 +560,7 @@ class _DesktopSelectionServiceWidgetState
builder: (context) => ContextMenu(
position: offset,
editorState: editorState,
items: builtInContextMenuItems,
items: widget.contextMenuItems,
onPressed: () => _clearContextMenu(),
),
);
Expand Down
Loading

0 comments on commit ff471a8

Please sign in to comment.