react-native-enriched 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +16 -17
  2. package/android/build.gradle +77 -72
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +21 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +7 -0
  5. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +156 -0
  6. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +147 -0
  7. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
  8. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +194 -0
  9. package/android/lint.gradle +70 -0
  10. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputConnectionWrapper.kt +140 -0
  11. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +304 -83
  12. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewLayoutManager.kt +3 -1
  13. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +166 -51
  14. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +1 -3
  15. package/android/src/main/java/com/swmansion/enriched/MeasurementStore.kt +70 -21
  16. package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +21 -11
  17. package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +8 -9
  18. package/android/src/main/java/com/swmansion/enriched/events/OnChangeSelectionEvent.kt +10 -9
  19. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateDeprecatedEvent.kt +21 -0
  20. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +9 -12
  21. package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +10 -10
  22. package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +7 -9
  23. package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +7 -9
  24. package/android/src/main/java/com/swmansion/enriched/events/OnInputKeyPressEvent.kt +27 -0
  25. package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +13 -11
  26. package/android/src/main/java/com/swmansion/enriched/events/OnMentionDetectedEvent.kt +10 -9
  27. package/android/src/main/java/com/swmansion/enriched/events/OnMentionEvent.kt +9 -8
  28. package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +32 -0
  29. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +24 -5
  30. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +8 -1
  31. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +10 -2
  32. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +8 -1
  33. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +8 -1
  34. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +8 -1
  35. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH4Span.kt +24 -0
  36. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH5Span.kt +24 -0
  37. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH6Span.kt +24 -0
  38. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +34 -17
  39. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +8 -1
  40. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +7 -1
  41. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +10 -4
  42. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +14 -11
  43. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +18 -11
  44. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +174 -72
  45. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +7 -1
  46. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +7 -1
  47. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +11 -5
  48. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +3 -2
  49. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +1 -2
  50. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +1 -2
  51. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +3 -2
  52. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +5 -0
  53. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +1 -2
  54. package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +2 -1
  55. package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +155 -20
  56. package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +25 -8
  57. package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +60 -20
  58. package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +161 -25
  59. package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +128 -52
  60. package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +10 -7
  61. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedConstants.kt +11 -0
  62. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedEditableFactory.kt +17 -0
  63. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +136 -87
  64. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSelection.kt +71 -42
  65. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +183 -48
  66. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannable.kt +82 -0
  67. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannableStringBuilder.kt +15 -0
  68. package/android/src/main/java/com/swmansion/enriched/utils/Utils.kt +0 -70
  69. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +46 -14
  70. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt +34 -11
  71. package/android/src/main/new_arch/CMakeLists.txt +6 -0
  72. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +6 -6
  73. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +6 -6
  74. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +19 -19
  75. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +40 -51
  76. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +13 -15
  77. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +23 -21
  78. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +35 -36
  79. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +4 -4
  80. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +13 -14
  81. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +33 -14
  82. package/ios/EnrichedTextInputView.h +26 -14
  83. package/ios/EnrichedTextInputView.mm +1209 -586
  84. package/ios/config/InputConfig.h +24 -6
  85. package/ios/config/InputConfig.mm +154 -38
  86. package/ios/{utils → extensions}/ColorExtension.mm +7 -5
  87. package/ios/extensions/FontExtension.mm +106 -0
  88. package/ios/{utils → extensions}/LayoutManagerExtension.h +1 -1
  89. package/ios/extensions/LayoutManagerExtension.mm +396 -0
  90. package/ios/{utils → extensions}/StringExtension.mm +19 -16
  91. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +156 -0
  92. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +147 -0
  93. package/ios/generated/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
  94. package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +194 -0
  95. package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +95 -0
  96. package/ios/inputParser/InputParser.h +5 -5
  97. package/ios/inputParser/InputParser.mm +864 -380
  98. package/ios/inputTextView/InputTextView.h +1 -1
  99. package/ios/inputTextView/InputTextView.mm +100 -59
  100. package/ios/{utils → interfaces}/BaseStyleProtocol.h +2 -2
  101. package/ios/interfaces/ImageAttachment.h +10 -0
  102. package/ios/interfaces/ImageAttachment.mm +36 -0
  103. package/ios/interfaces/LinkRegexConfig.h +19 -0
  104. package/ios/interfaces/LinkRegexConfig.mm +37 -0
  105. package/ios/interfaces/MediaAttachment.h +23 -0
  106. package/ios/interfaces/MediaAttachment.mm +31 -0
  107. package/ios/{utils → interfaces}/MentionParams.h +0 -1
  108. package/ios/{utils → interfaces}/MentionStyleProps.mm +27 -20
  109. package/ios/{utils → interfaces}/StyleHeaders.h +37 -15
  110. package/ios/{utils → interfaces}/StyleTypeEnum.h +3 -0
  111. package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +11 -9
  112. package/ios/internals/EnrichedTextInputViewShadowNode.h +28 -25
  113. package/ios/internals/EnrichedTextInputViewShadowNode.mm +45 -40
  114. package/ios/internals/EnrichedTextInputViewState.h +3 -1
  115. package/ios/styles/BlockQuoteStyle.mm +189 -118
  116. package/ios/styles/BoldStyle.mm +110 -63
  117. package/ios/styles/CodeBlockStyle.mm +204 -128
  118. package/ios/styles/H1Style.mm +10 -4
  119. package/ios/styles/H2Style.mm +10 -4
  120. package/ios/styles/H3Style.mm +10 -4
  121. package/ios/styles/H4Style.mm +17 -0
  122. package/ios/styles/H5Style.mm +17 -0
  123. package/ios/styles/H6Style.mm +17 -0
  124. package/ios/styles/HeadingStyleBase.mm +148 -86
  125. package/ios/styles/ImageStyle.mm +75 -73
  126. package/ios/styles/InlineCodeStyle.mm +162 -88
  127. package/ios/styles/ItalicStyle.mm +76 -52
  128. package/ios/styles/LinkStyle.mm +411 -232
  129. package/ios/styles/MentionStyle.mm +363 -246
  130. package/ios/styles/OrderedListStyle.mm +171 -106
  131. package/ios/styles/StrikethroughStyle.mm +52 -35
  132. package/ios/styles/UnderlineStyle.mm +68 -46
  133. package/ios/styles/UnorderedListStyle.mm +169 -106
  134. package/ios/utils/OccurenceUtils.h +42 -42
  135. package/ios/utils/OccurenceUtils.mm +142 -119
  136. package/ios/utils/ParagraphAttributesUtils.h +10 -2
  137. package/ios/utils/ParagraphAttributesUtils.mm +182 -71
  138. package/ios/utils/ParagraphsUtils.h +2 -1
  139. package/ios/utils/ParagraphsUtils.mm +41 -27
  140. package/ios/utils/TextInsertionUtils.h +13 -2
  141. package/ios/utils/TextInsertionUtils.mm +38 -20
  142. package/ios/utils/WordsUtils.h +2 -1
  143. package/ios/utils/WordsUtils.mm +32 -22
  144. package/ios/utils/ZeroWidthSpaceUtils.h +3 -1
  145. package/ios/utils/ZeroWidthSpaceUtils.mm +145 -79
  146. package/lib/module/EnrichedTextInput.js +61 -2
  147. package/lib/module/EnrichedTextInput.js.map +1 -1
  148. package/lib/module/EnrichedTextInputNativeComponent.ts +149 -12
  149. package/lib/module/{normalizeHtmlStyle.js → utils/normalizeHtmlStyle.js} +12 -0
  150. package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
  151. package/lib/module/utils/regexParser.js +46 -0
  152. package/lib/module/utils/regexParser.js.map +1 -0
  153. package/lib/typescript/src/EnrichedTextInput.d.ts +24 -14
  154. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
  155. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +129 -12
  156. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
  157. package/lib/typescript/src/index.d.ts +1 -1
  158. package/lib/typescript/src/index.d.ts.map +1 -1
  159. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +4 -0
  160. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
  161. package/lib/typescript/src/utils/regexParser.d.ts +3 -0
  162. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
  163. package/package.json +17 -6
  164. package/src/EnrichedTextInput.tsx +96 -13
  165. package/src/EnrichedTextInputNativeComponent.ts +149 -12
  166. package/src/index.tsx +2 -0
  167. package/src/{normalizeHtmlStyle.ts → utils/normalizeHtmlStyle.ts} +14 -2
  168. package/src/utils/regexParser.ts +56 -0
  169. package/ios/utils/FontExtension.mm +0 -91
  170. package/ios/utils/LayoutManagerExtension.mm +0 -286
  171. package/lib/module/normalizeHtmlStyle.js.map +0 -1
  172. package/lib/typescript/src/normalizeHtmlStyle.d.ts +0 -4
  173. package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +0 -1
  174. package/ios/{utils → extensions}/ColorExtension.h +0 -0
  175. package/ios/{utils → extensions}/FontExtension.h +0 -0
  176. package/ios/{utils → extensions}/StringExtension.h +1 -1
  177. package/ios/{utils → interfaces}/ImageData.h +0 -0
  178. package/ios/{utils → interfaces}/ImageData.mm +0 -0
  179. package/ios/{utils → interfaces}/LinkData.h +0 -0
  180. package/ios/{utils → interfaces}/LinkData.mm +0 -0
  181. package/ios/{utils → interfaces}/MentionParams.mm +0 -0
  182. package/ios/{utils → interfaces}/MentionStyleProps.h +1 -1
  183. /package/ios/{utils → interfaces}/StylePair.h +0 -0
  184. /package/ios/{utils → interfaces}/StylePair.mm +0 -0
  185. /package/ios/{utils → interfaces}/TextDecorationLineEnum.h +0 -0
  186. /package/ios/{utils → interfaces}/TextDecorationLineEnum.mm +0 -0
