react-native-enriched 0.1.6 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +4 -14
  2. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +4 -1
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +2 -1
  4. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
  5. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
  6. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +0 -45
  7. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +111 -2
  8. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +9 -3
  9. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +2 -0
  10. package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +1 -1
  11. package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +33 -0
  12. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +6 -0
  13. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +6 -0
  14. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +42 -1
  15. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +6 -0
  16. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +6 -0
  17. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +6 -0
  18. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +135 -9
  19. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +6 -0
  20. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +5 -0
  21. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +6 -0
  22. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +6 -0
  23. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +6 -0
  24. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +13 -3
  25. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +5 -0
  26. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +5 -0
  27. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +6 -0
  28. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +4 -0
  29. package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +13 -0
  30. package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +80 -9
  31. package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +1 -0
  32. package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +188 -5
  33. package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +57 -30
  34. package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +91 -0
  35. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +24 -13
  36. package/android/src/main/java/com/swmansion/enriched/utils/ResourceManager.kt +26 -0
  37. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +3 -0
  38. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +6 -6
  39. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +6 -6
  40. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +19 -19
  41. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +40 -51
  42. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +13 -15
  43. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +23 -21
  44. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +35 -36
  45. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +4 -4
  46. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +13 -14
  47. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +12 -13
  48. package/android/src/main/res/drawable/broken_image.xml +10 -0
  49. package/ios/EnrichedTextInputView.h +27 -12
  50. package/ios/EnrichedTextInputView.mm +906 -547
  51. package/ios/attachments/ImageAttachment.h +10 -0
  52. package/ios/attachments/ImageAttachment.mm +34 -0
  53. package/ios/attachments/MediaAttachment.h +23 -0
  54. package/ios/attachments/MediaAttachment.mm +31 -0
  55. package/ios/config/InputConfig.h +12 -6
  56. package/ios/config/InputConfig.mm +71 -33
  57. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
  58. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
  59. package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +0 -45
  60. package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +41 -4
  61. package/ios/inputParser/InputParser.h +5 -5
  62. package/ios/inputParser/InputParser.mm +867 -333
  63. package/ios/inputTextView/InputTextView.h +1 -1
  64. package/ios/inputTextView/InputTextView.mm +100 -59
  65. package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +11 -9
  66. package/ios/internals/EnrichedTextInputViewShadowNode.h +28 -24
  67. package/ios/internals/EnrichedTextInputViewShadowNode.mm +64 -47
  68. package/ios/internals/EnrichedTextInputViewState.h +3 -1
  69. package/ios/styles/BlockQuoteStyle.mm +192 -142
  70. package/ios/styles/BoldStyle.mm +96 -62
  71. package/ios/styles/CodeBlockStyle.mm +304 -0
  72. package/ios/styles/H1Style.mm +10 -3
  73. package/ios/styles/H2Style.mm +10 -3
  74. package/ios/styles/H3Style.mm +10 -3
  75. package/ios/styles/HeadingStyleBase.mm +129 -84
  76. package/ios/styles/ImageStyle.mm +160 -0
  77. package/ios/styles/InlineCodeStyle.mm +149 -84
  78. package/ios/styles/ItalicStyle.mm +77 -51
  79. package/ios/styles/LinkStyle.mm +353 -224
  80. package/ios/styles/MentionStyle.mm +434 -220
  81. package/ios/styles/OrderedListStyle.mm +172 -105
  82. package/ios/styles/StrikethroughStyle.mm +53 -34
  83. package/ios/styles/UnderlineStyle.mm +69 -45
  84. package/ios/styles/UnorderedListStyle.mm +170 -105
  85. package/ios/utils/BaseStyleProtocol.h +3 -2
  86. package/ios/utils/ColorExtension.mm +7 -5
  87. package/ios/utils/FontExtension.mm +42 -27
  88. package/ios/utils/ImageData.h +10 -0
  89. package/ios/utils/ImageData.mm +4 -0
  90. package/ios/utils/LayoutManagerExtension.h +1 -1
  91. package/ios/utils/LayoutManagerExtension.mm +334 -109
  92. package/ios/utils/MentionParams.h +0 -1
  93. package/ios/utils/MentionStyleProps.h +1 -1
  94. package/ios/utils/MentionStyleProps.mm +27 -20
  95. package/ios/utils/OccurenceUtils.h +42 -38
  96. package/ios/utils/OccurenceUtils.mm +177 -107
  97. package/ios/utils/ParagraphAttributesUtils.h +6 -1
  98. package/ios/utils/ParagraphAttributesUtils.mm +152 -41
  99. package/ios/utils/ParagraphsUtils.h +2 -1
  100. package/ios/utils/ParagraphsUtils.mm +40 -26
  101. package/ios/utils/StringExtension.h +1 -1
  102. package/ios/utils/StringExtension.mm +19 -16
  103. package/ios/utils/StyleHeaders.h +35 -11
  104. package/ios/utils/TextInsertionUtils.h +13 -2
  105. package/ios/utils/TextInsertionUtils.mm +38 -20
  106. package/ios/utils/WordsUtils.h +2 -1
  107. package/ios/utils/WordsUtils.mm +32 -22
  108. package/ios/utils/ZeroWidthSpaceUtils.h +3 -1
  109. package/ios/utils/ZeroWidthSpaceUtils.mm +153 -75
  110. package/lib/module/EnrichedTextInput.js +41 -3
  111. package/lib/module/EnrichedTextInput.js.map +1 -1
  112. package/lib/module/EnrichedTextInputNativeComponent.ts +17 -5
  113. package/lib/module/normalizeHtmlStyle.js +0 -4
  114. package/lib/module/normalizeHtmlStyle.js.map +1 -1
  115. package/lib/typescript/src/EnrichedTextInput.d.ts +2 -5
  116. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
  117. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +7 -5
  118. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
  119. package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +1 -1
  120. package/package.json +8 -1
  121. package/src/EnrichedTextInput.tsx +48 -7
  122. package/src/EnrichedTextInputNativeComponent.ts +17 -5
  123. package/src/normalizeHtmlStyle.ts +0 -4
