react-native-enriched 0.1.1 → 0.1.3
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 +50 -39
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +3 -1
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +2 -0
- package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +6 -1
- package/ios/inputTextView/InputTextView.mm +3 -1
- package/ios/styles/InlineCodeStyle.mm +7 -6
- package/ios/styles/MentionStyle.mm +3 -2
- package/ios/utils/ColorExtension.h +1 -0
- package/ios/utils/ColorExtension.mm +9 -0
- package/ios/utils/TextInsertionUtils.mm +2 -2
- package/ios/utils/ZeroWidthSpaceUtils.mm +2 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<img src="https://github.com/user-attachments/assets/abc75d3b-495b-4a76-a72f-d87ce3ca1ff9" alt="react-native-enriched by Software Mansion" width="100%">
|
|
2
|
+
|
|
1
3
|
# react-native-enriched
|
|
2
4
|
|
|
3
5
|
`react-native-enriched` is a powerful React Native library that exposes a rich text editor component:
|
|
@@ -19,6 +21,11 @@ Built by [Software Mansion](https://swmansion.com/) and sponsored by [Filament](
|
|
|
19
21
|
|
|
20
22
|
<img width="80" height="80" alt="Filament Logo" src="https://github.com/user-attachments/assets/4103ab79-da34-4164-aa5f-dcf08815bf65" />
|
|
21
23
|
|
|
24
|
+
\
|
|
25
|
+
Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues.
|
|
26
|
+
We can help you build your next dream product –
|
|
27
|
+
[Hire us](https://swmansion.com/contact/projects?utm_source=react-native-enriched&utm_medium=readme).
|
|
28
|
+
|
|
22
29
|
## Table of Contents
|
|
23
30
|
|
|
24
31
|
- [Prerequisites](#prerequisites)
|
|
@@ -119,6 +126,7 @@ const styles = StyleSheet.create({
|
|
|
119
126
|
alignItems: 'center',
|
|
120
127
|
},
|
|
121
128
|
input: {
|
|
129
|
+
width: '100%',
|
|
122
130
|
fontSize: 20,
|
|
123
131
|
padding: 10,
|
|
124
132
|
maxHeight: 200,
|
|
@@ -131,27 +139,27 @@ const styles = StyleSheet.create({
|
|
|
131
139
|
Summary of what happens here:
|
|
132
140
|
|
|
133
141
|
1. Any methods imperatively called on the input to e.g. toggle some style must be used through a `ref` of `EnrichedTextInputInstance` type. Here, `toggleBold` method that is called on the button press calls `ref.current?.toggleBold()`, which toggles the bold styling within the current selection.
|
|
134
|
-
2. All the active styles info is emitted by `onChangeState` event. Set up a proper callback that accepts a `NativeSyntheticEvent<OnChangeStateEvent>` argument and you can access an object with boolean properties indicating which styles are active, such as `isBold` in the example. Here, this info is stored in a
|
|
142
|
+
2. All the active styles info is emitted by `onChangeState` event. Set up a proper callback that accepts a `NativeSyntheticEvent<OnChangeStateEvent>` argument, and you can access an object with boolean properties indicating which styles are active, such as `isBold` in the example. Here, this info is stored in a React state and used to change colors on the button.
|
|
135
143
|
|
|
136
144
|
## Non Parametrized Styles
|
|
137
145
|
|
|
138
146
|
Supported styles:
|
|
139
147
|
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
148
|
+
- bold
|
|
149
|
+
- italic
|
|
150
|
+
- underline
|
|
151
|
+
- strikethrough
|
|
152
|
+
- inline code
|
|
145
153
|
- H1 heading
|
|
146
154
|
- H2 heading
|
|
147
155
|
- H3 heading
|
|
148
|
-
-
|
|
149
|
-
-
|
|
156
|
+
- codeblock
|
|
157
|
+
- blockquote
|
|
150
158
|
- ordered list
|
|
151
159
|
- unordered list
|
|
152
160
|
|
|
153
161
|
> [!NOTE]
|
|
154
|
-
> The iOS doesn't support codeblocks just yet but it's planned in the near future!
|
|
162
|
+
> The iOS doesn't support codeblocks just yet, but it's planned in the near future!
|
|
155
163
|
|
|
156
164
|
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.
|
|
157
165
|
|
|
@@ -168,7 +176,7 @@ The links are here, just like in any other editor, a piece of text with a URL at
|
|
|
168
176
|
|
|
169
177
|
### Automatic links detection
|
|
170
178
|
|
|
171
|
-
`react-native-enriched` automatically detects words that appear to be some URLs and makes them links. Currently we are using pretty naive approach to detect whether text can be treated as a link or not. On iOS it's a pretty simple regex, on Android we are using URL regex provided by the system.
|
|
179
|
+
`react-native-enriched` automatically detects words that appear to be some URLs and makes them links. Currently, we are using pretty naive approach to detect whether text can be treated as a link or not. On iOS it's a pretty simple regex, on Android we are using URL regex provided by the system.
|
|
172
180
|
|
|
173
181
|
### Applying links manually
|
|
174
182
|
|
|
@@ -186,7 +194,7 @@ Mentions are meant to be a customisable style that lets you put mentioning phras
|
|
|
186
194
|
|
|
187
195
|
### Mention Indicators
|
|
188
196
|
|
|
189
|
-
There is a [mentionIndicators](#mentionindicators) prop that lets you define what characters can start a mention. By default it is set to `[ @ ]`, meaning that typing a `@` character in the input will start the creation of a mention.
|
|
197
|
+
There is a [mentionIndicators](#mentionindicators) prop that lets you define what characters can start a mention. By default, it is set to `[ @ ]`, meaning that typing a `@` character in the input will start the creation of a mention.
|
|
190
198
|
|
|
191
199
|
### Starting a mention
|
|
192
200
|
|
|
@@ -208,10 +216,10 @@ Whenever you feel ready with the currently edited mention (so most likely user c
|
|
|
208
216
|
|
|
209
217
|
You can insert an image into the input using [setImage](#setimage) ref method.
|
|
210
218
|
|
|
211
|
-
The image will be put into a single line in the input and will
|
|
219
|
+
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.
|
|
212
220
|
|
|
213
221
|
> [!NOTE]
|
|
214
|
-
> The iOS doesn't support inline images just yet but it's planned in the near future!
|
|
222
|
+
> The iOS doesn't support inline images just yet, but it's planned in the near future!
|
|
215
223
|
|
|
216
224
|
## Style Detection
|
|
217
225
|
|
|
@@ -286,7 +294,7 @@ If `false`, text is not editable.
|
|
|
286
294
|
|
|
287
295
|
#### `htmlStyle`
|
|
288
296
|
|
|
289
|
-
A prop for customizing styles
|
|
297
|
+
A prop for customizing styles appearances.
|
|
290
298
|
|
|
291
299
|
| Type | Default Value | Platform |
|
|
292
300
|
|--------------------------------|----------------------------------------------------|----------|
|
|
@@ -322,9 +330,9 @@ interface OnChangeHtmlEvent {
|
|
|
322
330
|
|
|
323
331
|
- `value` is the new HTML.
|
|
324
332
|
|
|
325
|
-
| Type
|
|
326
|
-
|
|
327
|
-
| `(NativeSyntheticEvent
|
|
333
|
+
| Type | Default Value | Platform |
|
|
334
|
+
|------------------------------------------------------------|---------------|----------|
|
|
335
|
+
| `(event: NativeSyntheticEvent<OnChangeHtmlEvent>) => void` | - | Both |
|
|
328
336
|
|
|
329
337
|
#### `onChangeMention`
|
|
330
338
|
|
|
@@ -342,9 +350,9 @@ interface OnChangeMentionEvent {
|
|
|
342
350
|
- `indicator` is the indicator of the currently edited mention.
|
|
343
351
|
- `text` contains whole text that has been typed after the indicator.
|
|
344
352
|
|
|
345
|
-
| Type
|
|
346
|
-
|
|
347
|
-
| `(OnChangeMentionEvent) => void` | - | Both |
|
|
353
|
+
| Type | Default Value | Platform |
|
|
354
|
+
|-----------------------------------------|---------------|----------|
|
|
355
|
+
| `(event: OnChangeMentionEvent) => void` | - | Both |
|
|
348
356
|
|
|
349
357
|
#### `onChangeSelection`
|
|
350
358
|
|
|
@@ -353,7 +361,7 @@ Callback that is called each time user changes selection or moves the cursor in
|
|
|
353
361
|
Payload interface:
|
|
354
362
|
|
|
355
363
|
```ts
|
|
356
|
-
OnChangeSelectionEvent {
|
|
364
|
+
interface OnChangeSelectionEvent {
|
|
357
365
|
start: Int32;
|
|
358
366
|
end: Int32;
|
|
359
367
|
text: string;
|
|
@@ -364,9 +372,9 @@ OnChangeSelectionEvent {
|
|
|
364
372
|
- `end` is the first index after the selection's ending. For just a cursor in place (no selection), `start` equals `end`.
|
|
365
373
|
- `text` is the input's text in the current selection.
|
|
366
374
|
|
|
367
|
-
| Type
|
|
368
|
-
|
|
369
|
-
| `(NativeSyntheticEvent
|
|
375
|
+
| Type | Default Value | Platform |
|
|
376
|
+
|-----------------------------------------------------------------|---------------|----------|
|
|
377
|
+
| `(event: NativeSyntheticEvent<OnChangeSelectionEvent>) => void` | - | Both |
|
|
370
378
|
|
|
371
379
|
#### `onChangeState`
|
|
372
380
|
|
|
@@ -394,9 +402,9 @@ interface OnChangeStateEvent {
|
|
|
394
402
|
}
|
|
395
403
|
```
|
|
396
404
|
|
|
397
|
-
| Type
|
|
398
|
-
|
|
399
|
-
| `(NativeSyntheticEvent
|
|
405
|
+
| Type | Default Value | Platform |
|
|
406
|
+
|-------------------------------------------------------------|---------------|----------|
|
|
407
|
+
| `(event: NativeSyntheticEvent<OnChangeStateEvent>) => void` | - | Both |
|
|
400
408
|
|
|
401
409
|
#### `onChangeText`
|
|
402
410
|
|
|
@@ -412,9 +420,9 @@ interface OnChangeTextEvent {
|
|
|
412
420
|
|
|
413
421
|
- `value` is the new text value of the input.
|
|
414
422
|
|
|
415
|
-
| Type
|
|
416
|
-
|
|
417
|
-
| `(NativeSyntheticEvent
|
|
423
|
+
| Type | Default Value | Platform |
|
|
424
|
+
|------------------------------------------------------------|---------------|----------|
|
|
425
|
+
| `(event: NativeSyntheticEvent<OnChangeTextEvent>) => void` | - | Both |
|
|
418
426
|
|
|
419
427
|
#### `onEndMention`
|
|
420
428
|
|
|
@@ -454,9 +462,9 @@ interface OnLinkDetected {
|
|
|
454
462
|
- `start` is the starting index of the link.
|
|
455
463
|
- `end` is the first index after the ending index of the link.
|
|
456
464
|
|
|
457
|
-
| Type
|
|
458
|
-
|
|
459
|
-
| `(OnLinkDetected) => void` | - | Both |
|
|
465
|
+
| Type | Default Value | Platform |
|
|
466
|
+
|-----------------------------------|---------------|----------|
|
|
467
|
+
| `(event: OnLinkDetected) => void` | - | Both |
|
|
460
468
|
|
|
461
469
|
#### `onMentionDetected`
|
|
462
470
|
|
|
@@ -465,7 +473,7 @@ Callback called when mention has been detected - either a new mention has been a
|
|
|
465
473
|
Payload interface contains all the useful mention data:
|
|
466
474
|
|
|
467
475
|
```ts
|
|
468
|
-
OnMentionDetected {
|
|
476
|
+
interface OnMentionDetected {
|
|
469
477
|
text: string;
|
|
470
478
|
indicator: string;
|
|
471
479
|
attributes: Record<string, string>;
|
|
@@ -476,9 +484,9 @@ OnMentionDetected {
|
|
|
476
484
|
- `indicator` is the indicator of the mention.
|
|
477
485
|
- `attributes` are the additional user-defined attributes that are being stored with the mention.
|
|
478
486
|
|
|
479
|
-
| Type
|
|
480
|
-
|
|
481
|
-
| `(OnMentionDetected) => void` | - | Both |
|
|
487
|
+
| Type | Default Value | Platform |
|
|
488
|
+
|--------------------------------------|---------------|----------|
|
|
489
|
+
| `(event: OnMentionDetected) => void` | - | Both |
|
|
482
490
|
|
|
483
491
|
#### `onStartMention`
|
|
484
492
|
|
|
@@ -552,12 +560,12 @@ If true, Android will use experimental synchronous events. This will prevent fro
|
|
|
552
560
|
|
|
553
561
|
### Ref Methods
|
|
554
562
|
|
|
555
|
-
All
|
|
563
|
+
All the methods should be called on the input's [ref](#ref).
|
|
556
564
|
|
|
557
565
|
#### `.blur()`
|
|
558
566
|
|
|
559
567
|
```ts
|
|
560
|
-
blur: () => void
|
|
568
|
+
blur: () => void;
|
|
561
569
|
```
|
|
562
570
|
|
|
563
571
|
Blurs the input.
|
|
@@ -804,6 +812,9 @@ interface MentionStyleProperties {
|
|
|
804
812
|
- `fontSize` is the size of the heading's font, defaults to `32`/`24`/`20` for h1/h2/h3.
|
|
805
813
|
- `bold` defines whether the heading should be bolded, defaults to `false`.
|
|
806
814
|
|
|
815
|
+
> [!NOTE]
|
|
816
|
+
> On iOS, the headings cannot have same `fontSize` as the component's `fontSize`. Doing so results in unexpected behavior.
|
|
817
|
+
|
|
807
818
|
#### blockquote
|
|
808
819
|
|
|
809
820
|
- `borderColor` defines the color of the rectangular border drawn to the left of blockquote text. Takes [color](https://reactnative.dev/docs/colors) value, defaults to `darkgray`.
|
|
@@ -204,7 +204,9 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
// Currently, we do not support pasting images
|
|
208
|
+
if (item?.text == null) return
|
|
209
|
+
val finalText = currentText.mergeSpannables(start, end, item.text.toString())
|
|
208
210
|
setValue(finalText)
|
|
209
211
|
parametrizedStyles?.detectAllLinks()
|
|
210
212
|
}
|
|
@@ -154,6 +154,8 @@ class HtmlStyle {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
private fun withOpacity(color: Int, alpha: Int): Int {
|
|
157
|
+
// Do not apply opacity to transparent color
|
|
158
|
+
if (Color.alpha(color) == 0) return color
|
|
157
159
|
val a = alpha.coerceIn(0, 255)
|
|
158
160
|
return (color and 0x00FFFFFF) or (a shl 24)
|
|
159
161
|
}
|
|
@@ -148,7 +148,7 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
|
|
|
148
148
|
mentionStart = start
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
mentionHandler.onMention(indicator,
|
|
151
|
+
mentionHandler.onMention(indicator, text)
|
|
152
152
|
} else {
|
|
153
153
|
mentionHandler.endMention()
|
|
154
154
|
}
|
|
@@ -208,6 +208,11 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
|
|
|
208
208
|
val (safeStart, safeEnd) = spannable.getSafeSpanBoundaries(start, spanEnd)
|
|
209
209
|
spannable.setSpan(span, safeStart, safeEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
210
210
|
|
|
211
|
+
val hasSpaceAtTheEnd = spannable.length > safeEnd && spannable[safeEnd] == ' '
|
|
212
|
+
if (!hasSpaceAtTheEnd) {
|
|
213
|
+
spannable.insert(safeEnd, " ")
|
|
214
|
+
}
|
|
215
|
+
|
|
211
216
|
view.selection.validateStyles()
|
|
212
217
|
}
|
|
213
218
|
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
|
|
77
77
|
- (void)tryHandlingPlainTextItemsIn:(UIPasteboard *)pasteboard range:(NSRange)range input:(EnrichedTextInputView *)input {
|
|
78
78
|
NSArray *existingTypes = pasteboard.pasteboardTypes;
|
|
79
|
-
NSArray *handledTypes = @[UTTypeUTF8PlainText.identifier, UTTypePlainText.identifier];
|
|
79
|
+
NSArray *handledTypes = @[UTTypeUTF8PlainText.identifier, UTTypePlainText.identifier, UTTypeURL.identifier];
|
|
80
80
|
NSString *plainText;
|
|
81
81
|
|
|
82
82
|
for(NSString *type in handledTypes) {
|
|
@@ -90,6 +90,8 @@
|
|
|
90
90
|
plainText = [[NSString alloc]initWithData:value encoding:NSUTF8StringEncoding];
|
|
91
91
|
} else if([value isKindOfClass:[NSString class]]) {
|
|
92
92
|
plainText = (NSString *)value;
|
|
93
|
+
} else if([value isKindOfClass:[NSURL class]]) {
|
|
94
|
+
plainText = [(NSURL *)value absoluteString];
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#import "FontExtension.h"
|
|
4
4
|
#import "OccurenceUtils.h"
|
|
5
5
|
#import "ParagraphsUtils.h"
|
|
6
|
+
#import "ColorExtension.h"
|
|
6
7
|
|
|
7
8
|
@implementation InlineCodeStyle {
|
|
8
9
|
EnrichedTextInputView *_input;
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
NSRange currentRange = [value rangeValue];
|
|
34
35
|
[_input->textView.textStorage beginEditing];
|
|
35
36
|
|
|
36
|
-
[_input->textView.textStorage addAttribute:NSBackgroundColorAttributeName value:[[_input->config inlineCodeBgColor]
|
|
37
|
+
[_input->textView.textStorage addAttribute:NSBackgroundColorAttributeName value:[[_input->config inlineCodeBgColor] colorWithAlphaIfNotTransparent:0.4] range:currentRange];
|
|
37
38
|
[_input->textView.textStorage addAttribute:NSForegroundColorAttributeName value:[_input->config inlineCodeFgColor] range:currentRange];
|
|
38
39
|
[_input->textView.textStorage addAttribute:NSUnderlineColorAttributeName value:[_input->config inlineCodeFgColor] range:currentRange];
|
|
39
40
|
[_input->textView.textStorage addAttribute:NSStrikethroughColorAttributeName value:[_input->config inlineCodeFgColor] range:currentRange];
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
|
|
42
43
|
UIFont *font = (UIFont *)value;
|
|
43
44
|
if(font != nullptr) {
|
|
44
|
-
UIFont *newFont = [[_input->config monospacedFont] withFontTraits:font];
|
|
45
|
+
UIFont *newFont = [[[_input->config monospacedFont] withFontTraits:font] setSize:font.pointSize];
|
|
45
46
|
[_input->textView.textStorage addAttribute:NSFontAttributeName value:newFont range:range];
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -53,13 +54,13 @@
|
|
|
53
54
|
|
|
54
55
|
- (void)addTypingAttributes {
|
|
55
56
|
NSMutableDictionary *newTypingAttrs = [_input->textView.typingAttributes mutableCopy];
|
|
56
|
-
newTypingAttrs[NSBackgroundColorAttributeName] = [[_input->config inlineCodeBgColor]
|
|
57
|
+
newTypingAttrs[NSBackgroundColorAttributeName] = [[_input->config inlineCodeBgColor] colorWithAlphaIfNotTransparent:0.4];
|
|
57
58
|
newTypingAttrs[NSForegroundColorAttributeName] = [_input->config inlineCodeFgColor];
|
|
58
59
|
newTypingAttrs[NSUnderlineColorAttributeName] = [_input->config inlineCodeFgColor];
|
|
59
60
|
newTypingAttrs[NSStrikethroughColorAttributeName] = [_input->config inlineCodeFgColor];
|
|
60
61
|
UIFont* currentFont = (UIFont *)newTypingAttrs[NSFontAttributeName];
|
|
61
62
|
if(currentFont != nullptr) {
|
|
62
|
-
newTypingAttrs[NSFontAttributeName] = [[_input->config monospacedFont] withFontTraits:currentFont];
|
|
63
|
+
newTypingAttrs[NSFontAttributeName] = [[[_input->config monospacedFont] withFontTraits:currentFont] setSize:currentFont.pointSize];
|
|
63
64
|
}
|
|
64
65
|
_input->textView.typingAttributes = newTypingAttrs;
|
|
65
66
|
}
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
|
|
76
77
|
UIFont *font = (UIFont *)value;
|
|
77
78
|
if(font != nullptr) {
|
|
78
|
-
UIFont *newFont = [[_input->config primaryFont] withFontTraits:font];
|
|
79
|
+
UIFont *newFont = [[[_input->config primaryFont] withFontTraits:font] setSize:font.pointSize];
|
|
79
80
|
[_input->textView.textStorage addAttribute:NSFontAttributeName value:newFont range:range];
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
newTypingAttrs[NSStrikethroughColorAttributeName] = [_input->config primaryColor];
|
|
93
94
|
UIFont* currentFont = (UIFont *)newTypingAttrs[NSFontAttributeName];
|
|
94
95
|
if(currentFont != nullptr) {
|
|
95
|
-
newTypingAttrs[NSFontAttributeName] = [[_input->config primaryFont] withFontTraits:currentFont];
|
|
96
|
+
newTypingAttrs[NSFontAttributeName] = [[[_input->config primaryFont] withFontTraits:currentFont] setSize:currentFont.pointSize];
|
|
96
97
|
}
|
|
97
98
|
_input->textView.typingAttributes = newTypingAttrs;
|
|
98
99
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#import "TextInsertionUtils.h"
|
|
5
5
|
#import "WordsUtils.h"
|
|
6
6
|
#import "UIView+React.h"
|
|
7
|
+
#import "ColorExtension.h"
|
|
7
8
|
|
|
8
9
|
// custom NSAttributedStringKey to differentiate from links
|
|
9
10
|
static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
@@ -154,7 +155,7 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
154
155
|
NSForegroundColorAttributeName: styleProps.color,
|
|
155
156
|
NSUnderlineColorAttributeName: styleProps.color,
|
|
156
157
|
NSStrikethroughColorAttributeName: styleProps.color,
|
|
157
|
-
NSBackgroundColorAttributeName: [styleProps.backgroundColor
|
|
158
|
+
NSBackgroundColorAttributeName: [styleProps.backgroundColor colorWithAlphaIfNotTransparent:0.4],
|
|
158
159
|
} mutableCopy];
|
|
159
160
|
|
|
160
161
|
if(styleProps.decorationLine == DecorationUnderline) {
|
|
@@ -186,7 +187,7 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
186
187
|
NSForegroundColorAttributeName: styleProps.color,
|
|
187
188
|
NSUnderlineColorAttributeName: styleProps.color,
|
|
188
189
|
NSStrikethroughColorAttributeName: styleProps.color,
|
|
189
|
-
NSBackgroundColorAttributeName: [styleProps.backgroundColor
|
|
190
|
+
NSBackgroundColorAttributeName: [styleProps.backgroundColor colorWithAlphaIfNotTransparent:0.4],
|
|
190
191
|
} mutableCopy];
|
|
191
192
|
|
|
192
193
|
if(styleProps.decorationLine == DecorationUnderline) {
|
|
@@ -24,4 +24,13 @@
|
|
|
24
24
|
|
|
25
25
|
return [selfColor isEqual:otherColor];
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
- (UIColor *)colorWithAlphaIfNotTransparent:(CGFloat)newAlpha {
|
|
29
|
+
CGFloat alpha = 0.0;
|
|
30
|
+
[self getRed:nil green:nil blue:nil alpha:&alpha];
|
|
31
|
+
if (alpha > 0.0) {
|
|
32
|
+
return [self colorWithAlphaComponent:newAlpha];
|
|
33
|
+
}
|
|
34
|
+
return self;
|
|
35
|
+
}
|
|
27
36
|
@end
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
[textView.textStorage insertAttributedString:newAttrStr atIndex:index];
|
|
19
19
|
|
|
20
20
|
if(withSelection) {
|
|
21
|
-
if(!textView
|
|
21
|
+
if(![textView isFirstResponder]) {
|
|
22
22
|
[textView reactFocus];
|
|
23
23
|
}
|
|
24
24
|
textView.selectedRange = NSMakeRange(index + text.length, 0);
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if(withSelection) {
|
|
41
|
-
if(!textView
|
|
41
|
+
if(![textView isFirstResponder]) {
|
|
42
42
|
[textView reactFocus];
|
|
43
43
|
}
|
|
44
44
|
textView.selectedRange = NSMakeRange(range.location + text.length, 0);
|
|
@@ -63,8 +63,7 @@
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// fix the selection if needed
|
|
66
|
-
if(input->textView
|
|
67
|
-
[input->textView reactFocus];
|
|
66
|
+
if([input->textView isFirstResponder]) {
|
|
68
67
|
input->textView.selectedRange = NSMakeRange(preRemoveSelection.location + postRemoveOffset, preRemoveSelection.length);
|
|
69
68
|
}
|
|
70
69
|
}
|
|
@@ -112,8 +111,7 @@
|
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
// fix the selection if needed
|
|
115
|
-
if(input->textView
|
|
116
|
-
[input->textView reactFocus];
|
|
114
|
+
if([input->textView isFirstResponder]) {
|
|
117
115
|
input->textView.selectedRange = NSMakeRange(preAddSelection.location + postAddOffset, preAddSelection.length);
|
|
118
116
|
}
|
|
119
117
|
}
|