Skip to content

Commit f44bda6

Browse files
committed
docs: fundamentals
1 parent 5d34310 commit f44bda6

12 files changed

Lines changed: 3192 additions & 118 deletions

File tree

docs/docs/fundamentals/core-concepts.md

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,88 @@ sidebar_position: 3
44

55
# Core concepts
66

7-
<!-- TODO: write content for this page -->
7+
You've built an editor. Before going on, it's worth understanding the few
8+
ideas the whole library is built on. They explain why the API looks the way it
9+
does and help you understand further chapters better.
10+
11+
## The input is uncontrolled
12+
13+
`EnrichedTextInput` does not take its content from a prop and does not push
14+
every keystroke back into React state. It owns its content on the native side
15+
and you talk to it through a `ref`.
16+
17+
This is deliberate. Rich text changes constantly — every character, selection
18+
move and style toggle — and round-tripping all of that through JavaScript state
19+
would be extremely slow and open to a possible de-synchronization of those states.
20+
Keeping it native makes the editor fast and stable.
21+
22+
In practice this means:
23+
24+
- To **change** content or styling, call a method: `ref.current?.toggleBold()`,
25+
`ref.current?.setValue(html)`, `ref.current?.setLink(...)`.
26+
- To **observe** content or styling, listen to an event: `onChangeState`,
27+
`onChangeHtml`, `onChangeSelection`.
28+
29+
You never set a `value` prop and re-render to make an edit happen.
30+
31+
## HTML is the source of truth
32+
33+
The editor's content is HTML. `setValue` and `defaultValue` seeds it with an HTML string,
34+
`getHTML` reads the current content back, and `onChangeHtml` streams it as it
35+
changes. What you store and what you render is a string of HTML.
36+
37+
The library uses a fixed set of standard and custom tags, so the output is
38+
predictable and portable. [Supported HTML tags](/fundamentals/html-format-and-supported-tags)
39+
lists exactly what it produces and accepts.
40+
41+
:::caution
42+
43+
You own sanitization. The library doesn't guarantee safe or clean HTML, so
44+
sanitize anything you persist, render elsewhere, or accept from untrusted
45+
sources.
46+
47+
:::
48+
49+
## Normalization
50+
51+
## Normalization
52+
53+
HTML can often be messy. If a user pastes text from Google Docs or MS Word, it arrives packed with wrapper tags, inline styles, and structural quirks that don't match the format we expect.
54+
55+
To handle this, both components provide `useHtmlNormalizer` prop that normalizes any incoming HTML. The normalizer cleans and restructures the input into the predictable format the library expects. For example, it maps `<strong>` to `<b>`, safely unwraps `<div>` containers into `<p>` tags, and strips tags that are unsupported. The `useHtmlNormalizer` prop defaults to `true`.
56+
57+
All supported and canonical tags are listed in [Supported HTML tags](/fundamentals/html-format-and-supported-tags).
58+
59+
## Two components, one styling API
60+
61+
The library is split into an editor and a viewer:
62+
63+
- **`EnrichedTextInput`** — the interactive editor from the previous page.
64+
- **`EnrichedText`** — a read-only display component that renders the input's
65+
HTML.
66+
67+
Both accept the same `htmlStyle` prop, which describes how each tag looks
68+
(heading sizes, blockquote borders, code block colors, and so on). Because they
69+
share it, text looks identical whether it's being edited or displayed — no
70+
drift between the two. A common setup edits in `EnrichedTextInput`, stores the
71+
`getHTML` output, and later shows it with `EnrichedText`.
72+
73+
## The style state model
74+
75+
Not every style can combine with every other. A heading isn't a list; bold
76+
inside a code block doesn't make sense. The editor tracks this and reports it
77+
through `onChangeState`, which gives each style three booleans:
78+
79+
- **`isActive`** — the style is applied at the current selection. Use it to
80+
highlight a toolbar button.
81+
- **`isBlocking`** — another active style forbids this one entirely, so toggling
82+
it would do nothing. For example bold is blocked inside a code block. Use it
83+
to disable a button.
84+
- **`isConflicting`** — this style would replace an active one if toggled on.
85+
For example switching a blockquote paragraph to a heading removes the
86+
blockquote. Use it to hint that the toggle is a swap, not an addition.
87+
88+
Driving your toolbar from these three flags keeps the UI honest: buttons light
89+
up and grey out according do the editor's state.
90+
To find the comprehensive list about what style blocks or conflicts with, check out
91+
[Supported HTML tags](/fundamentals/html-format-and-supported-tags).