@@ -2,5 +2,5 @@
2
2
  #import <UIkit/UIKit.h>
3
3
 
4
4
  @interface InputTextView : UITextView
5
- @property (nonatomic, weak) id input;
5
+ @property(nonatomic, weak) id input;
6
6
  @end
@@ -1,114 +1,155 @@
1
1
  #import "InputTextView.h"
2
2
  #import "EnrichedTextInputView.h"
3
3
  #import "StringExtension.h"
4
- #import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
5
4
  #import "TextInsertionUtils.h"
5
+ #import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
6
6
 
7
7
  @implementation InputTextView
8
8
 
9
9
  - (void)copy:(id)sender {
10
10
  EnrichedTextInputView *typedInput = (EnrichedTextInputView *)_input;
11
- if(typedInput == nullptr) { return; }
12
-
11
+ if (typedInput == nullptr) {
12
+ return;
13
+ }
14
+
13
15
  // remove zero width spaces before copying the text
14
- NSString *plainText = [typedInput->textView.textStorage.string substringWithRange:typedInput->textView.selectedRange];
15
- NSString *fixedPlainText = [plainText stringByReplacingOccurrencesOfString:@"\u200B" withString:@""];
16
-
17
- NSString *parsedHtml = [typedInput->parser parseToHtmlFromRange:typedInput->textView.selectedRange];
18
-
19
- NSMutableAttributedString *attrStr = [[typedInput->textView.textStorage attributedSubstringFromRange:typedInput->textView.selectedRange] mutableCopy];
16
+ NSString *plainText = [typedInput->textView.textStorage.string
17
+ substringWithRange:typedInput->textView.selectedRange];
18
+ NSString *fixedPlainText =
19
+ [plainText stringByReplacingOccurrencesOfString:@"\u200B" withString:@""];
20
+
21
+ NSString *parsedHtml = [typedInput->parser
22
+ parseToHtmlFromRange:typedInput->textView.selectedRange];
23
+
24
+ NSMutableAttributedString *attrStr = [[typedInput->textView.textStorage
25
+ attributedSubstringFromRange:typedInput->textView.selectedRange]
26
+ mutableCopy];
20
27
  NSRange fullAttrStrRange = NSMakeRange(0, attrStr.length);
21
- [attrStr.mutableString replaceOccurrencesOfString:@"\u200B" withString:@"" options:0 range:fullAttrStrRange];
22
-
23
- NSData *rtfData = [attrStr dataFromRange:NSMakeRange(0, attrStr.length)
24
- documentAttributes:@{NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType}
25
- error:nullptr
26
- ];
27
-
28
+ [attrStr.mutableString replaceOccurrencesOfString:@"\u200B"
29
+ withString:@""
30
+ options:0
31
+ range:fullAttrStrRange];
32
+
33
+ NSData *rtfData =
34
+ [attrStr dataFromRange:NSMakeRange(0, attrStr.length)
35
+ documentAttributes:@{
36
+ NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType
37
+ }
38
+ error:nullptr];
39
+
28
40
  UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
29
- [pasteboard setItems:@[@{
30
- UTTypeUTF8PlainText.identifier : fixedPlainText,
31
- UTTypeHTML.identifier : parsedHtml,
32
- UTTypeRTF.identifier : rtfData
33
- }]];
41
+ [pasteboard setItems:@[ @{
42
+ UTTypeUTF8PlainText.identifier : fixedPlainText,
43
+ UTTypeHTML.identifier : parsedHtml,
44
+ UTTypeRTF.identifier : rtfData
45
+ } ]];
34
46
  }
