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
@@ -0,0 +1,304 @@
1
+ #import "ColorExtension.h"
2
+ #import "EnrichedTextInputView.h"
3
+ #import "FontExtension.h"
4
+ #import "OccurenceUtils.h"
5
+ #import "ParagraphsUtils.h"
6
+ #import "StyleHeaders.h"
7
+ #import "TextInsertionUtils.h"
8
+
9
+ @implementation CodeBlockStyle {
10
+ EnrichedTextInputView *_input;
11
+ NSArray *_stylesToExclude;
12
+ }
13
+
14
+ + (StyleType)getStyleType {
15
+ return CodeBlock;
16
+ }
17
+
18
+ + (BOOL)isParagraphStyle {
19
+ return YES;
20
+ }
21
+
22
+ - (instancetype)initWithInput:(id)input {
23
+ self = [super init];
24
+ _input = (EnrichedTextInputView *)input;
25
+ _stylesToExclude = @[ @(InlineCode), @(Mention), @(Link) ];
26
+ return self;
27
+ }
28
+
29
+ - (void)applyStyle:(NSRange)range {
30
+ BOOL isStylePresent = [self detectStyle:range];
31
+ if (range.length >= 1) {
32
+ isStylePresent ? [self removeAttributes:range]
33
+ : [self addAttributes:range withTypingAttr:YES];
34
+ } else {
35
+ isStylePresent ? [self removeTypingAttributes] : [self addTypingAttributes];
36
+ }
37
+ }
38
+
39
+ - (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
40
+ NSTextList *codeBlockList =
41
+ [[NSTextList alloc] initWithMarkerFormat:@"codeblock" options:0];
42
+ NSArray *paragraphs =
43
+ [ParagraphsUtils getSeparateParagraphsRangesIn:_input->textView
44
+ range:range];
45
+ // if we fill empty lines with zero width spaces, we need to offset later
46
+ // ranges
47
+ NSInteger offset = 0;
48
+ NSRange preModificationRange = _input->textView.selectedRange;
49
+
50
+ // to not emit any space filling selection/text changes
51
+ _input->blockEmitting = YES;
52
+
53
+ for (NSValue *value in paragraphs) {
54
+ NSRange pRange = NSMakeRange([value rangeValue].location + offset,
55
+ [value rangeValue].length);
56
+ // length 0 with first line, length 1 and newline with some empty lines in
57
+ // the middle
58
+ if (pRange.length == 0 ||
59
+ (pRange.length == 1 &&
60
+ [[NSCharacterSet newlineCharacterSet]
61
+ characterIsMember:[_input->textView.textStorage.string
62
+ characterAtIndex:pRange.location]])) {
63
+ [TextInsertionUtils insertText:@"\u200B"
64
+ at:pRange.location
65
+ additionalAttributes:nullptr
66
+ input:_input
67
+ withSelection:NO];
68
+ pRange = NSMakeRange(pRange.location, pRange.length + 1);
69
+ offset += 1;
70
+ }
71
+
72
+ [_input->textView.textStorage
73
+ enumerateAttribute:NSParagraphStyleAttributeName
74
+ inRange:pRange
75
+ options:0
76
+ usingBlock:^(id _Nullable value, NSRange range,
77
+ BOOL *_Nonnull stop) {
78
+ NSMutableParagraphStyle *pStyle =
79
+ [(NSParagraphStyle *)value mutableCopy];
80
+ pStyle.textLists = @[ codeBlockList ];
81
+ [_input->textView.textStorage
82
+ addAttribute:NSParagraphStyleAttributeName
83
+ value:pStyle
84
+ range:range];
85
+ }];
86
+ }
87
+
88
+ // back to emitting
89
+ _input->blockEmitting = NO;
90
+
91
+ if (preModificationRange.length == 0) {
92
+ // fix selection if only one line was possibly made a list and filled with a
93
+ // space
94
+ _input->textView.selectedRange = preModificationRange;
95
+ } else {
96
+ // in other cases, fix the selection with newly made offsets
97
+ _input->textView.selectedRange = NSMakeRange(
98
+ preModificationRange.location, preModificationRange.length + offset);
99
+ }
100
+
101
+ // also add typing attributes
102
+ if (withTypingAttr) {
103
+ NSMutableDictionary *typingAttrs =
104
+ [_input->textView.typingAttributes mutableCopy];
105
+ NSMutableParagraphStyle *pStyle =
106
+ [typingAttrs[NSParagraphStyleAttributeName] mutableCopy];
107
+ pStyle.textLists = @[ codeBlockList ];
108
+ typingAttrs[NSParagraphStyleAttributeName] = pStyle;
109
+
110
+ _input->textView.typingAttributes = typingAttrs;
111
+ }
112
+ }
113
+
114
+ - (void)addTypingAttributes {
115
+ [self addAttributes:_input->textView.selectedRange withTypingAttr:YES];
116
+ }
117
+
118
+ - (void)removeAttributes:(NSRange)range {
119
+ NSArray *paragraphs =
120
+ [ParagraphsUtils getSeparateParagraphsRangesIn:_input->textView
121
+ range:range];
122
+
123
+ [_input->textView.textStorage beginEditing];
124
+
125
+ for (NSValue *value in paragraphs) {
126
+ NSRange pRange = [value rangeValue];
127
+
128
+ [_input->textView.textStorage
129
+ enumerateAttribute:NSParagraphStyleAttributeName
130
+ inRange:pRange
131
+ options:0
132
+ usingBlock:^(id _Nullable value, NSRange range,
133
+ BOOL *_Nonnull stop) {
134
+ NSMutableParagraphStyle *pStyle =
135
+ [(NSParagraphStyle *)value mutableCopy];
136
+ pStyle.textLists = @[];
137
+ [_input->textView.textStorage
138
+ addAttribute:NSParagraphStyleAttributeName
139
+ value:pStyle
140
+ range:range];
141
+ }];
142
+ }
143
+
144
+ [_input->textView.textStorage endEditing];
145
+
146
+ // also remove typing attributes
147
+ NSMutableDictionary *typingAttrs =
148
+ [_input->textView.typingAttributes mutableCopy];
149
+ NSMutableParagraphStyle *pStyle =
150
+ [typingAttrs[NSParagraphStyleAttributeName] mutableCopy];
151
+ pStyle.textLists = @[];
152
+
153
+ typingAttrs[NSParagraphStyleAttributeName] = pStyle;
154
+
155
+ _input->textView.typingAttributes = typingAttrs;
156
+ }
157
+
158
+ - (void)removeTypingAttributes {
159
+ [self removeAttributes:_input->textView.selectedRange];
160
+ }
161
+
162
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text {
163
+ if ([self detectStyle:_input->textView.selectedRange] && text.length == 0) {
164
+ // backspace while the style is active
165
+
166
+ NSRange paragraphRange = [_input->textView.textStorage.string
167
+ paragraphRangeForRange:_input->textView.selectedRange];
168
+
169
+ if (NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0))) {
170
+ // a backspace on the very first input's line quote
171
+ // it doesn't run textVieDidChange so we need to manually remove
172
+ // attributes
173
+ [self removeAttributes:paragraphRange];
174
+ return YES;
175
+ }
176
+ }
177
+ return NO;
178
+ }
179
+
180
+ - (BOOL)styleCondition:(id _Nullable)value:(NSRange)range {
181
+ NSParagraphStyle *paragraph = (NSParagraphStyle *)value;
182
+ return paragraph != nullptr && paragraph.textLists.count == 1 &&
183
+ [paragraph.textLists.firstObject.markerFormat
184
+ isEqualToString:@"codeblock"];
185
+ }
186
+
187
+ - (BOOL)detectStyle:(NSRange)range {
188
+ if (range.length >= 1) {
189
+ return [OccurenceUtils detect:NSParagraphStyleAttributeName
190
+ withInput:_input
191
+ inRange:range
192
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
193
+ return [self styleCondition:value:range];
194
+ }];
195
+ } else {
196
+ return [OccurenceUtils detect:NSParagraphStyleAttributeName
197
+ withInput:_input
198
+ atIndex:range.location
199
+ checkPrevious:YES
200
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
201
+ return [self styleCondition:value:range];
202
+ }];
203
+ }
204
+ }
205
+
206
+ - (BOOL)anyOccurence:(NSRange)range {
207
+ return [OccurenceUtils any:NSParagraphStyleAttributeName
208
+ withInput:_input
209
+ inRange:range
210
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
211
+ return [self styleCondition:value:range];
212
+ }];
213
+ }
214
+
215
+ - (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
216
+ return [OccurenceUtils all:NSParagraphStyleAttributeName
217
+ withInput:_input
218
+ inRange:range
219
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
220
+ return [self styleCondition:value:range];
221
+ }];
222
+ }
223
+
224
+ - (void)manageCodeBlockFontAndColor {
225
+ if ([[_input->config codeBlockFgColor]
226
+ isEqualToColor:[_input->config primaryColor]]) {
227
+ return;
228
+ }
229
+
230
+ NSRange wholeRange =
231
+ NSMakeRange(0, _input->textView.textStorage.string.length);
232
+ NSArray *paragraphs =
233
+ [ParagraphsUtils getSeparateParagraphsRangesIn:_input->textView
234
+ range:wholeRange];
235
+
236
+ for (NSValue *pValue in paragraphs) {
237
+ NSRange paragraphRange = [pValue rangeValue];
238
+ NSArray *properRanges = [OccurenceUtils getRangesWithout:_stylesToExclude
239
+ withInput:_input
240
+ inRange:paragraphRange];
241
+
242
+ for (NSValue *value in properRanges) {
243
+ NSRange currRange = [value rangeValue];
244
+ BOOL selfDetected = [self detectStyle:currRange];
245
+
246
+ [_input->textView.textStorage
247
+ enumerateAttribute:NSFontAttributeName
248
+ inRange:currRange
249
+ options:0
250
+ usingBlock:^(id _Nullable value, NSRange range,
251
+ BOOL *_Nonnull stop) {
252
+ UIFont *currentFont = (UIFont *)value;
253
+ UIFont *newFont = nullptr;
254
+
255
+ BOOL isCodeFont = [[currentFont familyName]
256
+ isEqualToString:[[_input->config monospacedFont]
257
+ familyName]];
258
+
259
+ if (isCodeFont && !selfDetected) {
260
+ newFont = [[[_input->config primaryFont]
261
+ withFontTraits:currentFont]
262
+ setSize:currentFont.pointSize];
263
+ } else if (!isCodeFont && selfDetected) {
264
+ newFont = [[[_input->config monospacedFont]
265
+ withFontTraits:currentFont]
266
+ setSize:currentFont.pointSize];
267
+ }
268
+
269
+ if (newFont != nullptr) {
270
+ [_input->textView.textStorage
271
+ addAttribute:NSFontAttributeName
272
+ value:newFont
273
+ range:range];
274
+ }
275
+ }];
276
+
277
+ [_input->textView.textStorage
278
+ enumerateAttribute:NSForegroundColorAttributeName
279
+ inRange:currRange
280
+ options:0
281
+ usingBlock:^(id _Nullable value, NSRange range,
282
+ BOOL *_Nonnull stop) {
283
+ UIColor *newColor = nullptr;
284
+ BOOL colorApplied = [(UIColor *)value
285
+ isEqualToColor:[_input->config codeBlockFgColor]];
286
+
287
+ if (colorApplied && !selfDetected) {
288
+ newColor = [_input->config primaryColor];
289
+ } else if (!colorApplied && selfDetected) {
290
+ newColor = [_input->config codeBlockFgColor];
291
+ }
292
+
293
+ if (newColor != nullptr) {
294
+ [_input->textView.textStorage
295
+ addAttribute:NSForegroundColorAttributeName
296
+ value:newColor
297
+ range:range];
298
+ }
299
+ }];
300
+ }
301
+ }
302
+ }
303
+
304
+ @end
@@ -1,9 +1,16 @@
1
- #import "StyleHeaders.h"
2
1
  #import "EnrichedTextInputView.h"
