react-native-enriched 0.1.6 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -14
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +4 -1
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +2 -1
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +0 -45
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +111 -2
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +9 -3
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +2 -0
- package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +42 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +135 -9
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +13 -3
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +13 -0
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +80 -9
- package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +188 -5
- package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +57 -30
- package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +91 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +24 -13
- package/android/src/main/java/com/swmansion/enriched/utils/ResourceManager.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +3 -0
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +6 -6
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +6 -6
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +19 -19
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +40 -51
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +13 -15
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +23 -21
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +35 -36
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +4 -4
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +13 -14
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +12 -13
- package/android/src/main/res/drawable/broken_image.xml +10 -0
- package/ios/EnrichedTextInputView.h +27 -12
- package/ios/EnrichedTextInputView.mm +906 -547
- package/ios/attachments/ImageAttachment.h +10 -0
- package/ios/attachments/ImageAttachment.mm +34 -0
- package/ios/attachments/MediaAttachment.h +23 -0
- package/ios/attachments/MediaAttachment.mm +31 -0
- package/ios/config/InputConfig.h +12 -6
- package/ios/config/InputConfig.mm +71 -33
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +0 -45
- package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +41 -4
- package/ios/inputParser/InputParser.h +5 -5
- package/ios/inputParser/InputParser.mm +867 -333
- package/ios/inputTextView/InputTextView.h +1 -1
- package/ios/inputTextView/InputTextView.mm +100 -59
- package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +11 -9
- package/ios/internals/EnrichedTextInputViewShadowNode.h +28 -24
- package/ios/internals/EnrichedTextInputViewShadowNode.mm +64 -47
- package/ios/internals/EnrichedTextInputViewState.h +3 -1
- package/ios/styles/BlockQuoteStyle.mm +192 -142
- package/ios/styles/BoldStyle.mm +96 -62
- package/ios/styles/CodeBlockStyle.mm +304 -0
- package/ios/styles/H1Style.mm +10 -3
- package/ios/styles/H2Style.mm +10 -3
- package/ios/styles/H3Style.mm +10 -3
- package/ios/styles/HeadingStyleBase.mm +129 -84
- package/ios/styles/ImageStyle.mm +160 -0
- package/ios/styles/InlineCodeStyle.mm +149 -84
- package/ios/styles/ItalicStyle.mm +77 -51
- package/ios/styles/LinkStyle.mm +353 -224
- package/ios/styles/MentionStyle.mm +434 -220
- package/ios/styles/OrderedListStyle.mm +172 -105
- package/ios/styles/StrikethroughStyle.mm +53 -34
- package/ios/styles/UnderlineStyle.mm +69 -45
- package/ios/styles/UnorderedListStyle.mm +170 -105
- package/ios/utils/BaseStyleProtocol.h +3 -2
- package/ios/utils/ColorExtension.mm +7 -5
- package/ios/utils/FontExtension.mm +42 -27
- package/ios/utils/ImageData.h +10 -0
- package/ios/utils/ImageData.mm +4 -0
- package/ios/utils/LayoutManagerExtension.h +1 -1
- package/ios/utils/LayoutManagerExtension.mm +334 -109
- package/ios/utils/MentionParams.h +0 -1
- package/ios/utils/MentionStyleProps.h +1 -1
- package/ios/utils/MentionStyleProps.mm +27 -20
- package/ios/utils/OccurenceUtils.h +42 -38
- package/ios/utils/OccurenceUtils.mm +177 -107
- package/ios/utils/ParagraphAttributesUtils.h +6 -1
- package/ios/utils/ParagraphAttributesUtils.mm +152 -41
- package/ios/utils/ParagraphsUtils.h +2 -1
- package/ios/utils/ParagraphsUtils.mm +40 -26
- package/ios/utils/StringExtension.h +1 -1
- package/ios/utils/StringExtension.mm +19 -16
- package/ios/utils/StyleHeaders.h +35 -11
- package/ios/utils/TextInsertionUtils.h +13 -2
- package/ios/utils/TextInsertionUtils.mm +38 -20
- package/ios/utils/WordsUtils.h +2 -1
- package/ios/utils/WordsUtils.mm +32 -22
- package/ios/utils/ZeroWidthSpaceUtils.h +3 -1
- package/ios/utils/ZeroWidthSpaceUtils.mm +153 -75
- package/lib/module/EnrichedTextInput.js +41 -3
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/EnrichedTextInputNativeComponent.ts +17 -5
- package/lib/module/normalizeHtmlStyle.js +0 -4
- package/lib/module/normalizeHtmlStyle.js.map +1 -1
- package/lib/typescript/src/EnrichedTextInput.d.ts +2 -5
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +7 -5
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/EnrichedTextInput.tsx +48 -7
- package/src/EnrichedTextInputNativeComponent.ts +17 -5
- package/src/normalizeHtmlStyle.ts +0 -4
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
#import "EnrichedTextInputView.h"
|
|
2
|
+
#import "CoreText/CoreText.h"
|
|
3
|
+
#import "LayoutManagerExtension.h"
|
|
4
|
+
#import "ParagraphAttributesUtils.h"
|
|
2
5
|
#import "RCTFabricComponentsPlugins.h"
|
|
6
|
+
#import "StringExtension.h"
|
|
7
|
+
#import "StyleHeaders.h"
|
|
8
|
+
#import "UIView+React.h"
|
|
9
|
+
#import "WordsUtils.h"
|
|
10
|
+
#import "ZeroWidthSpaceUtils.h"
|
|
11
|
+
#import <React/RCTConversions.h>
|
|
3
12
|
#import <ReactNativeEnriched/EnrichedTextInputViewComponentDescriptor.h>
|
|
4
13
|
#import <ReactNativeEnriched/EventEmitters.h>
|
|
5
14
|
#import <ReactNativeEnriched/Props.h>
|
|
6
15
|
#import <ReactNativeEnriched/RCTComponentViewHelpers.h>
|
|
7
|
-
#import <react/utils/ManagedObjectWrapper.h>
|
|
8
16
|
#import <folly/dynamic.h>
|
|
9
|
-
#import
|
|
10
|
-
#import "StringExtension.h"
|
|
11
|
-
#import "CoreText/CoreText.h"
|
|
12
|
-
#import <React/RCTConversions.h>
|
|
13
|
-
#import "StyleHeaders.h"
|
|
14
|
-
#import "WordsUtils.h"
|
|
15
|
-
#import "LayoutManagerExtension.h"
|
|
16
|
-
#import "ZeroWidthSpaceUtils.h"
|
|
17
|
-
#import "ParagraphAttributesUtils.h"
|
|
17
|
+
#import <react/utils/ManagedObjectWrapper.h>
|
|
18
18
|
|
|
19
19
|
using namespace facebook::react;
|
|
20
20
|
|
|
21
|
-
@interface EnrichedTextInputView () <RCTEnrichedTextInputViewViewProtocol,
|
|
21
|
+
@interface EnrichedTextInputView () <RCTEnrichedTextInputViewViewProtocol,
|
|
22
|
+
UITextViewDelegate, NSObject>
|
|
22
23
|
|
|
23
24
|
@end
|
|
24
25
|
|
|
@@ -26,11 +27,9 @@ using namespace facebook::react;
|
|
|
26
27
|
EnrichedTextInputViewShadowNode::ConcreteState::Shared _state;
|
|
27
28
|
int _componentViewHeightUpdateCounter;
|
|
28
29
|
NSMutableSet<NSNumber *> *_activeStyles;
|
|
29
|
-
NSDictionary<NSNumber *, NSArray<NSNumber *> *> *_conflictingStyles;
|
|
30
|
-
NSDictionary<NSNumber *, NSArray<NSNumber *> *> *_blockingStyles;
|
|
31
30
|
LinkData *_recentlyActiveLinkData;
|
|
32
31
|
NSRange _recentlyActiveLinkRange;
|
|
33
|
-
NSString *
|
|
32
|
+
NSString *_recentInputString;
|
|
34
33
|
MentionParams *_recentlyActiveMentionParams;
|
|
35
34
|
NSRange _recentlyActiveMentionRange;
|
|
36
35
|
NSString *_recentlyEmittedHtml;
|
|
@@ -43,7 +42,8 @@ using namespace facebook::react;
|
|
|
43
42
|
// MARK: - Component utils
|
|
44
43
|
|
|
45
44
|
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
46
|
-
return concreteComponentDescriptorProvider<
|
|
45
|
+
return concreteComponentDescriptorProvider<
|
|
46
|
+
EnrichedTextInputViewComponentDescriptor>();
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
@@ -58,7 +58,8 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
58
58
|
|
|
59
59
|
- (instancetype)initWithFrame:(CGRect)frame {
|
|
60
60
|
if (self = [super initWithFrame:frame]) {
|
|
61
|
-
static const auto defaultProps =
|
|
61
|
+
static const auto defaultProps =
|
|
62
|
+
std::make_shared<const EnrichedTextInputViewProps>();
|
|
62
63
|
_props = defaultProps;
|
|
63
64
|
[self setDefaults];
|
|
64
65
|
[self setupTextView];
|
|
@@ -74,62 +75,118 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
74
75
|
_recentlyActiveLinkRange = NSMakeRange(0, 0);
|
|
75
76
|
_recentlyActiveMentionRange = NSMakeRange(0, 0);
|
|
76
77
|
recentlyChangedRange = NSMakeRange(0, 0);
|
|
77
|
-
|
|
78
|
+
_recentInputString = @"";
|
|
78
79
|
_recentlyEmittedHtml = @"<html>\n<p></p>\n</html>";
|
|
79
80
|
_emitHtml = NO;
|
|
80
81
|
blockEmitting = NO;
|
|
81
82
|
_emitFocusBlur = YES;
|
|
82
|
-
|
|
83
|
-
defaultTypingAttributes =
|
|
84
|
-
|
|
83
|
+
|
|
84
|
+
defaultTypingAttributes =
|
|
85
|
+
[[NSMutableDictionary<NSAttributedStringKey, id> alloc] init];
|
|
86
|
+
|
|
85
87
|
stylesDict = @{
|
|
86
88
|
@([BoldStyle getStyleType]) : [[BoldStyle alloc] initWithInput:self],
|
|
87
|
-
@([ItalicStyle getStyleType]): [[ItalicStyle alloc] initWithInput:self],
|
|
88
|
-
@([UnderlineStyle getStyleType])
|
|
89
|
-
|
|
90
|
-
@([
|
|
91
|
-
|
|
92
|
-
@([
|
|
93
|
-
|
|
94
|
-
@([
|
|
95
|
-
@([
|
|
96
|
-
@([
|
|
97
|
-
@([
|
|
98
|
-
@([
|
|
89
|
+
@([ItalicStyle getStyleType]) : [[ItalicStyle alloc] initWithInput:self],
|
|
90
|
+
@([UnderlineStyle getStyleType]) :
|
|
91
|
+
[[UnderlineStyle alloc] initWithInput:self],
|
|
92
|
+
@([StrikethroughStyle getStyleType]) :
|
|
93
|
+
[[StrikethroughStyle alloc] initWithInput:self],
|
|
94
|
+
@([InlineCodeStyle getStyleType]) :
|
|
95
|
+
[[InlineCodeStyle alloc] initWithInput:self],
|
|
96
|
+
@([LinkStyle getStyleType]) : [[LinkStyle alloc] initWithInput:self],
|
|
97
|
+
@([MentionStyle getStyleType]) : [[MentionStyle alloc] initWithInput:self],
|
|
98
|
+
@([H1Style getStyleType]) : [[H1Style alloc] initWithInput:self],
|
|
99
|
+
@([H2Style getStyleType]) : [[H2Style alloc] initWithInput:self],
|
|
100
|
+
@([H3Style getStyleType]) : [[H3Style alloc] initWithInput:self],
|
|
101
|
+
@([UnorderedListStyle getStyleType]) :
|
|
102
|
+
[[UnorderedListStyle alloc] initWithInput:self],
|
|
103
|
+
@([OrderedListStyle getStyleType]) :
|
|
104
|
+
[[OrderedListStyle alloc] initWithInput:self],
|
|
105
|
+
@([BlockQuoteStyle getStyleType]) :
|
|
106
|
+
[[BlockQuoteStyle alloc] initWithInput:self],
|
|
107
|
+
@([CodeBlockStyle getStyleType]) :
|
|
108
|
+
[[CodeBlockStyle alloc] initWithInput:self],
|
|
109
|
+
@([ImageStyle getStyleType]) : [[ImageStyle alloc] initWithInput:self]
|
|
99
110
|
};
|
|
100
|
-
|
|
101
|
-
|
|
111
|
+
|
|
112
|
+
conflictingStyles = @{
|
|
102
113
|
@([BoldStyle getStyleType]) : @[],
|
|
103
114
|
@([ItalicStyle getStyleType]) : @[],
|
|
104
115
|
@([UnderlineStyle getStyleType]) : @[],
|
|
105
116
|
@([StrikethroughStyle getStyleType]) : @[],
|
|
106
|
-
@([InlineCodeStyle getStyleType]) :
|
|
107
|
-
|
|
108
|
-
@([
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@([
|
|
113
|
-
|
|
114
|
-
@([
|
|
117
|
+
@([InlineCodeStyle getStyleType]) :
|
|
118
|
+
@[ @([LinkStyle getStyleType]), @([MentionStyle getStyleType]) ],
|
|
119
|
+
@([LinkStyle getStyleType]) : @[
|
|
120
|
+
@([InlineCodeStyle getStyleType]), @([LinkStyle getStyleType]),
|
|
121
|
+
@([MentionStyle getStyleType])
|
|
122
|
+
],
|
|
123
|
+
@([MentionStyle getStyleType]) :
|
|
124
|
+
@[ @([InlineCodeStyle getStyleType]), @([LinkStyle getStyleType]) ],
|
|
125
|
+
@([H1Style getStyleType]) : @[
|
|
126
|
+
@([H2Style getStyleType]), @([H3Style getStyleType]),
|
|
127
|
+
@([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
|
|
128
|
+
@([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
|
|
129
|
+
],
|
|
130
|
+
@([H2Style getStyleType]) : @[
|
|
131
|
+
@([H1Style getStyleType]), @([H3Style getStyleType]),
|
|
132
|
+
@([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
|
|
133
|
+
@([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
|
|
134
|
+
],
|
|
135
|
+
@([H3Style getStyleType]) : @[
|
|
136
|
+
@([H1Style getStyleType]), @([H2Style getStyleType]),
|
|
137
|
+
@([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
|
|
138
|
+
@([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
|
|
139
|
+
],
|
|
140
|
+
@([UnorderedListStyle getStyleType]) : @[
|
|
141
|
+
@([H1Style getStyleType]), @([H2Style getStyleType]),
|
|
142
|
+
@([H3Style getStyleType]), @([OrderedListStyle getStyleType]),
|
|
143
|
+
@([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
|
|
144
|
+
],
|
|
145
|
+
@([OrderedListStyle getStyleType]) : @[
|
|
146
|
+
@([H1Style getStyleType]), @([H2Style getStyleType]),
|
|
147
|
+
@([H3Style getStyleType]), @([UnorderedListStyle getStyleType]),
|
|
148
|
+
@([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
|
|
149
|
+
],
|
|
150
|
+
@([BlockQuoteStyle getStyleType]) : @[
|
|
151
|
+
@([H1Style getStyleType]), @([H2Style getStyleType]),
|
|
152
|
+
@([H3Style getStyleType]), @([UnorderedListStyle getStyleType]),
|
|
153
|
+
@([OrderedListStyle getStyleType]), @([CodeBlockStyle getStyleType])
|
|
154
|
+
],
|
|
155
|
+
@([CodeBlockStyle getStyleType]) : @[
|
|
156
|
+
@([H1Style getStyleType]), @([H2Style getStyleType]),
|
|
157
|
+
@([H3Style getStyleType]), @([BoldStyle getStyleType]),
|
|
158
|
+
@([ItalicStyle getStyleType]), @([UnderlineStyle getStyleType]),
|
|
159
|
+
@([StrikethroughStyle getStyleType]),
|
|
160
|
+
@([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
|
|
161
|
+
@([BlockQuoteStyle getStyleType]), @([InlineCodeStyle getStyleType]),
|
|
162
|
+
@([MentionStyle getStyleType]), @([LinkStyle getStyleType])
|
|
163
|
+
],
|
|
164
|
+
@([ImageStyle getStyleType]) :
|
|
165
|
+
@[ @([LinkStyle getStyleType]), @([MentionStyle getStyleType]) ]
|
|
115
166
|
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
@([BoldStyle getStyleType]) : @[],
|
|
119
|
-
@([ItalicStyle getStyleType]) : @[],
|
|
120
|
-
@([UnderlineStyle getStyleType]) : @[],
|
|
121
|
-
@([StrikethroughStyle getStyleType]) :
|
|
122
|
-
|
|
123
|
-
@([
|
|
124
|
-
|
|
125
|
-
@([
|
|
126
|
-
|
|
127
|
-
@([
|
|
128
|
-
|
|
129
|
-
@([
|
|
130
|
-
@([
|
|
167
|
+
|
|
168
|
+
blockingStyles = @{
|
|
169
|
+
@([BoldStyle getStyleType]) : @[ @([CodeBlockStyle getStyleType]) ],
|
|
170
|
+
@([ItalicStyle getStyleType]) : @[ @([CodeBlockStyle getStyleType]) ],
|
|
171
|
+
@([UnderlineStyle getStyleType]) : @[ @([CodeBlockStyle getStyleType]) ],
|
|
172
|
+
@([StrikethroughStyle getStyleType]) :
|
|
173
|
+
@[ @([CodeBlockStyle getStyleType]) ],
|
|
174
|
+
@([InlineCodeStyle getStyleType]) :
|
|
175
|
+
@[ @([CodeBlockStyle getStyleType]), @([ImageStyle getStyleType]) ],
|
|
176
|
+
@([LinkStyle getStyleType]) :
|
|
177
|
+
@[ @([CodeBlockStyle getStyleType]), @([ImageStyle getStyleType]) ],
|
|
178
|
+
@([MentionStyle getStyleType]) :
|
|
179
|
+
@[ @([CodeBlockStyle getStyleType]), @([ImageStyle getStyleType]) ],
|
|
180
|
+
@([H1Style getStyleType]) : @[],
|
|
181
|
+
@([H2Style getStyleType]) : @[],
|
|
182
|
+
@([H3Style getStyleType]) : @[],
|
|
183
|
+
@([UnorderedListStyle getStyleType]) : @[],
|
|
184
|
+
@([OrderedListStyle getStyleType]) : @[],
|
|
185
|
+
@([BlockQuoteStyle getStyleType]) : @[],
|
|
186
|
+
@([CodeBlockStyle getStyleType]) : @[],
|
|
187
|
+
@([ImageStyle getStyleType]) : @[ @([InlineCodeStyle getStyleType]) ]
|
|
131
188
|
};
|
|
132
|
-
|
|
189
|
+
|
|
133
190
|
parser = [[InputParser alloc] initWithInput:self];
|
|
134
191
|
}
|
|
135
192
|
|
|
@@ -147,11 +204,14 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
147
204
|
_placeholderLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
|
148
205
|
_placeholderLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
|
149
206
|
[textView addSubview:_placeholderLabel];
|
|
150
|
-
[NSLayoutConstraint activateConstraints
|
|
151
|
-
[_placeholderLabel.leadingAnchor
|
|
152
|
-
|
|
207
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
208
|
+
[_placeholderLabel.leadingAnchor
|
|
209
|
+
constraintEqualToAnchor:textView.leadingAnchor],
|
|
210
|
+
[_placeholderLabel.widthAnchor
|
|
211
|
+
constraintEqualToAnchor:textView.widthAnchor],
|
|
153
212
|
[_placeholderLabel.topAnchor constraintEqualToAnchor:textView.topAnchor],
|
|
154
|
-
[_placeholderLabel.bottomAnchor
|
|
213
|
+
[_placeholderLabel.bottomAnchor
|
|
214
|
+
constraintEqualToAnchor:textView.bottomAnchor]
|
|
155
215
|
]];
|
|
156
216
|
_placeholderLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
|
157
217
|
_placeholderLabel.text = @"";
|
|
@@ -160,25 +220,28 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
160
220
|
|
|
161
221
|
// MARK: - Props
|
|
162
222
|
|
|
163
|
-
- (void)updateProps:(Props::Shared const &)props
|
|
164
|
-
|
|
165
|
-
const auto &
|
|
223
|
+
- (void)updateProps:(Props::Shared const &)props
|
|
224
|
+
oldProps:(Props::Shared const &)oldProps {
|
|
225
|
+
const auto &oldViewProps =
|
|
226
|
+
*std::static_pointer_cast<EnrichedTextInputViewProps const>(_props);
|
|
227
|
+
const auto &newViewProps =
|
|
228
|
+
*std::static_pointer_cast<EnrichedTextInputViewProps const>(props);
|
|
166
229
|
BOOL isFirstMount = NO;
|
|
167
230
|
BOOL stylePropChanged = NO;
|
|
168
|
-
|
|
231
|
+
|
|
169
232
|
// initial config
|
|
170
|
-
if(config == nullptr) {
|
|
233
|
+
if (config == nullptr) {
|
|
171
234
|
isFirstMount = YES;
|
|
172
235
|
config = [[InputConfig alloc] init];
|
|
173
236
|
}
|
|
174
|
-
|
|
237
|
+
|
|
175
238
|
// any style prop changes:
|
|
176
239
|
// firstly we create the new config for the changes
|
|
177
|
-
|
|
240
|
+
|
|
178
241
|
InputConfig *newConfig = [config copy];
|
|
179
|
-
|
|
180
|
-
if(newViewProps.color != oldViewProps.color) {
|
|
181
|
-
if(isColorMeaningful(newViewProps.color)) {
|
|
242
|
+
|
|
243
|
+
if (newViewProps.color != oldViewProps.color) {
|
|
244
|
+
if (isColorMeaningful(newViewProps.color)) {
|
|
182
245
|
UIColor *uiColor = RCTUIColorFromSharedColor(newViewProps.color);
|
|
183
246
|
[newConfig setPrimaryColor:uiColor];
|
|
184
247
|
} else {
|
|
@@ -186,253 +249,342 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
186
249
|
}
|
|
187
250
|
stylePropChanged = YES;
|
|
188
251
|
}
|
|
189
|
-
|
|
190
|
-
if(newViewProps.fontSize != oldViewProps.fontSize) {
|
|
191
|
-
if(newViewProps.fontSize) {
|
|
192
|
-
NSNumber*
|
|
252
|
+
|
|
253
|
+
if (newViewProps.fontSize != oldViewProps.fontSize) {
|
|
254
|
+
if (newViewProps.fontSize) {
|
|
255
|
+
NSNumber *fontSize = @(newViewProps.fontSize);
|
|
193
256
|
[newConfig setPrimaryFontSize:fontSize];
|
|
194
257
|
} else {
|
|
195
258
|
[newConfig setPrimaryFontSize:nullptr];
|
|
196
259
|
}
|
|
197
260
|
stylePropChanged = YES;
|
|
198
261
|
}
|
|
199
|
-
|
|
200
|
-
if(newViewProps.fontWeight != oldViewProps.fontWeight) {
|
|
201
|
-
if(!newViewProps.fontWeight.empty()) {
|
|
202
|
-
[newConfig
|
|
262
|
+
|
|
263
|
+
if (newViewProps.fontWeight != oldViewProps.fontWeight) {
|
|
264
|
+
if (!newViewProps.fontWeight.empty()) {
|
|
265
|
+
[newConfig
|
|
266
|
+
setPrimaryFontWeight:[NSString
|
|
267
|
+
fromCppString:newViewProps.fontWeight]];
|
|
203
268
|
} else {
|
|
204
269
|
[newConfig setPrimaryFontWeight:nullptr];
|
|
205
270
|
}
|
|
206
271
|
stylePropChanged = YES;
|
|
207
272
|
}
|
|
208
|
-
|
|
209
|
-
if(newViewProps.fontFamily != oldViewProps.fontFamily) {
|
|
210
|
-
if(!newViewProps.fontFamily.empty()) {
|
|
211
|
-
[newConfig
|
|
273
|
+
|
|
274
|
+
if (newViewProps.fontFamily != oldViewProps.fontFamily) {
|
|
275
|
+
if (!newViewProps.fontFamily.empty()) {
|
|
276
|
+
[newConfig
|
|
277
|
+
setPrimaryFontFamily:[NSString
|
|
278
|
+
fromCppString:newViewProps.fontFamily]];
|
|
212
279
|
} else {
|
|
213
280
|
[newConfig setPrimaryFontFamily:nullptr];
|
|
214
281
|
}
|
|
215
282
|
stylePropChanged = YES;
|
|
216
283
|
}
|
|
217
|
-
|
|
284
|
+
|
|
218
285
|
// rich text style
|
|
219
|
-
|
|
220
|
-
if(newViewProps.htmlStyle.h1.fontSize !=
|
|
286
|
+
|
|
287
|
+
if (newViewProps.htmlStyle.h1.fontSize !=
|
|
288
|
+
oldViewProps.htmlStyle.h1.fontSize) {
|
|
221
289
|
[newConfig setH1FontSize:newViewProps.htmlStyle.h1.fontSize];
|
|
222
290
|
stylePropChanged = YES;
|
|
223
291
|
}
|
|
224
|
-
|
|
225
|
-
if(newViewProps.htmlStyle.h1.bold != oldViewProps.htmlStyle.h1.bold) {
|
|
292
|
+
|
|
293
|
+
if (newViewProps.htmlStyle.h1.bold != oldViewProps.htmlStyle.h1.bold) {
|
|
226
294
|
[newConfig setH1Bold:newViewProps.htmlStyle.h1.bold];
|
|
227
295
|
stylePropChanged = YES;
|
|
228
296
|
}
|
|
229
|
-
|
|
230
|
-
if(newViewProps.htmlStyle.h2.fontSize !=
|
|
297
|
+
|
|
298
|
+
if (newViewProps.htmlStyle.h2.fontSize !=
|
|
299
|
+
oldViewProps.htmlStyle.h2.fontSize) {
|
|
231
300
|
[newConfig setH2FontSize:newViewProps.htmlStyle.h2.fontSize];
|
|
232
301
|
stylePropChanged = YES;
|
|
233
302
|
}
|
|
234
|
-
|
|
235
|
-
if(newViewProps.htmlStyle.h2.bold != oldViewProps.htmlStyle.h2.bold) {
|
|
303
|
+
|
|
304
|
+
if (newViewProps.htmlStyle.h2.bold != oldViewProps.htmlStyle.h2.bold) {
|
|
236
305
|
[newConfig setH2Bold:newViewProps.htmlStyle.h2.bold];
|
|
237
306
|
stylePropChanged = YES;
|
|
238
307
|
}
|
|
239
|
-
|
|
240
|
-
if(newViewProps.htmlStyle.h3.fontSize !=
|
|
308
|
+
|
|
309
|
+
if (newViewProps.htmlStyle.h3.fontSize !=
|
|
310
|
+
oldViewProps.htmlStyle.h3.fontSize) {
|
|
241
311
|
[newConfig setH3FontSize:newViewProps.htmlStyle.h3.fontSize];
|
|
242
312
|
stylePropChanged = YES;
|
|
243
313
|
}
|
|
244
|
-
|
|
245
|
-
if(newViewProps.htmlStyle.h3.bold != oldViewProps.htmlStyle.h3.bold) {
|
|
314
|
+
|
|
315
|
+
if (newViewProps.htmlStyle.h3.bold != oldViewProps.htmlStyle.h3.bold) {
|
|
246
316
|
[newConfig setH3Bold:newViewProps.htmlStyle.h3.bold];
|
|
247
317
|
stylePropChanged = YES;
|
|
248
318
|
}
|
|
249
|
-
|
|
250
|
-
if(newViewProps.htmlStyle.blockquote.borderColor !=
|
|
251
|
-
|
|
252
|
-
|
|
319
|
+
|
|
320
|
+
if (newViewProps.htmlStyle.blockquote.borderColor !=
|
|
321
|
+
oldViewProps.htmlStyle.blockquote.borderColor) {
|
|
322
|
+
if (isColorMeaningful(newViewProps.htmlStyle.blockquote.borderColor)) {
|
|
323
|
+
[newConfig setBlockquoteBorderColor:RCTUIColorFromSharedColor(
|
|
324
|
+
newViewProps.htmlStyle.blockquote
|
|
325
|
+
.borderColor)];
|
|
253
326
|
stylePropChanged = YES;
|
|
254
327
|
}
|
|
255
328
|
}
|
|
256
|
-
|
|
257
|
-
if(newViewProps.htmlStyle.blockquote.borderWidth !=
|
|
258
|
-
|
|
329
|
+
|
|
330
|
+
if (newViewProps.htmlStyle.blockquote.borderWidth !=
|
|
331
|
+
oldViewProps.htmlStyle.blockquote.borderWidth) {
|
|
332
|
+
[newConfig
|
|
333
|
+
setBlockquoteBorderWidth:newViewProps.htmlStyle.blockquote.borderWidth];
|
|
259
334
|
stylePropChanged = YES;
|
|
260
335
|
}
|
|
261
|
-
|
|
262
|
-
if(newViewProps.htmlStyle.blockquote.gapWidth !=
|
|
263
|
-
|
|
336
|
+
|
|
337
|
+
if (newViewProps.htmlStyle.blockquote.gapWidth !=
|
|
338
|
+
oldViewProps.htmlStyle.blockquote.gapWidth) {
|
|
339
|
+
[newConfig
|
|
340
|
+
setBlockquoteGapWidth:newViewProps.htmlStyle.blockquote.gapWidth];
|
|
264
341
|
stylePropChanged = YES;
|
|
265
342
|
}
|
|
266
|
-
|
|
267
|
-
// since this prop defaults to undefined on JS side, we need to force set the
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
343
|
+
|
|
344
|
+
// since this prop defaults to undefined on JS side, we need to force set the
|
|
345
|
+
// value on first mount
|
|
346
|
+
if (newViewProps.htmlStyle.blockquote.color !=
|
|
347
|
+
oldViewProps.htmlStyle.blockquote.color ||
|
|
348
|
+
isFirstMount) {
|
|
349
|
+
if (isColorMeaningful(newViewProps.htmlStyle.blockquote.color)) {
|
|
350
|
+
[newConfig
|
|
351
|
+
setBlockquoteColor:RCTUIColorFromSharedColor(
|
|
352
|
+
newViewProps.htmlStyle.blockquote.color)];
|
|
271
353
|
} else {
|
|
272
354
|
[newConfig setBlockquoteColor:[newConfig primaryColor]];
|
|
273
355
|
}
|
|
274
356
|
stylePropChanged = YES;
|
|
275
357
|
}
|
|
276
|
-
|
|
277
|
-
if(newViewProps.htmlStyle.code.color != oldViewProps.htmlStyle.code.color) {
|
|
278
|
-
if(isColorMeaningful(newViewProps.htmlStyle.code.color)) {
|
|
279
|
-
[newConfig setInlineCodeFgColor:RCTUIColorFromSharedColor(
|
|
358
|
+
|
|
359
|
+
if (newViewProps.htmlStyle.code.color != oldViewProps.htmlStyle.code.color) {
|
|
360
|
+
if (isColorMeaningful(newViewProps.htmlStyle.code.color)) {
|
|
361
|
+
[newConfig setInlineCodeFgColor:RCTUIColorFromSharedColor(
|
|
362
|
+
newViewProps.htmlStyle.code.color)];
|
|
280
363
|
stylePropChanged = YES;
|
|
281
364
|
}
|
|
282
365
|
}
|
|
283
|
-
|
|
284
|
-
if(newViewProps.htmlStyle.code.backgroundColor !=
|
|
285
|
-
|
|
286
|
-
|
|
366
|
+
|
|
367
|
+
if (newViewProps.htmlStyle.code.backgroundColor !=
|
|
368
|
+
oldViewProps.htmlStyle.code.backgroundColor) {
|
|
369
|
+
if (isColorMeaningful(newViewProps.htmlStyle.code.backgroundColor)) {
|
|
370
|
+
[newConfig setInlineCodeBgColor:RCTUIColorFromSharedColor(
|
|
371
|
+
newViewProps.htmlStyle.code
|
|
372
|
+
.backgroundColor)];
|
|
287
373
|
stylePropChanged = YES;
|
|
288
374
|
}
|
|
289
375
|
}
|
|
290
|
-
|
|
291
|
-
if(newViewProps.htmlStyle.ol.gapWidth !=
|
|
376
|
+
|
|
377
|
+
if (newViewProps.htmlStyle.ol.gapWidth !=
|
|
378
|
+
oldViewProps.htmlStyle.ol.gapWidth) {
|
|
292
379
|
[newConfig setOrderedListGapWidth:newViewProps.htmlStyle.ol.gapWidth];
|
|
293
380
|
stylePropChanged = YES;
|
|
294
381
|
}
|
|
295
|
-
|
|
296
|
-
if(newViewProps.htmlStyle.ol.marginLeft !=
|
|
382
|
+
|
|
383
|
+
if (newViewProps.htmlStyle.ol.marginLeft !=
|
|
384
|
+
oldViewProps.htmlStyle.ol.marginLeft) {
|
|
297
385
|
[newConfig setOrderedListMarginLeft:newViewProps.htmlStyle.ol.marginLeft];
|
|
298
386
|
stylePropChanged = YES;
|
|
299
387
|
}
|
|
300
|
-
|
|
301
|
-
// since this prop defaults to undefined on JS side, we need to force set the
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
388
|
+
|
|
389
|
+
// since this prop defaults to undefined on JS side, we need to force set the
|
|
390
|
+
// value on first mount
|
|
391
|
+
if (newViewProps.htmlStyle.ol.markerFontWeight !=
|
|
392
|
+
oldViewProps.htmlStyle.ol.markerFontWeight ||
|
|
393
|
+
isFirstMount) {
|
|
394
|
+
if (!newViewProps.htmlStyle.ol.markerFontWeight.empty()) {
|
|
395
|
+
[newConfig
|
|
396
|
+
setOrderedListMarkerFontWeight:
|
|
397
|
+
[NSString
|
|
398
|
+
fromCppString:newViewProps.htmlStyle.ol.markerFontWeight]];
|
|
305
399
|
} else {
|
|
306
400
|
[newConfig setOrderedListMarkerFontWeight:[newConfig primaryFontWeight]];
|
|
307
401
|
}
|
|
308
402
|
stylePropChanged = YES;
|
|
309
403
|
}
|
|
310
|
-
|
|
311
|
-
// since this prop defaults to undefined on JS side, we need to force set the
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
404
|
+
|
|
405
|
+
// since this prop defaults to undefined on JS side, we need to force set the
|
|
406
|
+
// value on first mount
|
|
407
|
+
if (newViewProps.htmlStyle.ol.markerColor !=
|
|
408
|
+
oldViewProps.htmlStyle.ol.markerColor ||
|
|
409
|
+
isFirstMount) {
|
|
410
|
+
if (isColorMeaningful(newViewProps.htmlStyle.ol.markerColor)) {
|
|
411
|
+
[newConfig
|
|
412
|
+
setOrderedListMarkerColor:RCTUIColorFromSharedColor(
|
|
413
|
+
newViewProps.htmlStyle.ol.markerColor)];
|
|
315
414
|
} else {
|
|
316
415
|
[newConfig setOrderedListMarkerColor:[newConfig primaryColor]];
|
|
317
416
|
}
|
|
318
417
|
stylePropChanged = YES;
|
|
319
418
|
}
|
|
320
|
-
|
|
321
|
-
if(newViewProps.htmlStyle.ul.bulletColor !=
|
|
322
|
-
|
|
323
|
-
|
|
419
|
+
|
|
420
|
+
if (newViewProps.htmlStyle.ul.bulletColor !=
|
|
421
|
+
oldViewProps.htmlStyle.ul.bulletColor) {
|
|
422
|
+
if (isColorMeaningful(newViewProps.htmlStyle.ul.bulletColor)) {
|
|
423
|
+
[newConfig setUnorderedListBulletColor:RCTUIColorFromSharedColor(
|
|
424
|
+
newViewProps.htmlStyle.ul
|
|
425
|
+
.bulletColor)];
|
|
324
426
|
stylePropChanged = YES;
|
|
325
427
|
}
|
|
326
428
|
}
|
|
327
|
-
|
|
328
|
-
if(newViewProps.htmlStyle.ul.bulletSize !=
|
|
429
|
+
|
|
430
|
+
if (newViewProps.htmlStyle.ul.bulletSize !=
|
|
431
|
+
oldViewProps.htmlStyle.ul.bulletSize) {
|
|
329
432
|
[newConfig setUnorderedListBulletSize:newViewProps.htmlStyle.ul.bulletSize];
|
|
330
433
|
stylePropChanged = YES;
|
|
331
434
|
}
|
|
332
|
-
|
|
333
|
-
if(newViewProps.htmlStyle.ul.gapWidth !=
|
|
435
|
+
|
|
436
|
+
if (newViewProps.htmlStyle.ul.gapWidth !=
|
|
437
|
+
oldViewProps.htmlStyle.ul.gapWidth) {
|
|
334
438
|
[newConfig setUnorderedListGapWidth:newViewProps.htmlStyle.ul.gapWidth];
|
|
335
439
|
stylePropChanged = YES;
|
|
336
440
|
}
|
|
337
|
-
|
|
338
|
-
if(newViewProps.htmlStyle.ul.marginLeft !=
|
|
441
|
+
|
|
442
|
+
if (newViewProps.htmlStyle.ul.marginLeft !=
|
|
443
|
+
oldViewProps.htmlStyle.ul.marginLeft) {
|
|
339
444
|
[newConfig setUnorderedListMarginLeft:newViewProps.htmlStyle.ul.marginLeft];
|
|
340
445
|
stylePropChanged = YES;
|
|
341
446
|
}
|
|
342
|
-
|
|
343
|
-
if(newViewProps.htmlStyle.a.color != oldViewProps.htmlStyle.a.color) {
|
|
344
|
-
if(isColorMeaningful(newViewProps.htmlStyle.a.color)) {
|
|
345
|
-
[newConfig setLinkColor:RCTUIColorFromSharedColor(
|
|
447
|
+
|
|
448
|
+
if (newViewProps.htmlStyle.a.color != oldViewProps.htmlStyle.a.color) {
|
|
449
|
+
if (isColorMeaningful(newViewProps.htmlStyle.a.color)) {
|
|
450
|
+
[newConfig setLinkColor:RCTUIColorFromSharedColor(
|
|
451
|
+
newViewProps.htmlStyle.a.color)];
|
|
452
|
+
stylePropChanged = YES;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (newViewProps.htmlStyle.codeblock.color !=
|
|
457
|
+
oldViewProps.htmlStyle.codeblock.color) {
|
|
458
|
+
if (isColorMeaningful(newViewProps.htmlStyle.codeblock.color)) {
|
|
459
|
+
[newConfig
|
|
460
|
+
setCodeBlockFgColor:RCTUIColorFromSharedColor(
|
|
461
|
+
newViewProps.htmlStyle.codeblock.color)];
|
|
346
462
|
stylePropChanged = YES;
|
|
347
463
|
}
|
|
348
464
|
}
|
|
349
|
-
|
|
350
|
-
if(newViewProps.htmlStyle.
|
|
351
|
-
|
|
352
|
-
if(
|
|
465
|
+
|
|
466
|
+
if (newViewProps.htmlStyle.codeblock.backgroundColor !=
|
|
467
|
+
oldViewProps.htmlStyle.codeblock.backgroundColor) {
|
|
468
|
+
if (isColorMeaningful(newViewProps.htmlStyle.codeblock.backgroundColor)) {
|
|
469
|
+
[newConfig setCodeBlockBgColor:RCTUIColorFromSharedColor(
|
|
470
|
+
newViewProps.htmlStyle.codeblock
|
|
471
|
+
.backgroundColor)];
|
|
472
|
+
stylePropChanged = YES;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (newViewProps.htmlStyle.codeblock.borderRadius !=
|
|
477
|
+
oldViewProps.htmlStyle.codeblock.borderRadius) {
|
|
478
|
+
[newConfig
|
|
479
|
+
setCodeBlockBorderRadius:newViewProps.htmlStyle.codeblock.borderRadius];
|
|
480
|
+
stylePropChanged = YES;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (newViewProps.htmlStyle.a.textDecorationLine !=
|
|
484
|
+
oldViewProps.htmlStyle.a.textDecorationLine) {
|
|
485
|
+
NSString *objcString =
|
|
486
|
+
[NSString fromCppString:newViewProps.htmlStyle.a.textDecorationLine];
|
|
487
|
+
if ([objcString isEqualToString:DecorationUnderline]) {
|
|
353
488
|
[newConfig setLinkDecorationLine:DecorationUnderline];
|
|
354
489
|
} else {
|
|
355
|
-
// both DecorationNone and a different, wrong value gets a DecorationNone
|
|
490
|
+
// both DecorationNone and a different, wrong value gets a DecorationNone
|
|
491
|
+
// here
|
|
356
492
|
[newConfig setLinkDecorationLine:DecorationNone];
|
|
357
493
|
}
|
|
358
494
|
stylePropChanged = YES;
|
|
359
495
|
}
|
|
360
|
-
|
|
361
|
-
if(newViewProps.scrollEnabled != oldViewProps.scrollEnabled ||
|
|
496
|
+
|
|
497
|
+
if (newViewProps.scrollEnabled != oldViewProps.scrollEnabled ||
|
|
498
|
+
textView.scrollEnabled != newViewProps.scrollEnabled) {
|
|
362
499
|
[textView setScrollEnabled:newViewProps.scrollEnabled];
|
|
363
500
|
}
|
|
364
|
-
|
|
501
|
+
|
|
365
502
|
folly::dynamic oldMentionStyle = oldViewProps.htmlStyle.mention;
|
|
366
503
|
folly::dynamic newMentionStyle = newViewProps.htmlStyle.mention;
|
|
367
|
-
if(oldMentionStyle != newMentionStyle) {
|
|
504
|
+
if (oldMentionStyle != newMentionStyle) {
|
|
368
505
|
bool newSingleProps = NO;
|
|
369
|
-
|
|
370
|
-
for(const auto&
|
|
371
|
-
if(obj.second.isInt() || obj.second.isString()) {
|
|
506
|
+
|
|
507
|
+
for (const auto &obj : newMentionStyle.items()) {
|
|
508
|
+
if (obj.second.isInt() || obj.second.isString()) {
|
|
372
509
|
// we are in just a single MentionStyleProps object
|
|
373
510
|
newSingleProps = YES;
|
|
374
511
|
break;
|
|
375
|
-
} else if(obj.second.isObject()) {
|
|
512
|
+
} else if (obj.second.isObject()) {
|
|
376
513
|
// we are in map of indicators to MentionStyleProps
|
|
377
514
|
newSingleProps = NO;
|
|
378
515
|
break;
|
|
379
516
|
}
|
|
380
517
|
}
|
|
381
|
-
|
|
382
|
-
if(newSingleProps) {
|
|
383
|
-
[newConfig setMentionStyleProps:
|
|
518
|
+
|
|
519
|
+
if (newSingleProps) {
|
|
520
|
+
[newConfig setMentionStyleProps:
|
|
521
|
+
[MentionStyleProps
|
|
522
|
+
getSinglePropsFromFollyDynamic:newMentionStyle]];
|
|
384
523
|
} else {
|
|
385
|
-
[newConfig setMentionStyleProps:
|
|
524
|
+
[newConfig setMentionStyleProps:
|
|
525
|
+
[MentionStyleProps
|
|
526
|
+
getComplexPropsFromFollyDynamic:newMentionStyle]];
|
|
386
527
|
}
|
|
387
|
-
|
|
528
|
+
|
|
388
529
|
stylePropChanged = YES;
|
|
389
530
|
}
|
|
390
|
-
|
|
391
|
-
if(stylePropChanged) {
|
|
531
|
+
|
|
532
|
+
if (stylePropChanged) {
|
|
392
533
|
// all the text needs to be rebuilt
|
|
393
|
-
// we get the current html using old config, then switch to new config and
|
|
394
|
-
// this way, the newest config attributes are
|
|
395
|
-
|
|
534
|
+
// we get the current html using old config, then switch to new config and
|
|
535
|
+
// replace text using the html this way, the newest config attributes are
|
|
536
|
+
// being used!
|
|
537
|
+
|
|
396
538
|
// the html needs to be generated using the old config
|
|
397
|
-
NSString *currentHtml = [parser
|
|
398
|
-
|
|
539
|
+
NSString *currentHtml = [parser
|
|
540
|
+
parseToHtmlFromRange:NSMakeRange(0,
|
|
541
|
+
textView.textStorage.string.length)];
|
|
542
|
+
|
|
399
543
|
// now set the new config
|
|
400
544
|
config = newConfig;
|
|
401
|
-
|
|
545
|
+
|
|
402
546
|
// no emitting during styles reload
|
|
403
547
|
blockEmitting = YES;
|
|
404
|
-
|
|
548
|
+
|
|
405
549
|
// make sure everything is sound in the html
|
|
406
|
-
NSString *initiallyProcessedHtml =
|
|
407
|
-
|
|
550
|
+
NSString *initiallyProcessedHtml =
|
|
551
|
+
[parser initiallyProcessHtml:currentHtml];
|
|
552
|
+
if (initiallyProcessedHtml != nullptr) {
|
|
408
553
|
[parser replaceWholeFromHtml:initiallyProcessedHtml];
|
|
409
554
|
}
|
|
410
|
-
|
|
555
|
+
|
|
411
556
|
blockEmitting = NO;
|
|
412
|
-
|
|
557
|
+
|
|
413
558
|
// fill the typing attributes with style props
|
|
414
|
-
defaultTypingAttributes[NSForegroundColorAttributeName] =
|
|
559
|
+
defaultTypingAttributes[NSForegroundColorAttributeName] =
|
|
560
|
+
[config primaryColor];
|
|
415
561
|
defaultTypingAttributes[NSFontAttributeName] = [config primaryFont];
|
|
416
|
-
defaultTypingAttributes[NSUnderlineColorAttributeName] =
|
|
417
|
-
|
|
418
|
-
defaultTypingAttributes[
|
|
562
|
+
defaultTypingAttributes[NSUnderlineColorAttributeName] =
|
|
563
|
+
[config primaryColor];
|
|
564
|
+
defaultTypingAttributes[NSStrikethroughColorAttributeName] =
|
|
565
|
+
[config primaryColor];
|
|
566
|
+
defaultTypingAttributes[NSParagraphStyleAttributeName] =
|
|
567
|
+
[[NSParagraphStyle alloc] init];
|
|
419
568
|
textView.typingAttributes = defaultTypingAttributes;
|
|
420
|
-
|
|
569
|
+
|
|
421
570
|
// update the placeholder as well
|
|
422
571
|
[self refreshPlaceholderLabelStyles];
|
|
423
572
|
}
|
|
424
|
-
|
|
573
|
+
|
|
425
574
|
// editable
|
|
426
|
-
if(newViewProps.editable != textView.editable) {
|
|
575
|
+
if (newViewProps.editable != textView.editable) {
|
|
427
576
|
textView.editable = newViewProps.editable;
|
|
428
577
|
}
|
|
429
|
-
|
|
430
|
-
// default value - must be set before placeholder to make sure it correctly
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
578
|
+
|
|
579
|
+
// default value - must be set before placeholder to make sure it correctly
|
|
580
|
+
// shows on first mount
|
|
581
|
+
if (newViewProps.defaultValue != oldViewProps.defaultValue) {
|
|
582
|
+
NSString *newDefaultValue =
|
|
583
|
+
[NSString fromCppString:newViewProps.defaultValue];
|
|
584
|
+
|
|
585
|
+
NSString *initiallyProcessedHtml =
|
|
586
|
+
[parser initiallyProcessHtml:newDefaultValue];
|
|
587
|
+
if (initiallyProcessedHtml == nullptr) {
|
|
436
588
|
// just plain text
|
|
437
589
|
textView.text = newDefaultValue;
|
|
438
590
|
} else {
|
|
@@ -440,90 +592,94 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
440
592
|
[parser replaceWholeFromHtml:initiallyProcessedHtml];
|
|
441
593
|
}
|
|
442
594
|
}
|
|
443
|
-
|
|
595
|
+
|
|
444
596
|
// placeholderTextColor
|
|
445
|
-
if(newViewProps.placeholderTextColor != oldViewProps.placeholderTextColor) {
|
|
597
|
+
if (newViewProps.placeholderTextColor != oldViewProps.placeholderTextColor) {
|
|
446
598
|
// some real color
|
|
447
|
-
if(isColorMeaningful(newViewProps.placeholderTextColor)) {
|
|
448
|
-
_placeholderColor =
|
|
599
|
+
if (isColorMeaningful(newViewProps.placeholderTextColor)) {
|
|
600
|
+
_placeholderColor =
|
|
601
|
+
RCTUIColorFromSharedColor(newViewProps.placeholderTextColor);
|
|
449
602
|
} else {
|
|
450
603
|
_placeholderColor = nullptr;
|
|
451
604
|
}
|
|
452
605
|
[self refreshPlaceholderLabelStyles];
|
|
453
606
|
}
|
|
454
|
-
|
|
607
|
+
|
|
455
608
|
// placeholder
|
|
456
|
-
if(newViewProps.placeholder != oldViewProps.placeholder) {
|
|
609
|
+
if (newViewProps.placeholder != oldViewProps.placeholder) {
|
|
457
610
|
_placeholderLabel.text = [NSString fromCppString:newViewProps.placeholder];
|
|
458
611
|
[self refreshPlaceholderLabelStyles];
|
|
459
612
|
// additionally show placeholder on first mount if it should be there
|
|
460
|
-
if(isFirstMount && textView.text.length == 0) {
|
|
613
|
+
if (isFirstMount && textView.text.length == 0) {
|
|
461
614
|
[self setPlaceholderLabelShown:YES];
|
|
462
615
|
}
|
|
463
616
|
}
|
|
464
|
-
|
|
617
|
+
|
|
465
618
|
// mention indicators
|
|
466
|
-
auto mismatchPair = std::mismatch(
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if(mismatchPair.first != newViewProps.mentionIndicators.end() ||
|
|
619
|
+
auto mismatchPair = std::mismatch(newViewProps.mentionIndicators.begin(),
|
|
620
|
+
newViewProps.mentionIndicators.end(),
|
|
621
|
+
oldViewProps.mentionIndicators.begin(),
|
|
622
|
+
oldViewProps.mentionIndicators.end());
|
|
623
|
+
if (mismatchPair.first != newViewProps.mentionIndicators.end() ||
|
|
624
|
+
mismatchPair.second != oldViewProps.mentionIndicators.end()) {
|
|
471
625
|
NSMutableSet<NSNumber *> *newIndicators = [[NSMutableSet alloc] init];
|
|
472
|
-
for(const std::string &item : newViewProps.mentionIndicators) {
|
|
473
|
-
if(item.length() == 1) {
|
|
626
|
+
for (const std::string &item : newViewProps.mentionIndicators) {
|
|
627
|
+
if (item.length() == 1) {
|
|
474
628
|
[newIndicators addObject:@(item[0])];
|
|
475
629
|
}
|
|
476
630
|
}
|
|
477
631
|
[config setMentionIndicators:newIndicators];
|
|
478
632
|
}
|
|
479
|
-
|
|
633
|
+
|
|
480
634
|
// selection color sets both selection and cursor on iOS (just as in RN)
|
|
481
|
-
if(newViewProps.selectionColor != oldViewProps.selectionColor) {
|
|
482
|
-
if(isColorMeaningful(newViewProps.selectionColor)) {
|
|
483
|
-
textView.tintColor =
|
|
635
|
+
if (newViewProps.selectionColor != oldViewProps.selectionColor) {
|
|
636
|
+
if (isColorMeaningful(newViewProps.selectionColor)) {
|
|
637
|
+
textView.tintColor =
|
|
638
|
+
RCTUIColorFromSharedColor(newViewProps.selectionColor);
|
|
484
639
|
} else {
|
|
485
640
|
textView.tintColor = nullptr;
|
|
486
641
|
}
|
|
487
642
|
}
|
|
488
|
-
|
|
643
|
+
|
|
489
644
|
// autoCapitalize
|
|
490
|
-
if(newViewProps.autoCapitalize != oldViewProps.autoCapitalize) {
|
|
645
|
+
if (newViewProps.autoCapitalize != oldViewProps.autoCapitalize) {
|
|
491
646
|
NSString *str = [NSString fromCppString:newViewProps.autoCapitalize];
|
|
492
|
-
if([str isEqualToString
|
|
647
|
+
if ([str isEqualToString:@"none"]) {
|
|
493
648
|
textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
|
494
|
-
} else if([str isEqualToString
|
|
649
|
+
} else if ([str isEqualToString:@"sentences"]) {
|
|
495
650
|
textView.autocapitalizationType = UITextAutocapitalizationTypeSentences;
|
|
496
|
-
} else if([str isEqualToString
|
|
651
|
+
} else if ([str isEqualToString:@"words"]) {
|
|
497
652
|
textView.autocapitalizationType = UITextAutocapitalizationTypeWords;
|
|
498
|
-
} else if([str isEqualToString
|
|
499
|
-
textView.autocapitalizationType =
|
|
653
|
+
} else if ([str isEqualToString:@"characters"]) {
|
|
654
|
+
textView.autocapitalizationType =
|
|
655
|
+
UITextAutocapitalizationTypeAllCharacters;
|
|
500
656
|
}
|
|
501
|
-
|
|
502
|
-
// textView needs to be refocused on autocapitalization type change and we
|
|
503
|
-
|
|
657
|
+
|
|
658
|
+
// textView needs to be refocused on autocapitalization type change and we
|
|
659
|
+
// don't want to emit these events
|
|
660
|
+
if ([textView isFirstResponder]) {
|
|
504
661
|
_emitFocusBlur = NO;
|
|
505
662
|
[textView reactBlur];
|
|
506
663
|
[textView reactFocus];
|
|
507
664
|
_emitFocusBlur = YES;
|
|
508
665
|
}
|
|
509
666
|
}
|
|
510
|
-
|
|
667
|
+
|
|
511
668
|
// isOnChangeHtmlSet
|
|
512
669
|
_emitHtml = newViewProps.isOnChangeHtmlSet;
|
|
513
|
-
|
|
670
|
+
|
|
514
671
|
[super updateProps:props oldProps:oldProps];
|
|
515
|
-
//
|
|
672
|
+
// run the changes callback
|
|
516
673
|
[self anyTextMayHaveBeenModified];
|
|
517
|
-
|
|
518
|
-
|
|
674
|
+
|
|
519
675
|
// autofocus - needs to be done at the very end
|
|
520
|
-
if(isFirstMount && newViewProps.autoFocus) {
|
|
676
|
+
if (isFirstMount && newViewProps.autoFocus) {
|
|
521
677
|
[textView reactFocus];
|
|
522
678
|
}
|
|
523
679
|
}
|
|
524
680
|
|
|
525
681
|
- (void)setPlaceholderLabelShown:(BOOL)shown {
|
|
526
|
-
if(shown) {
|
|
682
|
+
if (shown) {
|
|
527
683
|
[self refreshPlaceholderLabelStyles];
|
|
528
684
|
_placeholderLabel.hidden = NO;
|
|
529
685
|
} else {
|
|
@@ -533,10 +689,12 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
533
689
|
|
|
534
690
|
- (void)refreshPlaceholderLabelStyles {
|
|
535
691
|
NSMutableDictionary *newAttrs = [defaultTypingAttributes mutableCopy];
|
|
536
|
-
if(_placeholderColor != nullptr) {
|
|
692
|
+
if (_placeholderColor != nullptr) {
|
|
537
693
|
newAttrs[NSForegroundColorAttributeName] = _placeholderColor;
|
|
538
694
|
}
|
|
539
|
-
NSAttributedString *newAttrStr =
|
|
695
|
+
NSAttributedString *newAttrStr =
|
|
696
|
+
[[NSAttributedString alloc] initWithString:_placeholderLabel.text
|
|
697
|
+
attributes:newAttrs];
|
|
540
698
|
_placeholderLabel.attributedText = newAttrStr;
|
|
541
699
|
}
|
|
542
700
|
|
|
@@ -544,183 +702,220 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
544
702
|
|
|
545
703
|
- (CGSize)measureSize:(CGFloat)maxWidth {
|
|
546
704
|
// copy the the whole attributed string
|
|
547
|
-
NSMutableAttributedString *currentStr = [[NSMutableAttributedString alloc]
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
705
|
+
NSMutableAttributedString *currentStr = [[NSMutableAttributedString alloc]
|
|
706
|
+
initWithAttributedString:textView.textStorage];
|
|
707
|
+
|
|
708
|
+
// edge case: empty input should still be of a height of a single line, so we
|
|
709
|
+
// add a mock "I" character
|
|
710
|
+
if ([currentStr length] == 0) {
|
|
711
|
+
[currentStr
|
|
712
|
+
appendAttributedString:[[NSAttributedString alloc]
|
|
713
|
+
initWithString:@"I"
|
|
714
|
+
attributes:textView.typingAttributes]];
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// edge case: input with only a zero width space should still be of a height
|
|
718
|
+
// of a single line, so we add a mock "I" character
|
|
719
|
+
if ([currentStr length] == 1 &&
|
|
720
|
+
[[currentStr.string substringWithRange:NSMakeRange(0, 1)]
|
|
721
|
+
isEqualToString:@"\u200B"]) {
|
|
722
|
+
[currentStr
|
|
723
|
+
appendAttributedString:[[NSAttributedString alloc]
|
|
724
|
+
initWithString:@"I"
|
|
725
|
+
attributes:textView.typingAttributes]];
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// edge case: trailing newlines aren't counted towards height calculations, so
|
|
729
|
+
// we add a mock "I" character
|
|
730
|
+
if (currentStr.length > 0) {
|
|
731
|
+
unichar lastChar =
|
|
732
|
+
[currentStr.string characterAtIndex:currentStr.length - 1];
|
|
733
|
+
if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastChar]) {
|
|
734
|
+
[currentStr
|
|
735
|
+
appendAttributedString:[[NSAttributedString alloc]
|
|
736
|
+
initWithString:@"I"
|
|
737
|
+
attributes:defaultTypingAttributes]];
|
|
570
738
|
}
|
|
571
739
|
}
|
|
572
|
-
|
|
573
|
-
CGRect boundingBox =
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
740
|
+
|
|
741
|
+
CGRect boundingBox =
|
|
742
|
+
[currentStr boundingRectWithSize:CGSizeMake(maxWidth, CGFLOAT_MAX)
|
|
743
|
+
options:NSStringDrawingUsesLineFragmentOrigin |
|
|
744
|
+
NSStringDrawingUsesFontLeading
|
|
745
|
+
context:nullptr];
|
|
746
|
+
|
|
579
747
|
return CGSizeMake(maxWidth, ceil(boundingBox.size.height));
|
|
580
748
|
}
|
|
581
749
|
|
|
582
750
|
// make sure the newest state is kept in _state property
|
|
583
|
-
- (void)updateState:(State::Shared const &)state
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
751
|
+
- (void)updateState:(State::Shared const &)state
|
|
752
|
+
oldState:(State::Shared const &)oldState {
|
|
753
|
+
_state = std::static_pointer_cast<
|
|
754
|
+
const EnrichedTextInputViewShadowNode::ConcreteState>(state);
|
|
755
|
+
|
|
756
|
+
// first render with all the needed stuff already defined (state and
|
|
757
|
+
// componentView) so we need to run a single height calculation for any
|
|
758
|
+
// initial values
|
|
759
|
+
if (oldState == nullptr) {
|
|
589
760
|
[self tryUpdatingHeight];
|
|
590
761
|
}
|
|
591
762
|
}
|
|
592
763
|
|
|
593
764
|
- (void)tryUpdatingHeight {
|
|
594
|
-
if(_state == nullptr) {
|
|
765
|
+
if (_state == nullptr) {
|
|
595
766
|
return;
|
|
596
767
|
}
|
|
597
768
|
_componentViewHeightUpdateCounter++;
|
|
598
769
|
auto selfRef = wrapManagedObjectWeakly(self);
|
|
599
|
-
_state->updateState(
|
|
770
|
+
_state->updateState(
|
|
771
|
+
EnrichedTextInputViewState(_componentViewHeightUpdateCounter, selfRef));
|
|
600
772
|
}
|
|
601
773
|
|
|
602
774
|
// MARK: - Active styles
|
|
603
775
|
|
|
604
776
|
- (void)tryUpdatingActiveStyles {
|
|
605
|
-
// style updates are emitted only if something differs from the previously
|
|
777
|
+
// style updates are emitted only if something differs from the previously
|
|
778
|
+
// active styles
|
|
606
779
|
BOOL updateNeeded = NO;
|
|
607
|
-
|
|
608
|
-
// active styles are kept in a separate set until we're sure they can be
|
|
780
|
+
|
|
781
|
+
// active styles are kept in a separate set until we're sure they can be
|
|
782
|
+
// emitted
|
|
609
783
|
NSMutableSet *newActiveStyles = [_activeStyles mutableCopy];
|
|
610
|
-
|
|
784
|
+
|
|
611
785
|
// data for onLinkDetected event
|
|
612
786
|
LinkData *detectedLinkData;
|
|
613
787
|
NSRange detectedLinkRange = NSMakeRange(0, 0);
|
|
614
|
-
|
|
788
|
+
|
|
615
789
|
// data for onMentionDetected event
|
|
616
790
|
MentionParams *detectedMentionParams;
|
|
617
791
|
NSRange detectedMentionRange = NSMakeRange(0, 0);
|
|
618
792
|
|
|
619
|
-
for (NSNumber*
|
|
793
|
+
for (NSNumber *type in stylesDict) {
|
|
620
794
|
id<BaseStyleProtocol> style = stylesDict[type];
|
|
621
|
-
BOOL wasActive = [newActiveStyles containsObject:
|
|
795
|
+
BOOL wasActive = [newActiveStyles containsObject:type];
|
|
622
796
|
BOOL isActive = [style detectStyle:textView.selectedRange];
|
|
623
|
-
if(wasActive != isActive) {
|
|
797
|
+
if (wasActive != isActive) {
|
|
624
798
|
updateNeeded = YES;
|
|
625
|
-
if(isActive) {
|
|
799
|
+
if (isActive) {
|
|
626
800
|
[newActiveStyles addObject:type];
|
|
627
801
|
} else {
|
|
628
802
|
[newActiveStyles removeObject:type];
|
|
629
803
|
}
|
|
630
804
|
}
|
|
631
|
-
|
|
805
|
+
|
|
632
806
|
// onLinkDetected event
|
|
633
|
-
if(isActive && [type intValue] == [LinkStyle getStyleType]) {
|
|
807
|
+
if (isActive && [type intValue] == [LinkStyle getStyleType]) {
|
|
634
808
|
// get the link data
|
|
635
809
|
LinkData *candidateLinkData;
|
|
636
810
|
NSRange candidateLinkRange = NSMakeRange(0, 0);
|
|
637
|
-
LinkStyle *linkStyleClass =
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
811
|
+
LinkStyle *linkStyleClass =
|
|
812
|
+
(LinkStyle *)stylesDict[@([LinkStyle getStyleType])];
|
|
813
|
+
if (linkStyleClass != nullptr) {
|
|
814
|
+
candidateLinkData =
|
|
815
|
+
[linkStyleClass getLinkDataAt:textView.selectedRange.location];
|
|
816
|
+
candidateLinkRange =
|
|
817
|
+
[linkStyleClass getFullLinkRangeAt:textView.selectedRange.location];
|
|
641
818
|
}
|
|
642
|
-
|
|
643
|
-
if(wasActive == NO) {
|
|
819
|
+
|
|
820
|
+
if (wasActive == NO) {
|
|
644
821
|
// we changed selection from non-link to a link
|
|
645
822
|
detectedLinkData = candidateLinkData;
|
|
646
823
|
detectedLinkRange = candidateLinkRange;
|
|
647
|
-
} else if(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
// we changed selection from one link to the other or modified current
|
|
824
|
+
} else if (![_recentlyActiveLinkData.url
|
|
825
|
+
isEqualToString:candidateLinkData.url] ||
|
|
826
|
+
![_recentlyActiveLinkData.text
|
|
827
|
+
isEqualToString:candidateLinkData.text] ||
|
|
828
|
+
!NSEqualRanges(_recentlyActiveLinkRange, candidateLinkRange)) {
|
|
829
|
+
// we changed selection from one link to the other or modified current
|
|
830
|
+
// link's text
|
|
653
831
|
detectedLinkData = candidateLinkData;
|
|
654
832
|
detectedLinkRange = candidateLinkRange;
|
|
655
833
|
}
|
|
656
834
|
}
|
|
657
|
-
|
|
835
|
+
|
|
658
836
|
// onMentionDetected event
|
|
659
|
-
if(isActive && [type intValue] == [MentionStyle getStyleType]) {
|
|
837
|
+
if (isActive && [type intValue] == [MentionStyle getStyleType]) {
|
|
660
838
|
// get mention data
|
|
661
839
|
MentionParams *candidateMentionParams;
|
|
662
840
|
NSRange candidateMentionRange = NSMakeRange(0, 0);
|
|
663
|
-
MentionStyle *mentionStyleClass =
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
841
|
+
MentionStyle *mentionStyleClass =
|
|
842
|
+
(MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
|
|
843
|
+
if (mentionStyleClass != nullptr) {
|
|
844
|
+
candidateMentionParams = [mentionStyleClass
|
|
845
|
+
getMentionParamsAt:textView.selectedRange.location];
|
|
846
|
+
candidateMentionRange = [mentionStyleClass
|
|
847
|
+
getFullMentionRangeAt:textView.selectedRange.location];
|
|
667
848
|
}
|
|
668
|
-
|
|
669
|
-
if(wasActive == NO) {
|
|
849
|
+
|
|
850
|
+
if (wasActive == NO) {
|
|
670
851
|
// selection was changed from a non-mention to a mention
|
|
671
852
|
detectedMentionParams = candidateMentionParams;
|
|
672
853
|
detectedMentionRange = candidateMentionRange;
|
|
673
|
-
} else if(
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
854
|
+
} else if (![_recentlyActiveMentionParams.text
|
|
855
|
+
isEqualToString:candidateMentionParams.text] ||
|
|
856
|
+
![_recentlyActiveMentionParams.attributes
|
|
857
|
+
isEqualToString:candidateMentionParams.attributes] ||
|
|
858
|
+
!NSEqualRanges(_recentlyActiveMentionRange,
|
|
859
|
+
candidateMentionRange)) {
|
|
678
860
|
// selection changed from one mention to another
|
|
679
861
|
detectedMentionParams = candidateMentionParams;
|
|
680
862
|
detectedMentionRange = candidateMentionRange;
|
|
681
863
|
}
|
|
682
864
|
}
|
|
683
865
|
}
|
|
684
|
-
|
|
685
|
-
if(updateNeeded) {
|
|
866
|
+
|
|
867
|
+
if (updateNeeded) {
|
|
686
868
|
auto emitter = [self getEventEmitter];
|
|
687
|
-
if(emitter != nullptr) {
|
|
869
|
+
if (emitter != nullptr) {
|
|
688
870
|
// update activeStyles only if emitter is available
|
|
689
871
|
_activeStyles = newActiveStyles;
|
|
690
|
-
|
|
872
|
+
|
|
691
873
|
emitter->onChangeState({
|
|
692
|
-
.isBold = [_activeStyles containsObject
|
|
693
|
-
.isItalic =
|
|
694
|
-
|
|
695
|
-
.
|
|
696
|
-
|
|
697
|
-
.
|
|
698
|
-
|
|
699
|
-
.
|
|
700
|
-
|
|
701
|
-
.
|
|
702
|
-
.
|
|
703
|
-
|
|
704
|
-
.
|
|
705
|
-
.
|
|
706
|
-
.
|
|
874
|
+
.isBold = [_activeStyles containsObject:@([BoldStyle getStyleType])],
|
|
875
|
+
.isItalic =
|
|
876
|
+
[_activeStyles containsObject:@([ItalicStyle getStyleType])],
|
|
877
|
+
.isUnderline =
|
|
878
|
+
[_activeStyles containsObject:@([UnderlineStyle getStyleType])],
|
|
879
|
+
.isStrikeThrough =
|
|
880
|
+
[_activeStyles containsObject:@([StrikethroughStyle getStyleType])],
|
|
881
|
+
.isInlineCode =
|
|
882
|
+
[_activeStyles containsObject:@([InlineCodeStyle getStyleType])],
|
|
883
|
+
.isLink = [_activeStyles containsObject:@([LinkStyle getStyleType])],
|
|
884
|
+
.isMention =
|
|
885
|
+
[_activeStyles containsObject:@([MentionStyle getStyleType])],
|
|
886
|
+
.isH1 = [_activeStyles containsObject:@([H1Style getStyleType])],
|
|
887
|
+
.isH2 = [_activeStyles containsObject:@([H2Style getStyleType])],
|
|
888
|
+
.isH3 = [_activeStyles containsObject:@([H3Style getStyleType])],
|
|
889
|
+
.isUnorderedList =
|
|
890
|
+
[_activeStyles containsObject:@([UnorderedListStyle getStyleType])],
|
|
891
|
+
.isOrderedList =
|
|
892
|
+
[_activeStyles containsObject:@([OrderedListStyle getStyleType])],
|
|
893
|
+
.isBlockQuote =
|
|
894
|
+
[_activeStyles containsObject:@([BlockQuoteStyle getStyleType])],
|
|
895
|
+
.isCodeBlock =
|
|
896
|
+
[_activeStyles containsObject:@([CodeBlockStyle getStyleType])],
|
|
897
|
+
.isImage = [_activeStyles containsObject:@([ImageStyle getStyleType])],
|
|
707
898
|
});
|
|
708
899
|
}
|
|
709
900
|
}
|
|
710
|
-
|
|
711
|
-
if(detectedLinkData != nullptr) {
|
|
901
|
+
|
|
902
|
+
if (detectedLinkData != nullptr) {
|
|
712
903
|
// emit onLinkeDetected event
|
|
713
|
-
[self emitOnLinkDetectedEvent:detectedLinkData.text
|
|
904
|
+
[self emitOnLinkDetectedEvent:detectedLinkData.text
|
|
905
|
+
url:detectedLinkData.url
|
|
906
|
+
range:detectedLinkRange];
|
|
714
907
|
}
|
|
715
|
-
|
|
716
|
-
if(detectedMentionParams != nullptr) {
|
|
908
|
+
|
|
909
|
+
if (detectedMentionParams != nullptr) {
|
|
717
910
|
// emit onMentionDetected event
|
|
718
|
-
[self emitOnMentionDetectedEvent:detectedMentionParams.text
|
|
719
|
-
|
|
911
|
+
[self emitOnMentionDetectedEvent:detectedMentionParams.text
|
|
912
|
+
indicator:detectedMentionParams.indicator
|
|
913
|
+
attributes:detectedMentionParams.attributes];
|
|
914
|
+
|
|
720
915
|
_recentlyActiveMentionParams = detectedMentionParams;
|
|
721
916
|
_recentlyActiveMentionRange = detectedMentionRange;
|
|
722
917
|
}
|
|
723
|
-
|
|
918
|
+
|
|
724
919
|
// emit onChangeHtml event if needed
|
|
725
920
|
[self tryEmittingOnChangeHtmlEvent];
|
|
726
921
|
}
|
|
@@ -728,55 +923,67 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
728
923
|
// MARK: - Native commands and events
|
|
729
924
|
|
|
730
925
|
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
|
|
731
|
-
if([commandName isEqualToString:@"focus"]) {
|
|
926
|
+
if ([commandName isEqualToString:@"focus"]) {
|
|
732
927
|
[self focus];
|
|
733
|
-
} else if([commandName isEqualToString:@"blur"]) {
|
|
928
|
+
} else if ([commandName isEqualToString:@"blur"]) {
|
|
734
929
|
[self blur];
|
|
735
|
-
} else if([commandName isEqualToString:@"setValue"]) {
|
|
930
|
+
} else if ([commandName isEqualToString:@"setValue"]) {
|
|
736
931
|
NSString *value = (NSString *)args[0];
|
|
737
932
|
[self setValue:value];
|
|
738
|
-
} else if([commandName isEqualToString:@"toggleBold"]) {
|
|
739
|
-
[self toggleRegularStyle:
|
|
740
|
-
} else if([commandName isEqualToString:@"toggleItalic"]) {
|
|
741
|
-
[self toggleRegularStyle:
|
|
742
|
-
} else if([commandName isEqualToString:@"toggleUnderline"]) {
|
|
743
|
-
[self toggleRegularStyle:
|
|
744
|
-
} else if([commandName isEqualToString:@"toggleStrikeThrough"]) {
|
|
745
|
-
[self toggleRegularStyle:
|
|
746
|
-
} else if([commandName isEqualToString:@"toggleInlineCode"]) {
|
|
747
|
-
[self toggleRegularStyle:
|
|
748
|
-
} else if([commandName isEqualToString:@"addLink"]) {
|
|
749
|
-
NSInteger start = [((NSNumber*)args[0]) integerValue];
|
|
750
|
-
NSInteger end = [((NSNumber*)args[1]) integerValue];
|
|
933
|
+
} else if ([commandName isEqualToString:@"toggleBold"]) {
|
|
934
|
+
[self toggleRegularStyle:[BoldStyle getStyleType]];
|
|
935
|
+
} else if ([commandName isEqualToString:@"toggleItalic"]) {
|
|
936
|
+
[self toggleRegularStyle:[ItalicStyle getStyleType]];
|
|
937
|
+
} else if ([commandName isEqualToString:@"toggleUnderline"]) {
|
|
938
|
+
[self toggleRegularStyle:[UnderlineStyle getStyleType]];
|
|
939
|
+
} else if ([commandName isEqualToString:@"toggleStrikeThrough"]) {
|
|
940
|
+
[self toggleRegularStyle:[StrikethroughStyle getStyleType]];
|
|
941
|
+
} else if ([commandName isEqualToString:@"toggleInlineCode"]) {
|
|
942
|
+
[self toggleRegularStyle:[InlineCodeStyle getStyleType]];
|
|
943
|
+
} else if ([commandName isEqualToString:@"addLink"]) {
|
|
944
|
+
NSInteger start = [((NSNumber *)args[0]) integerValue];
|
|
945
|
+
NSInteger end = [((NSNumber *)args[1]) integerValue];
|
|
751
946
|
NSString *text = (NSString *)args[2];
|
|
752
947
|
NSString *url = (NSString *)args[3];
|
|
753
948
|
[self addLinkAt:start end:end text:text url:url];
|
|
754
|
-
} else if([commandName isEqualToString:@"addMention"]) {
|
|
949
|
+
} else if ([commandName isEqualToString:@"addMention"]) {
|
|
755
950
|
NSString *indicator = (NSString *)args[0];
|
|
756
951
|
NSString *text = (NSString *)args[1];
|
|
757
952
|
NSString *attributes = (NSString *)args[2];
|
|
758
953
|
[self addMention:indicator text:text attributes:attributes];
|
|
759
|
-
} else if([commandName isEqualToString:@"startMention"]) {
|
|
954
|
+
} else if ([commandName isEqualToString:@"startMention"]) {
|
|
760
955
|
NSString *indicator = (NSString *)args[0];
|
|
761
956
|
[self startMentionWithIndicator:indicator];
|
|
762
|
-
} else if([commandName isEqualToString:@"toggleH1"]) {
|
|
957
|
+
} else if ([commandName isEqualToString:@"toggleH1"]) {
|
|
763
958
|
[self toggleParagraphStyle:[H1Style getStyleType]];
|
|
764
|
-
} else if([commandName isEqualToString:@"toggleH2"]) {
|
|
959
|
+
} else if ([commandName isEqualToString:@"toggleH2"]) {
|
|
765
960
|
[self toggleParagraphStyle:[H2Style getStyleType]];
|
|
766
|
-
} else if([commandName isEqualToString:@"toggleH3"]) {
|
|
961
|
+
} else if ([commandName isEqualToString:@"toggleH3"]) {
|
|
767
962
|
[self toggleParagraphStyle:[H3Style getStyleType]];
|
|
768
|
-
} else if([commandName isEqualToString:@"toggleUnorderedList"]) {
|
|
963
|
+
} else if ([commandName isEqualToString:@"toggleUnorderedList"]) {
|
|
769
964
|
[self toggleParagraphStyle:[UnorderedListStyle getStyleType]];
|
|
770
|
-
} else if([commandName isEqualToString:@"toggleOrderedList"]) {
|
|
965
|
+
} else if ([commandName isEqualToString:@"toggleOrderedList"]) {
|
|
771
966
|
[self toggleParagraphStyle:[OrderedListStyle getStyleType]];
|
|
772
|
-
} else if([commandName isEqualToString:@"toggleBlockQuote"]) {
|
|
967
|
+
} else if ([commandName isEqualToString:@"toggleBlockQuote"]) {
|
|
773
968
|
[self toggleParagraphStyle:[BlockQuoteStyle getStyleType]];
|
|
969
|
+
} else if ([commandName isEqualToString:@"toggleCodeBlock"]) {
|
|
970
|
+
[self toggleParagraphStyle:[CodeBlockStyle getStyleType]];
|
|
971
|
+
} else if ([commandName isEqualToString:@"addImage"]) {
|
|
972
|
+
NSString *uri = (NSString *)args[0];
|
|
973
|
+
CGFloat imgWidth = [(NSNumber *)args[1] floatValue];
|
|
974
|
+
CGFloat imgHeight = [(NSNumber *)args[2] floatValue];
|
|
975
|
+
|
|
976
|
+
[self addImage:uri width:imgWidth height:imgHeight];
|
|
977
|
+
} else if ([commandName isEqualToString:@"requestHTML"]) {
|
|
978
|
+
NSInteger requestId = [((NSNumber *)args[0]) integerValue];
|
|
979
|
+
[self requestHTML:requestId];
|
|
774
980
|
}
|
|
775
981
|
}
|
|
776
982
|
|
|
777
983
|
- (std::shared_ptr<EnrichedTextInputViewEventEmitter>)getEventEmitter {
|
|
778
|
-
if(_eventEmitter != nullptr && !blockEmitting) {
|
|
779
|
-
auto emitter =
|
|
984
|
+
if (_eventEmitter != nullptr && !blockEmitting) {
|
|
985
|
+
auto emitter =
|
|
986
|
+
static_cast<const EnrichedTextInputViewEventEmitter &>(*_eventEmitter);
|
|
780
987
|
return std::make_shared<EnrichedTextInputViewEventEmitter>(emitter);
|
|
781
988
|
} else {
|
|
782
989
|
return nullptr;
|
|
@@ -793,81 +1000,93 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
793
1000
|
|
|
794
1001
|
- (void)setValue:(NSString *)value {
|
|
795
1002
|
NSString *initiallyProcessedHtml = [parser initiallyProcessHtml:value];
|
|
796
|
-
if(initiallyProcessedHtml == nullptr) {
|
|
1003
|
+
if (initiallyProcessedHtml == nullptr) {
|
|
797
1004
|
// just plain text
|
|
798
1005
|
textView.text = value;
|
|
799
1006
|
} else {
|
|
800
1007
|
// we've got some seemingly proper html
|
|
801
1008
|
[parser replaceWholeFromHtml:initiallyProcessedHtml];
|
|
802
1009
|
}
|
|
803
|
-
|
|
1010
|
+
|
|
804
1011
|
// set recentlyChangedRange and check for changes
|
|
805
1012
|
recentlyChangedRange = NSMakeRange(0, textView.textStorage.string.length);
|
|
806
1013
|
[self anyTextMayHaveBeenModified];
|
|
807
1014
|
}
|
|
808
1015
|
|
|
809
|
-
- (void)emitOnLinkDetectedEvent:(NSString *)text
|
|
1016
|
+
- (void)emitOnLinkDetectedEvent:(NSString *)text
|
|
1017
|
+
url:(NSString *)url
|
|
1018
|
+
range:(NSRange)range {
|
|
810
1019
|
auto emitter = [self getEventEmitter];
|
|
811
|
-
if(emitter != nullptr) {
|
|
1020
|
+
if (emitter != nullptr) {
|
|
812
1021
|
// update recently active link info
|
|
813
1022
|
LinkData *newLinkData = [[LinkData alloc] init];
|
|
814
1023
|
newLinkData.text = text;
|
|
815
1024
|
newLinkData.url = url;
|
|
816
1025
|
_recentlyActiveLinkData = newLinkData;
|
|
817
1026
|
_recentlyActiveLinkRange = range;
|
|
818
|
-
|
|
1027
|
+
|
|
819
1028
|
emitter->onLinkDetected({
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1029
|
+
.text = [text toCppString],
|
|
1030
|
+
.url = [url toCppString],
|
|
1031
|
+
.start = static_cast<int>(range.location),
|
|
1032
|
+
.end = static_cast<int>(range.location + range.length),
|
|
824
1033
|
});
|
|
825
1034
|
}
|
|
826
1035
|
}
|
|
827
1036
|
|
|
828
|
-
- (void)emitOnMentionDetectedEvent:(NSString *)text
|
|
1037
|
+
- (void)emitOnMentionDetectedEvent:(NSString *)text
|
|
1038
|
+
indicator:(NSString *)indicator
|
|
1039
|
+
attributes:(NSString *)attributes {
|
|
829
1040
|
auto emitter = [self getEventEmitter];
|
|
830
|
-
if(emitter != nullptr) {
|
|
831
|
-
emitter->onMentionDetected({
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
.payload = [attributes toCppString]
|
|
835
|
-
});
|
|
1041
|
+
if (emitter != nullptr) {
|
|
1042
|
+
emitter->onMentionDetected({.text = [text toCppString],
|
|
1043
|
+
.indicator = [indicator toCppString],
|
|
1044
|
+
.payload = [attributes toCppString]});
|
|
836
1045
|
}
|
|
837
1046
|
}
|
|
838
1047
|
|
|
839
1048
|
- (void)emitOnMentionEvent:(NSString *)indicator text:(NSString *)text {
|
|
840
1049
|
auto emitter = [self getEventEmitter];
|
|
841
|
-
if(emitter != nullptr) {
|
|
842
|
-
if(text != nullptr) {
|
|
1050
|
+
if (emitter != nullptr) {
|
|
1051
|
+
if (text != nullptr) {
|
|
843
1052
|
folly::dynamic fdStr = [text toCppString];
|
|
844
|
-
emitter->onMention({
|
|
845
|
-
.indicator = [indicator toCppString],
|
|
846
|
-
.text = fdStr
|
|
847
|
-
});
|
|
1053
|
+
emitter->onMention({.indicator = [indicator toCppString], .text = fdStr});
|
|
848
1054
|
} else {
|
|
849
1055
|
folly::dynamic nul = nullptr;
|
|
850
|
-
emitter->onMention({
|
|
851
|
-
.indicator = [indicator toCppString],
|
|
852
|
-
.text = nul
|
|
853
|
-
});
|
|
1056
|
+
emitter->onMention({.indicator = [indicator toCppString], .text = nul});
|
|
854
1057
|
}
|
|
855
1058
|
}
|
|
856
1059
|
}
|
|
857
1060
|
|
|
858
1061
|
- (void)tryEmittingOnChangeHtmlEvent {
|
|
859
|
-
if(!_emitHtml || textView.markedTextRange != nullptr) {
|
|
1062
|
+
if (!_emitHtml || textView.markedTextRange != nullptr) {
|
|
860
1063
|
return;
|
|
861
1064
|
}
|
|
862
1065
|
auto emitter = [self getEventEmitter];
|
|
863
|
-
if(emitter != nullptr) {
|
|
864
|
-
NSString *htmlOutput = [parser
|
|
1066
|
+
if (emitter != nullptr) {
|
|
1067
|
+
NSString *htmlOutput = [parser
|
|
1068
|
+
parseToHtmlFromRange:NSMakeRange(0,
|
|
1069
|
+
textView.textStorage.string.length)];
|
|
865
1070
|
// make sure html really changed
|
|
866
|
-
if(![htmlOutput isEqualToString:_recentlyEmittedHtml]) {
|
|
1071
|
+
if (![htmlOutput isEqualToString:_recentlyEmittedHtml]) {
|
|
867
1072
|
_recentlyEmittedHtml = htmlOutput;
|
|
868
|
-
emitter->onChangeHtml({
|
|
869
|
-
|
|
870
|
-
|
|
1073
|
+
emitter->onChangeHtml({.value = [htmlOutput toCppString]});
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
- (void)requestHTML:(NSInteger)requestId {
|
|
1079
|
+
auto emitter = [self getEventEmitter];
|
|
1080
|
+
if (emitter != nullptr) {
|
|
1081
|
+
@try {
|
|
1082
|
+
NSString *htmlOutput = [parser
|
|
1083
|
+
parseToHtmlFromRange:NSMakeRange(0,
|
|
1084
|
+
textView.textStorage.string.length)];
|
|
1085
|
+
emitter->onRequestHtmlResult({.requestId = static_cast<int>(requestId),
|
|
1086
|
+
.html = [htmlOutput toCppString]});
|
|
1087
|
+
} @catch (NSException *exception) {
|
|
1088
|
+
emitter->onRequestHtmlResult({.requestId = static_cast<int>(requestId),
|
|
1089
|
+
.html = folly::dynamic(nullptr)});
|
|
871
1090
|
}
|
|
872
1091
|
}
|
|
873
1092
|
}
|
|
@@ -876,8 +1095,8 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
876
1095
|
|
|
877
1096
|
- (void)toggleRegularStyle:(StyleType)type {
|
|
878
1097
|
id<BaseStyleProtocol> styleClass = stylesDict[@(type)];
|
|
879
|
-
|
|
880
|
-
if([self handleStyleBlocksAndConflicts:type range:textView.selectedRange]) {
|
|
1098
|
+
|
|
1099
|
+
if ([self handleStyleBlocksAndConflicts:type range:textView.selectedRange]) {
|
|
881
1100
|
[styleClass applyStyle:textView.selectedRange];
|
|
882
1101
|
[self anyTextMayHaveBeenModified];
|
|
883
1102
|
}
|
|
@@ -886,42 +1105,82 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
886
1105
|
- (void)toggleParagraphStyle:(StyleType)type {
|
|
887
1106
|
id<BaseStyleProtocol> styleClass = stylesDict[@(type)];
|
|
888
1107
|
// we always pass whole paragraph/s range to these styles
|
|
889
|
-
NSRange paragraphRange = [textView.textStorage.string
|
|
890
|
-
|
|
891
|
-
|
|
1108
|
+
NSRange paragraphRange = [textView.textStorage.string
|
|
1109
|
+
paragraphRangeForRange:textView.selectedRange];
|
|
1110
|
+
|
|
1111
|
+
if ([self handleStyleBlocksAndConflicts:type range:paragraphRange]) {
|
|
892
1112
|
[styleClass applyStyle:paragraphRange];
|
|
893
1113
|
[self anyTextMayHaveBeenModified];
|
|
894
1114
|
}
|
|
895
1115
|
}
|
|
896
1116
|
|
|
897
|
-
- (void)addLinkAt:(NSInteger)start
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1117
|
+
- (void)addLinkAt:(NSInteger)start
|
|
1118
|
+
end:(NSInteger)end
|
|
1119
|
+
text:(NSString *)text
|
|
1120
|
+
url:(NSString *)url {
|
|
1121
|
+
LinkStyle *linkStyleClass =
|
|
1122
|
+
(LinkStyle *)stylesDict[@([LinkStyle getStyleType])];
|
|
1123
|
+
if (linkStyleClass == nullptr) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
901
1127
|
// translate the output start-end notation to range
|
|
902
1128
|
NSRange linkRange = NSMakeRange(start, end - start);
|
|
903
|
-
if([self handleStyleBlocksAndConflicts:[LinkStyle getStyleType]
|
|
904
|
-
|
|
1129
|
+
if ([self handleStyleBlocksAndConflicts:[LinkStyle getStyleType]
|
|
1130
|
+
range:linkRange]) {
|
|
1131
|
+
[linkStyleClass addLink:text
|
|
1132
|
+
url:url
|
|
1133
|
+
range:linkRange
|
|
1134
|
+
manual:YES
|
|
1135
|
+
withSelection:YES];
|
|
905
1136
|
[self anyTextMayHaveBeenModified];
|
|
906
1137
|
}
|
|
907
1138
|
}
|
|
908
1139
|
|
|
909
|
-
- (void)addMention:(NSString *)indicator
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if(
|
|
1140
|
+
- (void)addMention:(NSString *)indicator
|
|
1141
|
+
text:(NSString *)text
|
|
1142
|
+
attributes:(NSString *)attributes {
|
|
1143
|
+
MentionStyle *mentionStyleClass =
|
|
1144
|
+
(MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
|
|
1145
|
+
if (mentionStyleClass == nullptr) {
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
if ([mentionStyleClass getActiveMentionRange] == nullptr) {
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
if ([self handleStyleBlocksAndConflicts:[MentionStyle getStyleType]
|
|
1153
|
+
range:[[mentionStyleClass
|
|
1154
|
+
getActiveMentionRange]
|
|
1155
|
+
rangeValue]]) {
|
|
915
1156
|
[mentionStyleClass addMention:indicator text:text attributes:attributes];
|
|
916
1157
|
[self anyTextMayHaveBeenModified];
|
|
917
1158
|
}
|
|
918
1159
|
}
|
|
919
1160
|
|
|
1161
|
+
- (void)addImage:(NSString *)uri width:(float)width height:(float)height {
|
|
1162
|
+
ImageStyle *imageStyleClass =
|
|
1163
|
+
(ImageStyle *)stylesDict[@([ImageStyle getStyleType])];
|
|
1164
|
+
if (imageStyleClass == nullptr) {
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
if ([self handleStyleBlocksAndConflicts:[ImageStyle getStyleType]
|
|
1169
|
+
range:textView.selectedRange]) {
|
|
1170
|
+
[imageStyleClass addImage:uri width:width height:height];
|
|
1171
|
+
[self anyTextMayHaveBeenModified];
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
920
1175
|
- (void)startMentionWithIndicator:(NSString *)indicator {
|
|
921
|
-
MentionStyle *mentionStyleClass =
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1176
|
+
MentionStyle *mentionStyleClass =
|
|
1177
|
+
(MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
|
|
1178
|
+
if (mentionStyleClass == nullptr) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
if ([self handleStyleBlocksAndConflicts:[MentionStyle getStyleType]
|
|
1183
|
+
range:textView.selectedRange]) {
|
|
925
1184
|
[mentionStyleClass startMentionWithIndicator:indicator];
|
|
926
1185
|
[self anyTextMayHaveBeenModified];
|
|
927
1186
|
}
|
|
@@ -930,26 +1189,30 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
930
1189
|
// returns false when style shouldn't be applied and true when it can be
|
|
931
1190
|
- (BOOL)handleStyleBlocksAndConflicts:(StyleType)type range:(NSRange)range {
|
|
932
1191
|
// handle blocking styles: if any is present we do not apply the toggled style
|
|
933
|
-
NSArray<NSNumber *> *blocking =
|
|
934
|
-
|
|
1192
|
+
NSArray<NSNumber *> *blocking =
|
|
1193
|
+
[self getPresentStyleTypesFrom:blockingStyles[@(type)] range:range];
|
|
1194
|
+
if (blocking.count != 0) {
|
|
935
1195
|
return NO;
|
|
936
1196
|
}
|
|
937
|
-
|
|
1197
|
+
|
|
938
1198
|
// handle conflicting styles: all of their occurences have to be removed
|
|
939
|
-
NSArray<NSNumber *> *conflicting =
|
|
940
|
-
|
|
941
|
-
|
|
1199
|
+
NSArray<NSNumber *> *conflicting =
|
|
1200
|
+
[self getPresentStyleTypesFrom:conflictingStyles[@(type)] range:range];
|
|
1201
|
+
if (conflicting.count != 0) {
|
|
1202
|
+
for (NSNumber *style in conflicting) {
|
|
942
1203
|
id<BaseStyleProtocol> styleClass = stylesDict[style];
|
|
943
|
-
|
|
944
|
-
if(range.length >= 1) {
|
|
1204
|
+
|
|
1205
|
+
if (range.length >= 1) {
|
|
945
1206
|
// for ranges, we need to remove each occurence
|
|
946
|
-
NSArray<StylePair *> *allOccurences =
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1207
|
+
NSArray<StylePair *> *allOccurences =
|
|
1208
|
+
[styleClass findAllOccurences:range];
|
|
1209
|
+
|
|
1210
|
+
for (StylePair *pair in allOccurences) {
|
|
1211
|
+
[styleClass removeAttributes:[pair.rangeValue rangeValue]];
|
|
950
1212
|
}
|
|
951
1213
|
} else {
|
|
952
|
-
// with in-place selection, we just remove the adequate typing
|
|
1214
|
+
// with in-place selection, we just remove the adequate typing
|
|
1215
|
+
// attributes
|
|
953
1216
|
[styleClass removeTypingAttributes];
|
|
954
1217
|
}
|
|
955
1218
|
}
|
|
@@ -957,17 +1220,19 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
957
1220
|
return YES;
|
|
958
1221
|
}
|
|
959
1222
|
|
|
960
|
-
- (NSArray<NSNumber *> *)getPresentStyleTypesFrom:(NSArray<NSNumber *> *)types
|
|
961
|
-
|
|
962
|
-
|
|
1223
|
+
- (NSArray<NSNumber *> *)getPresentStyleTypesFrom:(NSArray<NSNumber *> *)types
|
|
1224
|
+
range:(NSRange)range {
|
|
1225
|
+
NSMutableArray<NSNumber *> *resultArray =
|
|
1226
|
+
[[NSMutableArray<NSNumber *> alloc] init];
|
|
1227
|
+
for (NSNumber *type in types) {
|
|
963
1228
|
id<BaseStyleProtocol> styleClass = stylesDict[type];
|
|
964
|
-
|
|
965
|
-
if(range.length >= 1) {
|
|
966
|
-
if([styleClass anyOccurence:range]) {
|
|
1229
|
+
|
|
1230
|
+
if (range.length >= 1) {
|
|
1231
|
+
if ([styleClass anyOccurence:range]) {
|
|
967
1232
|
[resultArray addObject:type];
|
|
968
1233
|
}
|
|
969
1234
|
} else {
|
|
970
|
-
if([styleClass detectStyle:range]) {
|
|
1235
|
+
if ([styleClass detectStyle:range]) {
|
|
971
1236
|
[resultArray addObject:type];
|
|
972
1237
|
}
|
|
973
1238
|
}
|
|
@@ -977,43 +1242,58 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
977
1242
|
|
|
978
1243
|
- (void)manageSelectionBasedChanges {
|
|
979
1244
|
// link typing attributes fix
|
|
980
|
-
LinkStyle *linkStyleClass =
|
|
981
|
-
|
|
1245
|
+
LinkStyle *linkStyleClass =
|
|
1246
|
+
(LinkStyle *)stylesDict[@([LinkStyle getStyleType])];
|
|
1247
|
+
if (linkStyleClass != nullptr) {
|
|
982
1248
|
[linkStyleClass manageLinkTypingAttributes];
|
|
983
1249
|
}
|
|
984
|
-
|
|
1250
|
+
|
|
985
1251
|
// mention typing attribtues fix and active editing
|
|
986
|
-
MentionStyle *mentionStyleClass =
|
|
987
|
-
|
|
1252
|
+
MentionStyle *mentionStyleClass =
|
|
1253
|
+
(MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
|
|
1254
|
+
if (mentionStyleClass != nullptr) {
|
|
988
1255
|
[mentionStyleClass manageMentionTypingAttributes];
|
|
989
|
-
|
|
1256
|
+
|
|
1257
|
+
// mention editing runs if only a selection was done (no text change)
|
|
1258
|
+
// otherwise we would double-emit with a second call in the
|
|
1259
|
+
// anyTextMayHaveBeenModified method
|
|
1260
|
+
if ([_recentInputString
|
|
1261
|
+
isEqualToString:[textView.textStorage.string copy]]) {
|
|
1262
|
+
[mentionStyleClass manageMentionEditing];
|
|
1263
|
+
}
|
|
990
1264
|
}
|
|
991
|
-
|
|
1265
|
+
|
|
992
1266
|
// typing attributes for empty lines selection reset
|
|
993
1267
|
NSString *currentString = [textView.textStorage.string copy];
|
|
994
|
-
if(textView.selectedRange.length == 0 &&
|
|
1268
|
+
if (textView.selectedRange.length == 0 &&
|
|
1269
|
+
[_recentInputString isEqualToString:currentString]) {
|
|
995
1270
|
// no string change means only a selection changed with no character changes
|
|
996
|
-
NSRange paragraphRange = [textView.textStorage.string
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1271
|
+
NSRange paragraphRange = [textView.textStorage.string
|
|
1272
|
+
paragraphRangeForRange:textView.selectedRange];
|
|
1273
|
+
if (paragraphRange.length == 0 ||
|
|
1274
|
+
(paragraphRange.length == 1 &&
|
|
1275
|
+
[[NSCharacterSet newlineCharacterSet]
|
|
1276
|
+
characterIsMember:[textView.textStorage.string
|
|
1277
|
+
characterAtIndex:paragraphRange
|
|
1278
|
+
.location]])) {
|
|
1002
1279
|
// user changed selection to an empty line (or empty line with a newline)
|
|
1003
1280
|
// typing attributes need to be reset
|
|
1004
1281
|
textView.typingAttributes = defaultTypingAttributes;
|
|
1005
1282
|
}
|
|
1006
1283
|
}
|
|
1007
|
-
|
|
1284
|
+
|
|
1008
1285
|
// update active styles as well
|
|
1009
1286
|
[self tryUpdatingActiveStyles];
|
|
1010
1287
|
}
|
|
1011
1288
|
|
|
1012
|
-
- (void)handleWordModificationBasedChanges:(NSString*)word
|
|
1289
|
+
- (void)handleWordModificationBasedChanges:(NSString *)word
|
|
1290
|
+
inRange:(NSRange)range {
|
|
1013
1291
|
// manual links refreshing and automatic links detection handling
|
|
1014
|
-
LinkStyle*
|
|
1015
|
-
|
|
1016
|
-
|
|
1292
|
+
LinkStyle *linkStyle = [stylesDict objectForKey:@([LinkStyle getStyleType])];
|
|
1293
|
+
|
|
1294
|
+
if (linkStyle != nullptr) {
|
|
1295
|
+
// manual links need to be handled first because they can block automatic
|
|
1296
|
+
// links after being refreshed
|
|
1017
1297
|
[linkStyle handleManualLinks:word inRange:range];
|
|
1018
1298
|
[linkStyle handleAutomaticLinks:word inRange:range];
|
|
1019
1299
|
}
|
|
@@ -1021,85 +1301,98 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
1021
1301
|
|
|
1022
1302
|
- (void)anyTextMayHaveBeenModified {
|
|
1023
1303
|
// we don't do no text changes when working with iOS marked text
|
|
1024
|
-
if(textView.markedTextRange != nullptr) {
|
|
1304
|
+
if (textView.markedTextRange != nullptr) {
|
|
1025
1305
|
return;
|
|
1026
1306
|
}
|
|
1027
|
-
|
|
1307
|
+
|
|
1028
1308
|
// zero width space adding or removal
|
|
1029
1309
|
[ZeroWidthSpaceUtils handleZeroWidthSpacesInInput:self];
|
|
1030
|
-
|
|
1310
|
+
|
|
1031
1311
|
// emptying input typing attributes management
|
|
1032
|
-
if(textView.textStorage.string.length == 0 &&
|
|
1312
|
+
if (textView.textStorage.string.length == 0 &&
|
|
1313
|
+
_recentInputString.length > 0) {
|
|
1033
1314
|
// reset typing attribtues
|
|
1034
1315
|
textView.typingAttributes = defaultTypingAttributes;
|
|
1035
1316
|
}
|
|
1036
|
-
|
|
1317
|
+
|
|
1037
1318
|
// inline code on newlines fix
|
|
1038
1319
|
InlineCodeStyle *codeStyle = stylesDict[@([InlineCodeStyle getStyleType])];
|
|
1039
|
-
if(codeStyle != nullptr) {
|
|
1320
|
+
if (codeStyle != nullptr) {
|
|
1040
1321
|
[codeStyle handleNewlines];
|
|
1041
1322
|
}
|
|
1042
|
-
|
|
1323
|
+
|
|
1043
1324
|
// blockquote colors management
|
|
1044
1325
|
BlockQuoteStyle *bqStyle = stylesDict[@([BlockQuoteStyle getStyleType])];
|
|
1045
|
-
if(bqStyle != nullptr) {
|
|
1326
|
+
if (bqStyle != nullptr) {
|
|
1046
1327
|
[bqStyle manageBlockquoteColor];
|
|
1047
1328
|
}
|
|
1048
|
-
|
|
1329
|
+
|
|
1330
|
+
// codeblock font and color management
|
|
1331
|
+
CodeBlockStyle *codeBlockStyle = stylesDict[@([CodeBlockStyle getStyleType])];
|
|
1332
|
+
if (codeBlockStyle != nullptr) {
|
|
1333
|
+
[codeBlockStyle manageCodeBlockFontAndColor];
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1049
1336
|
// improper headings fix
|
|
1050
1337
|
H1Style *h1Style = stylesDict[@([H1Style getStyleType])];
|
|
1051
1338
|
H2Style *h2Style = stylesDict[@([H2Style getStyleType])];
|
|
1052
1339
|
H3Style *h3Style = stylesDict[@([H3Style getStyleType])];
|
|
1053
|
-
if(h1Style != nullptr && h2Style != nullptr && h3Style != nullptr) {
|
|
1340
|
+
if (h1Style != nullptr && h2Style != nullptr && h3Style != nullptr) {
|
|
1054
1341
|
[h1Style handleImproperHeadings];
|
|
1055
1342
|
[h2Style handleImproperHeadings];
|
|
1056
1343
|
[h3Style handleImproperHeadings];
|
|
1057
1344
|
}
|
|
1058
|
-
|
|
1059
|
-
// mentions removal
|
|
1060
|
-
MentionStyle *mentionStyleClass =
|
|
1061
|
-
|
|
1345
|
+
|
|
1346
|
+
// mentions management: removal and editing
|
|
1347
|
+
MentionStyle *mentionStyleClass =
|
|
1348
|
+
(MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
|
|
1349
|
+
if (mentionStyleClass != nullptr) {
|
|
1062
1350
|
[mentionStyleClass handleExistingMentions];
|
|
1351
|
+
[mentionStyleClass manageMentionEditing];
|
|
1063
1352
|
}
|
|
1064
|
-
|
|
1353
|
+
|
|
1065
1354
|
// placholder management
|
|
1066
|
-
if(!_placeholderLabel.hidden && textView.textStorage.string.length > 0) {
|
|
1355
|
+
if (!_placeholderLabel.hidden && textView.textStorage.string.length > 0) {
|
|
1067
1356
|
[self setPlaceholderLabelShown:NO];
|
|
1068
|
-
} else if(textView.textStorage.string.length == 0 &&
|
|
1357
|
+
} else if (textView.textStorage.string.length == 0 &&
|
|
1358
|
+
_placeholderLabel.hidden) {
|
|
1069
1359
|
[self setPlaceholderLabelShown:YES];
|
|
1070
1360
|
}
|
|
1071
|
-
|
|
1072
|
-
if(![textView.textStorage.string isEqualToString:
|
|
1361
|
+
|
|
1362
|
+
if (![textView.textStorage.string isEqualToString:_recentInputString]) {
|
|
1073
1363
|
// modified words handling
|
|
1074
|
-
NSArray *modifiedWords =
|
|
1075
|
-
|
|
1076
|
-
|
|
1364
|
+
NSArray *modifiedWords =
|
|
1365
|
+
[WordsUtils getAffectedWordsFromText:textView.textStorage.string
|
|
1366
|
+
modificationRange:recentlyChangedRange];
|
|
1367
|
+
if (modifiedWords != nullptr) {
|
|
1368
|
+
for (NSDictionary *wordDict in modifiedWords) {
|
|
1077
1369
|
NSString *wordText = (NSString *)[wordDict objectForKey:@"word"];
|
|
1078
1370
|
NSValue *wordRange = (NSValue *)[wordDict objectForKey:@"range"];
|
|
1079
|
-
|
|
1080
|
-
if(wordText == nullptr || wordRange == nullptr) {
|
|
1371
|
+
|
|
1372
|
+
if (wordText == nullptr || wordRange == nullptr) {
|
|
1081
1373
|
continue;
|
|
1082
1374
|
}
|
|
1083
|
-
|
|
1084
|
-
[self handleWordModificationBasedChanges:wordText
|
|
1375
|
+
|
|
1376
|
+
[self handleWordModificationBasedChanges:wordText
|
|
1377
|
+
inRange:[wordRange rangeValue]];
|
|
1085
1378
|
}
|
|
1086
1379
|
}
|
|
1087
|
-
|
|
1088
|
-
// emit string without zero width spaces
|
|
1089
|
-
NSString *stringToBeEmitted = [[textView.textStorage.string stringByReplacingOccurrencesOfString:@"\u200B" withString:@""] copy];
|
|
1090
|
-
|
|
1380
|
+
|
|
1091
1381
|
// emit onChangeText event
|
|
1092
1382
|
auto emitter = [self getEventEmitter];
|
|
1093
|
-
if(emitter != nullptr) {
|
|
1094
|
-
// set the
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1383
|
+
if (emitter != nullptr) {
|
|
1384
|
+
// set the recent input string only if the emitter is defined
|
|
1385
|
+
_recentInputString = [textView.textStorage.string copy];
|
|
1386
|
+
|
|
1387
|
+
// emit string without zero width spaces
|
|
1388
|
+
NSString *stringToBeEmitted = [[textView.textStorage.string
|
|
1389
|
+
stringByReplacingOccurrencesOfString:@"\u200B"
|
|
1390
|
+
withString:@""] copy];
|
|
1391
|
+
|
|
1392
|
+
emitter->onChangeText({.value = [stringToBeEmitted toCppString]});
|
|
1100
1393
|
}
|
|
1101
1394
|
}
|
|
1102
|
-
|
|
1395
|
+
|
|
1103
1396
|
// update height on each character change
|
|
1104
1397
|
[self tryUpdatingHeight];
|
|
1105
1398
|
// update active styles as well
|
|
@@ -1108,25 +1401,41 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
1108
1401
|
[self scheduleRelayoutIfNeeded];
|
|
1109
1402
|
}
|
|
1110
1403
|
|
|
1111
|
-
// Debounced relayout helper - coalesces multiple requests into one per runloop
|
|
1112
|
-
|
|
1113
|
-
{
|
|
1404
|
+
// Debounced relayout helper - coalesces multiple requests into one per runloop
|
|
1405
|
+
// tick
|
|
1406
|
+
- (void)scheduleRelayoutIfNeeded {
|
|
1114
1407
|
// Cancel any previously scheduled invocation to debounce
|
|
1115
|
-
[NSObject cancelPreviousPerformRequestsWithTarget:self
|
|
1408
|
+
[NSObject cancelPreviousPerformRequestsWithTarget:self
|
|
1409
|
+
selector:@selector(_performRelayout)
|
|
1410
|
+
object:nil];
|
|
1116
1411
|
// Schedule on next runloop cycle
|
|
1117
|
-
[self performSelector:@selector(_performRelayout)
|
|
1412
|
+
[self performSelector:@selector(_performRelayout)
|
|
1413
|
+
withObject:nil
|
|
1414
|
+
afterDelay:0];
|
|
1118
1415
|
}
|
|
1119
1416
|
|
|
1120
|
-
- (void)_performRelayout
|
|
1121
|
-
{
|
|
1122
|
-
|
|
1417
|
+
- (void)_performRelayout {
|
|
1418
|
+
if (!textView) {
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1123
1421
|
|
|
1124
1422
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1125
|
-
NSRange wholeRange =
|
|
1423
|
+
NSRange wholeRange =
|
|
1424
|
+
NSMakeRange(0, self->textView.textStorage.string.length);
|
|
1126
1425
|
NSRange actualRange = NSMakeRange(0, 0);
|
|
1127
|
-
[self->textView.layoutManager
|
|
1426
|
+
[self->textView.layoutManager
|
|
1427
|
+
invalidateLayoutForCharacterRange:wholeRange
|
|
1428
|
+
actualCharacterRange:&actualRange];
|
|
1128
1429
|
[self->textView.layoutManager ensureLayoutForCharacterRange:actualRange];
|
|
1129
|
-
[self->textView.layoutManager
|
|
1430
|
+
[self->textView.layoutManager
|
|
1431
|
+
invalidateDisplayForCharacterRange:wholeRange];
|
|
1432
|
+
|
|
1433
|
+
// We have to explicitly set contentSize
|
|
1434
|
+
// That way textView knows if content overflows and if should be scrollable
|
|
1435
|
+
// We recall measureSize here because value returned from previous
|
|
1436
|
+
// measureSize may not be up-to date at that point
|
|
1437
|
+
CGSize measuredSize = [self measureSize:self->textView.frame.size.width];
|
|
1438
|
+
self->textView.contentSize = measuredSize;
|
|
1130
1439
|
});
|
|
1131
1440
|
}
|
|
1132
1441
|
|
|
@@ -1140,60 +1449,79 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
1140
1449
|
|
|
1141
1450
|
- (void)textViewDidBeginEditing:(UITextView *)textView {
|
|
1142
1451
|
auto emitter = [self getEventEmitter];
|
|
1143
|
-
if(emitter != nullptr) {
|
|
1144
|
-
//send onFocus event if allowed
|
|
1145
|
-
if(_emitFocusBlur) {
|
|
1452
|
+
if (emitter != nullptr) {
|
|
1453
|
+
// send onFocus event if allowed
|
|
1454
|
+
if (_emitFocusBlur) {
|
|
1146
1455
|
emitter->onInputFocus({});
|
|
1147
1456
|
}
|
|
1148
|
-
|
|
1149
|
-
NSString *textAtSelection =
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1457
|
+
|
|
1458
|
+
NSString *textAtSelection =
|
|
1459
|
+
[[[NSMutableString alloc] initWithString:textView.textStorage.string]
|
|
1460
|
+
substringWithRange:textView.selectedRange];
|
|
1461
|
+
emitter->onChangeSelection(
|
|
1462
|
+
{.start = static_cast<int>(textView.selectedRange.location),
|
|
1463
|
+
.end = static_cast<int>(textView.selectedRange.location +
|
|
1464
|
+
textView.selectedRange.length),
|
|
1465
|
+
.text = [textAtSelection toCppString]});
|
|
1466
|
+
}
|
|
1467
|
+
// manage selection changes since textViewDidChangeSelection sometimes doesn't
|
|
1468
|
+
// run on focus
|
|
1157
1469
|
[self manageSelectionBasedChanges];
|
|
1158
1470
|
}
|
|
1159
1471
|
|
|
1160
1472
|
- (void)textViewDidEndEditing:(UITextView *)textView {
|
|
1161
1473
|
auto emitter = [self getEventEmitter];
|
|
1162
|
-
if(emitter != nullptr && _emitFocusBlur) {
|
|
1163
|
-
//send onBlur event
|
|
1474
|
+
if (emitter != nullptr && _emitFocusBlur) {
|
|
1475
|
+
// send onBlur event
|
|
1164
1476
|
emitter->onInputBlur({});
|
|
1165
1477
|
}
|
|
1166
1478
|
}
|
|
1167
1479
|
|
|
1168
|
-
- (bool)textView:(UITextView *)textView
|
|
1480
|
+
- (bool)textView:(UITextView *)textView
|
|
1481
|
+
shouldChangeTextInRange:(NSRange)range
|
|
1482
|
+
replacementText:(NSString *)text {
|
|
1169
1483
|
recentlyChangedRange = NSMakeRange(range.location, text.length);
|
|
1170
|
-
|
|
1484
|
+
|
|
1171
1485
|
UnorderedListStyle *uStyle = stylesDict[@([UnorderedListStyle getStyleType])];
|
|
1172
1486
|
OrderedListStyle *oStyle = stylesDict[@([OrderedListStyle getStyleType])];
|
|
1173
1487
|
BlockQuoteStyle *bqStyle = stylesDict[@([BlockQuoteStyle getStyleType])];
|
|
1488
|
+
CodeBlockStyle *cbStyle = stylesDict[@([CodeBlockStyle getStyleType])];
|
|
1174
1489
|
LinkStyle *linkStyle = stylesDict[@([LinkStyle getStyleType])];
|
|
1175
1490
|
MentionStyle *mentionStyle = stylesDict[@([MentionStyle getStyleType])];
|
|
1176
1491
|
H1Style *h1Style = stylesDict[@([H1Style getStyleType])];
|
|
1177
1492
|
H2Style *h2Style = stylesDict[@([H2Style getStyleType])];
|
|
1178
1493
|
H3Style *h3Style = stylesDict[@([H3Style getStyleType])];
|
|
1179
|
-
|
|
1180
|
-
// some of the changes these checks do could interfere with later checks and
|
|
1181
|
-
// so here I rely on short circuiting evaluation of the logical
|
|
1182
|
-
// either way it's not possible to have two of them come off at the
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1494
|
+
|
|
1495
|
+
// some of the changes these checks do could interfere with later checks and
|
|
1496
|
+
// cause a crash so here I rely on short circuiting evaluation of the logical
|
|
1497
|
+
// expression either way it's not possible to have two of them come off at the
|
|
1498
|
+
// same time
|
|
1499
|
+
if ([uStyle handleBackspaceInRange:range replacementText:text] ||
|
|
1500
|
+
[uStyle tryHandlingListShorcutInRange:range replacementText:text] ||
|
|
1501
|
+
[oStyle handleBackspaceInRange:range replacementText:text] ||
|
|
1502
|
+
[oStyle tryHandlingListShorcutInRange:range replacementText:text] ||
|
|
1503
|
+
[bqStyle handleBackspaceInRange:range replacementText:text] ||
|
|
1504
|
+
[cbStyle handleBackspaceInRange:range replacementText:text] ||
|
|
1505
|
+
[linkStyle handleLeadingLinkReplacement:range replacementText:text] ||
|
|
1506
|
+
[mentionStyle handleLeadingMentionReplacement:range
|
|
1507
|
+
replacementText:text] ||
|
|
1508
|
+
[h1Style handleNewlinesInRange:range replacementText:text] ||
|
|
1509
|
+
[h2Style handleNewlinesInRange:range replacementText:text] ||
|
|
1510
|
+
[h3Style handleNewlinesInRange:range replacementText:text] ||
|
|
1511
|
+
[ZeroWidthSpaceUtils handleBackspaceInRange:range
|
|
1512
|
+
replacementText:text
|
|
1513
|
+
input:self] ||
|
|
1514
|
+
[ParagraphAttributesUtils handleBackspaceInRange:range
|
|
1515
|
+
replacementText:text
|
|
1516
|
+
input:self] ||
|
|
1517
|
+
// CRITICAL: This callback HAS TO be always evaluated last.
|
|
1518
|
+
//
|
|
1519
|
+
// This function is the "Generic Fallback": if no specific style claims
|
|
1520
|
+
// the backspace action to change its state, only then do we proceed to
|
|
1521
|
+
// physically delete the newline and merge paragraphs.
|
|
1522
|
+
[ParagraphAttributesUtils handleParagraphStylesMergeOnBackspace:range
|
|
1523
|
+
replacementText:text
|
|
1524
|
+
input:self]) {
|
|
1197
1525
|
[self anyTextMayHaveBeenModified];
|
|
1198
1526
|
return NO;
|
|
1199
1527
|
}
|
|
@@ -1203,27 +1531,58 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
1203
1531
|
|
|
1204
1532
|
- (void)textViewDidChangeSelection:(UITextView *)textView {
|
|
1205
1533
|
// emit the event
|
|
1206
|
-
NSString *textAtSelection =
|
|
1207
|
-
|
|
1534
|
+
NSString *textAtSelection =
|
|
1535
|
+
[[[NSMutableString alloc] initWithString:textView.textStorage.string]
|
|
1536
|
+
substringWithRange:textView.selectedRange];
|
|
1537
|
+
|
|
1208
1538
|
auto emitter = [self getEventEmitter];
|
|
1209
|
-
if(emitter != nullptr) {
|
|
1539
|
+
if (emitter != nullptr) {
|
|
1210
1540
|
// iOS range works differently because it specifies location and length
|
|
1211
|
-
// here, start is the location, but end is the first index BEHIND the end.
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1541
|
+
// here, start is the location, but end is the first index BEHIND the end.
|
|
1542
|
+
// So a 0 length range will have equal start and end
|
|
1543
|
+
emitter->onChangeSelection(
|
|
1544
|
+
{.start = static_cast<int>(textView.selectedRange.location),
|
|
1545
|
+
.end = static_cast<int>(textView.selectedRange.location +
|
|
1546
|
+
textView.selectedRange.length),
|
|
1547
|
+
.text = [textAtSelection toCppString]});
|
|
1217
1548
|
}
|
|
1218
|
-
|
|
1549
|
+
|
|
1219
1550
|
// manage selection changes
|
|
1220
1551
|
[self manageSelectionBasedChanges];
|
|
1221
1552
|
}
|
|
1222
1553
|
|
|
1223
|
-
// this function isn't called always when some text changes (for example setting
|
|
1224
|
-
// so all the logic is
|
|
1554
|
+
// this function isn't called always when some text changes (for example setting
|
|
1555
|
+
// link or starting mention with indicator doesn't fire it) so all the logic is
|
|
1556
|
+
// in anyTextMayHaveBeenModified
|
|
1225
1557
|
- (void)textViewDidChange:(UITextView *)textView {
|
|
1226
1558
|
[self anyTextMayHaveBeenModified];
|
|
1227
1559
|
}
|
|
1228
1560
|
|
|
1561
|
+
// MARK: - Media attachments delegate
|
|
1562
|
+
|
|
1563
|
+
- (void)mediaAttachmentDidUpdate:(NSTextAttachment *)attachment {
|
|
1564
|
+
NSTextStorage *storage = textView.textStorage;
|
|
1565
|
+
NSRange fullRange = NSMakeRange(0, storage.length);
|
|
1566
|
+
|
|
1567
|
+
__block NSRange foundRange = NSMakeRange(NSNotFound, 0);
|
|
1568
|
+
|
|
1569
|
+
[storage enumerateAttribute:NSAttachmentAttributeName
|
|
1570
|
+
inRange:fullRange
|
|
1571
|
+
options:0
|
|
1572
|
+
usingBlock:^(id value, NSRange range, BOOL *stop) {
|
|
1573
|
+
if (value == attachment) {
|
|
1574
|
+
foundRange = range;
|
|
1575
|
+
*stop = YES;
|
|
1576
|
+
}
|
|
1577
|
+
}];
|
|
1578
|
+
|
|
1579
|
+
if (foundRange.location == NSNotFound) {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
[storage edited:NSTextStorageEditedAttributes
|
|
1584
|
+
range:foundRange
|
|
1585
|
+
changeInLength:0];
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1229
1588
|
@end
|