@@ -1,10 +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
- + (BOOL)isParagraphStyle { return YES; }
7
- - (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
+ }
8
14
  - (BOOL)isHeadingBold {
9
15
  return [((EnrichedTextInputView *)input)->config h1Bold];
10
16
  }
@@ -1,10 +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
- + (BOOL)isParagraphStyle { return YES; }
7
- - (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
+ }
8
14
  - (BOOL)isHeadingBold {
9
15
  return [((EnrichedTextInputView *)input)->config h2Bold];
10
16
  }
@@ -1,10 +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
- + (BOOL)isParagraphStyle { return YES; }
7
- - (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
+ }
8
14
  - (BOOL)isHeadingBold {
9
15
  return [((EnrichedTextInputView *)input)->config h3Bold];
10
16
  }
@@ -0,0 +1,17 @@
1
+ #import "EnrichedTextInputView.h"
2
+ #import "StyleHeaders.h"
3
+
4
+ @implementation H4Style
5
+ + (StyleType)getStyleType {
6
+ return H4;
7
+ }
8
+ + (BOOL)isParagraphStyle {
9
+ return YES;
10
+ }
11
+ - (CGFloat)getHeadingFontSize {
12
+ return [((EnrichedTextInputView *)input)->config h4FontSize];
13
+ }
14
+ - (BOOL)isHeadingBold {
15
+ return [((EnrichedTextInputView *)input)->config h4Bold];
16
+ }
17
+ @end
@@ -0,0 +1,17 @@
1
+ #import "EnrichedTextInputView.h"
2
+ #import "StyleHeaders.h"
3
+
4
+ @implementation H5Style
5
+ + (StyleType)getStyleType {
6
+ return H5;
7
+ }
8
+ + (BOOL)isParagraphStyle {
9
+ return YES;
10
+ }
11
+ - (CGFloat)getHeadingFontSize {
12
+ return [((EnrichedTextInputView *)input)->config h5FontSize];
13
+ }
14
+ - (BOOL)isHeadingBold {
15
+ return [((EnrichedTextInputView *)input)->config h5Bold];
16
+ }
17
+ @end
@@ -0,0 +1,17 @@
1
+ #import "EnrichedTextInputView.h"
2
+ #import "StyleHeaders.h"
3
+
4
+ @implementation H6Style
5
+ + (StyleType)getStyleType {
6
+ return H6;
7
+ }
8
+ + (BOOL)isParagraphStyle {
9
+ return YES;
10
+ }
11
+ - (CGFloat)getHeadingFontSize {
12
+ return [((EnrichedTextInputView *)input)->config h6FontSize];
13
+ }
14
+ - (BOOL)isHeadingBold {
15
+ return [((EnrichedTextInputView *)input)->config h6Bold];
16
+ }
17
+ @end
@@ -1,15 +1,24 @@
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
- // 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; }
9
+ // mock values since H1/2/3/4/5/6Style classes anyway are used
10
+ + (StyleType)getStyleType {
11
+ return None;
12
+ }
13
+ - (CGFloat)getHeadingFontSize {
14
+ return 0;
15
+ }
16
+ - (BOOL)isHeadingBold {
17
+ return false;
18
+ }
19
+ + (BOOL)isParagraphStyle {
20
+ return true;
21
+ }
13
22
 