2
+ #import "StyleHeaders.h"
3
3
 
4
4
  @implementation H1Style
5
- + (StyleType)getStyleType { return H1; }
6
- - (CGFloat)getHeadingFontSize { return [((EnrichedTextInputView *)input)->config h1FontSize]; }
5
+ + (StyleType)getStyleType {
6
+ return H1;
7
+ }
8
+ + (BOOL)isParagraphStyle {
9
+ return YES;
10
+ }
11
+ - (CGFloat)getHeadingFontSize {
12
+ return [((EnrichedTextInputView *)input)->config h1FontSize];
13
+ }
7
14
  - (BOOL)isHeadingBold {
8
15
  return [((EnrichedTextInputView *)input)->config h1Bold];
9
16
  }
@@ -1,9 +1,16 @@
1
- #import "StyleHeaders.h"
2
1
  #import "EnrichedTextInputView.h"
2
+ #import "StyleHeaders.h"
3
3
 
4
4
  @implementation H2Style
5
- + (StyleType)getStyleType { return H2; }
6
- - (CGFloat)getHeadingFontSize { return [((EnrichedTextInputView *)input)->config h2FontSize]; }
5
+ + (StyleType)getStyleType {
6
+ return H2;
7
+ }
8
+ + (BOOL)isParagraphStyle {
9
+ return YES;
10
+ }
11
+ - (CGFloat)getHeadingFontSize {
12
+ return [((EnrichedTextInputView *)input)->config h2FontSize];
13
+ }
7
14
  - (BOOL)isHeadingBold {
8
15
  return [((EnrichedTextInputView *)input)->config h2Bold];
9
16
  }
