react-native-enriched 0.0.0 → 0.1.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.
Files changed (169) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +869 -0
  3. package/ReactNativeEnriched.podspec +27 -0
  4. package/android/build.gradle +101 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +146 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +55 -0
  7. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/ComponentDescriptors.cpp +22 -0
  8. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/ComponentDescriptors.h +24 -0
  9. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +118 -0
  10. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +95 -0
  11. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.cpp +128 -0
  12. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +577 -0
  13. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/ShadowNodes.cpp +17 -0
  14. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/ShadowNodes.h +23 -0
  15. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/States.cpp +16 -0
  16. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/States.h +20 -0
  17. package/android/gradle.properties +5 -0
  18. package/android/src/main/AndroidManifest.xml +3 -0
  19. package/android/src/main/AndroidManifestNew.xml +2 -0
  20. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +535 -0
  21. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewLayoutManager.kt +64 -0
  22. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +292 -0
  23. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +19 -0
  24. package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +40 -0
  25. package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +28 -0
  26. package/android/src/main/java/com/swmansion/enriched/events/OnChangeSelectionEvent.kt +29 -0
  27. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +24 -0
  28. package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +30 -0
  29. package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +27 -0
  30. package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +27 -0
  31. package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +30 -0
  32. package/android/src/main/java/com/swmansion/enriched/events/OnMentionDetectedEvent.kt +29 -0
  33. package/android/src/main/java/com/swmansion/enriched/events/OnMentionEvent.kt +33 -0
  34. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +34 -0
  35. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +10 -0
  36. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +38 -0
  37. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +17 -0
  38. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +17 -0
  39. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +17 -0
  40. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +41 -0
  41. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +16 -0
  42. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +10 -0
  43. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +24 -0
  44. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +36 -0
  45. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +71 -0
  46. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +111 -0
  47. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +9 -0
  48. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +9 -0
  49. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +49 -0
  50. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +4 -0
  51. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +4 -0
  52. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +4 -0
  53. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +4 -0
  54. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +4 -0
  55. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +5 -0
  56. package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +227 -0
  57. package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +146 -0
  58. package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +173 -0
  59. package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +186 -0
  60. package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +223 -0
  61. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +857 -0
  62. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSelection.kt +285 -0
  63. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +204 -0
  64. package/android/src/main/java/com/swmansion/enriched/utils/Utils.kt +91 -0
  65. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +73 -0
  66. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt +51 -0
  67. package/android/src/main/new_arch/CMakeLists.txt +56 -0
  68. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +22 -0
  69. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +26 -0
  70. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +35 -0
  71. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +51 -0
  72. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +26 -0
  73. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +34 -0
  74. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +54 -0
  75. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +9 -0
  76. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +25 -0
  77. package/ios/EnrichedTextInputView.h +33 -0
  78. package/ios/EnrichedTextInputView.mm +1190 -0
  79. package/ios/EnrichedTextInputViewManager.mm +13 -0
  80. package/ios/config/InputConfig.h +67 -0
  81. package/ios/config/InputConfig.mm +382 -0
  82. package/ios/generated/RNEnrichedTextInputViewSpec/ComponentDescriptors.cpp +22 -0
  83. package/ios/generated/RNEnrichedTextInputViewSpec/ComponentDescriptors.h +24 -0
  84. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +118 -0
  85. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +95 -0
  86. package/ios/generated/RNEnrichedTextInputViewSpec/Props.cpp +128 -0
  87. package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +577 -0
  88. package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +384 -0
  89. package/ios/generated/RNEnrichedTextInputViewSpec/ShadowNodes.cpp +17 -0
  90. package/ios/generated/RNEnrichedTextInputViewSpec/ShadowNodes.h +23 -0
  91. package/ios/generated/RNEnrichedTextInputViewSpec/States.cpp +16 -0
  92. package/ios/generated/RNEnrichedTextInputViewSpec/States.h +20 -0
  93. package/ios/inputParser/InputParser.h +11 -0
  94. package/ios/inputParser/InputParser.mm +669 -0
  95. package/ios/inputTextView/InputTextView.h +6 -0
  96. package/ios/inputTextView/InputTextView.mm +115 -0
  97. package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +17 -0
  98. package/ios/internals/EnrichedTextInputViewShadowNode.h +40 -0
  99. package/ios/internals/EnrichedTextInputViewShadowNode.mm +83 -0
  100. package/ios/internals/EnrichedTextInputViewState.cpp +10 -0
  101. package/ios/internals/EnrichedTextInputViewState.h +20 -0
  102. package/ios/styles/BlockQuoteStyle.mm +248 -0
  103. package/ios/styles/BoldStyle.mm +122 -0
  104. package/ios/styles/H1Style.mm +10 -0
  105. package/ios/styles/H2Style.mm +10 -0
  106. package/ios/styles/H3Style.mm +10 -0
  107. package/ios/styles/HeadingStyleBase.mm +144 -0
  108. package/ios/styles/InlineCodeStyle.mm +163 -0
  109. package/ios/styles/ItalicStyle.mm +110 -0
  110. package/ios/styles/LinkStyle.mm +463 -0
  111. package/ios/styles/MentionStyle.mm +476 -0
  112. package/ios/styles/OrderedListStyle.mm +225 -0
  113. package/ios/styles/StrikethroughStyle.mm +80 -0
  114. package/ios/styles/UnderlineStyle.mm +112 -0
  115. package/ios/styles/UnorderedListStyle.mm +225 -0
  116. package/ios/utils/BaseStyleProtocol.h +16 -0
  117. package/ios/utils/ColorExtension.h +6 -0
  118. package/ios/utils/ColorExtension.mm +27 -0
  119. package/ios/utils/FontExtension.h +13 -0
  120. package/ios/utils/FontExtension.mm +91 -0
  121. package/ios/utils/LayoutManagerExtension.h +6 -0
  122. package/ios/utils/LayoutManagerExtension.mm +171 -0
  123. package/ios/utils/LinkData.h +9 -0
  124. package/ios/utils/LinkData.mm +4 -0
  125. package/ios/utils/MentionParams.h +9 -0
  126. package/ios/utils/MentionParams.mm +4 -0
  127. package/ios/utils/MentionStyleProps.h +13 -0
  128. package/ios/utils/MentionStyleProps.mm +56 -0
  129. package/ios/utils/OccurenceUtils.h +37 -0
  130. package/ios/utils/OccurenceUtils.mm +124 -0
  131. package/ios/utils/ParagraphsUtils.h +7 -0
  132. package/ios/utils/ParagraphsUtils.mm +54 -0
  133. package/ios/utils/StringExtension.h +15 -0
  134. package/ios/utils/StringExtension.mm +57 -0
  135. package/ios/utils/StyleHeaders.h +74 -0
  136. package/ios/utils/StylePair.h +9 -0
  137. package/ios/utils/StylePair.mm +4 -0
  138. package/ios/utils/StyleTypeEnum.h +22 -0
  139. package/ios/utils/TextDecorationLineEnum.h +6 -0
  140. package/ios/utils/TextDecorationLineEnum.mm +4 -0
  141. package/ios/utils/TextInsertionUtils.h +6 -0
  142. package/ios/utils/TextInsertionUtils.mm +48 -0
  143. package/ios/utils/WordsUtils.h +6 -0
  144. package/ios/utils/WordsUtils.mm +88 -0
  145. package/ios/utils/ZeroWidthSpaceUtils.h +7 -0
  146. package/ios/utils/ZeroWidthSpaceUtils.mm +164 -0
  147. package/lib/module/EnrichedTextInput.js +191 -0
  148. package/lib/module/EnrichedTextInput.js.map +1 -0
  149. package/lib/module/EnrichedTextInputNativeComponent.ts +235 -0
  150. package/lib/module/index.js +4 -0
  151. package/lib/module/index.js.map +1 -0
  152. package/lib/module/normalizeHtmlStyle.js +141 -0
  153. package/lib/module/normalizeHtmlStyle.js.map +1 -0
  154. package/lib/module/package.json +1 -0
  155. package/lib/typescript/package.json +1 -0
  156. package/lib/typescript/src/EnrichedTextInput.d.ts +113 -0
  157. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -0
  158. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +160 -0
  159. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -0
  160. package/lib/typescript/src/index.d.ts +3 -0
  161. package/lib/typescript/src/index.d.ts.map +1 -0
  162. package/lib/typescript/src/normalizeHtmlStyle.d.ts +4 -0
  163. package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +1 -0
  164. package/package.json +172 -1
  165. package/react-native.config.js +13 -0
  166. package/src/EnrichedTextInput.tsx +358 -0
  167. package/src/EnrichedTextInputNativeComponent.ts +235 -0
  168. package/src/index.tsx +9 -0
  169. package/src/normalizeHtmlStyle.ts +188 -0