docs/docs/fundamentals/getting-started.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,133 @@ slug: /
33
sidebar_position: 1
44
---
55

6+
import Tabs from '@theme/Tabs';
7+
import TabItem from '@theme/TabItem';
8+
69
# Getting started
710

8-
<!-- TODO: write content for this page -->
11+
The goal of the _Fundamentals_ section is to get you from an empty project to a
12+
working rich text editor and to give you the mental model you need to build on
13+
your own. Let's dive in.
14+
15+
## What is React Native Enriched HTML?
16+
17+
React Native Enriched HTML is a rich text solution for React Native built by
18+
[Software Mansion](https://swmansion.com/).
19+
20+
It ships two fully native components: `EnrichedTextInput`, a rich text editor
21+
that styles text live as you type, and `EnrichedText`, a read-only display component that
22+
renders the input's output. Both speak HTML — the input
23+
produces it, the display consumes it.
24+
25+
Not only does this library allow you to apply basic rich text styles you know well,
26+
like *bold* or _italic_, but also provides more powerful tools like `mentions`, something
27+
you will learn more about in the next chapters.
28+
29+
iOS and Android are and Web are all supported. iOS and Android are both stable, where Web is still experimental, so expect
30+
its behavior to change between releases.
31+
32+
## Prerequisites
33+
34+
The library works only with the
35+
[React Native New Architecture (Fabric)](https://reactnative.dev/architecture/landing-page).
36+
It's enabled by default on recent React Native versions; if your app still runs
37+
the old architecture you'll need to switch before installing.
38+
39+
For the exact React Native versions we support, see
40+
[Compatibility](/misc/compatibility).
41+
42+
## Installation
43+
44+
### Bare React Native
45+
46+
Install the package:
47+
48+
<Tabs groupId="package-managers">
49+
<TabItem value="npm" label="NPM">
50+
```bash
51+
npm install react-native-enriched-html
52+
```
53+
</TabItem>
54+
55+
<TabItem value="yarn" label="YARN">
56+
```bash
57+
yarn add react-native-enriched-html
58+
```
59+
</TabItem>
60+
</Tabs>
61+
62+
The library contains native code, so rebuild your app after installing. On iOS,
63+
install the pods first:
64+
65+
```sh
66+
cd ios && bundler install && bundler exec pod install
67+
```
68+
69+
### Expo
70+
71+
Install with the Expo CLI so the correct version is picked for your SDK:
72+
73+
```sh
74+
npx expo install react-native-enriched-html
75+
```
76+
77+
Then regenerate the native projects:
78+
79+
```sh
80+
npx expo prebuild
81+
```
82+
83+
:::note
84+
85+
The library needs native code, so it won't run in Expo Go. Use a
86+
[development build](https://docs.expo.dev/develop/development-builds/introduction/)
87+
instead.
88+
89+
:::
90+
91+
### Web
92+
93+
Install the package:
94+
95+
<Tabs groupId="package-managers">
96+
<TabItem value="npm" label="NPM">
97+
```bash
98+
npm install react-native-enriched-html
99+
```
100+
</TabItem>
101+
102+
<TabItem value="yarn" label="YARN">
103+
```bash
104+
yarn add react-native-enriched-html
105+
```
106+
</TabItem>
107+
</Tabs>
108+
109+
The shipped components share the React Native's API, minus the functionalities a
110+
browser can't provide. See the _Web support_ guide for what's covered.
111+
112+
## Nightly builds
113+
114+
To try features before they land in a stable release, install the nightly
115+
build:
116+
117+
<Tabs groupId="package-managers">
118+
<TabItem value="npm" label="NPM">
119+
```bash
120+
npm install react-native-enriched-html@nightly
121+
```
122+
</TabItem>
123+
124+
<TabItem value="yarn" label="YARN">
125+
```bash
126+
yarn add react-native-enriched-html@nightly
127+
```
128+
</TabItem>
129+
</Tabs>
130+
131+
Nightlies are published to npm automatically and may contain breaking changes.
132+
133+
---
134+
135+
You're set up. Next, let's [build your first editor](/fundamentals/your-first-editor).

docs/docs/fundamentals/html-format-and-supported-tags.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,76 @@ sidebar_position: 4
44

55
# HTML format and supported tags
66

7-
<!-- TODO: write content for this page -->
7+
The editor works with a fixed set of standard and custom HTML tags — it both
8+
produces them in its output and accepts them as input. This page is the
9+
reference for that set.
10+
11+
Styles fall into two groups: **inline** tags that wrap a range of characters,
12+
and **paragraph** tags that apply to whole lines. Not all of them combine
13+
freely, and there are two kinds of restriction:
14+
15+
- **Conflicting** — toggling a style that conflicts with an active one replaces
16+
it. Toggling `<h2>` on a `<blockquote>` paragraph removes the blockquote and
17+
applies the heading.
18+
- **Blocking** — a blocked style can't be toggled at all while the blocking
19+
style is active. `<b>` is blocked inside `<codeblock>`, so bold can't be
20+
applied there.
21+
22+
Both show up in the [`onChangeState`](/fundamentals/core-concepts) payload as
23+
`isConflicting` and `isBlocking`.
24+
25+
## Inline tags
26+
27+
| Style | HTML tag | Conflicts with | Blocked by |
28+
| ------------- | ----------- | ---------------------------- | ---------------------- |
29+
| Bold | `<b>` | -- | `<codeblock>` |
30+
| Italic | `<i>` | -- | `<codeblock>` |
31+
| Underline | `<u>` | -- | `<codeblock>` |
32+
| Strikethrough | `<s>` | -- | `<codeblock>` |
33+
| Inline code | `<code>` | `<a>`, `<mention>` | `<codeblock>`, `<img>` |
34+
| Link | `<a>` | `<code>`, `<a>`, `<mention>` | `<codeblock>`, `<img>` |
35+
| Mention | `<mention>` | `<code>`, `<a>` | `<codeblock>`, `<img>` |
36+
| Image | `<img>` | `<a>`, `<mention>` | `<code>` |
37+
38+
:::note
39+
40+
Headings also block bold when `bold: true` is set on the heading in the
41+
`htmlStyle` prop. The heading already renders as bold, so toggling bold on top
42+
of it is redundant and therefore blocked.
43+
44+
:::
45+
46+
## Paragraph tags
47+
48+
Only one paragraph-level style can be active per paragraph — they all conflict
49+
with each other.
50+
51+
Some paragraph styles are containers that wrap each line inside them with an
52+
**inner content tag**. Each line of a `<ul>` is wrapped in `<li>`, and each line
53+
of a `<codeblock>` is wrapped in `<p>`.
54+
55+
| Style | HTML tag | Inner content tag | Conflicts with | Blocked by |
56+
| -------------- | --------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
57+
| Heading 1 | `<h1>` | -- | `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
58+
| Heading 2 | `<h2>` | -- | `<h1>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
59+
| Heading 3 | `<h3>` | -- | `<h1>`, `<h2>`, `<h4>`, `<h5>`, `<h6>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
60+
| Heading 4 | `<h4>` | -- | `<h1>`, `<h2>`, `<h3>`, `<h5>`, `<h6>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
61+
| Heading 5 | `<h5>` | -- | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h6>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
62+
| Heading 6 | `<h6>` | -- | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
63+
| Unordered list | `<ul>` | `<li>` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
64+
| Ordered list | `<ol>` | `<li>` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<ul>`, `<ul data-type="checkbox">`, `<blockquote>`, `<codeblock>` | -- |
65+
| Checkbox list | `<ul data-type="checkbox">` | `<li>` / `<li checked>` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<ul>`, `<ol>`, `<blockquote>`, `<codeblock>` | -- |
66+
| Blockquote | `<blockquote>` | `<p>` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<codeblock>` | -- |
67+
| Codeblock | `<codeblock>` | `<p>` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<b>`, `<u>`, `<i>`, `<s>`, `<ul>`, `<ol>`, `<ul data-type="checkbox">`, `<blockquote>`, `<code>`, `<mention>`, `<a>` | -- |
68+
69+
## Plain and empty paragraphs
70+
71+
A plain line of text with no paragraph style is wrapped in `<p>`. An empty line
72+
is represented by `<br>`. So a document with a heading, a blank line and a
73+
paragraph comes out like this:
74+
75+
```html
76+
<h1>Title</h1>
77+
<br />
78+
<p>Some body text.</p>
79+
```

docs/docs/fundamentals/your-first-editor.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)