@@ -1,9 +1,16 @@
1
- #import "StyleHeaders.h"
2
1
  #import "EnrichedTextInputView.h"
2
+ #import "StyleHeaders.h"
3
3
 
4
4
  @implementation H3Style
5
- + (StyleType)getStyleType { return H3; }
6
- - (CGFloat)getHeadingFontSize { return [((EnrichedTextInputView *)input)->config h3FontSize]; }
5
+ + (StyleType)getStyleType {
6
+ return H3;
7
+ }
8
+ + (BOOL)isParagraphStyle {
9
+ return YES;
10
+ }
11
+ - (CGFloat)getHeadingFontSize {
12
+ return [((EnrichedTextInputView *)input)->config h3FontSize];
13
+ }
7
14
  - (BOOL)isHeadingBold {
8
15
  return [((EnrichedTextInputView *)input)->config h3Bold];
9
16
  }
@@ -1,15 +1,21 @@
1
- #import "StyleHeaders.h"
2
1
  #import "EnrichedTextInputView.h"
3
2
  #import "FontExtension.h"
4
3
  #import "OccurenceUtils.h"
4
+ #import "StyleHeaders.h"
5
5
  #import "TextInsertionUtils.h"
6
6
 
7
7
  @implementation HeadingStyleBase
8
8
 
