Skip to content

Commit 55e8fd0

Browse files
committed
docs: lists, imgs, alignment, shortcuts sections
1 parent 9679241 commit 55e8fd0

12 files changed

Lines changed: 533 additions & 28 deletions

docs/docs/rich-text-formatting/inline-images.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
sidebar_position: 5
3+
---
4+
5+
import InteractiveExample from '@site/src/components/InteractiveExample';
6+
import ImagesEditor from '@site/src/examples/ImagesEditor';
7+
import ImagesEditorSrc from '!!raw-loader!@site/src/examples/ImagesEditor';
8+
9+
# Inline images
10+
11+
Aside from just styled text, the library offers much more. This includes inline images - pictures embedded straight into the text flow.
12+
13+
## Inserting an image
14+
15+
You can insert it explicitly with the `setImage` ref method:
16+
17+
```ts
18+
setImage(src: string, width: number, height: number)
19+
```
20+
21+
- `src` - an absolute file path or a remote image URL.
22+
- `width` / `height` - the size the image should render at.
23+
24+
The image lands on its own line at the current selection, replacing any
25+
selected text.
26+
27+
```tsx
28+
const insertImage = () => {
29+
ref.current?.setImage('https://picsum.photos/320/160', 160, 80);
30+
};
31+
```
32+
33+
:::note
34+
35+
You are responsible for the `width` and `height` you pass - the editor does not
36+
measure the image for you, so if you want to preserve a picture's aspect ratio you
37+
need to compute it yourself before calling `setImage`.
38+
39+
:::
40+
41+
## When the source can't load
42+
43+
If the `src` can't be resolved - a broken URL, a missing file - the editor doesn't
44+
error out and renders a static placeholder in the image's place instead.
45+
46+
## Try it out
47+
48+
Place the cursor in the input and insert an image. The first button inserts a real
49+
photo from [Lorem Picsum](https://picsum.photos) at a matching size; the second
50+
points at a source that doesn't exist, so you get the fallback placeholder rather
51+
than a crash.
52+
53+
<InteractiveExample src={ImagesEditorSrc} component={ImagesEditor} />
54+
55+
:::info
56+
57+
Images can also arrive by pasting rather than through `setImage` - the editor
58+
surfaces those through the `onPasteImages` event, which hands you each image's URI,
59+
MIME type, and dimensions so you can upload or resize before inserting.
60+
61+
:::

docs/docs/rich-text-formatting/lists.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
sidebar_position: 4
3+
---
4+
5+
import InteractiveExample from '@site/src/components/InteractiveExample';
6+
import ListsEditor from '@site/src/examples/ListsEditor';
7+
import ListsEditorSrc from '!!raw-loader!@site/src/examples/ListsEditor';
8+
9+
# Lists
10+
11+
Lists are [paragraph styles](/rich-text-formatting/basic-styles#paragraph-styles),
12+
just like headings and blockquotes - toggling one affects the whole paragraph the
13+
cursor sits in, or every paragraph the selection touches. The editor supports three
14+
kinds:
15+
16+
- **Unordered list** - `toggleUnorderedList()`
17+
- **Ordered list** - `toggleOrderedList()`
18+
- **Checkbox list** - `toggleCheckboxList(checked: boolean)`
19+
20+
Because they're paragraph styles, **only one can be active on a paragraph at a
21+
time**. Toggling a second list type (or any other paragraph style) replaces the
22+
first rather than stacking - the editor reports this through the `isConflicting`
23+
flag in `onChangeState`, exactly as described in
24+
[Basic styles](/rich-text-formatting/basic-styles#paragraph-styles).
25+
26+
:::note
27+
28+
The library does not support nested lists. You can only create a single level list. If you try to insert a nested list in any way, e.g. by calling `setValue` on the editor's `ref`, the list will get flattened by the [normalizer](/fundamentals/core-concepts#normalization).
29+
30+
:::
31+
32+
## Bulleted and numbered lists
33+
34+
These two take no arguments - each call converts the affected paragraphs into a
35+
list, and calling it again turns them back into plain paragraphs:
36+
37+
```tsx
38+
ref.current?.toggleUnorderedList();
39+
ref.current?.toggleOrderedList();
40+
```
41+
42+
## Checkbox lists
43+
44+
This list's items need a starting state. `toggleCheckboxList` takes a `checked` boolean that
45+
decides whether newly created boxes begin checked or unchecked:
46+
47+
```tsx
48+
// New items start unchecked.
49+
ref.current?.toggleCheckboxList(false);
50+
```
51+
52+
Once the list exists, the user can tick individual items by tapping their
53+
checkbox - you don't need to wire anything up for that.
54+
55+
## Try it out
56+
57+
Type a few lines, place the cursor on one (or select several), and toggle each
58+
list type. Notice how switching from **Bulleted** to **Numbered** swaps the style
59+
instead of stacking, inserting a new line keeps the list format by creating an another element and how tapping a checkbox in the checkbox list toggles just that item.
60+
61+
<InteractiveExample src={ListsEditorSrc} component={ListsEditor} />
62+
63+
:::info
64+
65+
This page covers creating lists. To change how they look - bullet color and size,
66+
marker weight, checkbox size, indentation - see
67+
[Styling the input](/core-functionalities/styling-the-input).
68+
69+
:::

docs/docs/rich-text-formatting/text-alignment.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
sidebar_position: 6
3+
---
4+
5+
import InteractiveExample from '@site/src/components/InteractiveExample';
6+
import TextAlignmentEditor from '@site/src/examples/TextAlignmentEditor';
7+
import TextAlignmentEditorSrc from '!!raw-loader!@site/src/examples/TextAlignmentEditor';
8+
9+
# Text alignment
10+
11+
Alignment controls how a paragraph's text sits within the input's width. It's a
12+
per-paragraph property - every paragraph the selection touches gets aligned - and
13+
you set it with the `setTextAlignment` ref method:
14+
15+
```ts
16+
setTextAlignment(alignment: 'left' | 'center' | 'right' | 'justify' | 'auto')
17+
```
18+
19+
The five values are:
20+
21+
- **`left`**, **`center`**, **`right`** - align the text to that direction.
22+
- **`justify`** - stretch each line to fill the full width.
23+
- **`auto`** - reset to the system's natural alignment.
24+
25+
Unlike the paragraph styles from [Basic styles](/rich-text-formatting/basic-styles),
26+
text alignment does not report its state with the `isActive` / `isConflicting` booleans in `onChangeState`. Instead it exposes `alignment` with its relevant string value.
27+
28+
```tsx
29+
const [state, setState] = useState<OnChangeStateEvent | null>(null);
30+
31+
// Highlight the button that matches the paragraph at the cursor.
32+
const isActive = state?.alignment === 'center';
33+
```
34+
35+
## Try it out
36+
37+
Type a paragraph or two, place the cursor on one, and try each alignment. The
38+
active button reflects `state.alignment` for the paragraph the cursor is in.
39+
40+
<InteractiveExample src={TextAlignmentEditorSrc} component={TextAlignmentEditor} />

docs/docs/rich-text-formatting/text-shortcuts.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
sidebar_position: 7
3+
---
4+
5+
import InteractiveExample from '@site/src/components/InteractiveExample';
6+
import TextShortcutsEditor from '@site/src/examples/TextShortcutsEditor';
7+
import TextShortcutsEditorSrc from '!!raw-loader!@site/src/examples/TextShortcutsEditor';
8+
9+
# Text shortcuts
10+
11+
Text shortcuts let users format as they type, the way Markdown editors do -
12+
typing `#` turns a line into a heading, wrapping a word in `**` makes it bold.
13+
You configure them with the `textShortcuts` prop, an array that maps a `trigger`
14+
string to a `style`:
15+
16+
```tsx
17+
<EnrichedTextInput
18+
textShortcuts={[
19+
{ trigger: '# ', style: 'h1' },
20+
{ trigger: '**', style: 'bold' },
21+
]}
22+
/* ... */
23+
/>;
24+
```
25+
26+
The `style` values are the same rich text styles you met in
27+
[Basic styles](/rich-text-formatting/basic-styles) - and the inline vs. paragraph
28+
distinction is exactly what decides how a shortcut fires.
29+
30+
## Paragraph vs. inline shortcuts
31+
32+
The two families of styles trigger differently, because they format different
33+
things:
34+
35+
- **Paragraph shortcuts** (`h1``h6`, `blockquote`, `codeblock`,
36+
`unordered_list`, `ordered_list`, `checkbox_list`) fire at the **start of a
37+
paragraph**. The trigger is the prefix you type before the line's content -
38+
e.g. `#` for a heading, `-` for a bulleted list. Since a paragraph can only hold
39+
one paragraph style, these only fire on a **plain** paragraph: if the line is
40+
already a heading or a list item, typing the prefix does nothing.
41+
42+
- **Inline shortcuts** (`bold`, `italic`, `underline`, `strikethrough`,
43+
`inline_code`) fire when you type a **closing delimiter** around some text, so
44+
typing `**word**` bolds `word`.
45+
46+
:::note
47+
48+
The usual [style rules](/rich-text-formatting/basic-styles#paragraph-styles) still
49+
apply to shortcut-triggered styles. If the target style is **blocked** by an
50+
active one (e.g. bold inside a code block).
51+
52+
:::
53+
54+
## Defaults
55+
56+
Even without the prop, two shortcuts are active out of the box:
57+
58+
```ts
59+
[
60+
{ trigger: '- ', style: 'unordered_list' },
61+
{ trigger: '1. ', style: 'ordered_list' },
62+
];
63+
```
64+
65+
Passing your own array replaces these defaults entirely, and passing an empty
66+
array (`textShortcuts={[]}`) disables shortcuts altogether.
67+
68+
## Try it out
69+
70+
The editor below wires up one shortcut of each kind - a paragraph one (`#` → H1)
71+
and an inline one (`**` → bold). Start a line with `#` and watch it become a
72+
heading, then wrap a word in `**stars**` to bold it.
73+
74+
<InteractiveExample src={TextShortcutsEditorSrc} component={TextShortcutsEditor} />
75+
76+
:::info
77+
78+
On Web, the same styles are also reachable through
79+
[keyboard shortcuts](/api-reference/enriched-text-input) like ⌘B / Ctrl+B,
80+
independent of the `textShortcuts` prop.
81+
82+
:::

docs/src/examples/ImagesEditor.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { EnrichedTextInput } from 'react-native-enriched-html';
2+
import type { EnrichedTextInputInstance } from 'react-native-enriched-html';
3+
import { useRef } from 'react';
4+
import { View, StyleSheet, Pressable, Text } from 'react-native';
5+
6+
export default function App() {
7+
const ref = useRef<EnrichedTextInputInstance>(null);
8+
9+
const insertImage = () => {
10+
// A real, loadable image. You supply the dimensions yourself - here we
11+
// ask Lorem Picsum for a 320x160 photo and pass the proportionally down-scaled size.
12+
ref.current?.setImage('https://picsum.photos/320/160', 160, 80);
13+
};
14+
15+
const insertBrokenImage = () => {
16+
// An unreachable source. The editor renders its static placeholder
17+
// instead of failing, so you can see what a broken image looks like.
18+
ref.current?.setImage('https://picsum.photos/does-not-exist', 160, 80);
19+
};
20+
21+
return (
22+
<View style={styles.container}>
23+
<EnrichedTextInput
24+
ref={ref}
25+
style={styles.input}
26+
placeholder="Place the cursor, then insert an image below..."
27+
/>
28+
<View style={styles.row}>
29+
<Pressable style={styles.button} onPress={insertImage}>
30+
<Text style={styles.text}>Insert image</Text>
31+
</Pressable>
32+
<Pressable style={styles.button} onPress={insertBrokenImage}>
33+
<Text style={styles.text}>Insert broken image</Text>
34+
</Pressable>
35+
</View>
36+
</View>
37+
);
38+
}
39+
40+
const styles = StyleSheet.create({
41+
container: { gap: 12 },
42+
input: {
43+
fontSize: 18,
44+
color: '#232736',
45+
padding: 12,
46+
borderRadius: 12,
47+
minHeight: 96,
48+
backgroundColor: '#eef0ff',
49+
},
50+
row: {
51+
flexDirection: 'row',
52+
flexWrap: 'wrap',
53+
justifyContent: 'center',
54+
gap: 8,
55+
},
56+
button: {
57+
padding: 8,
58+
paddingHorizontal: 16,
59+
borderRadius: 24,
60+
borderWidth: 1,
61+
borderColor: '#919fcf',
62+
},
63+
text: {
64+
textAlign: 'center',
65+
color: '#919fcf',
66+
},
67+
});

0 commit comments

Comments
 (0)