react-native-enriched 0.1.0 â 0.1.2
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
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
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
|
-
`react-native-enriched` is a powerful React Native library that
|
|
5
|
+
`react-native-enriched` is a powerful React Native library that exposes a rich text editor component:
|
|
4
6
|
|
|
5
7
|
- ⥠Fully native text input component
|
|
6
8
|
- đšī¸ Synchronous text styling
|
|
@@ -9,26 +11,37 @@
|
|
|
9
11
|
- đą Mobile platforms support
|
|
10
12
|
- đ Supports only the New Architecture
|
|
11
13
|
|
|
12
|
-
`EnrichedTextInput`, the rich text editor component
|
|
14
|
+
`EnrichedTextInput`, the rich text editor component is an uncontrolled input. This means that it doesn't use any state or props to store its value, but instead directly interacts with the underlying platform-specific components. Thanks to this, the component is really performant and simple to use while offering complex and advanced features no other solution has.
|
|
13
15
|
|
|
14
16
|
Built by [Software Mansion](https://swmansion.com/) and sponsored by [Filament](https://filament.dm/).
|
|
15
17
|
|
|
18
|
+
<img width="128" height="69" alt="Software Mansion Logo" src="https://github.com/user-attachments/assets/f0e18471-a7aa-4e80-86ac-87686a86fe56" />
|
|
19
|
+
|
|
20
|
+
<img width="48" height="48" alt="" src="https://github.com/user-attachments/assets/46c6bf1f-2685-497e-b699-d5a94b2582a3" />
|
|
21
|
+
|
|
22
|
+
<img width="80" height="80" alt="Filament Logo" src="https://github.com/user-attachments/assets/4103ab79-da34-4164-aa5f-dcf08815bf65" />
|
|
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
|
+
|
|
16
29
|
## Table of Contents
|
|
17
30
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
- [Prerequisites](#prerequisites)
|
|
32
|
+
- [Installation](#installation)
|
|
33
|
+
- [Usage](#usage)
|
|
34
|
+
- [Non Parametrized Styles](#non-parametrized-styles)
|
|
35
|
+
- [Links](#links)
|
|
36
|
+
- [Mentions](#mentions)
|
|
37
|
+
- [Inline Images](#inline-images)
|
|
38
|
+
- [Style Detection](#style-detection)
|
|
39
|
+
- [Other Events](#other-events)
|
|
40
|
+
- [Customizing \<EnrichedTextInput /> styles](#customizing-enrichedtextinput--styles)
|
|
41
|
+
- [API Reference](#api-reference)
|
|
42
|
+
- [Future Plans](#future-plans)
|
|
43
|
+
- [Contributing](#contributing)
|
|
44
|
+
- [License](#license)
|
|
32
45
|
|
|
33
46
|
## Prerequisites
|
|
34
47
|
|
|
@@ -113,10 +126,11 @@ const styles = StyleSheet.create({
|
|
|
113
126
|
alignItems: 'center',
|
|
114
127
|
},
|
|
115
128
|
input: {
|
|
129
|
+
width: '100%',
|
|
116
130
|
fontSize: 20,
|
|
117
|
-
padding:
|
|
131
|
+
padding: 10,
|
|
118
132
|
maxHeight: 200,
|
|
119
|
-
|
|
133
|
+
backgroundColor: 'lightgray',
|
|
120
134
|
},
|
|
121
135
|
});
|
|
122
136
|
|
|
@@ -158,7 +172,7 @@ If the selection spans more than one paragraph, logically more of them will be a
|
|
|
158
172
|
|
|
159
173
|
## Links
|
|
160
174
|
|
|
161
|
-
The links are here, just like in any other editor, a piece of text with a URL
|
|
175
|
+
The links are here, just like in any other editor, a piece of text with a URL attributed to it. They can be added in two ways: automatically or manually.
|
|
162
176
|
|
|
163
177
|
### Automatic links detection
|
|
164
178
|
|
|
@@ -218,7 +232,7 @@ You can find some examples in the [usage section](#usage) or in the example app.
|
|
|
218
232
|
`react-native-enriched` emits a few more events that may be of use:
|
|
219
233
|
|
|
220
234
|
- [onFocus](#onfocus) - emits whenever input focuses.
|
|
221
|
-
- [onBlur](#onblur) - emits
|
|
235
|
+
- [onBlur](#onblur) - emits whenever input blurs.
|
|
222
236
|
- [onChangeText](#onchangetext) - returns the input's text anytime it changes.
|
|
223
237
|
- [onChangeHtml](#onchangehtml) - returns HTML string parsed from current input text and styles anytime it would change. As parsing the HTML on each input change is a pretty expensive operation, not assigning the event's callback will speed up iOS input a bit. We are considering adding some API to improve it, see [future plans](#future-plans).
|
|
224
238
|
- [onChangeSelection](#onchangeselection) - returns all the data needed for working with selections (as of now it's mainly useful for [links](#links)).
|
|
@@ -237,9 +251,9 @@ You can find some examples in the [usage section](#usage) or in the example app.
|
|
|
237
251
|
|
|
238
252
|
If `true`, focuses the input.
|
|
239
253
|
|
|
240
|
-
| Type
|
|
241
|
-
|
|
242
|
-
| `bool` | `false`
|
|
254
|
+
| Type | Default Value | Platform |
|
|
255
|
+
|--------|---------------|----------|
|
|
256
|
+
| `bool` | `false` | Both |
|
|
243
257
|
|
|
244
258
|
#### `autoCapitalize`
|
|
245
259
|
|
|
@@ -250,57 +264,57 @@ Tells input to automatically capitalize certain characters.
|
|
|
250
264
|
- `sentences`: first letter of each sentence.
|
|
251
265
|
- `none`: don't auto capitalize anything.
|
|
252
266
|
|
|
253
|
-
| Type
|
|
254
|
-
|
|
255
|
-
| `'none' \| 'sentences' \| 'words' \| 'characters'` | `'sentences'` | Both
|
|
267
|
+
| Type | Default Value | Platform |
|
|
268
|
+
|----------------------------------------------------|---------------|----------|
|
|
269
|
+
| `'none' \| 'sentences' \| 'words' \| 'characters'` | `'sentences'` | Both |
|
|
256
270
|
|
|
257
271
|
#### `cursorColor`
|
|
258
272
|
|
|
259
273
|
When provided it will set the color of the cursor (or "caret") in the component.
|
|
260
274
|
|
|
261
|
-
| Type
|
|
262
|
-
|
|
263
|
-
| [`color`](https://reactnative.dev/docs/colors) | system default | Android
|
|
275
|
+
| Type | Default Value | Platform |
|
|
276
|
+
|------------------------------------------------|----------------|----------|
|
|
277
|
+
| [`color`](https://reactnative.dev/docs/colors) | system default | Android |
|
|
264
278
|
|
|
265
279
|
#### `defaultValue`
|
|
266
280
|
|
|
267
281
|
Provides an initial value for the input. If the string is a valid HTML output of the `EnrichedTextInput` component (or other HTML that the parser will accept), proper styles will be applied.
|
|
268
282
|
|
|
269
|
-
| Type
|
|
270
|
-
|
|
271
|
-
| `string` | -
|
|
283
|
+
| Type | Default Value | Platform |
|
|
284
|
+
|----------|---------------|----------|
|
|
285
|
+
| `string` | - | Both |
|
|
272
286
|
|
|
273
287
|
#### `editable`
|
|
274
288
|
|
|
275
289
|
If `false`, text is not editable.
|
|
276
290
|
|
|
277
|
-
| Type
|
|
278
|
-
|
|
279
|
-
| `bool` | `true`
|
|
291
|
+
| Type | Default Value | Platform |
|
|
292
|
+
|--------|---------------|----------|
|
|
293
|
+
| `bool` | `true` | Both |
|
|
280
294
|
|
|
281
295
|
#### `htmlStyle`
|
|
282
296
|
|
|
283
297
|
A prop for customizing styles' appearances.
|
|
284
298
|
|
|
285
|
-
| Type
|
|
286
|
-
|
|
287
|
-
| [`HtmlStyle`](#htmlstyle-type) | default values from [`HtmlStyle`](#htmlstyle-type)
|
|
299
|
+
| Type | Default Value | Platform |
|
|
300
|
+
|--------------------------------|----------------------------------------------------|----------|
|
|
301
|
+
| [`HtmlStyle`](#htmlstyle-type) | default values from [`HtmlStyle`](#htmlstyle-type) | Both |
|
|
288
302
|
|
|
289
303
|
#### `mentionIndicators`
|
|
290
304
|
|
|
291
305
|
The recognized mention indicators. Each item needs to be a 1 character long string.
|
|
292
306
|
|
|
293
|
-
| Type
|
|
294
|
-
|
|
295
|
-
| array of `string` | `['@']`
|
|
307
|
+
| Type | Default Value | Platform |
|
|
308
|
+
|-------------------|---------------|----------|
|
|
309
|
+
| array of `string` | `['@']` | Both |
|
|
296
310
|
|
|
297
311
|
#### `onBlur`
|
|
298
312
|
|
|
299
313
|
Callback that's called whenever the input loses focused (is blurred).
|
|
300
314
|
|
|
301
|
-
| Type
|
|
302
|
-
|
|
303
|
-
| `() => void` | -
|
|
315
|
+
| Type | Default Value | Platform |
|
|
316
|
+
|--------------|---------------|----------|
|
|
317
|
+
| `() => void` | - | Both |
|
|
304
318
|
|
|
305
319
|
#### `onChangeHtml`
|
|
306
320
|
|
|
@@ -316,9 +330,9 @@ interface OnChangeHtmlEvent {
|
|
|
316
330
|
|
|
317
331
|
- `value` is the new HTML.
|
|
318
332
|
|
|
319
|
-
| Type
|
|
320
|
-
|
|
321
|
-
| `(NativeSyntheticEvent\<OnChangeHtmlEvent>) => void` | -
|
|
333
|
+
| Type | Default Value | Platform |
|
|
334
|
+
|------------------------------------------------------|---------------|----------|
|
|
335
|
+
| `(NativeSyntheticEvent\<OnChangeHtmlEvent>) => void` | - | Both |
|
|
322
336
|
|
|
323
337
|
#### `onChangeMention`
|
|
324
338
|
|
|
@@ -336,9 +350,9 @@ interface OnChangeMentionEvent {
|
|
|
336
350
|
- `indicator` is the indicator of the currently edited mention.
|
|
337
351
|
- `text` contains whole text that has been typed after the indicator.
|
|
338
352
|
|
|
339
|
-
| Type
|
|
340
|
-
|
|
341
|
-
| `(OnChangeMentionEvent) => void` | -
|
|
353
|
+
| Type | Default Value | Platform |
|
|
354
|
+
|----------------------------------|---------------|----------|
|
|
355
|
+
| `(OnChangeMentionEvent) => void` | - | Both |
|
|
342
356
|
|
|
343
357
|
#### `onChangeSelection`
|
|
344
358
|
|
|
@@ -358,9 +372,9 @@ OnChangeSelectionEvent {
|
|
|
358
372
|
- `end` is the first index after the selection's ending. For just a cursor in place (no selection), `start` equals `end`.
|
|
359
373
|
- `text` is the input's text in the current selection.
|
|
360
374
|
|
|
361
|
-
| Type
|
|
362
|
-
|
|
363
|
-
| `(NativeSyntheticEvent\<OnChangeSelectionEvent>) => void` | -
|
|
375
|
+
| Type | Default Value | Platform |
|
|
376
|
+
|-----------------------------------------------------------|---------------|----------|
|
|
377
|
+
| `(NativeSyntheticEvent\<OnChangeSelectionEvent>) => void` | - | Both |
|
|
364
378
|
|
|
365
379
|
#### `onChangeState`
|
|
366
380
|
|
|
@@ -388,9 +402,9 @@ interface OnChangeStateEvent {
|
|
|
388
402
|
}
|
|
389
403
|
```
|
|
390
404
|
|
|
391
|
-
| Type
|
|
392
|
-
|
|
393
|
-
| `(NativeSyntheticEvent\<OnChangeStateEvent>) => void` | -
|
|
405
|
+
| Type | Default Value | Platform |
|
|
406
|
+
|-------------------------------------------------------|---------------|----------|
|
|
407
|
+
| `(NativeSyntheticEvent\<OnChangeStateEvent>) => void` | - | Both |
|
|
394
408
|
|
|
395
409
|
#### `onChangeText`
|
|
396
410
|
|
|
@@ -406,9 +420,9 @@ interface OnChangeTextEvent {
|
|
|
406
420
|
|
|
407
421
|
- `value` is the new text value of the input.
|
|
408
422
|
|
|
409
|
-
| Type
|
|
410
|
-
|
|
411
|
-
| `(NativeSyntheticEvent\<OnChangeTextEvent>) => void` | -
|
|
423
|
+
| Type | Default Value | Platform |
|
|
424
|
+
|------------------------------------------------------|---------------|----------|
|
|
425
|
+
| `(NativeSyntheticEvent\<OnChangeTextEvent>) => void` | - | Both |
|
|
412
426
|
|
|
413
427
|
#### `onEndMention`
|
|
414
428
|
|
|
@@ -416,17 +430,17 @@ Callback that is called when the user no longer edits a mention actively - has m
|
|
|
416
430
|
|
|
417
431
|
- `indicator` is the indicator of the mention that was being edited.
|
|
418
432
|
|
|
419
|
-
| Type
|
|
420
|
-
|
|
421
|
-
| `(indicator: string) => void` | -
|
|
433
|
+
| Type | Default Value | Platform |
|
|
434
|
+
|-------------------------------|---------------|----------|
|
|
435
|
+
| `(indicator: string) => void` | - | Both |
|
|
422
436
|
|
|
423
437
|
#### `onFocus`
|
|
424
438
|
|
|
425
439
|
Callback that's called whenever the input is focused.
|
|
426
440
|
|
|
427
|
-
| Type
|
|
428
|
-
|
|
429
|
-
| `() => void` | -
|
|
441
|
+
| Type | Default Value | Platform |
|
|
442
|
+
|--------------|---------------|----------|
|
|
443
|
+
| `() => void` | - | Both |
|
|
430
444
|
|
|
431
445
|
#### `onLinkDetected`
|
|
432
446
|
|
|
@@ -448,9 +462,9 @@ interface OnLinkDetected {
|
|
|
448
462
|
- `start` is the starting index of the link.
|
|
449
463
|
- `end` is the first index after the ending index of the link.
|
|
450
464
|
|
|
451
|
-
| Type
|
|
452
|
-
|
|
453
|
-
| `(OnLinkDetected) => void` | -
|
|
465
|
+
| Type | Default Value | Platform |
|
|
466
|
+
|----------------------------|---------------|----------|
|
|
467
|
+
| `(OnLinkDetected) => void` | - | Both |
|
|
454
468
|
|
|
455
469
|
#### `onMentionDetected`
|
|
456
470
|
|
|
@@ -468,11 +482,11 @@ OnMentionDetected {
|
|
|
468
482
|
|
|
469
483
|
- `text` is the mention's displayed text.
|
|
470
484
|
- `indicator` is the indicator of the mention.
|
|
471
|
-
- `attributes` are the additional user-defined
|
|
485
|
+
- `attributes` are the additional user-defined attributes that are being stored with the mention.
|
|
472
486
|
|
|
473
|
-
| Type
|
|
474
|
-
|
|
475
|
-
| `(OnMentionDetected) => void` | -
|
|
487
|
+
| Type | Default Value | Platform |
|
|
488
|
+
|-------------------------------|---------------|----------|
|
|
489
|
+
| `(OnMentionDetected) => void` | - | Both |
|
|
476
490
|
|
|
477
491
|
#### `onStartMention`
|
|
478
492
|
|
|
@@ -480,41 +494,41 @@ Callback that gets called whenever a mention editing starts (after placing the i
|
|
|
480
494
|
|
|
481
495
|
- `indicator` is the indicator of the mention that begins editing.
|
|
482
496
|
|
|
483
|
-
| Type
|
|
484
|
-
|
|
485
|
-
| `(indicator: string) => void` | -
|
|
497
|
+
| Type | Default Value | Platform |
|
|
498
|
+
|-------------------------------|---------------|----------|
|
|
499
|
+
| `(indicator: string) => void` | - | Both |
|
|
486
500
|
|
|
487
501
|
#### `placeholder`
|
|
488
502
|
|
|
489
503
|
The placeholder text that is displayed in the input if nothing has been typed yet. Disappears when something is typed.
|
|
490
504
|
|
|
491
|
-
| Type
|
|
492
|
-
|
|
493
|
-
| `string` | `''`
|
|
505
|
+
| Type | Default Value | Platform |
|
|
506
|
+
|----------|---------------|----------|
|
|
507
|
+
| `string` | `''` | Both |
|
|
494
508
|
|
|
495
509
|
#### `placeholderTextColor`
|
|
496
510
|
|
|
497
511
|
Input placeholder's text color.
|
|
498
512
|
|
|
499
|
-
| Type
|
|
500
|
-
|
|
501
|
-
| [`color`](https://reactnative.dev/docs/colors) | input's [color](#style) | Both
|
|
513
|
+
| Type | Default Value | Platform |
|
|
514
|
+
|------------------------------------------------|-------------------------|----------|
|
|
515
|
+
| [`color`](https://reactnative.dev/docs/colors) | input's [color](#style) | Both |
|
|
502
516
|
|
|
503
517
|
#### `ref`
|
|
504
518
|
|
|
505
519
|
A React ref that lets you call any ref methods on the input.
|
|
506
520
|
|
|
507
|
-
| Type
|
|
508
|
-
|
|
509
|
-
| `RefObject<EnrichedTextInputInstance \| null>` | -
|
|
521
|
+
| Type | Default Value | Platform |
|
|
522
|
+
|------------------------------------------------|---------------|----------|
|
|
523
|
+
| `RefObject<EnrichedTextInputInstance \| null>` | - | Both |
|
|
510
524
|
|
|
511
525
|
#### `selectionColor`
|
|
512
526
|
|
|
513
527
|
Color of the selection rectangle that gets drawn over the selected text. On iOS, the cursor (caret) also gets set to this color.
|
|
514
528
|
|
|
515
|
-
| Type
|
|
516
|
-
|
|
517
|
-
| [`color`](https://reactnative.dev/docs/colors) | system default | Both
|
|
529
|
+
| Type | Default Value | Platform |
|
|
530
|
+
|------------------------------------------------|----------------|----------|
|
|
531
|
+
| [`color`](https://reactnative.dev/docs/colors) | system default | Both |
|
|
518
532
|
|
|
519
533
|
#### `style`
|
|
520
534
|
|
|
@@ -528,9 +542,9 @@ Additionally following [TextStyle](https://reactnative.dev/docs/text#style) prop
|
|
|
528
542
|
- fontWeight
|
|
529
543
|
- fontStyle only on Android
|
|
530
544
|
|
|
531
|
-
| Type
|
|
532
|
-
|
|
533
|
-
| [`View Style`](https://reactnative.dev/docs/view#style) \| [`Text Style`](https://reactnative.dev/docs/text#style) | -
|
|
545
|
+
| Type | Default Value | Platform |
|
|
546
|
+
|--------------------------------------------------------------------------------------------------------------------|---------------|----------|
|
|
547
|
+
| [`View Style`](https://reactnative.dev/docs/view#style) \| [`Text Style`](https://reactnative.dev/docs/text#style) | - | Both |
|
|
534
548
|
|
|
535
549
|
#### `ViewProps`
|
|
536
550
|
|
|
@@ -540,9 +554,9 @@ The input inherits [ViewProps](https://reactnative.dev/docs/view#props), but kee
|
|
|
540
554
|
|
|
541
555
|
If true, Android will use experimental synchronous events. This will prevent from input flickering when updating component size. However, this is an experimental feature, which has not been thoroughly tested. We may decide to enable it by default in a future release.
|
|
542
556
|
|
|
543
|
-
| Type
|
|
544
|
-
|
|
545
|
-
| `bool` | `false`
|
|
557
|
+
| Type | Default Value | Platform |
|
|
558
|
+
|--------|---------------|----------|
|
|
559
|
+
| `bool` | `false` | Android |
|
|
546
560
|
|
|
547
561
|
### Ref Methods
|
|
548
562
|
|
|
@@ -609,7 +623,7 @@ Sets the currently edited mention with a given indicator, displayed text and cus
|
|
|
609
623
|
|
|
610
624
|
- `indicator: string` - the indicator of the set mention.
|
|
611
625
|
- `text: string` - the text that should be displayed for the mention. Anything the user typed gets replaced by that text. The mention indicator isn't added to that text.
|
|
612
|
-
- `attributes?: Record<string, string>` - additional, custom
|
|
626
|
+
- `attributes?: Record<string, string>` - additional, custom attributes for the mention that can be passed as a typescript record. They are properly preserved through parsing from and to the HTML format.
|
|
613
627
|
|
|
614
628
|
#### `.setValue()`
|
|
615
629
|
|
|
@@ -831,7 +845,7 @@ If only a single config is given, the style applies to all mention types. You ca
|
|
|
831
845
|
|
|
832
846
|
#### img (inline image)
|
|
833
847
|
|
|
834
|
-
- `width` is the width of the inline image,
|
|
848
|
+
- `width` is the width of the inline image, defaults to `80`.
|
|
835
849
|
- `height` is the height of the inline image, defaults to `80`.
|
|
836
850
|
|
|
837
851
|
#### ol (ordered list)
|
|
@@ -850,12 +864,12 @@ By bullet we mean the dot that begins each line of the list.
|
|
|
850
864
|
- `bulletColor` defines the color of the bullet, takes [color](https://reactnative.dev/docs/colors) value and defaults to `black`.
|
|
851
865
|
- `bulletSize` sets both the height and the width of the bullet, defaults to `8`.
|
|
852
866
|
- `marginLeft` is the margin to the left of the bullet (between the bullet and input's left edge), defaults to `16`.
|
|
853
|
-
- `gapWidth` sets the gap between the bullet and the list item's text,
|
|
867
|
+
- `gapWidth` sets the gap between the bullet and the list item's text, defaults to `16`.
|
|
854
868
|
|
|
855
869
|
## Future Plans
|
|
856
870
|
|
|
857
871
|
- Adding Codeblocks and Inline Images to iOS input.
|
|
858
|
-
- Making some
|
|
872
|
+
- Making some optimizations around `onChangeHtml` event, maybe some imperative API to get the HTML output.
|
|
859
873
|
- Creating `EnrichedText` text component that supports our HTML output format with all additional interactions like pressing links or mentions.
|
|
860
874
|
- Adding API for custom link detection regex.
|
|
861
875
|
- Web library implementation via `react-native-web`.
|
|
@@ -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
|
|
|
@@ -171,10 +171,11 @@
|
|
|
171
171
|
|
|
172
172
|
for(NSNumber *activeStyle in currentActiveStyles) {
|
|
173
173
|
NSInteger activeStyleBeginning = [currentActiveStylesBeginning[activeStyle] integerValue];
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
|
|
174
|
+
|
|
175
|
+
// we end the styles that began after the currently ended style but not at the "i" (cause the old style ended at exactly "i-1"
|
|
176
|
+
// also the ones that began in the exact same place but are "inner" in relation to them due to StyleTypeEnum integer values
|
|
177
|
+
|
|
178
|
+
if((activeStyleBeginning > styleBeginning && activeStyleBeginning < i) ||
|
|
178
179
|
(activeStyleBeginning == styleBeginning && activeStyleBeginning < i && [activeStyle integerValue] > [style integerValue])) {
|
|
179
180
|
[fixedEndedStyles addObject:activeStyle];
|
|
180
181
|
[stylesToBeReAdded addObject:activeStyle];
|
|
@@ -405,24 +406,16 @@
|
|
|
405
406
|
if(html.length >= 13) {
|
|
406
407
|
NSString *firstSix = [html substringWithRange:NSMakeRange(0, 6)];
|
|
407
408
|
NSString *lastSeven = [html substringWithRange:NSMakeRange(html.length-7, 7)];
|
|
408
|
-
NSInteger newlinesCount = [[html componentsSeparatedByString:@"\n"] count] - 1;
|
|
409
409
|
|
|
410
410
|
if([firstSix isEqualToString:@"<html>"] && [lastSeven isEqualToString:@"</html>"]) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
// firstly remove newlined html tags if any:
|
|
420
|
-
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>\n" withString:@""];
|
|
421
|
-
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"\n</html>" withString:@""];
|
|
422
|
-
// fallback; remove html tags without their newlines
|
|
423
|
-
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>" withString:@""];
|
|
424
|
-
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</html>" withString:@""];
|
|
425
|
-
}
|
|
411
|
+
// remove html tags, might be with newlines or without them
|
|
412
|
+
fixedHtml = [html copy];
|
|
413
|
+
// firstly remove newlined html tags if any:
|
|
414
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>\n" withString:@""];
|
|
415
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"\n</html>" withString:@""];
|
|
416
|
+
// fallback; remove html tags without their newlines
|
|
417
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>" withString:@""];
|
|
418
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</html>" withString:@""];
|
|
426
419
|
} else {
|
|
427
420
|
// in other case we are most likely working with some external html - try getting the styles from between body tags
|
|
428
421
|
NSRange openingBodyRange = [html rangeOfString:@"<body>"];
|
|
@@ -438,38 +431,35 @@
|
|
|
438
431
|
|
|
439
432
|
// second processing - try fixing htmls with wrong newlines' setup
|
|
440
433
|
if(fixedHtml != nullptr) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
fixedHtml = [self stringByAddingNewlinesToTag:@"</h2>" inString:fixedHtml leading:NO trailing:YES];
|
|
471
|
-
fixedHtml = [self stringByAddingNewlinesToTag:@"</h3>" inString:fixedHtml leading:NO trailing:YES];
|
|
472
|
-
}
|
|
434
|
+
// add <br> tag wherever needed
|
|
435
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<p></p>" withString:@"<br>"];
|
|
436
|
+
|
|
437
|
+
// remove <p> tags inside of <li>
|
|
438
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<li><p>" withString:@"<li>"];
|
|
439
|
+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</p></li>" withString:@"</li>"];
|
|
440
|
+
|
|
441
|
+
// tags that have to be in separate lines
|
|
442
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<br>" inString:fixedHtml leading:YES trailing:YES];
|
|
443
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<ul>" inString:fixedHtml leading:YES trailing:YES];
|
|
444
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</ul>" inString:fixedHtml leading:YES trailing:YES];
|
|
445
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<ol>" inString:fixedHtml leading:YES trailing:YES];
|
|
446
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</ol>" inString:fixedHtml leading:YES trailing:YES];
|
|
447
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<blockquote>" inString:fixedHtml leading:YES trailing:YES];
|
|
448
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</blockquote>" inString:fixedHtml leading:YES trailing:YES];
|
|
449
|
+
|
|
450
|
+
// line opening tags
|
|
451
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<p>" inString:fixedHtml leading:YES trailing:NO];
|
|
452
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<li>" inString:fixedHtml leading:YES trailing:NO];
|
|
453
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<h1>" inString:fixedHtml leading:YES trailing:NO];
|
|
454
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<h2>" inString:fixedHtml leading:YES trailing:NO];
|
|
455
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"<h3>" inString:fixedHtml leading:YES trailing:NO];
|
|
456
|
+
|
|
457
|
+
// line closing tags
|
|
458
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</p>" inString:fixedHtml leading:NO trailing:YES];
|
|
459
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</li>" inString:fixedHtml leading:NO trailing:YES];
|
|
460
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</h1>" inString:fixedHtml leading:NO trailing:YES];
|
|
461
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</h2>" inString:fixedHtml leading:NO trailing:YES];
|
|
462
|
+
fixedHtml = [self stringByAddingNewlinesToTag:@"</h3>" inString:fixedHtml leading:NO trailing:YES];
|
|
473
463
|
}
|
|
474
464
|
|
|
475
465
|
return fixedHtml;
|
|
@@ -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
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-enriched",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Rich Text Editor component for React Native",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -48,14 +48,14 @@
|
|
|
48
48
|
],
|
|
49
49
|
"repository": {
|
|
50
50
|
"type": "git",
|
|
51
|
-
"url": "git+https://github.com/software-mansion-labs/react-native-
|
|
51
|
+
"url": "git+https://github.com/software-mansion-labs/react-native-enriched.git"
|
|
52
52
|
},
|
|
53
53
|
"author": "Software Mansion <contact@swmansion.com> (https://swmansion.com)",
|
|
54
54
|
"license": "MIT",
|
|
55
55
|
"bugs": {
|
|
56
|
-
"url": "https://github.com/software-mansion-labs/react-native-
|
|
56
|
+
"url": "https://github.com/software-mansion-labs/react-native-enriched/issues"
|
|
57
57
|
},
|
|
58
|
-
"homepage": "https://github.com/software-mansion-labs/react-native-
|
|
58
|
+
"homepage": "https://github.com/software-mansion-labs/react-native-enriched#readme",
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"registry": "https://registry.npmjs.org/"
|
|
61
61
|
},
|