9
9
  // mock values since H1/2/3Style classes anyway are used
10
- + (StyleType)getStyleType { return None; }
11
- - (CGFloat)getHeadingFontSize { return 0; }
12
- - (BOOL)isHeadingBold { return false; }
10
+ + (StyleType)getStyleType {
11
+ return None;
12
+ }
13
+ - (CGFloat)getHeadingFontSize {
14
+ return 0;
15
+ }
16
+ - (BOOL)isHeadingBold {
17
+ return false;
18
+ }
13
19
 
14
20
  - (EnrichedTextInputView *)typedInput {
15
21
  return (EnrichedTextInputView *)input;
@@ -25,41 +31,54 @@
25
31
  // but if the paragraph is empty it still is of length 0
26
32
  - (void)applyStyle:(NSRange)range {
27
33
  BOOL isStylePresent = [self detectStyle:range];
28
- if(range.length >= 1) {
29
- isStylePresent ? [self removeAttributes:range] : [self addAttributes:range];
34
+ if (range.length >= 1) {
35
+ isStylePresent ? [self removeAttributes:range]
36
+ : [self addAttributes:range withTypingAttr:YES];
30
37
  } else {
31
38
  isStylePresent ? [self removeTypingAttributes] : [self addTypingAttributes];
32
39
  }
33
40
  }
34
41
 
35
42
  // the range will already be the proper full paragraph/s range
36
- - (void)addAttributes:(NSRange)range {
43
+ - (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
37
44
  [[self typedInput]->textView.textStorage beginEditing];
38
- [[self typedInput]->textView.textStorage enumerateAttribute:NSFontAttributeName inRange:range options:0
39
- usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
40
- UIFont *font = (UIFont *)value;
41
- if(font != nullptr) {
42
- UIFont *newFont = [font setSize:[self getHeadingFontSize]];
43
- if([self isHeadingBold]) {
44
- newFont = [newFont setBold];
45
- }
46
- [[self typedInput]->textView.textStorage addAttribute:NSFontAttributeName value:newFont range:range];
47
- }
48
- }
49
- ];
45
+ [[self typedInput]->textView.textStorage
46
+ enumerateAttribute:NSFontAttributeName
47
+ inRange:range
48
+ options:0
49
+ usingBlock:^(id _Nullable value, NSRange range,
50
+ BOOL *_Nonnull stop) {
51
+ UIFont *font = (UIFont *)value;
52
+ if (font != nullptr) {
53
+ UIFont *newFont = [font setSize:[self getHeadingFontSize]];
54
+ if ([self isHeadingBold]) {
55
+ newFont = [newFont setBold];
56
+ }
57
+ [[self typedInput]->textView.textStorage
58
+ addAttribute:NSFontAttributeName
59
+ value:newFont
60
+ range:range];
61
+ }
62
+ }];
50
63
  [[self typedInput]->textView.textStorage endEditing];
51
-
64
+
52
65
  // also toggle typing attributes
53
- [self addTypingAttributes];
66
+ if (withTypingAttr) {
67
+ [self addTypingAttributes];
68
+ }
54
69
  }
55
70
 
56
- // will always be called on empty paragraphs so only typing attributes can be changed
71
+ // will always be called on empty paragraphs so only typing attributes can be
72
+ // changed
57
73
  - (void)addTypingAttributes {
58
- UIFont *currentFontAttr = (UIFont *)[self typedInput]->textView.typingAttributes[NSFontAttributeName];
59
- if(currentFontAttr != nullptr) {
60
- NSMutableDictionary *newTypingAttrs = [[self typedInput]->textView.typingAttributes mutableCopy];
74
+ UIFont *currentFontAttr =
75
+ (UIFont *)[self typedInput]
76
+ ->textView.typingAttributes[NSFontAttributeName];
77
+ if (currentFontAttr != nullptr) {
78
+ NSMutableDictionary *newTypingAttrs =
79
+ [[self typedInput]->textView.typingAttributes mutableCopy];
61
80
  UIFont *newFont = [currentFontAttr setSize:[self getHeadingFontSize]];
62
- if([self isHeadingBold]) {
81
+ if ([self isHeadingBold]) {
63
82
  newFont = [newFont setBold];
64
83
  }
65
84
  newTypingAttrs[NSFontAttributeName] = newFont;
@@ -69,28 +88,41 @@
69
88
 
70
89
  // we need to remove the style from the whole paragraph
71
90
  - (void)removeAttributes:(NSRange)range {
72
- NSRange paragraphRange = [[self typedInput]->textView.textStorage.string paragraphRangeForRange:range];
73
-
91
+ NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
92
+ paragraphRangeForRange:range];
93
+
74
94
  [[self typedInput]->textView.textStorage beginEditing];
75
- [[self typedInput]->textView.textStorage enumerateAttribute:NSFontAttributeName inRange:paragraphRange options:0
76
- usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
77
- if([self styleCondition:value :range]) {
78
- UIFont *newFont = [(UIFont *)value setSize:[[[self typedInput]->config primaryFontSize] floatValue]];
79
- if([self isHeadingBold]) {
80
- newFont = [newFont removeBold];
81
- }
82
- [[self typedInput]->textView.textStorage addAttribute:NSFontAttributeName value:newFont range:range];
83
- }
84
- }
85
- ];
95
+ [[self typedInput]->textView.textStorage
96
+ enumerateAttribute:NSFontAttributeName
97
+ inRange:paragraphRange
98
+ options:0
99
+ usingBlock:^(id _Nullable value, NSRange range,
100
+ BOOL *_Nonnull stop) {
101
+ if ([self styleCondition:value:range]) {
102
+ UIFont *newFont = [(UIFont *)value
103
+ setSize:[[[self typedInput]->config primaryFontSize]
104
+ floatValue]];
105
+ if ([self isHeadingBold]) {
106
+ newFont = [newFont removeBold];
107
+ }
108
+ [[self typedInput]->textView.textStorage
109
+ addAttribute:NSFontAttributeName
110
+ value:newFont
111
+ range:range];
112
+ }
113
+ }];
86
114
  [[self typedInput]->textView.textStorage endEditing];
87
-
115
+
88
116
  // typing attributes still need to be removed
89
- UIFont *currentFontAttr = (UIFont *)[self typedInput]->textView.typingAttributes[NSFontAttributeName];
90
- if(currentFontAttr != nullptr) {
91
- NSMutableDictionary *newTypingAttrs = [[self typedInput]->textView.typingAttributes mutableCopy];
92
- UIFont *newFont = [currentFontAttr setSize:[[[self typedInput]->config primaryFontSize] floatValue]];
93
- if([self isHeadingBold]) {
117
+ UIFont *currentFontAttr =
118
+ (UIFont *)[self typedInput]
119
+ ->textView.typingAttributes[NSFontAttributeName];
120
+ if (currentFontAttr != nullptr) {
121
+ NSMutableDictionary *newTypingAttrs =
122
+ [[self typedInput]->textView.typingAttributes mutableCopy];
123
+ UIFont *newFont = [currentFontAttr
124
+ setSize:[[[self typedInput]->config primaryFontSize] floatValue]];
125
+ if ([self isHeadingBold]) {
94
126
  newFont = [newFont removeBold];
95
127
  }
96
128
  newTypingAttrs[NSFontAttributeName] = newFont;
@@ -99,58 +131,67 @@
99
131
  }
100
132
 
101
133
  - (void)removeTypingAttributes {
102
- // all the heading still needs to be removed because this function may be called in conflicting styles logic
103
- // typing attributes already get removed in there as well
134
+ // all the heading still needs to be removed because this function may be
135
+ // called in conflicting styles logic typing attributes already get removed in
136
+ // there as well
104
137
  [self removeAttributes:[self typedInput]->textView.selectedRange];
105
138
  }
106
139
 
107
- - (BOOL)styleCondition:(id _Nullable)value :(NSRange)range {
140
+ - (BOOL)styleCondition:(id _Nullable)value:(NSRange)range {
108
141
  UIFont *font = (UIFont *)value;
109
142
  return font != nullptr && font.pointSize == [self getHeadingFontSize];
110
143
  }
111
144
 
112
145
  - (BOOL)detectStyle:(NSRange)range {
113
- if(range.length >= 1) {
114
- return [OccurenceUtils detect:NSFontAttributeName withInput:[self typedInput] inRange:range
115
- withCondition: ^BOOL(id _Nullable value, NSRange range) {
116
- return [self styleCondition:value :range];
117
- }
118
- ];
146
+ if (range.length >= 1) {
147
+ return [OccurenceUtils detect:NSFontAttributeName
148
+ withInput:[self typedInput]
149
+ inRange:range
150
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
151
+ return [self styleCondition:value:range];
152
+ }];
119
153
  } else {
120
- return [OccurenceUtils detect:NSFontAttributeName withInput:[self typedInput] atIndex:range.location checkPrevious:YES
121
- withCondition:^BOOL(id _Nullable value, NSRange range) {
122
- return [self styleCondition:value :range];
123
- }
124
- ];
154
+ return [OccurenceUtils detect:NSFontAttributeName
155
+ withInput:[self typedInput]
156
+ atIndex:range.location
157
+ checkPrevious:YES
158
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
159
+ return [self styleCondition:value:range];
160
+ }];
125
161
  }
126
162
  }
127
163
 
128
164
  - (BOOL)anyOccurence:(NSRange)range {
129
- return [OccurenceUtils any:NSFontAttributeName withInput:[self typedInput] inRange:range
130
- withCondition:^BOOL(id _Nullable value, NSRange range) {
131
- return [self styleCondition:value :range];
132
- }
133
- ];
165
+ return [OccurenceUtils any:NSFontAttributeName
166
+ withInput:[self typedInput]
167
+ inRange:range
168
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
169
+ return [self styleCondition:value:range];
170
+ }];
134
171
  }
135
172
 
136
173
  - (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
137
- return [OccurenceUtils all:NSFontAttributeName withInput:[self typedInput] inRange:range
138
- withCondition:^BOOL(id _Nullable value, NSRange range) {
139
- return [self styleCondition:value :range];
140
- }
141
- ];
174
+ return [OccurenceUtils all:NSFontAttributeName
175
+ withInput:[self typedInput]
176
+ inRange:range
177
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
178
+ return [self styleCondition:value:range];
179
+ }];
142
180
  }
143
181
 
144
182
  // used to make sure headings dont persist after a newline is placed
145
183
  - (BOOL)handleNewlinesInRange:(NSRange)range replacementText:(NSString *)text {
146
184
  // in a heading and a new text ends with a newline
147
- if(
148
- [self detectStyle:[self typedInput]->textView.selectedRange] &&
149
- text.length > 0 &&
150
- [[NSCharacterSet newlineCharacterSet] characterIsMember: [text characterAtIndex:text.length-1]]
151
- ) {
185
+ if ([self detectStyle:[self typedInput]->textView.selectedRange] &&
186
+ text.length > 0 &&
187
+ [[NSCharacterSet newlineCharacterSet]
188
+ characterIsMember:[text characterAtIndex:text.length - 1]]) {
152
189
  // do the replacement manually
153
- [TextInsertionUtils replaceText:text at:range additionalAttributes:nullptr input:[self typedInput] withSelection:YES];
190
+ [TextInsertionUtils replaceText:text
191
+ at:range
192
+ additionalAttributes:nullptr
193
+ input:[self typedInput]
194
+ withSelection:YES];
154
195
  // remove the attribtues at the new selection
155
196
  [self removeAttributes:[self typedInput]->textView.selectedRange];
156
197
  return YES;
@@ -158,19 +199,23 @@
158
199
  return NO;
159
200
  }
160
201
 
161
- // backspacing a line after a heading "into" a heading will not result in the text attaining heading attributes
162
- // so, we do it manually
202
+ // backspacing a line after a heading "into" a heading will not result in the
203
+ // text attaining heading attributes so, we do it manually
163
204
  - (void)handleImproperHeadings {
164
- NSArray *occurences = [self findAllOccurences:NSMakeRange(0, [self typedInput]->textView.textStorage.string.length)];
165
- for(StylePair *pair in occurences) {
205
+ NSArray *occurences = [self
206
+ findAllOccurences:NSMakeRange(0,
207
+ [self typedInput]
208
+ ->textView.textStorage.string.length)];
209
+ for (StylePair *pair in occurences) {
166
210
  NSRange occurenceRange = [pair.rangeValue rangeValue];
167
- NSRange paragraphRange = [[self typedInput]->textView.textStorage.string paragraphRangeForRange:occurenceRange];
168
- if(!NSEqualRanges(occurenceRange, paragraphRange)) {
169
- // we have a heading but it does not span its whole paragraph - let's fix it
170
- [self addAttributes:paragraphRange];
211
+ NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
212
+ paragraphRangeForRange:occurenceRange];
213
+ if (!NSEqualRanges(occurenceRange, paragraphRange)) {
214
+ // we have a heading but it does not span its whole paragraph - let's fix
215
+ // it
216
+ [self addAttributes:paragraphRange withTypingAttr:NO];
171
217
  }
172
218
  }
173
219
  }
174
220
 
175
221
  @end
176
-