14
23
  - (EnrichedTextInputView *)typedInput {
15
24
  return (EnrichedTextInputView *)input;
@@ -18,6 +27,7 @@
18
27
  - (instancetype)initWithInput:(id)input {
19
28
  self = [super init];
20
29
  self->input = input;
30
+ _lastAppliedFontSize = 0.0;
21
31
  return self;
22
32
  }
23
33
 
@@ -25,41 +35,55 @@
25
35
  // but if the paragraph is empty it still is of length 0
26
36
  - (void)applyStyle:(NSRange)range {
27
37
  BOOL isStylePresent = [self detectStyle:range];
28
- if(range.length >= 1) {
29
- isStylePresent ? [self removeAttributes:range] : [self addAttributes:range];
38
+ if (range.length >= 1) {
39
+ isStylePresent ? [self removeAttributes:range]
40
+ : [self addAttributes:range withTypingAttr:YES];
30
41
  } else {
31
42
  isStylePresent ? [self removeTypingAttributes] : [self addTypingAttributes];
32
43
  }
44
+ _lastAppliedFontSize = [self getHeadingFontSize];
33
45
  }
34
46
 
35
47
  // the range will already be the proper full paragraph/s range
36
- - (void)addAttributes:(NSRange)range {
48
+ - (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
37
49
  [[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
- ];
50
+ [[self typedInput]->textView.textStorage
51
+ enumerateAttribute:NSFontAttributeName
52
+ inRange:range
53
+ options:0
54
+ usingBlock:^(id _Nullable value, NSRange range,
55
+ BOOL *_Nonnull stop) {
56
+ UIFont *font = (UIFont *)value;
57
+ if (font != nullptr) {
58
+ UIFont *newFont = [font setSize:[self getHeadingFontSize]];
59
+ if ([self isHeadingBold]) {
60
+ newFont = [newFont setBold];
61
+ }
62
+ [[self typedInput]->textView.textStorage
63
+ addAttribute:NSFontAttributeName
64
+ value:newFont
65
+ range:range];
66
+ }
67
+ }];
50
68
  [[self typedInput]->textView.textStorage endEditing];
51
-
69
+
52
70
  // also toggle typing attributes
53
- [self addTypingAttributes];
71
+ if (withTypingAttr) {
72
+ [self addTypingAttributes];
73
+ }
54
74
  }
55
75
 
56
- // will always be called on empty paragraphs so only typing attributes can be changed
76
+ // will always be called on empty paragraphs so only typing attributes can be
77
+ // changed
57
78
  - (void)addTypingAttributes {
58
- UIFont *currentFontAttr = (UIFont *)[self typedInput]->textView.typingAttributes[NSFontAttributeName];
59
- if(currentFontAttr != nullptr) {
60
- NSMutableDictionary *newTypingAttrs = [[self typedInput]->textView.typingAttributes mutableCopy];
79
+ UIFont *currentFontAttr =
80
+ (UIFont *)[self typedInput]
81
+ ->textView.typingAttributes[NSFontAttributeName];
82
+ if (currentFontAttr != nullptr) {
83
+ NSMutableDictionary *newTypingAttrs =
84
+ [[self typedInput]->textView.typingAttributes mutableCopy];
61
85
  UIFont *newFont = [currentFontAttr setSize:[self getHeadingFontSize]];
62
- if([self isHeadingBold]) {
86
+ if ([self isHeadingBold]) {
63
87
  newFont = [newFont setBold];
64
88
  }
65
89
  newTypingAttrs[NSFontAttributeName] = newFont;
@@ -69,28 +93,41 @@
69
93
 
70
94
  // we need to remove the style from the whole paragraph
71
95
  - (void)removeAttributes:(NSRange)range {
72
- NSRange paragraphRange = [[self typedInput]->textView.textStorage.string paragraphRangeForRange:range];
73
-
96
+ NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
97
+ paragraphRangeForRange:range];
98
+
74
99
  [[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
- ];
100
+ [[self typedInput]->textView.textStorage
101
+ enumerateAttribute:NSFontAttributeName
102
+ inRange:paragraphRange
103
+ options:0
104
+ usingBlock:^(id _Nullable value, NSRange range,
105
+ BOOL *_Nonnull stop) {
106
+ if ([self styleCondition:value range:range]) {
107
+ UIFont *newFont = [(UIFont *)value
108
+ setSize:[[[self typedInput]->config scaledPrimaryFontSize]
109
+ floatValue]];
110
+ if ([self isHeadingBold]) {
111
+ newFont = [newFont removeBold];
112
+ }
113
+ [[self typedInput]->textView.textStorage
114
+ addAttribute:NSFontAttributeName
115
+ value:newFont
116
+ range:range];
117
+ }
118
+ }];
86
119
  [[self typedInput]->textView.textStorage endEditing];
87
-
120
+
88
121
  // 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]) {
122
+ UIFont *currentFontAttr =
123
+ (UIFont *)[self typedInput]
124
+ ->textView.typingAttributes[NSFontAttributeName];
125
+ if (currentFontAttr != nullptr) {
126
+ NSMutableDictionary *newTypingAttrs =
127
+ [[self typedInput]->textView.typingAttributes mutableCopy];
128
+ UIFont *newFont = [currentFontAttr
129
+ setSize:[[[self typedInput]->config scaledPrimaryFontSize] floatValue]];
130
+ if ([self isHeadingBold]) {
94
131
  newFont = [newFont removeBold];
95
132
  }
96
133
  newTypingAttrs[NSFontAttributeName] = newFont;
@@ -99,58 +136,78 @@
99
136
  }
100
137
 
101
138
  - (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
139
+ // all the heading still needs to be removed because this function may be
140
+ // called in conflicting styles logic typing attributes already get removed in
141
+ // there as well
104
142
  [self removeAttributes:[self typedInput]->textView.selectedRange];
105
143
  }
106
144
 
107
- - (BOOL)styleCondition:(id _Nullable)value :(NSRange)range {
145
+ // when the traits already change, the getHeadginFontSize will return the new
146
+ // font size and no headings would be properly detected, so that's why we have
147
+ // to use the latest applied font size rather than that value.
148
+ - (BOOL)styleCondition:(id _Nullable)value range:(NSRange)range {
108
149
  UIFont *font = (UIFont *)value;
109
- return font != nullptr && font.pointSize == [self getHeadingFontSize];
150
+ if (font == nullptr) {
151
+ return NO;
152
+ }
153
+
154
+ if (self.lastAppliedFontSize > 0.0) {
155
+ return font.pointSize == self.lastAppliedFontSize;
156
+ }
157
+
158
+ return font.pointSize == [self getHeadingFontSize];
110
159
  }
111
160
 
112
161
  - (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
- ];
162
+ if (range.length >= 1) {
163
+ return [OccurenceUtils detect:NSFontAttributeName
164
+ withInput:[self typedInput]
165
+ inRange:range
166
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
167
+ return [self styleCondition:value range:range];
168
+ }];
119
169
  } 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
- ];
170
+ return [OccurenceUtils detect:NSFontAttributeName
171
+ withInput:[self typedInput]
172
+ atIndex:range.location
173
+ checkPrevious:YES
174
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
175
+ return [self styleCondition:value range:range];
176
+ }];
125
177
  }
126
178
  }
127
179
 
128
180
  - (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
- ];
181
+ return [OccurenceUtils any:NSFontAttributeName
182
+ withInput:[self typedInput]
183
+ inRange:range
184
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
185
+ return [self styleCondition:value range:range];
186
+ }];
134
187
  }
135
188
 
136
189
  - (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
- ];
190
+ return [OccurenceUtils all:NSFontAttributeName
191
+ withInput:[self typedInput]
192
+ inRange:range
193
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
194
+ return [self styleCondition:value range:range];
195
+ }];
142
196
  }
143
197
 
144
198
  // used to make sure headings dont persist after a newline is placed
145
199
  - (BOOL)handleNewlinesInRange:(NSRange)range replacementText:(NSString *)text {
146
200
  // 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
- ) {
201
+ if ([self detectStyle:[self typedInput]->textView.selectedRange] &&
202
+ text.length > 0 &&
203
+ [[NSCharacterSet newlineCharacterSet]
204
+ characterIsMember:[text characterAtIndex:text.length - 1]]) {
152
205
  // do the replacement manually
153
- [TextInsertionUtils replaceText:text at:range additionalAttributes:nullptr input:[self typedInput] withSelection:YES];
206
+ [TextInsertionUtils replaceText:text
207
+ at:range
208
+ additionalAttributes:nullptr
209
+ input:[self typedInput]
210
+ withSelection:YES];
154
211
  // remove the attribtues at the new selection
155
212
  [self removeAttributes:[self typedInput]->textView.selectedRange];
156
213
  return YES;
@@ -158,19 +215,24 @@
158
215
  return NO;
159
216
  }
160
217
 
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
218
+ // backspacing a line after a heading "into" a heading will not result in the
219
+ // text attaining heading attributes so, we do it manually
163
220
  - (void)handleImproperHeadings {
164
- NSArray *occurences = [self findAllOccurences:NSMakeRange(0, [self typedInput]->textView.textStorage.string.length)];
165
- for(StylePair *pair in occurences) {
221
+ NSArray *occurences = [self
222
+ findAllOccurences:NSMakeRange(0,
223
+ [self typedInput]
224
+ ->textView.textStorage.string.length)];
225
+ for (StylePair *pair in occurences) {
166
226
  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];
227
+ NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
228
+ paragraphRangeForRange:occurenceRange];
229
+ if (!NSEqualRanges(occurenceRange, paragraphRange)) {
230
+ // we have a heading but it does not span its whole paragraph - let's fix
231
+ // it
232
+ [self addAttributes:paragraphRange withTypingAttr:NO];
171
233
  }
172
234
  }
235
+ _lastAppliedFontSize = [self getHeadingFontSize];
173
236
  }
174
237
 
175
238
  @end
176
-
@@ -1,6 +1,8 @@
1
- #import "StyleHeaders.h"
2
1
  #import "EnrichedTextInputView.h"
2
+ #import "ImageAttachment.h"
3
+ #import "MediaAttachment.h"
3
4
  #import "OccurenceUtils.h"
5
+ #import "StyleHeaders.h"
4
6
  #import "TextInsertionUtils.h"
5
7
 
6
8
  // custom NSAttributedStringKey to differentiate the image
@@ -10,9 +12,13 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
10
12
  EnrichedTextInputView *_input;
11
13
  }
