chore: sync the latest code from main repo (#25)
This commit is contained in:
parent
16b64cf922
commit
c89ea36ce7
27 changed files with 185 additions and 81 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -1,8 +1,11 @@
|
|||
## 0.1.3
|
||||
* chore: update the dependencies to the latest release by @LucasXu0 ([#25](https://github.com/AppFlowy-IO/appflowy-editor/pull/25)).
|
||||
|
||||
## 0.1.2
|
||||
* fix: #7 bug on node iterator with nested nodes by @LucasXu0 in https://github.com/AppFlowy-IO/appflowy-editor/pull/11
|
||||
* fix: #8 SVG display error in the latest version by @LucasXu0 in https://github.com/AppFlowy-IO/appflowy-editor/pull/12
|
||||
* fix: #9 Using the mouse to highlight text very easy to miss the first letter by @LucasXu0 in https://github.com/AppFlowy-IO/appflowy-editor/pull/13
|
||||
* chore: fix some known issues by @LucasXu0 in https://github.com/AppFlowy-IO/appflowy-editor/pull/14
|
||||
* fix: bug on node iterator with nested nodes by @LucasXu0 ([#11](https://github.com/AppFlowy-IO/appflowy-editor/pull/11)).
|
||||
* fix: SVG display error in the latest version by @LucasXu0 ([#12](https://github.com/AppFlowy-IO/appflowy-editor/pull/12)).
|
||||
* fix: Using the mouse to highlight text very easy to miss the first letter by @LucasXu0 ([#13](https://github.com/AppFlowy-IO/appflowy-editor/pull/13)).
|
||||
* chore: fix some known issues by @LucasXu0 in ([#14](https://github.com/AppFlowy-IO/appflowy-editor/pull/14)).
|
||||
|
||||
## 0.1.1
|
||||
* Relicense Appflowy Editor by @hyj1204.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>9.0</string>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
04FEAAC38F2370365B8414DC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1F5D64F559698A15DB17B36 /* Pods_Runner.framework */; };
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
|
|
@ -35,6 +36,8 @@
|
|||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7B9564C525FDA21960DC1568 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
8ED982CC43DE110A1567B441 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -42,6 +45,8 @@
|
|||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
E1F5D64F559698A15DB17B36 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EA2F6824C2F8DF616F38D702 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -49,12 +54,24 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
04FEAAC38F2370365B8414DC /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
2181B39B01004E1610D231F6 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7B9564C525FDA21960DC1568 /* Pods-Runner.debug.xcconfig */,
|
||||
EA2F6824C2F8DF616F38D702 /* Pods-Runner.release.xcconfig */,
|
||||
8ED982CC43DE110A1567B441 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -72,6 +89,8 @@
|
|||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
2181B39B01004E1610D231F6 /* Pods */,
|
||||
DBB82516CCE88A0A80E570A6 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
|
@ -98,6 +117,14 @@
|
|||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DBB82516CCE88A0A80E570A6 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E1F5D64F559698A15DB17B36 /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
|
@ -105,12 +132,14 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
D1756A9F757523FB742DC39D /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
6953CBC33F9B7A821F1D3D6F /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
|
@ -171,6 +200,7 @@
|
|||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
|
@ -183,8 +213,26 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
6953CBC33F9B7A821F1D3D6F /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
|
@ -197,6 +245,28 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
D1756A9F757523FB742DC39D /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
|
@ -272,7 +342,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
|
@ -350,7 +420,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
|
@ -399,7 +469,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
|
|
|||
|
|
@ -4,4 +4,7 @@
|
|||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
|
|||
|
|
@ -45,5 +45,7 @@
|
|||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class _HomePageState extends State<HomePage> {
|
|||
ThemeData _themeData = ThemeData.light().copyWith(
|
||||
extensions: [
|
||||
...lightEditorStyleExtension,
|
||||
...lightPlguinStyleExtension,
|
||||
...lightPluginStyleExtension,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
|||
_themeData = ThemeData.dark().copyWith(
|
||||
extensions: [
|
||||
...darkEditorStyleExtension,
|
||||
...darkPlguinStyleExtension,
|
||||
...darkPluginStyleExtension,
|
||||
],
|
||||
);
|
||||
});
|
||||
|
|
@ -372,7 +372,7 @@ Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
|||
|
||||
return Theme.of(context).copyWith(extensions: [
|
||||
editorStyle,
|
||||
...darkPlguinStyleExtension,
|
||||
...darkPluginStyleExtension,
|
||||
quote,
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ ThemeData customizeEditorTheme(BuildContext context) {
|
|||
|
||||
return Theme.of(context).copyWith(extensions: [
|
||||
editorStyle,
|
||||
...darkPlguinStyleExtension,
|
||||
...darkPluginStyleExtension,
|
||||
quote,
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export 'src/extensions/attributes_extension.dart';
|
|||
export 'src/render/rich_text/default_selectable.dart';
|
||||
export 'src/render/rich_text/flowy_rich_text.dart';
|
||||
export 'src/render/selection_menu/selection_menu_widget.dart';
|
||||
export 'src/render/selection_menu/selection_menu_item_widget.dart';
|
||||
export 'src/l10n/l10n.dart';
|
||||
export 'src/render/style/plugin_styles.dart';
|
||||
export 'src/plugins/markdown/encoder/delta_markdown_encoder.dart';
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ extension CommandExtension on EditorState {
|
|||
} else if (path != null) {
|
||||
return document.nodeAtPath(path)!;
|
||||
}
|
||||
|
||||
throw Exception('path and node cannot be null at the same time');
|
||||
}
|
||||
|
||||
|
|
@ -38,33 +37,26 @@ extension CommandExtension on EditorState {
|
|||
} else if (path != null) {
|
||||
return document.nodeAtPath(path)! as TextNode;
|
||||
}
|
||||
|
||||
throw Exception('path and node cannot be null at the same time');
|
||||
}
|
||||
|
||||
Selection getSelection(
|
||||
Selection? selection,
|
||||
) {
|
||||
final currentSelection = service.selectionService.currentSelection.value;
|
||||
if (selection != null) {
|
||||
return selection;
|
||||
}
|
||||
|
||||
final currentSelection = service.selectionService.currentSelection.value;
|
||||
if (currentSelection != null) {
|
||||
} else if (currentSelection != null) {
|
||||
return currentSelection;
|
||||
}
|
||||
|
||||
throw Exception(
|
||||
'selection and selectionService.currentSelection cannot be null at the same time',
|
||||
);
|
||||
throw Exception('path and textNode cannot be null at the same time');
|
||||
}
|
||||
|
||||
String getTextInSelection(
|
||||
List<String> getTextInSelection(
|
||||
List<TextNode> textNodes,
|
||||
Selection selection,
|
||||
) {
|
||||
List<String> res = [];
|
||||
|
||||
if (selection.isSingle) {
|
||||
final plainText = textNodes.first.toPlainText();
|
||||
res.add(plainText.substring(selection.startIndex, selection.endIndex));
|
||||
|
|
@ -85,7 +77,6 @@ extension CommandExtension on EditorState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.join('\n');
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,20 +235,20 @@ class UpdateTextOperation extends Operation {
|
|||
|
||||
// TODO(Lucas.Xu): refactor this part
|
||||
Path transformPath(Path preInsertPath, Path b, [int delta = 1]) {
|
||||
if (preInsertPath.length > b.length || preInsertPath.isEmpty || b.isEmpty) {
|
||||
if (preInsertPath.length > b.length) {
|
||||
return b;
|
||||
}
|
||||
if (preInsertPath.isEmpty || b.isEmpty) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// check the prefix
|
||||
for (var i = 0; i < preInsertPath.length - 1; i++) {
|
||||
if (preInsertPath[i] != b[i]) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
final prefix = preInsertPath.sublist(0, preInsertPath.length - 1);
|
||||
final suffix = b.sublist(preInsertPath.length);
|
||||
|
||||
final preInsertLast = preInsertPath.last;
|
||||
final bAtIndex = b[preInsertPath.length - 1];
|
||||
if (preInsertLast <= bAtIndex) {
|
||||
|
|
@ -256,9 +256,7 @@ Path transformPath(Path preInsertPath, Path b, [int delta = 1]) {
|
|||
} else {
|
||||
prefix.add(bAtIndex);
|
||||
}
|
||||
|
||||
prefix.addAll(suffix);
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -347,24 +347,22 @@ extension TextTransaction on Transaction {
|
|||
textNode.toPlainText().length,
|
||||
texts.first,
|
||||
);
|
||||
} else if (i == length - 1) {
|
||||
} else if (i == length - 1 && texts.length >= 2) {
|
||||
replaceText(
|
||||
textNode,
|
||||
0,
|
||||
selection.endIndex,
|
||||
texts.last,
|
||||
);
|
||||
} else if (i < texts.length - 1) {
|
||||
replaceText(
|
||||
textNode,
|
||||
0,
|
||||
textNode.toPlainText().length,
|
||||
texts[i],
|
||||
);
|
||||
} else {
|
||||
if (i < texts.length - 1) {
|
||||
replaceText(
|
||||
textNode,
|
||||
0,
|
||||
textNode.toPlainText().length,
|
||||
texts[i],
|
||||
);
|
||||
} else {
|
||||
deleteNode(textNode);
|
||||
}
|
||||
deleteNode(textNode);
|
||||
}
|
||||
}
|
||||
afterSelection = null;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class EditorState {
|
|||
|
||||
// TODO: only for testing.
|
||||
bool disableSealTimer = false;
|
||||
bool disbaleRules = false;
|
||||
bool disableRules = false;
|
||||
|
||||
bool editable = true;
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ class EditorState {
|
|||
|
||||
void _applyRules(int ruleCount) {
|
||||
// Set a maximum count to prevent a dead loop.
|
||||
if (ruleCount >= 5 || disbaleRules) {
|
||||
if (ruleCount >= 5 || disableRules) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class SelectionMenu implements SelectionMenuService {
|
|||
editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
|
||||
final editorHeight = editorState.renderBox!.size.height;
|
||||
|
||||
// show below defualt
|
||||
// show below default
|
||||
var showBelow = true;
|
||||
_alignment = Alignment.bottomLeft;
|
||||
final bottomRight = selectionRects.first.bottomRight;
|
||||
|
|
@ -91,20 +91,24 @@ class SelectionMenu implements SelectionMenuService {
|
|||
top: showBelow ? _offset.dy : null,
|
||||
bottom: showBelow ? null : _offset.dy,
|
||||
left: offset.dx,
|
||||
child: SelectionMenuWidget(
|
||||
items: [
|
||||
..._defaultSelectionMenuItems,
|
||||
...editorState.selectionMenuItems,
|
||||
],
|
||||
maxItemInRow: 5,
|
||||
editorState: editorState,
|
||||
menuService: this,
|
||||
onExit: () {
|
||||
dismiss();
|
||||
},
|
||||
onSelectionUpdate: () {
|
||||
_selectionUpdateByInner = true;
|
||||
},
|
||||
right: 0,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SelectionMenuWidget(
|
||||
items: [
|
||||
..._defaultSelectionMenuItems,
|
||||
...editorState.selectionMenuItems,
|
||||
],
|
||||
maxItemInRow: 5,
|
||||
editorState: editorState,
|
||||
menuService: this,
|
||||
onExit: () {
|
||||
dismiss();
|
||||
},
|
||||
onSelectionUpdate: () {
|
||||
_selectionUpdateByInner = true;
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_item_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
|
|
@ -324,7 +323,8 @@ class _SelectionMenuWidgetState extends State<SelectionMenuWidget> {
|
|||
_deleteLastCharacters();
|
||||
return KeyEventResult.handled;
|
||||
} else if (event.character != null &&
|
||||
!arrowKeys.contains(event.logicalKey)) {
|
||||
!arrowKeys.contains(event.logicalKey) &&
|
||||
event.logicalKey != LogicalKeyboardKey.tab) {
|
||||
keyword += event.character!;
|
||||
_insertText(event.character!);
|
||||
return KeyEventResult.handled;
|
||||
|
|
@ -339,7 +339,14 @@ class _SelectionMenuWidgetState extends State<SelectionMenuWidget> {
|
|||
newSelectedIndex -= 1;
|
||||
} else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
||||
newSelectedIndex += 1;
|
||||
} else if (event.logicalKey == LogicalKeyboardKey.tab) {
|
||||
newSelectedIndex += widget.maxItemInRow;
|
||||
var currRow = (newSelectedIndex) % widget.maxItemInRow;
|
||||
if (newSelectedIndex >= _showingItems.length) {
|
||||
newSelectedIndex = (currRow + 1) % widget.maxItemInRow;
|
||||
}
|
||||
}
|
||||
|
||||
if (newSelectedIndex != _selectedIndex) {
|
||||
setState(() {
|
||||
_selectedIndex = newSelectedIndex.clamp(0, _showingItems.length - 1);
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
|||
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Iterable<ThemeExtension<dynamic>> get lightPlguinStyleExtension => [
|
||||
Iterable<ThemeExtension<dynamic>> get lightPluginStyleExtension => [
|
||||
HeadingPluginStyle.light,
|
||||
CheckboxPluginStyle.light,
|
||||
NumberListPluginStyle.light,
|
||||
QuotedTextPluginStyle.light,
|
||||
];
|
||||
|
||||
Iterable<ThemeExtension<dynamic>> get darkPlguinStyleExtension => [
|
||||
Iterable<ThemeExtension<dynamic>> get darkPluginStyleExtension => [
|
||||
HeadingPluginStyle.dark,
|
||||
CheckboxPluginStyle.dark,
|
||||
NumberListPluginStyle.dark,
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ class ToolbarWidget extends StatefulWidget {
|
|||
required this.layerLink,
|
||||
required this.offset,
|
||||
required this.items,
|
||||
this.aligment = Alignment.topLeft,
|
||||
this.alignment = Alignment.topLeft,
|
||||
}) : super(key: key);
|
||||
|
||||
final EditorState editorState;
|
||||
final LayerLink layerLink;
|
||||
final Offset offset;
|
||||
final List<ToolbarItem> items;
|
||||
final Alignment aligment;
|
||||
final Alignment alignment;
|
||||
|
||||
@override
|
||||
State<ToolbarWidget> createState() => _ToolbarWidgetState();
|
||||
|
|
@ -41,7 +41,7 @@ class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
|
|||
link: widget.layerLink,
|
||||
showWhenUnlinked: true,
|
||||
offset: widget.offset,
|
||||
followerAnchor: widget.aligment,
|
||||
followerAnchor: widget.alignment,
|
||||
child: _buildToolbar(context),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class AppFlowyEditor extends StatefulWidget {
|
|||
this.themeData = themeData ??
|
||||
ThemeData.light().copyWith(extensions: [
|
||||
...lightEditorStyleExtension,
|
||||
...lightPlguinStyleExtension,
|
||||
...lightPluginStyleExtension,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ ShortcutEventHandler selectAllHandler = (editorState, event) {
|
|||
if (editorState.document.root.children.isEmpty) {
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
final firstNode = editorState.document.root.children.first;
|
||||
final firstNode = editorState.document.root.children.firstWhere(
|
||||
(element) => element is TextNode,
|
||||
);
|
||||
final lastNode = editorState.document.root.children.last;
|
||||
var offset = 0;
|
||||
if (lastNode is TextNode) {
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@ abstract class AppFlowySelectionService {
|
|||
|
||||
/// The current selection areas's rect in editor.
|
||||
List<Rect> get selectionRects;
|
||||
|
||||
void register(SelectionInterceptor interceptor);
|
||||
void unRegister(SelectionInterceptor interceptor);
|
||||
}
|
||||
|
||||
class SelectionInterceptor {
|
||||
bool Function(TapDownDetails details)? canTap;
|
||||
}
|
||||
|
||||
class AppFlowySelection extends StatefulWidget {
|
||||
|
|
@ -212,6 +219,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
|||
|
||||
selectionRects.clear();
|
||||
clearSelection();
|
||||
_clearToolbar();
|
||||
|
||||
if (selection != null) {
|
||||
if (selection.isCollapsed) {
|
||||
|
|
@ -286,6 +294,10 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
|||
}
|
||||
|
||||
void _onTapDown(TapDownDetails details) {
|
||||
final canTap =
|
||||
_interceptors.every((element) => element.canTap?.call(details) ?? true);
|
||||
if (!canTap) return;
|
||||
|
||||
// clear old state.
|
||||
_panStartOffset = null;
|
||||
|
||||
|
|
@ -337,7 +349,8 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
|||
// try to select the word.
|
||||
final selection = currentSelection.value;
|
||||
if (selection == null ||
|
||||
(selection.isCollapsed && currentSelectedNodes.first is TextNode)) {
|
||||
(selection.isCollapsed == true &&
|
||||
currentSelectedNodes.first is TextNode)) {
|
||||
_onDoubleTapDown(details);
|
||||
}
|
||||
|
||||
|
|
@ -700,4 +713,15 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
|||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
final List<SelectionInterceptor> _interceptors = [];
|
||||
@override
|
||||
void register(SelectionInterceptor interceptor) {
|
||||
_interceptors.add(interceptor);
|
||||
}
|
||||
|
||||
@override
|
||||
void unRegister(SelectionInterceptor interceptor) {
|
||||
_interceptors.removeWhere((element) => element == interceptor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue