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