12
14
 
13
- + (StyleType)getStyleType { return Image; }
15
+ + (StyleType)getStyleType {
16
+ return Image;
17
+ }
14
18
 
15
- + (BOOL)isParagraphStyle { return NO; }
19
+ + (BOOL)isParagraphStyle {
20
+ return NO;
21
+ }
16
22
 
17
23
  - (instancetype)initWithInput:(id)input {
18
24
  self = [super init];
@@ -24,7 +30,7 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
24
30
  // no-op for image
25
31
  }
26
32
 
27
- - (void)addAttributes:(NSRange)range {
33
+ - (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
28
34
  // no-op for image
29
35
  }
30
36
 
@@ -35,91 +41,104 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
35
41
  - (void)removeAttributes:(NSRange)range {
36
42
  [_input->textView.textStorage beginEditing];
37
43
  [_input->textView.textStorage removeAttribute:ImageAttributeName range:range];
38
- [_input->textView.textStorage removeAttribute:NSAttachmentAttributeName range:range];
44
+ [_input->textView.textStorage removeAttribute:NSAttachmentAttributeName
45
+ range:range];
39
46
  [_input->textView.textStorage endEditing];
40
47
  }
41
48
 
42
49
  - (void)removeTypingAttributes {
43
- NSMutableDictionary *currentAttributes = [_input->textView.typingAttributes mutableCopy];
50
+ NSMutableDictionary *currentAttributes =
51
+ [_input->textView.typingAttributes mutableCopy];
44
52
  [currentAttributes removeObjectForKey:ImageAttributeName];
45
53
  [currentAttributes removeObjectForKey:NSAttachmentAttributeName];
46
54
  _input->textView.typingAttributes = currentAttributes;
47
55
  }
48
56
 
49
- - (BOOL)styleCondition:(id _Nullable)value :(NSRange)range {
57
+ - (BOOL)styleCondition:(id _Nullable)value range:(NSRange)range {
50
58
  return [value isKindOfClass:[ImageData class]];
51
59
  }
52
60
 
53
61
  - (BOOL)anyOccurence:(NSRange)range {
54
- return [OccurenceUtils any:ImageAttributeName withInput:_input inRange:range
55
- withCondition:^BOOL(id _Nullable value, NSRange range) {
56
- return [self styleCondition:value :range];
57
- }
58
- ];
62
+ return [OccurenceUtils any:ImageAttributeName
63
+ withInput:_input
64
+ inRange:range
65
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
66
+ return [self styleCondition:value range:range];
67
+ }];
59
68
  }
60
69
 
61
70
  - (BOOL)detectStyle:(NSRange)range {
62
71
  if (range.length >= 1) {
63
- return [OccurenceUtils detect:ImageAttributeName withInput:_input inRange:range
64
- withCondition:^BOOL(id _Nullable value, NSRange range) {
65
- return [self styleCondition:value :range];
66
- }
67
- ];
72
+ return [OccurenceUtils detect:ImageAttributeName
73
+ withInput:_input
74
+ inRange:range
75
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
76
+ return [self styleCondition:value range:range];
77
+ }];
68
78
  } else {
69
- return [OccurenceUtils detect:ImageAttributeName withInput:_input atIndex:range.location checkPrevious:YES
70
- withCondition:^BOOL(id _Nullable value, NSRange range) {
71
- return [self styleCondition:value :range];
72
- }
73
- ];
79
+ return [OccurenceUtils detect:ImageAttributeName
80
+ withInput:_input
81
+ atIndex:range.location
82
+ checkPrevious:YES
83
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
84
+ return [self styleCondition:value range:range];
85
+ }];
74
86
  }