@@ -0,0 +1,171 @@
1
+ #import "LayoutManagerExtension.h"
2
+ #import <objc/runtime.h>
3
+ #import "EnrichedTextInputView.h"
4
+ #import "StyleHeaders.h"
5
+ #import "ParagraphsUtils.h"
6
+
7
+ @implementation NSLayoutManager (LayoutManagerExtension)
8
+
9
+ static void const *kInputKey = &kInputKey;
10
+
11
+ - (id)input {
12
+ return objc_getAssociatedObject(self, kInputKey);
13
+ }
14
+
15
+ - (void)setInput:(id)value {
16
+ objc_setAssociatedObject(
17
+ self,
18
+ kInputKey,
19
+ value,
20
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC
21
+ );
22
+ }
23
+
24
+ + (void)load {
25
+ static dispatch_once_t onceToken;
26
+ dispatch_once(&onceToken, ^{
27
+ Class myClass = [NSLayoutManager class];
28
+ SEL originalSelector = @selector(drawBackgroundForGlyphRange:atPoint:);
29
+ SEL swizzledSelector = @selector(my_drawBackgroundForGlyphRange:atPoint:);
30
+ Method originalMethod = class_getInstanceMethod(myClass, originalSelector);
31
+ Method swizzledMethod = class_getInstanceMethod(myClass, swizzledSelector);
32
+
33
+ BOOL didAddMethod = class_addMethod(myClass, originalSelector,
34
+ method_getImplementation(swizzledMethod),
35
+ method_getTypeEncoding(swizzledMethod)
36
+ );
37
+
38
+ if(didAddMethod) {
39
+ class_replaceMethod(myClass, swizzledSelector,
40
+ method_getImplementation(originalMethod),
41
+ method_getTypeEncoding(originalMethod)
42
+ );
43
+ } else {
44
+ method_exchangeImplementations(originalMethod, swizzledMethod);
45
+ }
46
+ });
47
+ }
48
+
49
+ - (void)my_drawBackgroundForGlyphRange:(NSRange)glyphRange atPoint:(CGPoint)origin {
50
+ [self my_drawBackgroundForGlyphRange:glyphRange atPoint:origin];
51
+
52
+ EnrichedTextInputView *typedInput = (EnrichedTextInputView *)self.input;
53
+ if(typedInput == nullptr) { return; }
54
+
55
+ BlockQuoteStyle *bqStyle = typedInput->stylesDict[@([BlockQuoteStyle getStyleType])];
56
+ if(bqStyle == nullptr) { return; }
57
+
58
+ NSRange inputRange = NSMakeRange(0, typedInput->textView.textStorage.length);
59
+
60
+ // it isn't the most performant but we have to check for all the blockquotes each time and redraw them
61
+ NSArray *allBlockquotes = [bqStyle findAllOccurences:inputRange];
62
+
63
+ for(StylePair *pair in allBlockquotes) {
64
+ NSRange paragraphRange = [typedInput->textView.textStorage.string paragraphRangeForRange:[pair.rangeValue rangeValue]];
65
+ NSRange paragraphGlyphRange = [self glyphRangeForCharacterRange:paragraphRange actualCharacterRange:nullptr];
66
+ [self enumerateLineFragmentsForGlyphRange:paragraphGlyphRange
67
+ usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
68
+ CGFloat paddingLeft = origin.x;
69
+ CGFloat paddingTop = origin.y;
70
+ CGFloat x = paddingLeft;
71
+ CGFloat y = paddingTop + rect.origin.y;
72
+ CGFloat width = [typedInput->config blockquoteBorderWidth];
73
+ CGFloat height = rect.size.height;
74
+
75
+ CGRect lineRect = CGRectMake(x, y, width, height);
76
+ [[typedInput->config blockquoteBorderColor] setFill];
77
+ UIRectFill(lineRect);
78
+ }
79
+ ];
80
+ }
81
+
82
+ UnorderedListStyle *ulStyle = typedInput->stylesDict[@([UnorderedListStyle getStyleType])];
83
+ OrderedListStyle *olStyle = typedInput->stylesDict[@([OrderedListStyle getStyleType])];
84
+ if(ulStyle == nullptr || olStyle == nullptr) { return; }
85
+
86
+ // also not the most performant but we redraw all the lists
87
+ NSMutableArray *allLists = [[NSMutableArray alloc] init];
88
+ [allLists addObjectsFromArray:[ulStyle findAllOccurences:inputRange]];
89
+ [allLists addObjectsFromArray:[olStyle findAllOccurences:inputRange]];
90
+
91
+ for(StylePair *pair in allLists) {
92
+ NSParagraphStyle *pStyle = (NSParagraphStyle *)pair.styleValue;
93
+ NSDictionary *markerAttributes = @{
94
+ NSFontAttributeName: [typedInput->config orderedListMarkerFont],
95
+ NSForegroundColorAttributeName: [typedInput->config orderedListMarkerColor]
96
+ };
97
+
98
+ NSArray *paragraphs = [ParagraphsUtils getSeparateParagraphsRangesIn:typedInput->textView range:[pair.rangeValue rangeValue]];
99
+
100
+ for(NSValue *paragraph in paragraphs) {
101
+ NSRange paragraphGlyphRange = [self glyphRangeForCharacterRange:[paragraph rangeValue] actualCharacterRange:nullptr];
102
+
103
+ [self enumerateLineFragmentsForGlyphRange:paragraphGlyphRange
104
+ usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *container, NSRange lineGlyphRange, BOOL *stop) {
105
+ NSString *marker = [self markerForList:pStyle.textLists.firstObject charIndex:[self characterIndexForGlyphAtIndex:lineGlyphRange.location] input:typedInput];
106
+
107
+ if(pStyle.textLists.firstObject.markerFormat == NSTextListMarkerDecimal) {
108
+ CGFloat gapWidth = [typedInput->config orderedListGapWidth];
109
+ CGFloat markerWidth = [marker sizeWithAttributes:markerAttributes].width;
110
+ CGFloat markerX = usedRect.origin.x - gapWidth - markerWidth/2;
111
+
112
+ [marker drawAtPoint:CGPointMake(markerX, usedRect.origin.y + origin.y) withAttributes:markerAttributes];
113
+ } else {
114
+ CGFloat gapWidth = [typedInput->config unorderedListGapWidth];
115
+ CGFloat bulletSize = [typedInput->config unorderedListBulletSize];
116
+ CGFloat bulletX = usedRect.origin.x - gapWidth - bulletSize/2;
117
+ CGFloat centerY = CGRectGetMidY(usedRect);
118
+
119
+ CGContextRef context = UIGraphicsGetCurrentContext();
120
+ CGContextSaveGState(context); {
121
+ [[typedInput->config unorderedListBulletColor] setFill];
122
+ CGContextAddArc(context, bulletX, centerY, bulletSize/2, 0, 2 * M_PI, YES);
123
+ CGContextFillPath(context);
124
+ }
125
+ CGContextRestoreGState(context);
126
+ }
127
+ // only first line of a list gets its marker drawn
128
+ *stop = YES;
129
+ }
130
+ ];
131
+ }
132
+ }
133
+ }
134
+
135
+ - (NSString *)markerForList:(NSTextList *)list charIndex:(NSUInteger)index input:(EnrichedTextInputView *)input {
136
+ if(list.markerFormat == NSTextListMarkerDecimal) {
137
+ NSString *fullText = input->textView.textStorage.string;
138
+ NSInteger itemNumber = 1;
139
+
140
+ NSRange currentParagraph = [fullText paragraphRangeForRange:NSMakeRange(index, 0)];
141
+ if(currentParagraph.location > 0) {
142
+ OrderedListStyle *olStyle = input->stylesDict[@([OrderedListStyle getStyleType])];
143
+
144
+ NSInteger prevParagraphsCount = 0;
145
+ NSInteger recentParagraphLocation = [fullText paragraphRangeForRange:NSMakeRange(currentParagraph.location - 1, 0)].location;
146
+
147
+ // seek for previous lists
148
+ while(true) {
149
+ if([olStyle detectStyle:NSMakeRange(recentParagraphLocation, 0)]) {
150
+ prevParagraphsCount += 1;
151
+
152
+ if(recentParagraphLocation > 0) {
153
+ recentParagraphLocation = [fullText paragraphRangeForRange:NSMakeRange(recentParagraphLocation - 1, 0)].location;
154
+ } else {
155
+ break;
156
+ }
157
+ } else {
158
+ break;
159
+ }
160
+ }
161
+
162
+ itemNumber = prevParagraphsCount + 1;
163
+ }
164
+
165
+ return [NSString stringWithFormat:@"%ld.", (long)(itemNumber)];
166
+ } else {
167
+ return @"•";
168
+ }
169
+ }
170
+
171
+ @end
@@ -0,0 +1,9 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+
4
+ @interface LinkData : NSObject
5
+
6
+ @property NSString *text;
7
+ @property NSString *url;
8
+
9
+ @end
@@ -0,0 +1,4 @@
1
+ #import "LinkData.h"
2
+
3
+ @implementation LinkData
4
+ @end
@@ -0,0 +1,9 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+
4
+ @interface MentionParams : NSObject
5
+ @property NSString *text;
6
+ @property NSString *indicator;
7
+ @property NSString *attributes;
8
+ @end
9
+
@@ -0,0 +1,4 @@
1
+ #import "MentionParams.h"
2
+
3
+ @implementation MentionParams
4
+ @end
@@ -0,0 +1,13 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+ #import "TextDecorationLineEnum.h"
4
+ #import "string"
5
+ #import <folly/dynamic.h>
6
+
7
+ @interface MentionStyleProps : NSObject
8
+ @property UIColor *color;
9
+ @property UIColor *backgroundColor;
10
+ @property TextDecorationLineEnum decorationLine;
11
+ + (NSDictionary *)getSinglePropsFromFollyDynamic:(folly::dynamic)folly;
12
+ + (NSDictionary *)getComplexPropsFromFollyDynamic:(folly::dynamic)folly;
13
+ @end
@@ -0,0 +1,56 @@
1
+ #import "MentionStyleProps.h"
2
+ #import <React/RCTConversions.h>
3
+ #import "StringExtension.h"
4
+
5
+ @implementation MentionStyleProps
6
+
7
+ + (MentionStyleProps *)getSingleMentionStylePropsFromFollyDynamic:(folly::dynamic)folly {
8
+ MentionStyleProps *nativeProps = [[MentionStyleProps alloc] init];
9
+
10
+ if(folly["color"].isNumber()) {
11
+ facebook::react::SharedColor color = facebook::react::SharedColor(facebook::react::Color(folly["color"].asInt()));
12
+ nativeProps.color = RCTUIColorFromSharedColor(color);
13
+ } else {
14
+ nativeProps.color = [UIColor blueColor];
15
+ }
16
+
17
+ if(folly["backgroundColor"].isNumber()) {
18
+ facebook::react::SharedColor bgColor = facebook::react::SharedColor(facebook::react::Color(folly["backgroundColor"].asInt()));
19
+ nativeProps.backgroundColor = RCTUIColorFromSharedColor(bgColor);
20
+ } else {
21
+ nativeProps.backgroundColor = [UIColor yellowColor];
22
+ }
23
+
24
+ if(folly["textDecorationLine"].isString()) {
25
+ std::string textDecorationLine = folly["textDecorationLine"].asString();
26
+ nativeProps.decorationLine = [[NSString fromCppString:textDecorationLine] isEqualToString:DecorationUnderline] ? DecorationUnderline : DecorationNone;
27
+ } else {
28
+ nativeProps.decorationLine = DecorationUnderline;
29
+ }
30
+
31
+ return nativeProps;
32
+ }
33
+
34
+ + (NSDictionary *)getSinglePropsFromFollyDynamic:(folly::dynamic)folly {
35
+ MentionStyleProps *nativeProps = [MentionStyleProps getSingleMentionStylePropsFromFollyDynamic:folly];
36
+ // the single props need to be somehow distinguishable in config
37
+ NSDictionary *dict = @{@"all": nativeProps};
38
+ return dict;
39
+ }
40
+
41
+ + (NSDictionary *)getComplexPropsFromFollyDynamic:(folly::dynamic)folly {
42
+ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
43
+
44
+ for(const auto& obj: folly.items()) {
45
+ if(obj.first.isString() && obj.second.isObject()) {
46
+ std::string key = obj.first.asString();
47
+ MentionStyleProps *props = [MentionStyleProps getSingleMentionStylePropsFromFollyDynamic:obj.second];
48
+ dict[[NSString fromCppString:key]] = props;
49
+ }
50
+ }
51
+
52
+ return dict;
53
+ }
54
+
55
+ @end
56
+
@@ -0,0 +1,37 @@
1
+ #pragma once
2
+ #import "StylePair.h"
3
+ #import "EnrichedTextInputView.h"
4
+
5
+
6
+ @interface OccurenceUtils : NSObject
7
+ + (BOOL)detect
8
+ :(NSAttributedStringKey _Nonnull)key
9
+ withInput:(EnrichedTextInputView* _Nonnull)input
10
+ inRange:(NSRange)range
11
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
12
+ + (BOOL)detectMultiple
13
+ :(NSArray<NSAttributedStringKey> *_Nonnull)keys
14
+ withInput:(EnrichedTextInputView* _Nonnull)input
15
+ inRange:(NSRange)range
16
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
17
+ + (BOOL)any
18
+ :(NSAttributedStringKey _Nonnull)key
19
+ withInput:(EnrichedTextInputView* _Nonnull)input
20
+ inRange:(NSRange)range
21
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
22
+ + (BOOL)anyMultiple
23
+ :(NSArray<NSAttributedStringKey> *_Nonnull)keys
24
+ withInput:(EnrichedTextInputView* _Nonnull)input
25
+ inRange:(NSRange)range
26
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
27
+ + (NSArray<StylePair *> *_Nullable)all
28
+ :(NSAttributedStringKey _Nonnull)key
29
+ withInput:(EnrichedTextInputView* _Nonnull)input
30
+ inRange:(NSRange)range
31
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
32
+ + (NSArray<StylePair *> *_Nullable)allMultiple
33
+ :(NSArray<NSAttributedStringKey> *_Nonnull)keys
34
+ withInput:(EnrichedTextInputView* _Nonnull)input
35
+ inRange:(NSRange)range
36
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
37
+ @end
@@ -0,0 +1,124 @@
1
+ #import "OccurenceUtils.h"
2
+
3
+ @implementation OccurenceUtils
4
+
5
+ + (BOOL)detect
6
+ :(NSAttributedStringKey _Nonnull)key
7
+ withInput:(EnrichedTextInputView* _Nonnull)input
8
+ inRange:(NSRange)range
9
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
10
+ {
11
+ __block NSInteger totalLength = 0;
12
+ [input->textView.textStorage enumerateAttribute:key inRange:range options:0 usingBlock:
13
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
14
+ if(condition(value, range)) {
15
+ totalLength += range.length;
16
+ }
17
+ }
18
+ ];
19
+ return totalLength == range.length;
20
+ }
21
+
22
+ + (BOOL)detectMultiple
23
+ :(NSArray<NSAttributedStringKey> *_Nonnull)keys
24
+ withInput:(EnrichedTextInputView* _Nonnull)input
25
+ inRange:(NSRange)range
26
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
27
+ {
28
+ __block NSInteger totalLength = 0;
29
+ for(NSString* key in keys) {
30
+ [input->textView.textStorage enumerateAttribute:key inRange:range options:0 usingBlock:
31
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
32
+ if(condition(value, range)) {
33
+ totalLength += range.length;
34
+ }
35
+ }
36
+ ];
37
+ }
38
+ return totalLength == range.length;
39
+ }
40
+
41
+ + (BOOL)any
42
+ :(NSAttributedStringKey _Nonnull)key
43
+ withInput:(EnrichedTextInputView* _Nonnull)input
44
+ inRange:(NSRange)range
45
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
46
+ {
47
+ __block BOOL found = NO;
48
+ [input->textView.textStorage enumerateAttribute:key inRange:range options:0 usingBlock:
49
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
50
+ if(condition(value, range)) {
51
+ found = YES;
52
+ *stop = YES;
53
+ }
54
+ }
55
+ ];
56
+ return found;
57
+ }
58
+
59
+ + (BOOL)anyMultiple
60
+ :(NSArray<NSAttributedStringKey> *_Nonnull)keys
61
+ withInput:(EnrichedTextInputView* _Nonnull)input
62
+ inRange:(NSRange)range
63
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
64
+ {
65
+ __block BOOL found = NO;
66
+ for(NSString *key in keys) {
67
+ [input->textView.textStorage enumerateAttribute:key inRange:range options:0 usingBlock:
68
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
69
+ if(condition(value, range)) {
70
+ found = YES;
71
+ *stop = YES;
72
+ }
73
+ }
74
+ ];
75
+ if(found) {
76
+ return YES;
77
+ }
78
+ }
79
+ return NO;
80
+ }
81
+
82
+ + (NSArray<StylePair *> *_Nullable)all
83
+ :(NSAttributedStringKey _Nonnull)key
84
+ withInput:(EnrichedTextInputView* _Nonnull)input
85
+ inRange:(NSRange)range
86
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
87
+ {
88
+ __block NSMutableArray<StylePair *> *occurences = [[NSMutableArray<StylePair *> alloc] init];
89
+ [input->textView.textStorage enumerateAttribute:key inRange:range options:0 usingBlock:
90
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
91
+ if(condition(value, range)) {
92
+ StylePair *pair = [[StylePair alloc] init];
93
+ pair.rangeValue = [NSValue valueWithRange:range];
94
+ pair.styleValue = value;
95
+ [occurences addObject:pair];
96
+ }
97
+ }
98
+ ];
99
+ return occurences;
100
+ }
101
+
102
+ + (NSArray<StylePair *> *_Nullable)allMultiple
103
+ :(NSArray<NSAttributedStringKey> *_Nonnull)keys
104
+ withInput:(EnrichedTextInputView* _Nonnull)input
105
+ inRange:(NSRange)range
106
+ withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
107
+ {
108
+ __block NSMutableArray<StylePair *> *occurences = [[NSMutableArray<StylePair *> alloc] init];
109
+ for(NSString *key in keys) {
110
+ [input->textView.textStorage enumerateAttribute:key inRange:range options:0 usingBlock:
111
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
112
+ if(condition(value, range)) {
113
+ StylePair *pair = [[StylePair alloc] init];
114
+ pair.rangeValue = [NSValue valueWithRange:range];
115
+ pair.styleValue = value;
116
+ [occurences addObject:pair];
117
+ }
118
+ }
119
+ ];
120
+ }
121
+ return occurences;
122
+ }
123
+
124
+ @end
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+
4
+ @interface ParagraphsUtils : NSObject
5
+ + (NSArray *)getSeparateParagraphsRangesIn:(UITextView *)textView range:(NSRange)range;
6
+ + (NSArray *)getNonNewlineRangesIn:(UITextView *)textView range:(NSRange)range;
7
+ @end
@@ -0,0 +1,54 @@
1
+ #import "ParagraphsUtils.h"
2
+
3
+ @implementation ParagraphsUtils
4
+
5
+ + (NSArray *)getSeparateParagraphsRangesIn:(UITextView *)textView range:(NSRange)range {
6
+ // just in case, get full paragraphs range
7
+ NSRange fullRange = [textView.textStorage.string paragraphRangeForRange:range];
8
+
9
+ // we are in an empty paragraph
10
+ if(fullRange.length == 0) {
11
+ return @[[NSValue valueWithRange:fullRange]];
12
+ }
13
+
14
+ NSMutableArray *results = [[NSMutableArray alloc] init];
15
+
16
+ NSInteger lastStart = fullRange.location;
17
+ for(int i = fullRange.location; i < fullRange.location + fullRange.length; i++) {
18
+ unichar currentChar = [textView.textStorage.string characterAtIndex:i];
19
+ if([[NSCharacterSet newlineCharacterSet] characterIsMember:currentChar]) {
20
+ NSRange paragraphRange = [textView.textStorage.string paragraphRangeForRange:NSMakeRange(lastStart, i - lastStart)];
21
+ [results addObject: [NSValue valueWithRange:paragraphRange]];
22
+ lastStart = i+1;
23
+ }
24
+ }
25
+
26
+ if(lastStart < fullRange.location + fullRange.length) {
27
+ NSRange paragraphRange = [textView.textStorage.string paragraphRangeForRange:NSMakeRange(lastStart, fullRange.location + fullRange.length - lastStart)];
28
+ [results addObject: [NSValue valueWithRange:paragraphRange]];
29
+ }
30
+
31
+ return results;
32
+ }
33
+
34
+ + (NSArray *)getNonNewlineRangesIn:(UITextView *)textView range:(NSRange)range {
35
+ NSMutableArray *nonNewlineRanges = [[NSMutableArray alloc] init];
36
+ int lastRangeLocation = range.location;
37
+
38
+ for(int i = range.location; i < range.location + range.length; i++) {
39
+ unichar currentChar = [textView.textStorage.string characterAtIndex:i];
40
+ if([[NSCharacterSet newlineCharacterSet] characterIsMember:currentChar]) {
41
+ if(i - lastRangeLocation > 0) {
42
+ [nonNewlineRanges addObject:[NSValue valueWithRange:NSMakeRange(lastRangeLocation, i - lastRangeLocation)]];
43
+ }
44
+ lastRangeLocation = i+1;
45
+ }
46
+ }
47
+ if(lastRangeLocation < range.location + range.length) {
48
+ [nonNewlineRanges addObject:[NSValue valueWithRange:NSMakeRange(lastRangeLocation, range.location + range.length - lastRangeLocation)]];
49
+ }
50
+
51
+ return nonNewlineRanges;
52
+ }
53
+
54
+ @end
@@ -0,0 +1,15 @@
1
+ #import <UIKit/UIKit.h>
2
+ #include "string"
3
+ #pragma once
4
+
5
+ @interface NSString (StringExtension)
6
+ - (std::string)toCppString;
7
+ + (NSString *)fromCppString:(std::string)string;
8
+ + (NSString *)stringByEscapingHtml:(NSString *)html;
9
+ + (NSString *)stringByUnescapingHtml:(NSString *)html;
10
+ @end
11
+
12
+ @interface NSMutableString (StringExtension)
13
+ - (std::string)toCppString;
14
+ + (NSMutableString *)fromCppString:(std::string)string;
15
+ @end
@@ -0,0 +1,57 @@
1
+ #import "StringExtension.h"
2
+
3
+ @implementation NSString (StringExtension)
4
+
5
+ - (std::string)toCppString {
6
+ return std::string([self UTF8String]);
7
+ }
8
+
9
+ + (NSString *)fromCppString:(std::string)string {
10
+ return [NSString stringWithUTF8String:string.c_str()];
11
+ }
12
+
13
+ + (NSString *)stringByEscapingHtml:(NSString *)html {
14
+ NSMutableString *escaped = [html mutableCopy];
15
+ NSDictionary *escapeMap = @{
16
+ @"&": @"&amp;",
17
+ @"<": @"&lt;",
18
+ @">": @"&gt;",
19
+ @"\"": @"&quot;",
20
+ @"'": @"&apos;"
21
+ };
22
+
23
+ for(NSString *key in escapeMap) {
24
+ [escaped replaceOccurrencesOfString:key withString:escapeMap[key] options:NSLiteralSearch range:NSMakeRange(0, escaped.length)];
25
+ }
26
+ return escaped;
27
+ }
28
+
29
+ + (NSString *)stringByUnescapingHtml:(NSString *)html {
30
+ NSMutableString *unescaped = [html mutableCopy];
31
+ NSDictionary *unescapeMap = @{
32
+ @"&amp;": @"&",
33
+ @"&lt;": @"<",
34
+ @"&gt;": @">",
35
+ @"&quot;": @"\"",
36
+ @"&apos;": @"'",
37
+ };
38
+
39
+ for(NSString *key in unescapeMap) {
40
+ [unescaped replaceOccurrencesOfString:key withString:unescapeMap[key] options:NSLiteralSearch range:NSMakeRange(0, unescaped.length)];
41
+ }
42
+ return unescaped;
43
+ }
44
+
45
+ @end
46
+
47
+ @implementation NSMutableString (StringExtension)
48
+
49
+ - (std::string)toCppString {
50
+ return std::string([self UTF8String]);
51
+ }
52
+
53
+ + (NSMutableString *)fromCppString:(std::string)string {
54
+ return [NSMutableString stringWithUTF8String:string.c_str()];
55
+ }
56
+
57
+ @end
@@ -0,0 +1,74 @@
1
+ #pragma once
2
+ #import "BaseStyleProtocol.h"
3
+ #import "LinkData.h"
4
+ #import "MentionParams.h"
5
+
6
+ @interface BoldStyle : NSObject <BaseStyleProtocol>
7
+ @end
8
+
9
+ @interface ItalicStyle : NSObject <BaseStyleProtocol>
10
+ @end
11
+
12
+ @interface UnderlineStyle : NSObject <BaseStyleProtocol>
13
+ @end
14
+
15
+ @interface StrikethroughStyle : NSObject <BaseStyleProtocol>
16
+ @end
17
+
18
+ @interface InlineCodeStyle : NSObject <BaseStyleProtocol>
19
+ - (void)handleNewlines;
20
+ @end
21
+
22
+ @interface LinkStyle : NSObject <BaseStyleProtocol>
23
+ - (void)addLink:(NSString*)text url:(NSString*)url range:(NSRange)range manual:(BOOL)manual;
24
+ - (LinkData *)getLinkDataAt:(NSUInteger)location;
25
+ - (NSRange)getFullLinkRangeAt:(NSUInteger)location;
26
+ - (void)manageLinkTypingAttributes;
27
+ - (void)handleAutomaticLinks:(NSString *)word inRange:(NSRange)wordRange;
28
+ - (void)handleManualLinks:(NSString *)word inRange:(NSRange)wordRange;
29
+ - (BOOL)handleLeadingLinkReplacement:(NSRange)range replacementText:(NSString *)text;
30
+ @end
31
+
32
+ @interface MentionStyle : NSObject<BaseStyleProtocol>
33
+ - (void)addMention:(NSString *)indicator text:(NSString *)text attributes:(NSString *)attributes;
34
+ - (void)addMentionAtRange:(NSRange)range params:(MentionParams *)params;
35
+ - (void)startMentionWithIndicator:(NSString *)indicator;
36
+ - (void)handleExistingMentions;
37
+ - (void)manageMentionEditing;
38
+ - (void)manageMentionTypingAttributes;
39
+ - (BOOL)handleLeadingMentionReplacement:(NSRange)range replacementText:(NSString *)text;
40
+ - (MentionParams *)getMentionParamsAt:(NSUInteger)location;
41
+ - (NSRange)getFullMentionRangeAt:(NSUInteger)location;
42
+ - (NSValue *)getActiveMentionRange;
43
+ @end
44
+
45
+ @interface HeadingStyleBase : NSObject<BaseStyleProtocol> {
46
+ id input;
47
+ }
48
+ - (CGFloat)getHeadingFontSize;
49
+ - (BOOL)isHeadingBold;
50
+ @end
51
+
52
+ @interface H1Style : HeadingStyleBase
53
+ @end
54
+
55
+ @interface H2Style : HeadingStyleBase
56
+ @end
57
+
58
+ @interface H3Style : HeadingStyleBase
59
+ @end
60
+
61
+ @interface UnorderedListStyle : NSObject<BaseStyleProtocol>
62
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text;
63
+ - (BOOL)tryHandlingListShorcutInRange:(NSRange)range replacementText:(NSString *)text;
64
+ @end
65
+
66
+ @interface OrderedListStyle : NSObject<BaseStyleProtocol>
67
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text;
68
+ - (BOOL)tryHandlingListShorcutInRange:(NSRange)range replacementText:(NSString *)text;
69
+ @end
70
+
71
+ @interface BlockQuoteStyle : NSObject<BaseStyleProtocol>
72
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text;
73
+ - (void)manageBlockquoteColor;
74
+ @end
@@ -0,0 +1,9 @@
1
+ #pragma once
2
+ #import <UIkit/UIKit.h>
3
+
4
+ @interface StylePair : NSObject
5
+
6
+ @property NSValue *rangeValue;
7
+ @property id styleValue;
8
+
9
+ @end
@@ -0,0 +1,4 @@
1
+ #import "StylePair.h"
2
+
3
+ @implementation StylePair
4
+ @end
@@ -0,0 +1,22 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+
4
+ // the order is aligned with the order of tags in parser
5
+ typedef NS_ENUM(NSInteger, StyleType) {
6
+ BlockQuote,
7
+ CodeBlock,
8
+ UnorderedList,
9
+ OrderedList,
10
+ H1,
11
+ H2,
12
+ H3,
13
+ Link,
14
+ Mention,
15
+ Image,
16
+ InlineCode,
17
+ Bold,
18
+ Italic,
19
+ Underline,
20
+ Strikethrough,
21
+ None,
22
+ };