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.
- package/README.md +4 -14
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +4 -1
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +2 -1
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +0 -45
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +111 -2
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +9 -3
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +2 -0
- package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +42 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +135 -9
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +13 -3
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +13 -0
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +80 -9
- package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +188 -5
- package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +57 -30
- package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +91 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +24 -13
- package/android/src/main/java/com/swmansion/enriched/utils/ResourceManager.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +3 -0
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +6 -6
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +6 -6
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +19 -19
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +40 -51
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +13 -15
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +23 -21
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +35 -36
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +4 -4
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +13 -14
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +12 -13
- package/android/src/main/res/drawable/broken_image.xml +10 -0
- package/ios/EnrichedTextInputView.h +27 -12
- package/ios/EnrichedTextInputView.mm +906 -547
- package/ios/attachments/ImageAttachment.h +10 -0
- package/ios/attachments/ImageAttachment.mm +34 -0
- package/ios/attachments/MediaAttachment.h +23 -0
- package/ios/attachments/MediaAttachment.mm +31 -0
- package/ios/config/InputConfig.h +12 -6
- package/ios/config/InputConfig.mm +71 -33
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +0 -45
- package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +41 -4
- package/ios/inputParser/InputParser.h +5 -5
- package/ios/inputParser/InputParser.mm +867 -333
- package/ios/inputTextView/InputTextView.h +1 -1
- package/ios/inputTextView/InputTextView.mm +100 -59
- package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +11 -9
- package/ios/internals/EnrichedTextInputViewShadowNode.h +28 -24
- package/ios/internals/EnrichedTextInputViewShadowNode.mm +64 -47
- package/ios/internals/EnrichedTextInputViewState.h +3 -1
- package/ios/styles/BlockQuoteStyle.mm +192 -142
- package/ios/styles/BoldStyle.mm +96 -62
- package/ios/styles/CodeBlockStyle.mm +304 -0
- package/ios/styles/H1Style.mm +10 -3
- package/ios/styles/H2Style.mm +10 -3
- package/ios/styles/H3Style.mm +10 -3
- package/ios/styles/HeadingStyleBase.mm +129 -84
- package/ios/styles/ImageStyle.mm +160 -0
- package/ios/styles/InlineCodeStyle.mm +149 -84
- package/ios/styles/ItalicStyle.mm +77 -51
- package/ios/styles/LinkStyle.mm +353 -224
- package/ios/styles/MentionStyle.mm +434 -220
- package/ios/styles/OrderedListStyle.mm +172 -105
- package/ios/styles/StrikethroughStyle.mm +53 -34
- package/ios/styles/UnderlineStyle.mm +69 -45
- package/ios/styles/UnorderedListStyle.mm +170 -105
- package/ios/utils/BaseStyleProtocol.h +3 -2
- package/ios/utils/ColorExtension.mm +7 -5
- package/ios/utils/FontExtension.mm +42 -27
- package/ios/utils/ImageData.h +10 -0
- package/ios/utils/ImageData.mm +4 -0
- package/ios/utils/LayoutManagerExtension.h +1 -1
- package/ios/utils/LayoutManagerExtension.mm +334 -109
- package/ios/utils/MentionParams.h +0 -1
- package/ios/utils/MentionStyleProps.h +1 -1
- package/ios/utils/MentionStyleProps.mm +27 -20
- package/ios/utils/OccurenceUtils.h +42 -38
- package/ios/utils/OccurenceUtils.mm +177 -107
- package/ios/utils/ParagraphAttributesUtils.h +6 -1
- package/ios/utils/ParagraphAttributesUtils.mm +152 -41
- package/ios/utils/ParagraphsUtils.h +2 -1
- package/ios/utils/ParagraphsUtils.mm +40 -26
- package/ios/utils/StringExtension.h +1 -1
- package/ios/utils/StringExtension.mm +19 -16
- package/ios/utils/StyleHeaders.h +35 -11
- package/ios/utils/TextInsertionUtils.h +13 -2
- package/ios/utils/TextInsertionUtils.mm +38 -20
- package/ios/utils/WordsUtils.h +2 -1
- package/ios/utils/WordsUtils.mm +32 -22
- package/ios/utils/ZeroWidthSpaceUtils.h +3 -1
- package/ios/utils/ZeroWidthSpaceUtils.mm +153 -75
- package/lib/module/EnrichedTextInput.js +41 -3
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/EnrichedTextInputNativeComponent.ts +17 -5
- package/lib/module/normalizeHtmlStyle.js +0 -4
- package/lib/module/normalizeHtmlStyle.js.map +1 -1
- package/lib/typescript/src/EnrichedTextInput.d.ts +2 -5
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +7 -5
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/EnrichedTextInput.tsx +48 -7
- package/src/EnrichedTextInputNativeComponent.ts +17 -5
- package/src/normalizeHtmlStyle.ts +0 -4
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<img src="https://github.com/user-attachments/assets/
|
|
1
|
+
<img src="https://github.com/user-attachments/assets/b010571e-e4a3-4d92-a409-4f9fe614025d" alt="react-native-enriched by Software Mansion" width="100%">
|
|
2
2
|
|
|
3
3
|
# react-native-enriched
|
|
4
4
|
|
|
@@ -40,7 +40,7 @@ We can help you build your next dream product –
|
|
|
40
40
|
## Prerequisites
|
|
41
41
|
|
|
42
42
|
- `react-native-enriched` currently supports only Android and iOS platforms
|
|
43
|
-
- It works only with [the React Native New Architecture (Fabric)](https://reactnative.dev/architecture/landing-page) and supports following React Native releases: `0.79`, `0.80`, `0.81` and `0.
|
|
43
|
+
- It works only with [the React Native New Architecture (Fabric)](https://reactnative.dev/architecture/landing-page) and supports following React Native releases: `0.79`, `0.80`, `0.81`, `0.82` and `0.83`
|
|
44
44
|
|
|
45
45
|
## Installation
|
|
46
46
|
|
|
@@ -101,11 +101,11 @@ export default function App() {
|
|
|
101
101
|
<View style={styles.container}>
|
|
102
102
|
<EnrichedTextInput
|
|
103
103
|
ref={ref}
|
|
104
|
-
onChangeState={
|
|
104
|
+
onChangeState={e => setStylesState(e.nativeEvent)}
|
|
105
105
|
style={styles.input}
|
|
106
106
|
/>
|
|
107
107
|
<Button
|
|
108
|
-
title=
|
|
108
|
+
title={stylesState?.isBold ? 'Unbold' : 'Bold'}
|
|
109
109
|
color={stylesState?.isBold ? 'green' : 'gray'}
|
|
110
110
|
onPress={() => ref.current?.toggleBold()}
|
|
111
111
|
/>
|
|
@@ -152,9 +152,6 @@ Supported styles:
|
|
|
152
152
|
- ordered list
|
|
153
153
|
- unordered list
|
|
154
154
|
|
|
155
|
-
> [!NOTE]
|
|
156
|
-
> The iOS doesn't support codeblocks just yet, but it's planned in the near future!
|
|
157
|
-
|
|
158
155
|
Each of the styles can be toggled the same way as in the example from [usage section](#usage); call a proper `toggle` function on the component ref.
|
|
159
156
|
|
|
160
157
|
Each call toggles the style within the current text selection. We can still divide styles into two categories based on how they treat the selection:
|
|
@@ -212,9 +209,6 @@ You can insert an image into the input using [setImage](docs/API_REFERENCE.md#se
|
|
|
212
209
|
|
|
213
210
|
The image will be put into a single line in the input and will affect the line's height as well as input's height. Keep in mind, that image will replace currently selected text or insert into the cursor position if there is no text selection.
|
|
214
211
|
|
|
215
|
-
> [!NOTE]
|
|
216
|
-
> The iOS doesn't support inline images just yet, but it's planned in the near future!
|
|
217
|
-
|
|
218
212
|
## Style Detection
|
|
219
213
|
|
|
220
214
|
All of the above styles can be detected with the use of [onChangeState](docs/API_REFERENCE.md#onchangestate) event payload.
|
|
@@ -244,14 +238,10 @@ See the [API Reference](docs/API_REFERENCE.md) for a detailed overview of all th
|
|
|
244
238
|
## Known limitations
|
|
245
239
|
|
|
246
240
|
- Only one level of lists is supported. We currently do not support nested lists.
|
|
247
|
-
- Inline images are supported only on Android.
|
|
248
|
-
- Codeblocks are supported only on Android.
|
|
249
241
|
- iOS headings can't have the same `fontSize` in their config as input's `fontSize`. Doing so results in incorrect headings behavior.
|
|
250
242
|
|
|
251
243
|
## Future Plans
|
|
252
244
|
|
|
253
|
-
- Adding Codeblocks and Inline Images to iOS input.
|
|
254
|
-
- Making some optimizations around `onChangeHtml` event, maybe some imperative API to get the HTML output.
|
|
255
245
|
- Creating `EnrichedText` text component that supports our HTML output format with all additional interactions like pressing links or mentions.
|
|
256
246
|
- Adding API for custom link detection regex.
|
|
257
247
|
- Web library implementation via `react-native-web`.
|
|
@@ -136,7 +136,7 @@ public class EnrichedTextInputViewManagerDelegate<T extends View, U extends Base
|
|
|
136
136
|
mViewManager.addLink(view, args.getInt(0), args.getInt(1), args.getString(2), args.getString(3));
|
|
137
137
|
break;
|
|
138
138
|
case "addImage":
|
|
139
|
-
mViewManager.addImage(view, args.getString(0));
|
|
139
|
+
mViewManager.addImage(view, args.getString(0), (float) args.getDouble(1), (float) args.getDouble(2));
|
|
140
140
|
break;
|
|
141
141
|
case "startMention":
|
|
142
142
|
mViewManager.startMention(view, args.getString(0));
|
|
@@ -144,6 +144,9 @@ public class EnrichedTextInputViewManagerDelegate<T extends View, U extends Base
|
|
|
144
144
|
case "addMention":
|
|
145
145
|
mViewManager.addMention(view, args.getString(0), args.getString(1), args.getString(2));
|
|
146
146
|
break;
|
|
147
|
+
case "requestHTML":
|
|
148
|
+
mViewManager.requestHTML(view, args.getInt(0));
|
|
149
|
+
break;
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
}
|
|
@@ -50,7 +50,8 @@ public interface EnrichedTextInputViewManagerInterface<T extends View> extends V
|
|
|
50
50
|
void toggleOrderedList(T view);
|
|
51
51
|
void toggleUnorderedList(T view);
|
|
52
52
|
void addLink(T view, int start, int end, String text, String url);
|
|
53
|
-
void addImage(T view, String uri);
|
|
53
|
+
void addImage(T view, String uri, float width, float height);
|
|
54
54
|
void startMention(T view, String indicator);
|
|
55
55
|
void addMention(T view, String indicator, String text, String payload);
|
|
56
|
+
void requestHTML(T view, int requestId);
|
|
56
57
|
}
|
|
@@ -115,4 +115,14 @@ payload.setProperty(runtime, "text", event.text);
|
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
|
|
119
|
+
void EnrichedTextInputViewEventEmitter::onRequestHtmlResult(OnRequestHtmlResult event) const {
|
|
120
|
+
dispatchEvent("requestHtmlResult", [event=std::move(event)](jsi::Runtime &runtime) {
|
|
121
|
+
auto payload = jsi::Object(runtime);
|
|
122
|
+
payload.setProperty(runtime, "requestId", event.requestId);
|
|
123
|
+
payload.setProperty(runtime, "html", jsi::valueFromDynamic(runtime, event.html));
|
|
124
|
+
return payload;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
} // namespace facebook::react
|
package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h
CHANGED
|
@@ -74,6 +74,11 @@ class EnrichedTextInputViewEventEmitter : public ViewEventEmitter {
|
|
|
74
74
|
int end;
|
|
75
75
|
std::string text;
|
|
76
76
|
};
|
|
77
|
+
|
|
78
|
+
struct OnRequestHtmlResult {
|
|
79
|
+
int requestId;
|
|
80
|
+
folly::dynamic html;
|
|
81
|
+
};
|
|
77
82
|
void onInputFocus(OnInputFocus value) const;
|
|
78
83
|
|
|
79
84
|
void onInputBlur(OnInputBlur value) const;
|
|
@@ -91,5 +96,7 @@ class EnrichedTextInputViewEventEmitter : public ViewEventEmitter {
|
|
|
91
96
|
void onMention(OnMention value) const;
|
|
92
97
|
|
|
93
98
|
void onChangeSelection(OnChangeSelection value) const;
|
|
99
|
+
|
|
100
|
+
void onRequestHtmlResult(OnRequestHtmlResult value) const;
|
|
94
101
|
};
|
|
95
102
|
} // namespace facebook::react
|
|
@@ -309,45 +309,6 @@ static inline folly::dynamic toDynamic(const EnrichedTextInputViewHtmlStyleAStru
|
|
|
309
309
|
}
|
|
310
310
|
#endif
|
|
311
311
|
|
|
312
|
-
struct EnrichedTextInputViewHtmlStyleImgStruct {
|
|
313
|
-
Float width{0.0};
|
|
314
|
-
Float height{0.0};
|
|
315
|
-
|
|
316
|
-
#ifdef RN_SERIALIZABLE_STATE
|
|
317
|
-
bool operator==(const EnrichedTextInputViewHtmlStyleImgStruct&) const = default;
|
|
318
|
-
|
|
319
|
-
folly::dynamic toDynamic() const {
|
|
320
|
-
folly::dynamic result = folly::dynamic::object();
|
|
321
|
-
result["width"] = width;
|
|
322
|
-
result["height"] = height;
|
|
323
|
-
return result;
|
|
324
|
-
}
|
|
325
|
-
#endif
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedTextInputViewHtmlStyleImgStruct &result) {
|
|
329
|
-
auto map = (std::unordered_map<std::string, RawValue>)value;
|
|
330
|
-
|
|
331
|
-
auto tmp_width = map.find("width");
|
|
332
|
-
if (tmp_width != map.end()) {
|
|
333
|
-
fromRawValue(context, tmp_width->second, result.width);
|
|
334
|
-
}
|
|
335
|
-
auto tmp_height = map.find("height");
|
|
336
|
-
if (tmp_height != map.end()) {
|
|
337
|
-
fromRawValue(context, tmp_height->second, result.height);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
static inline std::string toString(const EnrichedTextInputViewHtmlStyleImgStruct &value) {
|
|
342
|
-
return "[Object EnrichedTextInputViewHtmlStyleImgStruct]";
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
#ifdef RN_SERIALIZABLE_STATE
|
|
346
|
-
static inline folly::dynamic toDynamic(const EnrichedTextInputViewHtmlStyleImgStruct &value) {
|
|
347
|
-
return value.toDynamic();
|
|
348
|
-
}
|
|
349
|
-
#endif
|
|
350
|
-
|
|
351
312
|
struct EnrichedTextInputViewHtmlStyleOlStruct {
|
|
352
313
|
Float gapWidth{0.0};
|
|
353
314
|
Float marginLeft{0.0};
|
|
@@ -459,7 +420,6 @@ struct EnrichedTextInputViewHtmlStyleStruct {
|
|
|
459
420
|
EnrichedTextInputViewHtmlStyleCodeStruct code{};
|
|
460
421
|
EnrichedTextInputViewHtmlStyleAStruct a{};
|
|
461
422
|
folly::dynamic mention{};
|
|
462
|
-
EnrichedTextInputViewHtmlStyleImgStruct img{};
|
|
463
423
|
EnrichedTextInputViewHtmlStyleOlStruct ol{};
|
|
464
424
|
EnrichedTextInputViewHtmlStyleUlStruct ul{};
|
|
465
425
|
|
|
@@ -476,7 +436,6 @@ struct EnrichedTextInputViewHtmlStyleStruct {
|
|
|
476
436
|
result["code"] = ::facebook::react::toDynamic(code);
|
|
477
437
|
result["a"] = ::facebook::react::toDynamic(a);
|
|
478
438
|
result["mention"] = mention;
|
|
479
|
-
result["img"] = ::facebook::react::toDynamic(img);
|
|
480
439
|
result["ol"] = ::facebook::react::toDynamic(ol);
|
|
481
440
|
result["ul"] = ::facebook::react::toDynamic(ul);
|
|
482
441
|
return result;
|
|
@@ -519,10 +478,6 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
|
|
|
519
478
|
if (tmp_mention != map.end()) {
|
|
520
479
|
fromRawValue(context, tmp_mention->second, result.mention);
|
|
521
480
|
}
|
|
522
|
-
auto tmp_img = map.find("img");
|
|
523
|
-
if (tmp_img != map.end()) {
|
|
524
|
-
fromRawValue(context, tmp_img->second, result.img);
|
|
525
|
-
}
|
|
526
481
|
auto tmp_ol = map.find("ol");
|
|
527
482
|
if (tmp_ol != map.end()) {
|
|
528
483
|
fromRawValue(context, tmp_ol->second, result.ol);
|
|
@@ -29,7 +29,13 @@ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
|
|
|
29
29
|
import com.swmansion.enriched.events.MentionHandler
|
|
30
30
|
import com.swmansion.enriched.events.OnInputBlurEvent
|
|
31
31
|
import com.swmansion.enriched.events.OnInputFocusEvent
|
|
32
|
+
import com.swmansion.enriched.events.OnRequestHtmlResultEvent
|
|
33
|
+
import com.swmansion.enriched.spans.EnrichedH1Span
|
|
34
|
+
import com.swmansion.enriched.spans.EnrichedH2Span
|
|
35
|
+
import com.swmansion.enriched.spans.EnrichedH3Span
|
|
36
|
+
import com.swmansion.enriched.spans.EnrichedImageSpan
|
|
32
37
|
import com.swmansion.enriched.spans.EnrichedSpans
|
|
38
|
+
import com.swmansion.enriched.spans.interfaces.EnrichedSpan
|
|
33
39
|
import com.swmansion.enriched.styles.InlineStyles
|
|
34
40
|
import com.swmansion.enriched.styles.ListStyles
|
|
35
41
|
import com.swmansion.enriched.styles.ParagraphStyles
|
|
@@ -58,9 +64,17 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
58
64
|
|
|
59
65
|
val mentionHandler: MentionHandler? = MentionHandler(this)
|
|
60
66
|
var htmlStyle: HtmlStyle = HtmlStyle(this, null)
|
|
67
|
+
set(value) {
|
|
68
|
+
if (field != value) {
|
|
69
|
+
val prev = field
|
|
70
|
+
field = value
|
|
71
|
+
reApplyHtmlStyleForSpans(prev, value)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
61
74
|
var spanWatcher: EnrichedSpanWatcher? = null
|
|
62
75
|
var layoutManager: EnrichedTextInputViewLayoutManager = EnrichedTextInputViewLayoutManager(this)
|
|
63
76
|
|
|
77
|
+
var shouldEmitHtml: Boolean = true
|
|
64
78
|
var experimentalSynchronousEvents: Boolean = false
|
|
65
79
|
|
|
66
80
|
var fontSize: Float? = null
|
|
@@ -254,6 +268,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
254
268
|
val newText = parseText(value)
|
|
255
269
|
setText(newText)
|
|
256
270
|
|
|
271
|
+
observeAsyncImages()
|
|
257
272
|
// Assign SpanWatcher one more time as our previous spannable has been replaced
|
|
258
273
|
addSpanWatcher(EnrichedSpanWatcher(this))
|
|
259
274
|
|
|
@@ -262,6 +277,20 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
262
277
|
}
|
|
263
278
|
}
|
|
264
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Finds all async images in the current text and sets up listeners
|
|
282
|
+
* to redraw the text layout when they finish downloading.
|
|
283
|
+
*/
|
|
284
|
+
private fun observeAsyncImages() {
|
|
285
|
+
val liveText = text ?: return
|
|
286
|
+
|
|
287
|
+
val spans = liveText.getSpans(0, liveText.length, EnrichedImageSpan::class.java)
|
|
288
|
+
|
|
289
|
+
for (span in spans) {
|
|
290
|
+
span.observeAsyncDrawableLoaded(liveText)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
265
294
|
fun setAutoFocus(autoFocus: Boolean) {
|
|
266
295
|
this.autoFocus = autoFocus
|
|
267
296
|
}
|
|
@@ -318,6 +347,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
318
347
|
// This ensured that newly created spans will take the new font size into account
|
|
319
348
|
htmlStyle.invalidateStyles()
|
|
320
349
|
layoutManager.invalidateLayout()
|
|
350
|
+
forceScrollToSelection()
|
|
321
351
|
}
|
|
322
352
|
|
|
323
353
|
fun setFontFamily(family: String?) {
|
|
@@ -527,11 +557,11 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
527
557
|
parametrizedStyles?.setLinkSpan(start, end, text, url)
|
|
528
558
|
}
|
|
529
559
|
|
|
530
|
-
fun addImage(src: String) {
|
|
560
|
+
fun addImage(src: String, width: Float, height: Float) {
|
|
531
561
|
val isValid = verifyStyle(EnrichedSpans.IMAGE)
|
|
532
562
|
if (!isValid) return
|
|
533
563
|
|
|
534
|
-
parametrizedStyles?.setImageSpan(src)
|
|
564
|
+
parametrizedStyles?.setImageSpan(src, width, height)
|
|
535
565
|
layoutManager.invalidateLayout()
|
|
536
566
|
}
|
|
537
567
|
|
|
@@ -549,6 +579,19 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
549
579
|
parametrizedStyles?.setMentionSpan(text, indicator, attributes)
|
|
550
580
|
}
|
|
551
581
|
|
|
582
|
+
fun requestHTML(requestId: Int) {
|
|
583
|
+
val html = try {
|
|
584
|
+
EnrichedParser.toHtmlWithDefault(text)
|
|
585
|
+
} catch (e: Exception) {
|
|
586
|
+
null
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
val reactContext = context as ReactContext
|
|
590
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
591
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
592
|
+
dispatcher?.dispatchEvent(OnRequestHtmlResultEvent(surfaceId, id, requestId, html, experimentalSynchronousEvents))
|
|
593
|
+
}
|
|
594
|
+
|
|
552
595
|
// Sometimes setting up style triggers many changes in sequence
|
|
553
596
|
// Eg. removing conflicting styles -> changing text -> applying spans
|
|
554
597
|
// In such scenario we want to prevent from handling side effects (eg. onTextChanged)
|
|
@@ -561,6 +604,72 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
561
604
|
}
|
|
562
605
|
}
|
|
563
606
|
|
|
607
|
+
private fun forceScrollToSelection() {
|
|
608
|
+
val textLayout = layout ?: return
|
|
609
|
+
val cursorOffset = selectionStart
|
|
610
|
+
if (cursorOffset <= 0) return
|
|
611
|
+
|
|
612
|
+
val selectedLineIndex = textLayout.getLineForOffset(cursorOffset)
|
|
613
|
+
val selectedLineTop = textLayout.getLineTop(selectedLineIndex)
|
|
614
|
+
val selectedLineBottom = textLayout.getLineBottom(selectedLineIndex)
|
|
615
|
+
val visibleTextHeight = height - paddingTop - paddingBottom
|
|
616
|
+
|
|
617
|
+
if (visibleTextHeight <= 0) return
|
|
618
|
+
|
|
619
|
+
val visibleTop = scrollY
|
|
620
|
+
val visibleBottom = scrollY + visibleTextHeight
|
|
621
|
+
var targetScrollY = scrollY
|
|
622
|
+
|
|
623
|
+
if (selectedLineTop < visibleTop) {
|
|
624
|
+
targetScrollY = selectedLineTop
|
|
625
|
+
} else if (selectedLineBottom > visibleBottom) {
|
|
626
|
+
targetScrollY = selectedLineBottom - visibleTextHeight
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
val maxScrollY = (textLayout.height - visibleTextHeight).coerceAtLeast(0)
|
|
630
|
+
targetScrollY = targetScrollY.coerceIn(0, maxScrollY)
|
|
631
|
+
scrollTo(scrollX, targetScrollY)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private fun reApplyHtmlStyleForSpans(previousHtmlStyle: HtmlStyle, nextHtmlStyle: HtmlStyle) {
|
|
635
|
+
val shouldRemoveBoldSpanFromH1Span = !previousHtmlStyle.h1Bold && nextHtmlStyle.h1Bold
|
|
636
|
+
val shouldRemoveBoldSpanFromH2Span = !previousHtmlStyle.h2Bold && nextHtmlStyle.h2Bold
|
|
637
|
+
val shouldRemoveBoldSpanFromH3Span = !previousHtmlStyle.h3Bold && nextHtmlStyle.h3Bold
|
|
638
|
+
|
|
639
|
+
val spannable = text as? Spannable ?: return
|
|
640
|
+
if (spannable.isEmpty()) return
|
|
641
|
+
|
|
642
|
+
var shouldEmitStateChange = false
|
|
643
|
+
|
|
644
|
+
runAsATransaction {
|
|
645
|
+
val spans = spannable.getSpans(0, spannable.length, EnrichedSpan::class.java)
|
|
646
|
+
for (span in spans) {
|
|
647
|
+
if (!span.dependsOnHtmlStyle) continue
|
|
648
|
+
|
|
649
|
+
val start = spannable.getSpanStart(span)
|
|
650
|
+
val end = spannable.getSpanEnd(span)
|
|
651
|
+
val flags = spannable.getSpanFlags(span)
|
|
652
|
+
|
|
653
|
+
if (start == -1 || end == -1) continue
|
|
654
|
+
|
|
655
|
+
if ((span is EnrichedH1Span && shouldRemoveBoldSpanFromH1Span) || (span is EnrichedH2Span && shouldRemoveBoldSpanFromH2Span) || (span is EnrichedH3Span && shouldRemoveBoldSpanFromH3Span)) {
|
|
656
|
+
val isRemoved = removeStyle(EnrichedSpans.BOLD, start, end)
|
|
657
|
+
if (isRemoved) shouldEmitStateChange = true
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
spannable.removeSpan(span)
|
|
661
|
+
val newSpan = span.rebuildWithStyle(htmlStyle)
|
|
662
|
+
spannable.setSpan(newSpan, start, end, flags)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (shouldEmitStateChange) {
|
|
666
|
+
selection?.validateStyles()
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
layoutManager.invalidateLayout()
|
|
670
|
+
forceScrollToSelection()
|
|
671
|
+
}
|
|
672
|
+
|
|
564
673
|
override fun onAttachedToWindow() {
|
|
565
674
|
super.onAttachedToWindow()
|
|
566
675
|
|
|
@@ -24,6 +24,7 @@ import com.swmansion.enriched.events.OnInputFocusEvent
|
|
|
24
24
|
import com.swmansion.enriched.events.OnLinkDetectedEvent
|
|
25
25
|
import com.swmansion.enriched.events.OnMentionDetectedEvent
|
|
26
26
|
import com.swmansion.enriched.events.OnMentionEvent
|
|
27
|
+
import com.swmansion.enriched.events.OnRequestHtmlResultEvent
|
|
27
28
|
import com.swmansion.enriched.spans.EnrichedSpans
|
|
28
29
|
import com.swmansion.enriched.styles.HtmlStyle
|
|
29
30
|
import com.swmansion.enriched.utils.jsonStringToStringMap
|
|
@@ -71,6 +72,7 @@ class EnrichedTextInputViewManager : SimpleViewManager<EnrichedTextInputView>(),
|
|
|
71
72
|
map.put(OnMentionDetectedEvent.EVENT_NAME, mapOf("registrationName" to OnMentionDetectedEvent.EVENT_NAME))
|
|
72
73
|
map.put(OnMentionEvent.EVENT_NAME, mapOf("registrationName" to OnMentionEvent.EVENT_NAME))
|
|
73
74
|
map.put(OnChangeSelectionEvent.EVENT_NAME, mapOf("registrationName" to OnChangeSelectionEvent.EVENT_NAME))
|
|
75
|
+
map.put(OnRequestHtmlResultEvent.EVENT_NAME, mapOf("registrationName" to OnRequestHtmlResultEvent.EVENT_NAME))
|
|
74
76
|
|
|
75
77
|
return map
|
|
76
78
|
}
|
|
@@ -177,7 +179,7 @@ class EnrichedTextInputViewManager : SimpleViewManager<EnrichedTextInputView>(),
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
override fun setIsOnChangeHtmlSet(view: EnrichedTextInputView?, value: Boolean) {
|
|
180
|
-
|
|
182
|
+
view?.shouldEmitHtml = value
|
|
181
183
|
}
|
|
182
184
|
|
|
183
185
|
override fun setAutoCapitalize(view: EnrichedTextInputView?, flag: String?) {
|
|
@@ -255,8 +257,8 @@ class EnrichedTextInputViewManager : SimpleViewManager<EnrichedTextInputView>(),
|
|
|
255
257
|
view?.addLink(start, end, text, url)
|
|
256
258
|
}
|
|
257
259
|
|
|
258
|
-
override fun addImage(view: EnrichedTextInputView?, src: String) {
|
|
259
|
-
view?.addImage(src)
|
|
260
|
+
override fun addImage(view: EnrichedTextInputView?, src: String, width: Float, height: Float) {
|
|
261
|
+
view?.addImage(src, width, height)
|
|
260
262
|
}
|
|
261
263
|
|
|
262
264
|
override fun startMention(view: EnrichedTextInputView?, indicator: String) {
|
|
@@ -268,6 +270,10 @@ class EnrichedTextInputViewManager : SimpleViewManager<EnrichedTextInputView>(),
|
|
|
268
270
|
view?.addMention(text, indicator, attributes)
|
|
269
271
|
}
|
|
270
272
|
|
|
273
|
+
override fun requestHTML(view: EnrichedTextInputView?, requestId: Int) {
|
|
274
|
+
view?.requestHTML(requestId)
|
|
275
|
+
}
|
|
276
|
+
|
|
271
277
|
override fun measure(
|
|
272
278
|
context: Context,
|
|
273
279
|
localData: ReadableMap?,
|
|
@@ -4,10 +4,12 @@ import com.facebook.react.ReactPackage
|
|
|
4
4
|
import com.facebook.react.bridge.NativeModule
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
6
|
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
import com.swmansion.enriched.utils.ResourceManager
|
|
7
8
|
import java.util.ArrayList
|
|
8
9
|
|
|
9
10
|
class EnrichedTextInputViewPackage : ReactPackage {
|
|
10
11
|
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
12
|
+
ResourceManager.init(reactContext.applicationContext)
|
|
11
13
|
val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
|
|
12
14
|
viewManagers.add(EnrichedTextInputViewManager())
|
|
13
15
|
return viewManagers
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.swmansion.enriched.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
class OnRequestHtmlResultEvent(
|
|
8
|
+
surfaceId: Int,
|
|
9
|
+
viewId: Int,
|
|
10
|
+
private val requestId: Int,
|
|
11
|
+
private val html: String?,
|
|
12
|
+
private val experimentalSynchronousEvents: Boolean
|
|
13
|
+
) : Event<OnRequestHtmlResultEvent>(surfaceId, viewId) {
|
|
14
|
+
|
|
15
|
+
override fun getEventName(): String = EVENT_NAME
|
|
16
|
+
|
|
17
|
+
override fun getEventData(): WritableMap {
|
|
18
|
+
val eventData: WritableMap = Arguments.createMap()
|
|
19
|
+
eventData.putInt("requestId", requestId)
|
|
20
|
+
if (html != null) {
|
|
21
|
+
eventData.putString("html", html)
|
|
22
|
+
} else {
|
|
23
|
+
eventData.putNull("html")
|
|
24
|
+
}
|
|
25
|
+
return eventData
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override fun experimental_isSynchronous(): Boolean = experimentalSynchronousEvents
|
|
29
|
+
|
|
30
|
+
companion object {
|
|
31
|
+
const val EVENT_NAME: String = "onRequestHtmlResult"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -11,6 +11,8 @@ import com.swmansion.enriched.styles.HtmlStyle
|
|
|
11
11
|
|
|
12
12
|
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/text/style/QuoteSpan.java
|
|
13
13
|
class EnrichedBlockQuoteSpan(private val htmlStyle: HtmlStyle) : MetricAffectingSpan(), LeadingMarginSpan, EnrichedBlockSpan {
|
|
14
|
+
override val dependsOnHtmlStyle: Boolean = true
|
|
15
|
+
|
|
14
16
|
override fun updateMeasureState(p0: TextPaint) {
|
|
15
17
|
// Do nothing, but inform layout that this span affects text metrics
|
|
16
18
|
}
|
|
@@ -35,4 +37,8 @@ class EnrichedBlockQuoteSpan(private val htmlStyle: HtmlStyle) : MetricAffecting
|
|
|
35
37
|
textPaint?.color = color
|
|
36
38
|
}
|
|
37
39
|
}
|
|
40
|
+
|
|
41
|
+
override fun rebuildWithStyle(htmlStyle: HtmlStyle): EnrichedBlockQuoteSpan {
|
|
42
|
+
return EnrichedBlockQuoteSpan(htmlStyle)
|
|
43
|
+
}
|
|
38
44
|
}
|
|
@@ -2,9 +2,15 @@ package com.swmansion.enriched.spans
|
|
|
2
2
|
|
|
3
3
|
import android.graphics.Typeface
|
|
4
4
|
import android.text.style.StyleSpan
|
|
5
|
+
import com.swmansion.enriched.spans.interfaces.EnrichedBlockSpan
|
|
5
6
|
import com.swmansion.enriched.spans.interfaces.EnrichedInlineSpan
|
|
6
7
|
import com.swmansion.enriched.styles.HtmlStyle
|
|
7
8
|
|
|
8
9
|
@Suppress("UNUSED_PARAMETER")
|
|
9
10
|
class EnrichedBoldSpan(htmlStyle: HtmlStyle) : StyleSpan(Typeface.BOLD), EnrichedInlineSpan {
|
|
11
|
+
override val dependsOnHtmlStyle: Boolean = false
|
|
12
|
+
|
|
13
|
+
override fun rebuildWithStyle(htmlStyle: HtmlStyle): EnrichedBoldSpan {
|
|
14
|
+
return EnrichedBoldSpan(htmlStyle)
|
|
15
|
+
}
|
|
10
16
|
}
|
|
@@ -2,8 +2,10 @@ package com.swmansion.enriched.spans
|
|
|
2
2
|
|
|
3
3
|
import android.graphics.Canvas
|
|
4
4
|
import android.graphics.Paint
|
|
5
|
+
import android.graphics.Path
|
|
5
6
|
import android.graphics.RectF
|
|
6
7
|
import android.graphics.Typeface
|
|
8
|
+
import android.text.Spanned
|
|
7
9
|
import android.text.TextPaint
|
|
8
10
|
import android.text.style.LineBackgroundSpan
|
|
9
11
|
import android.text.style.MetricAffectingSpan
|
|
@@ -11,6 +13,8 @@ import com.swmansion.enriched.spans.interfaces.EnrichedBlockSpan
|
|
|
11
13
|
import com.swmansion.enriched.styles.HtmlStyle
|
|
12
14
|
|
|
13
15
|
class EnrichedCodeBlockSpan(private val htmlStyle: HtmlStyle) : MetricAffectingSpan(), LineBackgroundSpan, EnrichedBlockSpan {
|
|
16
|
+
override val dependsOnHtmlStyle: Boolean = true
|
|
17
|
+
|
|
14
18
|
override fun updateDrawState(paint: TextPaint) {
|
|
15
19
|
paint.typeface = Typeface.MONOSPACE
|
|
16
20
|
paint.color = htmlStyle.codeBlockColor
|
|
@@ -33,10 +37,47 @@ class EnrichedCodeBlockSpan(private val htmlStyle: HtmlStyle) : MetricAffectingS
|
|
|
33
37
|
end: Int,
|
|
34
38
|
lineNum: Int
|
|
35
39
|
) {
|
|
40
|
+
if (text !is Spanned) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
val previousColor = p.color
|
|
37
45
|
p.color = htmlStyle.codeBlockBackgroundColor
|
|
46
|
+
|
|
47
|
+
val radius = htmlStyle.codeBlockRadius
|
|
48
|
+
|
|
49
|
+
val spanStart = text.getSpanStart(this)
|
|
50
|
+
val spanEnd = text.getSpanEnd(this)
|
|
51
|
+
val isFirstLineOfSpan = start == spanStart
|
|
52
|
+
val isLastLineOfSpan = end == spanEnd || (spanEnd + 1 == end && text[spanEnd] == '\n')
|
|
53
|
+
|
|
54
|
+
val path = Path()
|
|
55
|
+
val radii = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f)
|
|
56
|
+
|
|
57
|
+
if (isFirstLineOfSpan) {
|
|
58
|
+
// Top-Left and Top-Right corners
|
|
59
|
+
radii[0] = radius
|
|
60
|
+
radii[1] = radius
|
|
61
|
+
radii[2] = radius
|
|
62
|
+
radii[3] = radius
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (isLastLineOfSpan) {
|
|
66
|
+
// Bottom-Right and Bottom-Left corners
|
|
67
|
+
radii[4] = radius
|
|
68
|
+
radii[5] = radius
|
|
69
|
+
radii[6] = radius
|
|
70
|
+
radii[7] = radius
|
|
71
|
+
}
|
|
72
|
+
|
|
38
73
|
val rect = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
|
|
39
|
-
|
|
74
|
+
|
|
75
|
+
path.addRoundRect(rect, radii, Path.Direction.CW)
|
|
76
|
+
canvas.drawPath(path, p)
|
|
40
77
|
p.color = previousColor
|
|
41
78
|
}
|
|
79
|
+
|
|
80
|
+
override fun rebuildWithStyle(htmlStyle: HtmlStyle): EnrichedCodeBlockSpan {
|
|
81
|
+
return EnrichedCodeBlockSpan(htmlStyle)
|
|
82
|
+
}
|
|
42
83
|
}
|
|
@@ -7,6 +7,8 @@ import com.swmansion.enriched.spans.interfaces.EnrichedHeadingSpan
|
|
|
7
7
|
import com.swmansion.enriched.styles.HtmlStyle
|
|
8
8
|
|
|
9
9
|
class EnrichedH1Span(private val style: HtmlStyle) : AbsoluteSizeSpan(style.h1FontSize), EnrichedHeadingSpan {
|
|
10
|
+
override val dependsOnHtmlStyle: Boolean = true
|
|
11
|
+
|
|
10
12
|
override fun updateDrawState(tp: TextPaint) {
|
|
11
13
|
super.updateDrawState(tp)
|
|
12
14
|
val bold = style.h1Bold
|
|
@@ -14,4 +16,8 @@ class EnrichedH1Span(private val style: HtmlStyle) : AbsoluteSizeSpan(style.h1Fo
|
|
|
14
16
|
tp.typeface = Typeface.create(tp.typeface, Typeface.BOLD)
|
|
15
17
|
}
|
|
16
18
|
}
|
|
19
|
+
|
|
20
|
+
override fun rebuildWithStyle(htmlStyle: HtmlStyle): EnrichedH1Span {
|
|
21
|
+
return EnrichedH1Span(htmlStyle)
|
|
22
|
+
}
|
|
17
23
|
}
|
|
@@ -7,6 +7,8 @@ import com.swmansion.enriched.spans.interfaces.EnrichedHeadingSpan
|
|
|
7
7
|
import com.swmansion.enriched.styles.HtmlStyle
|
|
8
8
|
|
|
9
9
|
class EnrichedH2Span(private val htmlStyle: HtmlStyle) : AbsoluteSizeSpan(htmlStyle.h2FontSize), EnrichedHeadingSpan {
|
|
10
|
+
override val dependsOnHtmlStyle: Boolean = true
|
|
11
|
+
|
|
10
12
|
override fun updateDrawState(tp: TextPaint) {
|
|
11
13
|
super.updateDrawState(tp)
|
|
12
14
|
val bold = htmlStyle.h2Bold
|
|
@@ -14,4 +16,8 @@ class EnrichedH2Span(private val htmlStyle: HtmlStyle) : AbsoluteSizeSpan(htmlSt
|
|
|
14
16
|
tp.typeface = Typeface.create(tp.typeface, Typeface.BOLD)
|
|
15
17
|
}
|
|
16
18
|
}
|
|
19
|
+
|
|
20
|
+
override fun rebuildWithStyle(htmlStyle: HtmlStyle): EnrichedH2Span {
|
|
21
|
+
return EnrichedH2Span(htmlStyle)
|
|
22
|
+
}
|
|
17
23
|
}
|
|
@@ -7,6 +7,8 @@ import com.swmansion.enriched.spans.interfaces.EnrichedHeadingSpan
|
|
|
7
7
|
import com.swmansion.enriched.styles.HtmlStyle
|
|
8
8
|
|
|
9
9
|
class EnrichedH3Span(private val htmlStyle: HtmlStyle) : AbsoluteSizeSpan(htmlStyle.h3FontSize), EnrichedHeadingSpan {
|
|
10
|
+
override val dependsOnHtmlStyle: Boolean = true
|
|
11
|
+
|
|
10
12
|
override fun updateDrawState(tp: TextPaint) {
|
|
11
13
|
super.updateDrawState(tp)
|
|
12
14
|
val bold = htmlStyle.h3Bold
|
|
@@ -14,4 +16,8 @@ class EnrichedH3Span(private val htmlStyle: HtmlStyle) : AbsoluteSizeSpan(htmlSt
|
|
|
14
16
|
tp.typeface = Typeface.create(tp.typeface, Typeface.BOLD)
|
|
15
17
|
}
|
|
16
18
|
}
|
|
19
|
+
|
|
20
|
+
override fun rebuildWithStyle(htmlStyle: HtmlStyle): EnrichedH3Span {
|
|
21
|
+
return EnrichedH3Span(htmlStyle)
|
|
22
|
+
}
|
|
17
23
|
}
|