react-native-richify 1.0.6 → 1.0.7
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 +189 -258
- package/lib/commonjs/components/Toolbar.js +1 -0
- package/lib/commonjs/components/Toolbar.js.map +1 -1
- package/lib/commonjs/components/ToolbarButton.js +37 -9
- package/lib/commonjs/components/ToolbarButton.js.map +1 -1
- package/lib/commonjs/constants/defaultStyles.js +61 -32
- package/lib/commonjs/constants/defaultStyles.js.map +1 -1
- package/lib/module/components/Toolbar.js +1 -0
- package/lib/module/components/Toolbar.js.map +1 -1
- package/lib/module/components/ToolbarButton.js +38 -10
- package/lib/module/components/ToolbarButton.js.map +1 -1
- package/lib/module/constants/defaultStyles.js +60 -32
- package/lib/module/constants/defaultStyles.js.map +1 -1
- package/lib/typescript/src/components/Toolbar.d.ts.map +1 -1
- package/lib/typescript/src/components/ToolbarButton.d.ts.map +1 -1
- package/lib/typescript/src/constants/defaultStyles.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +11 -5
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/package.json +10 -4
- package/src/components/Toolbar.tsx +1 -0
- package/src/components/ToolbarButton.tsx +68 -16
- package/src/constants/defaultStyles.ts +47 -18
- package/src/types/index.d.ts +13 -7
- package/src/types/index.ts +11 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# react-native-richify
|
|
2
2
|
|
|
3
|
-
A rich text input
|
|
3
|
+
A React Native rich text input with a normal `TextInput` editing surface, a horizontally scrollable toolbar, and live Markdown or HTML output below the editor.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/react-native-richify)
|
|
6
6
|
[](https://github.com/soumya-99/react-native-richify/blob/main/LICENSE)
|
|
@@ -8,25 +8,39 @@ A rich text input for React Native with a normal `TextInput` editing surface, a
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
10
|
- Native editing with no WebView
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
11
|
+
- Built-in toolbar uses Lucide React Native icons by default
|
|
12
|
+
- Inline formatting: bold, italic, underline, strikethrough, code
|
|
13
|
+
- Line formatting: H1, H2, H3, bullet list, ordered list, left, center, right
|
|
14
|
+
- Link formatting on selected text
|
|
15
|
+
- Image insertion through the built-in toolbar
|
|
16
|
+
- Output panel can show Markdown or HTML
|
|
17
|
+
- Output panel can show raw serialized text or rendered preview
|
|
18
|
+
- Auto-growing editor with configurable input and preview height limits
|
|
19
|
+
- Custom toolbar items accept text, emoji, or React elements
|
|
19
20
|
- Headless `useRichText` hook for fully custom editors
|
|
21
|
+
- Typed JSON import and export of editor content
|
|
20
22
|
|
|
21
23
|
## Installation
|
|
22
24
|
|
|
25
|
+
Install the package and `react-native-svg`:
|
|
26
|
+
|
|
23
27
|
```bash
|
|
24
|
-
npm install react-native-richify
|
|
25
|
-
# or
|
|
26
|
-
yarn add react-native-richify
|
|
28
|
+
npm install react-native-richify react-native-svg
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
or:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
yarn add react-native-richify react-native-svg
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`react-native-svg` is required because the built-in toolbar uses Lucide icons. If you want to use Lucide icons in your own custom toolbar items, install that in your app too:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install lucide-react-native
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The package works in Expo and bare React Native apps. In Expo, `react-native-svg` is usually already available.
|
|
30
44
|
|
|
31
45
|
## Quick Start
|
|
32
46
|
|
|
@@ -43,10 +57,11 @@ export default function App() {
|
|
|
43
57
|
showToolbar
|
|
44
58
|
showOutputPreview
|
|
45
59
|
defaultOutputFormat="markdown"
|
|
60
|
+
defaultOutputPreviewMode="rendered"
|
|
46
61
|
onChangeText={(text) => console.log('Plain text:', text)}
|
|
47
|
-
onChangeOutput={(output, format) =>
|
|
48
|
-
console.log(
|
|
49
|
-
}
|
|
62
|
+
onChangeOutput={(output, format) => {
|
|
63
|
+
console.log(format, output);
|
|
64
|
+
}}
|
|
50
65
|
/>
|
|
51
66
|
</View>
|
|
52
67
|
);
|
|
@@ -56,137 +71,139 @@ export default function App() {
|
|
|
56
71
|
This gives you:
|
|
57
72
|
|
|
58
73
|
- a visible auto-growing `TextInput`
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
74
|
+
- the default Lucide-based toolbar
|
|
75
|
+
- live Markdown output by default
|
|
76
|
+
- a preview panel that opens below the input when content exists
|
|
62
77
|
|
|
63
|
-
## How
|
|
78
|
+
## How The Editor Works
|
|
64
79
|
|
|
65
|
-
The
|
|
80
|
+
The editing surface is always a normal `TextInput`. The library does not render styled text on top of the input.
|
|
81
|
+
|
|
82
|
+
Internally, content is stored as `StyledSegment[]`. Each segment contains plain text and formatting metadata. That lets the library:
|
|
83
|
+
|
|
84
|
+
- keep typing behavior predictable
|
|
85
|
+
- apply formatting to selected ranges or future input
|
|
86
|
+
- serialize the same content to Markdown or HTML
|
|
87
|
+
- export and re-import structured JSON safely
|
|
66
88
|
|
|
67
89
|
Formatting rules:
|
|
68
90
|
|
|
69
|
-
- If
|
|
70
|
-
- If text is selected, pressing a
|
|
71
|
-
-
|
|
72
|
-
- Every formatting button is toggleable except
|
|
91
|
+
- If nothing is selected, pressing a format button affects the next characters you type.
|
|
92
|
+
- If text is selected, pressing a format button applies or removes that format immediately.
|
|
93
|
+
- Heading, list, and alignment controls work at line level.
|
|
94
|
+
- Every formatting button is toggleable except `MD`, `HTML`, `Raw`, and `View`.
|
|
73
95
|
|
|
74
96
|
## Built-in Toolbar
|
|
75
97
|
|
|
76
|
-
The default toolbar
|
|
98
|
+
The default toolbar is horizontally scrollable and ships with these controls:
|
|
77
99
|
|
|
78
|
-
|
|
|
100
|
+
| Control | Behavior |
|
|
79
101
|
| --- | --- |
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
87
|
-
|
|
|
88
|
-
| `🔗` | Apply or clear a hyperlink on the current selection |
|
|
89
|
-
| `⇤`, `↔`, `⇥` | Toggle left, center, or right alignment on the current line |
|
|
90
|
-
| `MD`, `HTML` | Switch serialized output format |
|
|
91
|
-
| `Raw`, `View` | Switch between literal serialized output and rendered preview |
|
|
102
|
+
| Bold, Italic, Underline, Strikethrough, Code | Toggle inline formatting |
|
|
103
|
+
| Heading 1, Heading 2, Heading 3 | Toggle heading level on the current line |
|
|
104
|
+
| Bullet List, Ordered List | Toggle list type on the current line |
|
|
105
|
+
| Link | Apply or clear a hyperlink on the selection |
|
|
106
|
+
| Image | Insert an image through your app's image-picking flow |
|
|
107
|
+
| Align Left, Align Center, Align Right | Toggle paragraph alignment |
|
|
108
|
+
| MD, HTML | Switch serialization format |
|
|
109
|
+
| Raw, View | Switch between literal output and rendered preview |
|
|
92
110
|
|
|
93
111
|
Notes:
|
|
94
112
|
|
|
95
|
-
- Pressing
|
|
96
|
-
- Pressing
|
|
97
|
-
-
|
|
98
|
-
- Image
|
|
113
|
+
- Pressing an active heading button again clears that heading.
|
|
114
|
+
- Pressing an active list or alignment button again clears it.
|
|
115
|
+
- Link clears when the current selection already has a link.
|
|
116
|
+
- Image is a callback-driven action. Your app decides how the URI is chosen.
|
|
99
117
|
|
|
100
118
|
## Output Panel
|
|
101
119
|
|
|
102
|
-
The panel below the
|
|
120
|
+
The preview panel below the editor is optional and controlled by `showOutputPreview`.
|
|
121
|
+
|
|
122
|
+
It supports two output formats:
|
|
103
123
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
124
|
+
- `markdown`
|
|
125
|
+
- `html`
|
|
106
126
|
|
|
107
|
-
It
|
|
127
|
+
It also supports two display modes:
|
|
108
128
|
|
|
109
|
-
- Markdown
|
|
110
|
-
-
|
|
129
|
+
- `literal`: show the raw Markdown or HTML text
|
|
130
|
+
- `rendered`: render the rich output visually
|
|
111
131
|
|
|
112
132
|
Useful props:
|
|
113
133
|
|
|
114
|
-
| Prop |
|
|
134
|
+
| Prop | Purpose |
|
|
115
135
|
| --- | --- |
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `onChangeOutputFormat` | Called when toolbar output format changes |
|
|
136
|
+
| `outputFormat` | Controlled Markdown or HTML mode |
|
|
137
|
+
| `defaultOutputFormat` | Initial format for uncontrolled usage |
|
|
138
|
+
| `outputPreviewMode` | Controlled raw or rendered mode |
|
|
139
|
+
| `defaultOutputPreviewMode` | Initial preview mode |
|
|
140
|
+
| `maxOutputHeight` | Max preview height before the panel scrolls |
|
|
141
|
+
| `onChangeOutput` | Receives the serialized output on every change |
|
|
142
|
+
| `onChangeOutputFormat` | Called when toolbar format changes |
|
|
124
143
|
| `onChangeOutputPreviewMode` | Called when toolbar preview mode changes |
|
|
125
144
|
|
|
126
|
-
Example:
|
|
127
|
-
|
|
128
|
-
```tsx
|
|
129
|
-
import React, { useState } from 'react';
|
|
130
|
-
import { RichTextInput, type OutputFormat } from 'react-native-richify';
|
|
131
|
-
|
|
132
|
-
export function ControlledOutputEditor() {
|
|
133
|
-
const [format, setFormat] = useState<OutputFormat>('html');
|
|
134
|
-
|
|
135
|
-
return (
|
|
136
|
-
<RichTextInput
|
|
137
|
-
outputFormat={format}
|
|
138
|
-
onChangeOutputFormat={setFormat}
|
|
139
|
-
defaultOutputPreviewMode="rendered"
|
|
140
|
-
maxOutputHeight={220}
|
|
141
|
-
onChangeOutput={(output) => {
|
|
142
|
-
console.log(output);
|
|
143
|
-
}}
|
|
144
|
-
/>
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
145
|
## Links
|
|
150
146
|
|
|
151
147
|
Link formatting is selection-based. Select text, then press the link button.
|
|
152
148
|
|
|
153
|
-
|
|
149
|
+
You have two common approaches:
|
|
154
150
|
|
|
155
|
-
1. Provide `onRequestLink` and
|
|
156
|
-
2.
|
|
157
|
-
|
|
158
|
-
Custom link flow:
|
|
151
|
+
1. Provide `onRequestLink` and open your own prompt, modal, or bottom sheet.
|
|
152
|
+
2. Use the built-in fallback, which auto-links only when the selected text already looks like a URL, domain, or email address.
|
|
159
153
|
|
|
160
154
|
```tsx
|
|
161
155
|
<RichTextInput
|
|
162
156
|
onRequestLink={({ selectedText, currentUrl, applyLink }) => {
|
|
163
|
-
console.log(
|
|
164
|
-
console.log('Existing URL:', currentUrl);
|
|
165
|
-
|
|
166
|
-
// Replace this with your own modal, bottom sheet, or form.
|
|
157
|
+
console.log(selectedText, currentUrl);
|
|
167
158
|
applyLink('https://example.com');
|
|
168
159
|
}}
|
|
169
160
|
/>
|
|
170
161
|
```
|
|
171
162
|
|
|
172
|
-
If the selection already
|
|
163
|
+
If the current selection already contains a link, pressing the button clears it.
|
|
173
164
|
|
|
174
|
-
##
|
|
165
|
+
## Images
|
|
175
166
|
|
|
176
|
-
`
|
|
167
|
+
The built-in toolbar includes an image button. It does not open the device picker itself. Instead, it calls `onRequestImage`, and your app decides how to produce the final image URI.
|
|
177
168
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
169
|
+
```tsx
|
|
170
|
+
<RichTextInput
|
|
171
|
+
onRequestImage={async ({ insertImage }) => {
|
|
172
|
+
const result = await pickImageFromYourApp();
|
|
173
|
+
if (!result?.uri) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
insertImage(result.uri, {
|
|
178
|
+
alt: result.fileName ?? 'Selected image',
|
|
179
|
+
placeholder: '[image]',
|
|
180
|
+
});
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
182
184
|
|
|
183
|
-
|
|
185
|
+
Behavior notes:
|
|
186
|
+
|
|
187
|
+
- The editor inserts a plain text placeholder into the input so typing remains stable.
|
|
188
|
+
- The segment also stores `imageSrc` and optional `imageAlt` metadata.
|
|
189
|
+
- `Raw` mode shows Markdown or HTML image output.
|
|
190
|
+
- `View` mode renders the image in the output panel.
|
|
191
|
+
- If you do not provide `onRequestImage`, the fallback only works when the selected text already looks like an image URL such as `https://site.com/photo.png`.
|
|
192
|
+
|
|
193
|
+
## Sizing And Input Behavior
|
|
194
|
+
|
|
195
|
+
`RichTextInput` grows with the text by default.
|
|
196
|
+
|
|
197
|
+
- `minHeight` sets the minimum input height.
|
|
198
|
+
- `maxHeight` limits the input height before the `TextInput` itself scrolls.
|
|
199
|
+
- `maxOutputHeight` limits the preview panel height before it scrolls.
|
|
200
|
+
- `textInputProps` passes additional native `TextInput` props through to the editor.
|
|
184
201
|
|
|
185
202
|
```tsx
|
|
186
203
|
<RichTextInput
|
|
187
204
|
minHeight={140}
|
|
188
205
|
maxHeight={280}
|
|
189
|
-
maxOutputHeight={
|
|
206
|
+
maxOutputHeight={220}
|
|
190
207
|
textInputProps={{
|
|
191
208
|
autoCapitalize: 'sentences',
|
|
192
209
|
keyboardType: 'default',
|
|
@@ -194,89 +211,69 @@ Example:
|
|
|
194
211
|
/>
|
|
195
212
|
```
|
|
196
213
|
|
|
197
|
-
##
|
|
198
|
-
|
|
199
|
-
### `<RichTextInput />`
|
|
200
|
-
|
|
201
|
-
Most common props:
|
|
202
|
-
|
|
203
|
-
| Prop | Type | Default | Description |
|
|
204
|
-
| --- | --- | --- | --- |
|
|
205
|
-
| `initialSegments` | `StyledSegment[]` | empty content | Initial document value |
|
|
206
|
-
| `onChangeSegments` | `(segments) => void` | - | Called with the rich document model |
|
|
207
|
-
| `onChangeText` | `(text) => void` | - | Called with plain text |
|
|
208
|
-
| `placeholder` | `string` | `"Start typing..."` | Placeholder text |
|
|
209
|
-
| `showToolbar` | `boolean` | `true` | Show the built-in toolbar |
|
|
210
|
-
| `toolbarPosition` | `'top' \| 'bottom'` | `'top'` | Place toolbar above or below the editor |
|
|
211
|
-
| `toolbarItems` | `ToolbarItem[]` | default items | Replace the built-in toolbar item list |
|
|
212
|
-
| `theme` | `RichTextTheme` | default theme | Visual overrides |
|
|
213
|
-
| `showOutputPreview` | `boolean` | `true` | Enable the output panel |
|
|
214
|
-
| `multiline` | `boolean` | `true` | Standard `TextInput` multiline editing |
|
|
215
|
-
| `minHeight` | `number` | `120` | Minimum editor height |
|
|
216
|
-
| `maxHeight` | `number` | - | Maximum editor height before scrolling |
|
|
217
|
-
| `autoFocus` | `boolean` | `false` | Focus input on mount |
|
|
218
|
-
| `textInputProps` | `TextInputProps` subset | - | Additional native input props |
|
|
219
|
-
| `renderToolbar` | `(props) => ReactElement` | - | Render a completely custom toolbar |
|
|
220
|
-
| `onReady` | `(actions) => void` | - | Access editor actions outside the toolbar |
|
|
221
|
-
|
|
222
|
-
### Actions from `onReady` or `useRichText`
|
|
223
|
-
|
|
224
|
-
| Action | Description |
|
|
225
|
-
| --- | --- |
|
|
226
|
-
| `toggleFormat(format)` | Toggle `bold`, `italic`, `underline`, `strikethrough`, or `code` |
|
|
227
|
-
| `setHeading(level)` | Toggle `h1`, `h2`, `h3`, or clear with `none` |
|
|
228
|
-
| `setListType(type)` | Toggle `bullet`, `ordered`, or clear with `none` |
|
|
229
|
-
| `setTextAlign(align)` | Toggle `left`, `center`, or `right` alignment |
|
|
230
|
-
| `setLink(url?)` | Apply or clear hyperlink formatting |
|
|
231
|
-
| `setColor(color)` | Set text color |
|
|
232
|
-
| `setBackgroundColor(color)` | Set highlight color |
|
|
233
|
-
| `setFontSize(size)` | Set font size |
|
|
234
|
-
| `handleTextChange(text)` | Sync plain text input changes |
|
|
235
|
-
| `handleSelectionChange(selection)` | Sync `TextInput` selection changes |
|
|
236
|
-
| `isFormatActive(format)` | Check active state for inline formats |
|
|
237
|
-
| `getSelectionStyle()` | Read the common style for the current selection |
|
|
238
|
-
| `getOutput(format?)` | Serialize current content as Markdown or HTML |
|
|
239
|
-
| `getPlainText()` | Get plain text only |
|
|
240
|
-
| `exportJSON()` | Export the current segment array |
|
|
241
|
-
| `importJSON(segments)` | Replace content from a saved segment array |
|
|
242
|
-
| `clear()` | Reset the editor |
|
|
243
|
-
|
|
244
|
-
## Custom Toolbar
|
|
245
|
-
|
|
246
|
-
Use `toolbarItems` when you only want to replace the built-in buttons, or `renderToolbar` when you want full control.
|
|
247
|
-
|
|
248
|
-
### `toolbarItems`
|
|
214
|
+
## Customizing The Toolbar
|
|
249
215
|
|
|
250
|
-
|
|
216
|
+
Use `toolbarItems` when you want to keep the built-in toolbar behavior but replace some or all buttons.
|
|
251
217
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
- `
|
|
255
|
-
-
|
|
256
|
-
-
|
|
257
|
-
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
- `renderButton`
|
|
218
|
+
`ToolbarItem.label` accepts any React node, so you can use:
|
|
219
|
+
|
|
220
|
+
- plain text such as `'B'`
|
|
221
|
+
- emoji content
|
|
222
|
+
- a Lucide icon such as `<Bold />`
|
|
223
|
+
- any custom React element
|
|
224
|
+
|
|
225
|
+
When the label is not plain text, set `accessibilityLabel` so screen readers and tests can identify the button correctly.
|
|
261
226
|
|
|
262
227
|
Example:
|
|
263
228
|
|
|
264
229
|
```tsx
|
|
230
|
+
import React from 'react';
|
|
231
|
+
import { Bold, ImagePlus, List } from 'lucide-react-native';
|
|
232
|
+
import { RichTextInput } from 'react-native-richify';
|
|
233
|
+
|
|
265
234
|
<RichTextInput
|
|
266
235
|
toolbarItems={[
|
|
267
|
-
{
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
236
|
+
{
|
|
237
|
+
id: 'bold',
|
|
238
|
+
label: <Bold />,
|
|
239
|
+
accessibilityLabel: 'Bold',
|
|
240
|
+
format: 'bold',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
id: 'note',
|
|
244
|
+
label: 'Note',
|
|
245
|
+
onPress: () => console.log('Custom action'),
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: 'bullet',
|
|
249
|
+
label: <List />,
|
|
250
|
+
accessibilityLabel: 'Bullet list',
|
|
251
|
+
listType: 'bullet',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
id: 'image',
|
|
255
|
+
label: <ImagePlus />,
|
|
256
|
+
accessibilityLabel: 'Insert image',
|
|
257
|
+
actionType: 'image',
|
|
258
|
+
},
|
|
271
259
|
{ id: 'html', label: 'HTML', outputFormat: 'html' },
|
|
272
|
-
{ id: 'link', label: '🔗', actionType: 'link' },
|
|
273
260
|
]}
|
|
274
261
|
/>
|
|
275
262
|
```
|
|
276
263
|
|
|
277
|
-
|
|
264
|
+
Supported built-in item fields:
|
|
265
|
+
|
|
266
|
+
- `format`
|
|
267
|
+
- `heading`
|
|
268
|
+
- `listType`
|
|
269
|
+
- `textAlign`
|
|
270
|
+
- `outputFormat`
|
|
271
|
+
- `outputPreviewMode`
|
|
272
|
+
- `actionType: 'link' | 'image'`
|
|
273
|
+
- `onPress`
|
|
274
|
+
- `renderButton`
|
|
278
275
|
|
|
279
|
-
|
|
276
|
+
If you need a completely custom layout, use `renderToolbar`:
|
|
280
277
|
|
|
281
278
|
```tsx
|
|
282
279
|
<RichTextInput
|
|
@@ -286,10 +283,12 @@ Use `renderToolbar` if you need a custom layout or your own button components.
|
|
|
286
283
|
outputPreviewMode,
|
|
287
284
|
onOutputFormatChange,
|
|
288
285
|
onOutputPreviewModeChange,
|
|
286
|
+
onRequestImage,
|
|
289
287
|
}) => (
|
|
290
288
|
<>
|
|
291
289
|
<MyButton onPress={() => actions.toggleFormat('bold')} label="Bold" />
|
|
292
290
|
<MyButton onPress={() => actions.setHeading('h2')} label="Heading" />
|
|
291
|
+
<MyButton onPress={onRequestImage} label="Image" />
|
|
293
292
|
<MyButton
|
|
294
293
|
onPress={() => onOutputFormatChange('html')}
|
|
295
294
|
label={outputFormat === 'html' ? 'HTML on' : 'HTML'}
|
|
@@ -305,7 +304,7 @@ Use `renderToolbar` if you need a custom layout or your own button components.
|
|
|
305
304
|
|
|
306
305
|
## Theming
|
|
307
306
|
|
|
308
|
-
|
|
307
|
+
Use the `theme` prop to override container, toolbar, input, and output styles.
|
|
309
308
|
|
|
310
309
|
```tsx
|
|
311
310
|
<RichTextInput
|
|
@@ -326,48 +325,42 @@ The theme object lets you style the editor container, input, toolbar, output pan
|
|
|
326
325
|
borderColor: '#CBD5E1',
|
|
327
326
|
},
|
|
328
327
|
outputContainerStyle: {
|
|
329
|
-
|
|
330
|
-
marginBottom: 12,
|
|
328
|
+
margin: 12,
|
|
331
329
|
padding: 12,
|
|
332
330
|
borderRadius: 12,
|
|
333
331
|
backgroundColor: '#F8FAFC',
|
|
334
332
|
},
|
|
335
|
-
toolbarButtonActiveStyle: {
|
|
336
|
-
backgroundColor: '#CCFBF1',
|
|
337
|
-
},
|
|
338
333
|
}}
|
|
339
334
|
/>
|
|
340
335
|
```
|
|
341
336
|
|
|
342
|
-
|
|
337
|
+
Common theme keys:
|
|
343
338
|
|
|
344
339
|
- `containerStyle`
|
|
345
340
|
- `inputStyle`
|
|
346
341
|
- `baseTextStyle`
|
|
347
|
-
- `outputContainerStyle`
|
|
348
|
-
- `outputLabelStyle`
|
|
349
|
-
- `outputTextStyle`
|
|
350
|
-
- `renderedOutputStyle`
|
|
351
342
|
- `toolbarStyle`
|
|
352
343
|
- `toolbarButtonStyle`
|
|
353
344
|
- `toolbarButtonActiveStyle`
|
|
354
345
|
- `toolbarButtonTextStyle`
|
|
355
346
|
- `toolbarButtonActiveTextStyle`
|
|
347
|
+
- `outputContainerStyle`
|
|
348
|
+
- `outputLabelStyle`
|
|
349
|
+
- `outputTextStyle`
|
|
350
|
+
- `renderedOutputStyle`
|
|
356
351
|
- `codeStyle`
|
|
357
|
-
- `colors.primary`
|
|
358
|
-
- `colors.link`
|
|
359
352
|
|
|
360
|
-
## Headless
|
|
353
|
+
## Headless Usage
|
|
361
354
|
|
|
362
|
-
Use `useRichText` when you want to build your own editor
|
|
355
|
+
Use `useRichText` when you want to build your own editor shell instead of using `<RichTextInput />`.
|
|
363
356
|
|
|
364
357
|
```tsx
|
|
365
358
|
import React from 'react';
|
|
366
|
-
import { TextInput, View
|
|
359
|
+
import { Button, TextInput, View } from 'react-native';
|
|
367
360
|
import { useRichText } from 'react-native-richify';
|
|
368
361
|
|
|
369
362
|
export function HeadlessEditor() {
|
|
370
|
-
const {
|
|
363
|
+
const { actions } = useRichText({
|
|
371
364
|
onChangeText: (text) => console.log(text),
|
|
372
365
|
});
|
|
373
366
|
|
|
@@ -389,58 +382,9 @@ export function HeadlessEditor() {
|
|
|
389
382
|
}
|
|
390
383
|
```
|
|
391
384
|
|
|
392
|
-
##
|
|
385
|
+
## Data Model And Serialization
|
|
393
386
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
Important: the shipped `<RichTextInput />` manages its own state. Wrapping it in `RichTextProvider` does not automatically bind it to external context state.
|
|
397
|
-
|
|
398
|
-
Use context when you want to split a custom editor into multiple components:
|
|
399
|
-
|
|
400
|
-
```tsx
|
|
401
|
-
import React from 'react';
|
|
402
|
-
import { Button, TextInput, View } from 'react-native';
|
|
403
|
-
import {
|
|
404
|
-
RichTextProvider,
|
|
405
|
-
useRichTextContext,
|
|
406
|
-
} from 'react-native-richify';
|
|
407
|
-
|
|
408
|
-
function ToolbarRow() {
|
|
409
|
-
const { actions } = useRichTextContext();
|
|
410
|
-
return <Button title="Italic" onPress={() => actions.toggleFormat('italic')} />;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function EditorField() {
|
|
414
|
-
const { actions } = useRichTextContext();
|
|
415
|
-
|
|
416
|
-
return (
|
|
417
|
-
<TextInput
|
|
418
|
-
multiline
|
|
419
|
-
value={actions.getPlainText()}
|
|
420
|
-
onChangeText={actions.handleTextChange}
|
|
421
|
-
onSelectionChange={(event) =>
|
|
422
|
-
actions.handleSelectionChange(event.nativeEvent.selection)
|
|
423
|
-
}
|
|
424
|
-
style={{ minHeight: 120, borderWidth: 1, padding: 12 }}
|
|
425
|
-
/>
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
export function SplitEditor() {
|
|
430
|
-
return (
|
|
431
|
-
<RichTextProvider>
|
|
432
|
-
<View>
|
|
433
|
-
<ToolbarRow />
|
|
434
|
-
<EditorField />
|
|
435
|
-
</View>
|
|
436
|
-
</RichTextProvider>
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
## Data Model
|
|
442
|
-
|
|
443
|
-
Content is stored as segments:
|
|
387
|
+
The editor stores content as typed segments:
|
|
444
388
|
|
|
445
389
|
```ts
|
|
446
390
|
type StyledSegment = {
|
|
@@ -458,36 +402,23 @@ type StyledSegment = {
|
|
|
458
402
|
listType?: 'bullet' | 'ordered' | 'none';
|
|
459
403
|
textAlign?: 'left' | 'center' | 'right';
|
|
460
404
|
link?: string;
|
|
405
|
+
imageSrc?: string;
|
|
406
|
+
imageAlt?: string;
|
|
461
407
|
};
|
|
462
408
|
};
|
|
463
409
|
```
|
|
464
410
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
- store and restore content with `exportJSON()` and `importJSON()`
|
|
468
|
-
- inspect formatting state in your own UI
|
|
469
|
-
- serialize on demand to Markdown or HTML
|
|
470
|
-
|
|
471
|
-
Example:
|
|
472
|
-
|
|
473
|
-
```tsx
|
|
474
|
-
const saved = actions.exportJSON();
|
|
475
|
-
actions.importJSON(saved);
|
|
476
|
-
|
|
477
|
-
const markdown = actions.getOutput('markdown');
|
|
478
|
-
const html = actions.getOutput('html');
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
## Current Scope
|
|
482
|
-
|
|
483
|
-
Stable built-in features documented above are the recommended way to use the library.
|
|
411
|
+
That makes it straightforward to:
|
|
484
412
|
|
|
485
|
-
-
|
|
486
|
-
-
|
|
413
|
+
- save content with `exportJSON()`
|
|
414
|
+
- restore content with `importJSON()`
|
|
415
|
+
- read plain text with `getPlainText()`
|
|
416
|
+
- generate Markdown with `getOutput('markdown')`
|
|
417
|
+
- generate HTML with `getOutput('html')`
|
|
487
418
|
|
|
488
419
|
## Contributing
|
|
489
420
|
|
|
490
|
-
See [AGENTS.md](AGENTS.md) for contributor
|
|
421
|
+
See [AGENTS.md](AGENTS.md) for contributor workflow notes.
|
|
491
422
|
|
|
492
423
|
## License
|
|
493
424
|
|
|
@@ -96,6 +96,7 @@ const Toolbar = exports.Toolbar = /*#__PURE__*/_react.default.memo(({
|
|
|
96
96
|
contentContainerStyle: styles.scrollContent,
|
|
97
97
|
children: enrichedItems.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_ToolbarButton.ToolbarButton, {
|
|
98
98
|
label: item.label,
|
|
99
|
+
accessibilityLabel: item.accessibilityLabel,
|
|
99
100
|
active: !!item.active,
|
|
100
101
|
theme: resolvedTheme,
|
|
101
102
|
renderButton: item.renderButton,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_defaultStyles","_ToolbarButton","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","Toolbar","exports","React","memo","actions","state","items","theme","visible","outputFormat","outputPreviewMode","onOutputFormatChange","onOutputPreviewModeChange","onRequestLink","onRequestImage","renderToolbar","resolvedTheme","DEFAULT_THEME","toolbarItems","DEFAULT_TOOLBAR_ITEMS","enrichedItems","useMemo","selectionStyle","getSelectionStyle","map","item","isActive","format","isFormatActive","heading","listType","textAlign","actionType","link","active","undefined","toolbarStyle","jsx","View","style","children","ScrollView","horizontal","showsHorizontalScrollIndicator","keyboardShouldPersistTaps","contentContainerStyle","styles","scrollContent","ToolbarButton","label","renderButton","onPress","toggleFormat","setHeading","setListType","setTextAlign","id","displayName","StyleSheet","create","flexDirection","alignItems","gap"],"sourceRoot":"../../../src","sources":["components/Toolbar.tsx"],"mappings":"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
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_defaultStyles","_ToolbarButton","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","Toolbar","exports","React","memo","actions","state","items","theme","visible","outputFormat","outputPreviewMode","onOutputFormatChange","onOutputPreviewModeChange","onRequestLink","onRequestImage","renderToolbar","resolvedTheme","DEFAULT_THEME","toolbarItems","DEFAULT_TOOLBAR_ITEMS","enrichedItems","useMemo","selectionStyle","getSelectionStyle","map","item","isActive","format","isFormatActive","heading","listType","textAlign","actionType","link","active","undefined","toolbarStyle","jsx","View","style","children","ScrollView","horizontal","showsHorizontalScrollIndicator","keyboardShouldPersistTaps","contentContainerStyle","styles","scrollContent","ToolbarButton","label","accessibilityLabel","renderButton","onPress","toggleFormat","setHeading","setListType","setTextAlign","id","displayName","StyleSheet","create","flexDirection","alignItems","gap"],"sourceRoot":"../../../src","sources":["components/Toolbar.tsx"],"mappings":"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","ignoreList":[]}
|