-
Notifications
You must be signed in to change notification settings - Fork 57
docs: core funtionalities section #715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: @ksienkiewicz/docs-rich-text-formatting
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,4 +4,56 @@ sidebar_position: 3 | |
|
|
||
| # Handling events | ||
|
|
||
| <!-- TODO: write content for this page --> | ||
| Since the input is [uncontrolled](/fundamentals/core-concepts#the-input-is-uncontrolled), | ||
| events are how you observe it. You change content by calling ref methods; you | ||
| react to changes by listening to the callbacks below. | ||
|
|
||
| Full payload shapes of the available callbacks can be found in the `EnrichedTextInput` reference. | ||
|
|
||
| ## Content | ||
|
|
||
| - **`onChangeText`** - plain-text content changed. | ||
| - **`onChangeHtml`** - the HTML changed. | ||
|
|
||
| :::tip | ||
|
|
||
| The `onChangeHtml` callback has to parse the content into HTML on every keystroke. | ||
| This is a heavy computational operation that might slow down your app's performance. Consider using the `getHTML()` ref method instead if it meets your requirements. | ||
|
|
||
| ::: | ||
|
|
||
| ## Selection and style state | ||
|
|
||
| - **`onChangeSelection`** - the cursor moved or the selection changed. Gives you | ||
| `start`, `end`, and the selected `text`. Useful for range-based methods like | ||
| [`setLink`](/rich-text-formatting/links). | ||
| - **`onChangeState`** - the active styles at the cursor changed. This is the | ||
| event that drives a toolbar by using reported `isActive`, `isBlocking`, and | ||
| `isConflicting`, plus the current `alignment`. See the | ||
| [style state model](/fundamentals/core-concepts#the-style-state-model). | ||
|
|
||
| ## Focus | ||
|
|
||
| - **`onFocus`** / **`onBlur`** - the input gained or lost focus. | ||
|
|
||
| ## Mentions | ||
|
|
||
| - **`onStartMention`** - a mention started being edited. | ||
| - **`onChangeMention`** - the query after the indicator changed. | ||
| - **`onEndMention`** - editing a mention stopped. | ||
| - **`onMentionDetected`** - the cursor entered or left a mention. | ||
|
|
||
| ## Links | ||
|
|
||
| - **`onLinkDetected`** - the cursor entered or left a link. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also add some info about |
||
|
|
||
| ## Images | ||
|
|
||
| - **`onPasteImages`** - the user pasted one or more images; hands you each | ||
| image's data so you can upload and insert them with | ||
| [`setImage`](/rich-text-formatting/inline-images). | ||
|
|
||
| ## Keyboard and submission | ||
|
|
||
| - **`onKeyPress`** - a key was pressed. | ||
| - **`onSubmitEditing`** - the user presses return/enter key. Fires when `submitBehavior` is set to either `submit` or `blurAndSubmit`. | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| --- | ||
| sidebar_position: 2 | ||
| --- | ||
|
|
||
| import InteractiveExample from '@site/src/components/InteractiveExample'; | ||
| import RenderingEditor from '@site/src/examples/RenderingEditor'; | ||
| import RenderingEditorSrc from '!!raw-loader!@site/src/examples/RenderingEditor'; | ||
|
|
||
| # Rendering rich text | ||
|
|
||
| `EnrichedTextInput` is for editing. To _display_ rich text without an editor - | ||
| a chat message, a comment, an article - use its read-only counterpart, | ||
| **`EnrichedText`**. | ||
|
|
||
| Both components speak the same [HTML format](/fundamentals/html-format-and-supported-tags), | ||
| so the typical flow is: edit in `EnrichedTextInput`, persist the | ||
| `getHTML` output, and later feed that | ||
| string to `EnrichedText`. | ||
|
|
||
| ## Passing content | ||
|
|
||
| `EnrichedText` takes the HTML string as its `children`: | ||
|
|
||
| ```tsx | ||
| import { EnrichedText } from 'react-native-enriched-html'; | ||
|
|
||
| <EnrichedText>{'<p>Hello <b>world</b></p>'}</EnrichedText>; | ||
| ``` | ||
|
|
||
| ## Styling | ||
|
|
||
| Styling mirrors the input. `style` controls the container and base typography, | ||
| and `htmlStyle` controls per-element appearance. `EnrichedText` extends | ||
| `htmlStyle` with **press states** for interactive elements, since links and | ||
| mentions are pressable here: | ||
|
|
||
| ```tsx | ||
| <EnrichedText | ||
| style={{ fontSize: 16, color: '#232736' }} | ||
| htmlStyle={{ | ||
| a: { pressColor: '#1e40af' }, | ||
| mention: { pressColor: '#16a34a', pressBackgroundColor: '#dcfce7' }, | ||
| }}> | ||
| {html} | ||
| </EnrichedText> | ||
| ``` | ||
|
|
||
| The added `pressColor` / `pressBackgroundColor` fields on `a` and `mention` are | ||
| the only shape difference from the input's `htmlStyle`. See the | ||
| `EnrichedText` reference for the full type. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that |
||
|
|
||
| ## Notable props | ||
|
|
||
| - **`selectable`** - allow the user to select and copy the rendered text. | ||
| Defaults to `false`. | ||
| - **`onLinkPress` / `onMentionPress`** - fire when a link or mention is pressed. | ||
| - **`numberOfLines` / `ellipsizeMode`** - truncate long content to a fixed | ||
| number of lines with an ellipsis. | ||
| - **`useHtmlNormalizer`** - normalize external or messy HTML into the library's canonical | ||
| tag subset before rendering. Defaults to `true`. See | ||
| [Normalization](/fundamentals/core-concepts#normalization). | ||
|
|
||
| :::note | ||
|
|
||
| On web, the default behavior of the pressed `<a>` tag is suppressed. To navigate to the link's URL, you need to properly handle the `onLinkPress` event. | ||
|
|
||
| ::: | ||
|
|
||
| ## Try it out | ||
|
|
||
| Format some text in the editor, then press **Render** - the current HTML is read | ||
| with `getHTML()` and handed to an `EnrichedText` below. | ||
|
|
||
| <InteractiveExample src={RenderingEditorSrc} component={RenderingEditor} /> | ||
|
|
||
| :::caution | ||
|
|
||
| On iOS and Android, `EnrichedText` does not sanitize HTML for you. Sanitize anything you render that | ||
| came from users or other untrusted sources. To know more about the web's built-in sanitization, visit [Web support](/core-functionalities/web-support#sanitization). | ||
|
|
||
| ::: | ||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,4 +4,93 @@ sidebar_position: 4 | |||||||||||
|
|
||||||||||||
| # Web support | ||||||||||||
|
|
||||||||||||
| <!-- TODO: write content for this page --> | ||||||||||||
| Both `EnrichedTextInput` and `EnrichedText` run on the web. On native the editor | ||||||||||||
| is backed by the platform's text engine; on the web it is built on | ||||||||||||
| [Tiptap](https://tiptap.dev/) (on top of ProseMirror). That implementation | ||||||||||||
| detail stays behind the same public API. | ||||||||||||
|
|
||||||||||||
| ## One API across platforms | ||||||||||||
|
|
||||||||||||
| The web build exposes the **same props, ref methods, and events** as native. | ||||||||||||
| Events keep their native shape too - they arrive as | ||||||||||||
| `NativeSyntheticEvent`, read off `e.nativeEvent`, so | ||||||||||||
| [event-handling](/core-functionalities/handling-events) code is portable as-is: | ||||||||||||
|
|
||||||||||||
| ```tsx | ||||||||||||
| <EnrichedTextInput | ||||||||||||
| onChangeHtml={e => setHtml(e.nativeEvent.value)} | ||||||||||||
| onChangeState={e => setState(e.nativeEvent)} | ||||||||||||
| /> | ||||||||||||
| ``` | ||||||||||||
|
|
||||||||||||
| The interactive examples throughout these docs are the web build running live. | ||||||||||||
|
|
||||||||||||
| ## Keyboard shortcuts | ||||||||||||
|
|
||||||||||||
| The web editor ships desktop-style formatting shortcuts out of the box, along | ||||||||||||
| with native browser **undo/redo**. `Mod` is `⌘` on macOS and `Ctrl` on | ||||||||||||
| Windows/Linux. | ||||||||||||
|
Comment on lines
+30
to
+32
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think that we don't need this info about |
||||||||||||
|
|
||||||||||||
| | Action | macOS | Windows / Linux | | ||||||||||||
| | ------------------- | -------------- | --------------------------- | | ||||||||||||
| | Bold | `⌘B` | `Ctrl+B` | | ||||||||||||
| | Italic | `⌘I` | `Ctrl+I` | | ||||||||||||
| | Underline | `⌘U` | `Ctrl+U` | | ||||||||||||
| | Strikethrough | `⌘⇧X` | `Ctrl+Shift+X` | | ||||||||||||
| | Inline code | `⌘⇧C` | `Ctrl+Shift+C` | | ||||||||||||
| | Code block | `⌘⌥⇧C` | `Ctrl+Alt+Shift+C` | | ||||||||||||
| | Normal paragraph | `⌘⌥0` | `Ctrl+Alt+0` | | ||||||||||||
| | Heading 1–6 | `⌘⌥1` – `⌘⌥6` | `Ctrl+Alt+1` – `Ctrl+Alt+6` | | ||||||||||||
| | Numbered list | `⌘⇧7` | `Ctrl+Shift+7` | | ||||||||||||
| | Unordered list | `⌘⇧8` | `Ctrl+Shift+8` | | ||||||||||||
| | Checkbox list | `⌘⇧9` | `Ctrl+Shift+9` | | ||||||||||||
| | Paste as plain text | `⌘⇧V` | `Ctrl+Shift+V` | | ||||||||||||
| | Undo | `⌘Z` | `Ctrl+Z` | | ||||||||||||
| | Redo | `⌘⇧Z` | `Ctrl+Shift+Z` | | ||||||||||||
| | Select all | `⌘A` | `Ctrl+A` | | ||||||||||||
|
|
||||||||||||
| ## Platform differences | ||||||||||||
|
|
||||||||||||
| A few native-only features have no web equivalent and are ignored there: | ||||||||||||
|
|
||||||||||||
| - **`contextMenuItems`** - the native editing menu isn't available; use your own | ||||||||||||
| UI instead. | ||||||||||||
| - **`returnKeyLabel`** - can't be set inside a browser. `returnKeyType` maps to | ||||||||||||
| the browser's [`enterkeyhint`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint). | ||||||||||||
| - **RN layout ref methods** - `measure`, `measureInWindow`, `measureLayout`, and | ||||||||||||
| `setNativeProps` are no-ops. | ||||||||||||
|
|
||||||||||||
| The [`EnrichedTextInput`](/api-reference/enriched-text-input) and | ||||||||||||
| [`EnrichedText`](/api-reference/enriched-text) references note per-prop platform | ||||||||||||
| support. | ||||||||||||
|
|
||||||||||||
| :::note | ||||||||||||
|
|
||||||||||||
| On web, `onPasteImages` gives each image a `blob:` URL. If you hold onto those | ||||||||||||
| URIs, call `URL.revokeObjectURL(uri)` once you're done with them (e.g. after an | ||||||||||||
| upload) so the browser can release the memory. | ||||||||||||
|
|
||||||||||||
| ::: | ||||||||||||
|
|
||||||||||||
| ## Sanitization | ||||||||||||
|
|
||||||||||||
| Unlike the native platforms, the web build sanitizes HTML for you. It runs | ||||||||||||
| [DOMPurify](https://github.com/cure53/DOMPurify) at **every entrypoint** - the | ||||||||||||
| `children` of `EnrichedText`, and `defaultValue`, `setValue`, and pasted content | ||||||||||||
| on `EnrichedTextInput`. Sanitization is also run on the input component's **output** - `getHTML()`. | ||||||||||||
| This ensures untrusted markup can't inject scripts or unsafe attributes into the DOM. | ||||||||||||
| :::caution | ||||||||||||
|
|
||||||||||||
| Sanitization is tied to link detection: the [`linkRegex`](/rich-text-formatting/links) | ||||||||||||
| you provide determines which `href` values are allowed to survive on `<a>` | ||||||||||||
| elements. Anchors whose URLs don't match the pattern have their `href` stripped | ||||||||||||
| during sanitization. | ||||||||||||
|
|
||||||||||||
| ::: | ||||||||||||
|
|
||||||||||||
| ## Server-side rendering | ||||||||||||
|
|
||||||||||||
| The library does **not** support SSR. Normalization and sanitization both need a | ||||||||||||
| DOM to work against, which isn't available during server rendering. In an SSR | ||||||||||||
| framework (Next.js, Remix, …), make sure both `EnrichedTextInput` and | ||||||||||||
| `EnrichedText` render **client-side only**. | ||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be worth mentioning that when the cursor leaves a mention, the event fires with empty values so you can clean up any related state?