35
47
 
36
48
  - (void)paste:(id)sender {
37
49
  EnrichedTextInputView *typedInput = (EnrichedTextInputView *)_input;
38
- if(typedInput == nullptr) { return; }
50
+ if (typedInput == nullptr) {
51
+ return;
52
+ }
39
53
 
40
54
  UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
41
55
  NSArray<NSString *> *pasteboardTypes = pasteboard.pasteboardTypes;
42
56
  NSRange currentRange = typedInput->textView.selectedRange;
43
-
44
- if([pasteboardTypes containsObject:UTTypeHTML.identifier]) {
57
+
58
+ if ([pasteboardTypes containsObject:UTTypeHTML.identifier]) {
45
59
  // we try processing the html contents
46
-
60
+
47
61
  NSString *htmlString;
48
62
  id htmlValue = [pasteboard valueForPasteboardType:UTTypeHTML.identifier];
49
-
50
- if([htmlValue isKindOfClass:[NSData class]]) {
51
- htmlString = [[NSString alloc]initWithData:htmlValue encoding:NSUTF8StringEncoding];
52
- } else if([htmlValue isKindOfClass:[NSString class]]) {
63
+
64
+ if ([htmlValue isKindOfClass:[NSData class]]) {
65
+ htmlString = [[NSString alloc] initWithData:htmlValue
66
+ encoding:NSUTF8StringEncoding];
67
+ } else if ([htmlValue isKindOfClass:[NSString class]]) {
53
68
  htmlString = htmlValue;
54
69
  }
55
-
70
+
56
71
  // validate the html
57
- NSString *initiallyProcessedHtml = [typedInput->parser initiallyProcessHtml:htmlString];
58
-
59
- if(initiallyProcessedHtml != nullptr) {
72
+ NSString *initiallyProcessedHtml =
73
+ [typedInput->parser initiallyProcessHtml:htmlString];
74
+
75
+ if (initiallyProcessedHtml != nullptr) {
60
76
  // valid html, let's apply it
61
77
  currentRange.length > 0
62
- ? [typedInput->parser replaceFromHtml:initiallyProcessedHtml range:currentRange]
63
- : [typedInput->parser insertFromHtml:initiallyProcessedHtml location:currentRange.location];
78
+ ? [typedInput->parser replaceFromHtml:initiallyProcessedHtml
79
+ range:currentRange]
80
+ : [typedInput->parser insertFromHtml:initiallyProcessedHtml
81
+ location:currentRange.location];
64
82
  } else {
65
83
  // fall back to plain text, otherwise do nothing
66
- [self tryHandlingPlainTextItemsIn:pasteboard range:currentRange input:typedInput];
84
+ [self tryHandlingPlainTextItemsIn:pasteboard
85
+ range:currentRange
86
+ input:typedInput];
67
87
  }
68
88
  } else {
69
- [self tryHandlingPlainTextItemsIn:pasteboard range:currentRange input:typedInput];
89
+ [self tryHandlingPlainTextItemsIn:pasteboard
90
+ range:currentRange
91
+ input:typedInput];
70
92
  }
71
-
93
+
72
94
  [typedInput anyTextMayHaveBeenModified];
73
95
  }
74
96
 
75
- - (void)tryHandlingPlainTextItemsIn:(UIPasteboard *)pasteboard range:(NSRange)range input:(EnrichedTextInputView *)input {
97
+ - (void)tryHandlingPlainTextItemsIn:(UIPasteboard *)pasteboard
98
+ range:(NSRange)range
99
+ input:(EnrichedTextInputView *)input {
76
100
  NSArray *existingTypes = pasteboard.pasteboardTypes;
77
- NSArray *handledTypes = @[UTTypeUTF8PlainText.identifier, UTTypePlainText.identifier, UTTypeURL.identifier];
101
+ NSArray *handledTypes = @[
102
+ UTTypeUTF8PlainText.identifier, UTTypePlainText.identifier,
103
+ UTTypeURL.identifier
104
+ ];
78
105
  NSString *plainText;
79
-
80
- for(NSString *type in handledTypes) {
81
- if(![existingTypes containsObject:type]) {
106
+
107
+ for (NSString *type in handledTypes) {
108
+ if (![existingTypes containsObject:type]) {
82
109
  continue;
83
110
  }
84
-
111
+
85
112
  id value = [pasteboard valueForPasteboardType:type];
86
-
87
- if([value isKindOfClass:[NSData class]]) {
88
- plainText = [[NSString alloc]initWithData:value encoding:NSUTF8StringEncoding];
89
- } else if([value isKindOfClass:[NSString class]]) {
113
+
114
+ if ([value isKindOfClass:[NSData class]]) {
115
+ plainText = [[NSString alloc] initWithData:value
116
+ encoding:NSUTF8StringEncoding];
117
+ } else if ([value isKindOfClass:[NSString class]]) {
90
118
  plainText = (NSString *)value;
91
- } else if([value isKindOfClass:[NSURL class]]) {
119
+ } else if ([value isKindOfClass:[NSURL class]]) {
92
120
  plainText = [(NSURL *)value absoluteString];
93
121
  }
94
122
  }
95
-
96
- if(!plainText) {
123
+
124
+ if (!plainText) {
97
125
  return;
98
126
  }
99
-
100
- range.length > 0
101
- ? [TextInsertionUtils replaceText:plainText at:range additionalAttributes:nullptr input:input withSelection:YES]
102
- : [TextInsertionUtils insertText:plainText at:range.location additionalAttributes:nullptr input:input withSelection:YES];
127
+
128
+ range.length > 0 ? [TextInsertionUtils replaceText:plainText
129
+ at:range
130
+ additionalAttributes:nullptr
131
+ input:input
132
+ withSelection:YES]
133
+ : [TextInsertionUtils insertText:plainText
134
+ at:range.location
135
+ additionalAttributes:nullptr
136
+ input:input
137
+ withSelection:YES];
103
138
  }
104
139
 
105
140
  - (void)cut:(id)sender {
106
141
  EnrichedTextInputView *typedInput = (EnrichedTextInputView *)_input;
107
- if(typedInput == nullptr) { return; }
108
-
142
+ if (typedInput == nullptr) {
143
+ return;
144
+ }
145
+
109
146
  [self copy:sender];
110
- [TextInsertionUtils replaceText:@"" at:typedInput->textView.selectedRange additionalAttributes:nullptr input:typedInput withSelection:YES];
111
-
147
+ [TextInsertionUtils replaceText:@""
148
+ at:typedInput->textView.selectedRange
149
+ additionalAttributes:nullptr
150
+ input:typedInput
151
+ withSelection:YES];
152
+
112
153
  [typedInput anyTextMayHaveBeenModified];
113
154
  }
114
155
 
@@ -1,17 +1,19 @@
1
1
  #pragma once
2
- #include <react/debug/react_native_assert.h>
2
+ #include <ReactNativeEnriched/EnrichedTextInputViewShadowNode.h>
3
3
  #include <ReactNativeEnriched/Props.h>
4
+ #include <react/debug/react_native_assert.h>
4
5
  #include <react/renderer/core/ConcreteComponentDescriptor.h>
5
- #include <ReactNativeEnriched/EnrichedTextInputViewShadowNode.h>
6
6
 
7
7
  namespace facebook::react {
8
- class EnrichedTextInputViewComponentDescriptor final : public ConcreteComponentDescriptor<EnrichedTextInputViewShadowNode> {
9
- public:
10
- using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
11
- void adopt(ShadowNode &shadowNode) const override {
12
- react_native_assert(dynamic_cast<EnrichedTextInputViewShadowNode *>(&shadowNode));
13
- ConcreteComponentDescriptor::adopt(shadowNode);
14
- }
8
+ class EnrichedTextInputViewComponentDescriptor final
9
+ : public ConcreteComponentDescriptor<EnrichedTextInputViewShadowNode> {
10
+ public:
11
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
12
+ void adopt(ShadowNode &shadowNode) const override {
13
+ react_native_assert(
14
+ dynamic_cast<EnrichedTextInputViewShadowNode *>(&shadowNode));
15
+ ConcreteComponentDescriptor::adopt(shadowNode);
16
+ }
15
17
  };
16
18
 
17
19
  } // namespace facebook::react
@@ -1,10 +1,10 @@
1
1
  #pragma once
2
+ #include <ReactNativeEnriched/EnrichedTextInputViewState.h>
2
3
  #include <ReactNativeEnriched/EventEmitters.h>
3
4
  #include <ReactNativeEnriched/Props.h>
4
- #include <ReactNativeEnriched/EnrichedTextInputViewState.h>
5
+ #include <jsi/jsi.h>
5
6
  #include <react/renderer/components/view/ConcreteViewShadowNode.h>
6
7
  #include <react/renderer/core/LayoutConstraints.h>
7
- #include <jsi/jsi.h>
8
8
 
9
9
  namespace facebook::react {
10
10
 
@@ -13,28 +13,32 @@ JSI_EXPORT extern const char EnrichedTextInputViewComponentName[];
13
13
  /*
14
14
  * `ShadowNode` for <EnrichedTextInputView> component.
15
15
  */
16
- class EnrichedTextInputViewShadowNode : public ConcreteViewShadowNode<
17
- EnrichedTextInputViewComponentName,
18
- EnrichedTextInputViewProps,
19
- EnrichedTextInputViewEventEmitter,
20
- EnrichedTextInputViewState> {
21
- public:
22
- using ConcreteViewShadowNode::ConcreteViewShadowNode;
23
- EnrichedTextInputViewShadowNode(const ShadowNodeFragment& fragment, const ShadowNodeFamily::Shared& family, ShadowNodeTraits traits);
24
- EnrichedTextInputViewShadowNode(const ShadowNode& sourceShadowNode, const ShadowNodeFragment& fragment);
25
- void dirtyLayoutIfNeeded();
26
- Size measureContent(const LayoutContext& layoutContext, const LayoutConstraints& layoutConstraints) const override;
27
-
28
-
29
- static ShadowNodeTraits BaseTraits() {
30
- auto traits = ConcreteViewShadowNode::BaseTraits();
31
- traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
32
- traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
33
- return traits;
34
- }
35
-
36
- private:
37
- int localForceHeightRecalculationCounter_;
16
+ class EnrichedTextInputViewShadowNode
17
+ : public ConcreteViewShadowNode<
18
+ EnrichedTextInputViewComponentName, EnrichedTextInputViewProps,
19
+ EnrichedTextInputViewEventEmitter, EnrichedTextInputViewState> {
20
+ public:
21
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
22
+ EnrichedTextInputViewShadowNode(const ShadowNodeFragment &fragment,
23
+ const ShadowNodeFamily::Shared &family,
24
+ ShadowNodeTraits traits);
25
+ EnrichedTextInputViewShadowNode(const ShadowNode &sourceShadowNode,
26
+ const ShadowNodeFragment &fragment);
27
+ void dirtyLayoutIfNeeded();
28
+ Size
29
+ measureContent(const LayoutContext &layoutContext,
30
+ const LayoutConstraints &layoutConstraints) const override;
31
+
32
+ static ShadowNodeTraits BaseTraits() {
33
+ auto traits = ConcreteViewShadowNode::BaseTraits();
34
+ traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
35
+ traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
36
+ return traits;
37
+ }
38
+
39
+ private:
40
+ int localForceHeightRecalculationCounter_;
41
+ id setupMockTextInputView_() const;
38
42
  };
39
43
 
40
44
  } // namespace facebook::react
@@ -1,86 +1,103 @@
1
1
  #import "EnrichedTextInputViewShadowNode.h"
2
+ #import "CoreText/CoreText.h"
2
3
  #import <EnrichedTextInputView.h>
4
+ #import <React/RCTShadowView+Layout.h>
3
5
  #import <react/utils/ManagedObjectWrapper.h>
4
6
  #import <yoga/Yoga.h>
5
- #import <React/RCTShadowView+Layout.h>
6
- #import "CoreText/CoreText.h"
7
7
 
8
8
  namespace facebook::react {
9
9
 
10
- extern const char EnrichedTextInputViewComponentName[] = "EnrichedTextInputView";
10
+ extern const char EnrichedTextInputViewComponentName[] =
11
+ "EnrichedTextInputView";
11
12
 
12
13
  EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode(
13
- const ShadowNodeFragment& fragment,
14
- const ShadowNodeFamily::Shared& family,
15
- ShadowNodeTraits traits
16
- ): ConcreteViewShadowNode(fragment, family, traits) {
14
+ const ShadowNodeFragment &fragment, const ShadowNodeFamily::Shared &family,
15
+ ShadowNodeTraits traits)
16
+ : ConcreteViewShadowNode(fragment, family, traits) {
17
17
  localForceHeightRecalculationCounter_ = 0;
18
18
  }
19
19
 
20
+ // mock input is used for the first measure calls that need to be done when the
21
+ // real input isn't defined yet
22
+ id EnrichedTextInputViewShadowNode::setupMockTextInputView_() const {
23
+ // it's rendered far away from the viewport
24
+ const int veryFarAway = 20000;
25
+ const int mockSize = 1000;
26
+ EnrichedTextInputView *mockTextInputView_ = [[EnrichedTextInputView alloc]
27
+ initWithFrame:(CGRectMake(veryFarAway, veryFarAway, mockSize, mockSize))];
28
+ const auto props = this->getProps();
29
+ mockTextInputView_->blockEmitting = YES;
30
+ [mockTextInputView_ updateProps:props oldProps:nullptr];
31
+ return mockTextInputView_;
32
+ }
33
+
20
34
  EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode(
21
- const ShadowNode& sourceShadowNode,
22
- const ShadowNodeFragment& fragment
23
- ): ConcreteViewShadowNode(sourceShadowNode, fragment) {
35
+ const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment)
36
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
24
37
  dirtyLayoutIfNeeded();
25
38
  }
26
39
 
27
40
  void EnrichedTextInputViewShadowNode::dirtyLayoutIfNeeded() {
28
41
  const auto state = this->getStateData();
29
42
  const int receivedCounter = state.getForceHeightRecalculationCounter();
30
-
31
- if(receivedCounter > localForceHeightRecalculationCounter_) {
43
+
44
+ if (receivedCounter > localForceHeightRecalculationCounter_) {
32
45
  localForceHeightRecalculationCounter_ = receivedCounter;
33
46
  YGNodeMarkDirty(&yogaNode_);
34
47
  }
35
48
  }
36
49
 
37
- Size EnrichedTextInputViewShadowNode::measureContent(const LayoutContext& layoutContext, const LayoutConstraints& layoutConstraints) const {
50
+ Size EnrichedTextInputViewShadowNode::measureContent(
51
+ const LayoutContext &layoutContext,
52
+ const LayoutConstraints &layoutConstraints) const {
38
53
  const auto state = this->getStateData();
39
54
  const auto componentRef = state.getComponentViewRef();
40
- RCTInternalGenericWeakWrapper *weakWrapper = (RCTInternalGenericWeakWrapper *)unwrapManagedObject(componentRef);
41
-
42
- if(weakWrapper != nullptr) {
55
+ RCTInternalGenericWeakWrapper *weakWrapper =
56
+ (RCTInternalGenericWeakWrapper *)unwrapManagedObject(componentRef);
57
+
58
+ if (weakWrapper != nullptr) {
43
59
  id componentObject = weakWrapper.object;
44
- EnrichedTextInputView *typedComponentObject = (EnrichedTextInputView *) componentObject;
45
-
46
- if(typedComponentObject != nullptr) {
60
+ EnrichedTextInputView *typedComponentObject =
61
+ (EnrichedTextInputView *)componentObject;
62
+
63
+ if (typedComponentObject != nullptr) {
47
64
  __block CGSize estimatedSize;
48
-
65
+
49
66
  // synchronously dispatch to main thread if needed
50
- if([NSThread isMainThread]) {
51
- estimatedSize = [typedComponentObject measureSize:layoutConstraints.maximumSize.width];
67
+ if ([NSThread isMainThread]) {
68
+ estimatedSize = [typedComponentObject
69
+ measureSize:layoutConstraints.maximumSize.width];
52
70
  } else {
53
71
  dispatch_sync(dispatch_get_main_queue(), ^{
54
- estimatedSize = [typedComponentObject measureSize:layoutConstraints.maximumSize.width];
72
+ estimatedSize = [typedComponentObject
73
+ measureSize:layoutConstraints.maximumSize.width];
55
74
  });
56
75
  }
57
-
58
- return {
59
- estimatedSize.width,
60
- MIN(estimatedSize.height, layoutConstraints.maximumSize.height)
61
- };
76
+
77
+ return {estimatedSize.width,
78
+ MIN(estimatedSize.height, layoutConstraints.maximumSize.height)};
62
79
  }
63
80
  } else {
64
- // on the very first call there is no componentView that we can query for the component height
65
- // thus, a little heuristic: just put a height that is exactly height of letter "I" with default apple font and size from props
66
- // in a lot of cases it will be the desired height
67
- // in others, the jump on the second call will at least be smaller
68
- const auto props = this->getProps();
69
- const auto &typedProps = *std::static_pointer_cast<EnrichedTextInputViewProps const>(props);
70
- NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:@"I" attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:typedProps.fontSize]}];
71
- CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrStr);
72
- const CGSize &suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(
73
- framesetter,
74
- CFRangeMake(0, 1),
75
- nullptr,
76
- CGSizeMake(layoutConstraints.maximumSize.width, DBL_MAX),
77
- nullptr
78
- );
79
-
80
- return {suggestedSize.width, suggestedSize.height};
81
+ __block CGSize estimatedSize;
82
+
83
+ // synchronously dispatch to main thread if needed
84
+ if ([NSThread isMainThread]) {
85
+ EnrichedTextInputView *mockTextInputView = setupMockTextInputView_();
86
+ estimatedSize =
87
+ [mockTextInputView measureSize:layoutConstraints.maximumSize.width];
88
+ } else {
89
+ dispatch_sync(dispatch_get_main_queue(), ^{
90
+ EnrichedTextInputView *mockTextInputView = setupMockTextInputView_();
91
+ estimatedSize =
92
+ [mockTextInputView measureSize:layoutConstraints.maximumSize.width];
93
+ });
94
+ }
95
+
96
+ return {estimatedSize.width,
97
+ MIN(estimatedSize.height, layoutConstraints.maximumSize.height)};
81
98
  }
82
-
99
+
83
100
  return Size();
84
101
  }
85
-
102
+
86
103
  } // namespace facebook::react
@@ -5,13 +5,15 @@ namespace facebook::react {
5
5
 
6
6
  class EnrichedTextInputViewState {
7
7
  public:
8
- EnrichedTextInputViewState(): forceHeightRecalculationCounter_(0), componentViewRef_(nullptr) {}
8
+ EnrichedTextInputViewState()
9
+ : forceHeightRecalculationCounter_(0), componentViewRef_(nullptr) {}
9
10
  EnrichedTextInputViewState(int counter, std::shared_ptr<void> ref) {
10
11
  forceHeightRecalculationCounter_ = counter;
11
12
  componentViewRef_ = ref;
12
13
  }
13
14
  int getForceHeightRecalculationCounter() const;
14
15
  std::shared_ptr<void> getComponentViewRef() const;
16
+
15
17
  private:
16
18
  int forceHeightRecalculationCounter_{};
17
19
  std::shared_ptr<void> componentViewRef_{};