75
87
  }
76
88
 
77
- - (NSArray<StylePair *> * _Nullable)findAllOccurences:(NSRange)range {
78
- return [OccurenceUtils all:ImageAttributeName withInput:_input inRange:range
79
- withCondition:^BOOL(id _Nullable value, NSRange range) {
80
- return [self styleCondition:value :range];
81
- }
82
- ];
89
+ - (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
90
+ return [OccurenceUtils all:ImageAttributeName
91
+ withInput:_input
92
+ inRange:range
93
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
94
+ return [self styleCondition:value range:range];
95
+ }];
83
96
  }
84
97
 
85
- - (ImageData *)getImageDataAt:(NSUInteger)location
86
- {
98
+ - (ImageData *)getImageDataAt:(NSUInteger)location {
87
99
  NSRange imageRange = NSMakeRange(0, 0);
88
100
  NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
89
-
101
+
90
102
  // don't search at the very end of input
91
103
  NSUInteger searchLocation = location;
92
- if(searchLocation == _input->textView.textStorage.length) {
104
+ if (searchLocation == _input->textView.textStorage.length) {
93
105
  return nullptr;
94
106
  }
95
-
96
- ImageData *imageData = [_input->textView.textStorage
97
- attribute:ImageAttributeName
98
- atIndex:searchLocation
99
- longestEffectiveRange: &imageRange
100
- inRange:inputRange
101
- ];
102
-
107
+
108
+ ImageData *imageData =
109
+ [_input->textView.textStorage attribute:ImageAttributeName
110
+ atIndex:searchLocation
111
+ longestEffectiveRange:&imageRange
112
+ inRange:inputRange];
113
+
103
114
  return imageData;
104
115
  }
105
116
 
106
- - (void)addImageAtRange:(NSRange)range imageData:(ImageData *)imageData withSelection:(BOOL)withSelection
107
- {
108
- UIImage *img = [self prepareImageFromUri:imageData.uri];
109
-
110
- NSDictionary *attributes = [@{
111
- NSAttachmentAttributeName: [self prepareImageAttachement:img width:imageData.width height:imageData.height],
112
- ImageAttributeName: imageData,
113
- } mutableCopy];
114
-
117
+ - (void)addImageAtRange:(NSRange)range
118
+ imageData:(ImageData *)imageData
119
+ withSelection:(BOOL)withSelection {
120
+ if (!imageData)
121
+ return;
122
+
123
+ ImageAttachment *attachment =
124
+ [[ImageAttachment alloc] initWithImageData:imageData];
125
+ attachment.delegate = _input;
126
+
127
+ NSDictionary *attributes =
128
+ @{NSAttachmentAttributeName : attachment, ImageAttributeName : imageData};
129
+
115
130
  // Use the Object Replacement Character for Image.
116
131
  // This tells TextKit "something non-text goes here".
117
- NSString *imagePlaceholder = @"\uFFFC";
118
-
132
+ NSString *placeholderChar = @"\uFFFC";
133
+
119
134
  if (range.length == 0) {
120
- [TextInsertionUtils insertText:imagePlaceholder at:range.location additionalAttributes:attributes input:_input withSelection:withSelection];
135
+ [TextInsertionUtils insertText:placeholderChar
136
+ at:range.location
137
+ additionalAttributes:attributes
138
+ input:_input
139
+ withSelection:withSelection];
121
140
  } else {
122
- [TextInsertionUtils replaceText:imagePlaceholder
141
+ [TextInsertionUtils replaceText:placeholderChar
123
142
  at:range
124
143
  additionalAttributes:attributes
125
144
  input:_input
@@ -132,27 +151,10 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
132
151
  data.uri = uri;
133
152
  data.width = width;
134
153
  data.height = height;
135
-
136
- [self addImageAtRange:_input->textView.selectedRange imageData:data withSelection:YES];
137
- }
138
-
139
- -(NSTextAttachment *)prepareImageAttachement:(UIImage *)image width:(CGFloat)width height:(CGFloat)height
140
- {
141
-
142
- NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
143
- attachment.image = image;
144
- attachment.bounds = CGRectMake(0, 0, width, height);
145
-
146
- return attachment;
147
- }
148
154
 
149
- - (UIImage *)prepareImageFromUri:(NSString *)uri
150
- {
151
- NSURL *url = [NSURL URLWithString:uri];
152
- NSData *imgData = [NSData dataWithContentsOfURL:url];
153
- UIImage *image = [UIImage imageWithData:imgData];
154
-
155
- return image;
155
+ [self addImageAtRange:_input->textView.selectedRange
156
+ imageData:data
157
+ withSelection:YES];
156
158
  }
157
159
 
158
160
  @end