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