Browse Source

INT-2490: Updated react documentation (#1934)

* INT-2490: Updated react documentation

Added:
- scriptLoading
- uncontrolled component example
- prelude grouping options into categories

Changed
- Updated most examples to be current best practice
- Fixed some slightly odd English

Deprecated:
- outputFormat and documented alternative method

* INT-2490: Fixed a link to match the title it links to

* INT-2490: Improve description of event handler arguments

* INT-2490: Added missing "the" to improve text flow

* INT-2490: Skip installation of create-react-app, tweak path of App.js

* INT-2490: Explain self-hosting better

* INT-2490: Remove heading inside list

* INT-2490: Add example of script tag using PUBLIC_URL to reference tinymce

* INT-2490: Fixed `init` default value

* INT-2490: Expanded description of `value` prop

* INT-2490: Remove duplicate 'the'

Co-authored-by: Lee Newson <lee.newson@tiny.cloud>

* INT-2490: Changed `edRef` to `editorRef`

* INT-2490: Removed unchecked negative statement about bundling

* INT-2490: Added empty lines after headings

* INT-2490: Added comma

* INT-2490: Removed patch version from cloud channel examples

* INT-2490: Fixed indentation

* INT-2490: Grammer edits to the value description

* INT-2490: Remove "when possible"

* INT-2490: Removed unneeded "then"

* INT-2490: Added comma

* INT-2490: Added comma

* INT-2490: Change "build" to "channel"

* INT-2490: punctuation fixes

* INT-2490: describe iframe mode as classic mode

* INT-2490: Emphasised not to update initialValue from onEditorChange

* INT-2490: Replaced <b> with <strong>

* INT-2490: Replaced `edRef` with `editorRef`

* INT-2490: Grammer fix

* INT-2490: Reword "Change into" to "Change to"

* INT-2490: Used the react term 'prop' instead of 'property'

* Revert "INT-2490: Used the react term 'prop' instead of 'property'"

This reverts commit 44fa8da440.

* Apply suggestions from code review

Co-authored-by: Tyler Kelly <tyler.kelly@tiny.cloud>

* Apply suggestions from code review

Co-authored-by: Lee Newson <lee.newson@tiny.cloud>

* react property(ies) to prop(s)

* minor edits to react page

* Apply suggestions from code review

* Update _includes/integrations/react-tech-ref.md

Co-authored-by: Lee Newson <lee.newson@tiny.cloud>
Co-authored-by: Tyler Kelly <tyler.kelly@tiny.cloud>
pull/1939/head
James Johnson 4 years ago
committed by GitHub
parent
commit
0097e7e341
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 145
      _includes/integrations/react-quick-start.md
  2. 480
      _includes/integrations/react-tech-ref.md
  3. 1
      _includes/misc/concept-dirty-state.md

145
_includes/integrations/react-quick-start.md

@ -18,45 +18,42 @@ This procedure requires:
### Procedure
1. On a command line or command prompt, install the [Create React App](https://github.com/facebook/create-react-app) package.
1. Use the [Create React App](https://github.com/facebook/create-react-app) package to create a new React project named `tinymce-react-demo`.
```sh
$ npm install -g create-react-app
$ npx create-react-app tinymce-react-demo
```
2. Create a new React project named `tinymce-react-demo`.
```sh
$ create-react-app tinymce-react-demo
```
3. Change into the newly created directory.
2. Change to the newly created directory.
```sh
$ cd tinymce-react-demo
```
4. Install the `tinymce-react` package and save it to your `package.json` with `--save`.
3. Install the `tinymce-react` package and save it to your `package.json` with `--save`.
```sh
$ npm install --save @tinymce/tinymce-react
```
5. Using a text editor, open `/path/to/tinymce-react-demo/src/App.js` and replace the contents with:
4. Using a text editor, open `./src/App.js` and replace the contents with:
```jsx
import React from 'react';
import React, { useRef } from 'react';
import { Editor } from '@tinymce/tinymce-react';
class App extends React.Component {
handleEditorChange = (content, editor) => {
console.log('Content was updated:', content);
}
render() {
return (
export default function App() {
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
return (
<>
<Editor
initialValue="<p>This is the initial content of the editor</p>"
onInit={(evt, editor) => editorRef.current = editor}
initialValue="<p>This is the initial content of the editor.</p>"
init={% raw %}{{{% endraw %}
height: 500,
menubar: false,
@ -65,22 +62,21 @@ This procedure requires:
'searchreplace visualblocks code fullscreen',
'insertdatetime media table paste code help wordcount'
],
toolbar:
'undo redo | formatselect | bold italic backcolor | \
alignleft aligncenter alignright alignjustify | \
bullist numlist outdent indent | removeformat | help'
toolbar: 'undo redo | formatselect | ' +
'bold italic backcolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
{% raw %}}}{% endraw %}
onEditorChange={this.handleEditorChange}
/>
);
}
<button onClick={log}>Log editor content</button>
</>
);
}
export default App;
```
This JavaScript file will create the class `App` containing a {{site.productname}} editor configured to replicate the example on the [Basic example page]({{site.baseurl}}/demo/basic-example/).
6. Provide access to {{site.productname}} using either {{site.cloudname}} or by self-hosting {{site.productname}}.
5. Provide access to {{site.productname}} using either {{site.cloudname}} or by self-hosting {{site.productname}}.
* **{{site.cloudname}}**
@ -96,22 +92,101 @@ This procedure requires:
{{site.productname}} can be self-hosted by: deploying {{site.productname}} independent of the React application, or bundling {{site.productname}} with the React application.
* **Deploy {{site.productname}} independent of the React application**
* **Deploy {{site.productname}} independent of the React application using `tinymceScriptSrc`**
To use an independent deployment of {{site.productname}}, add a script to either the `<head>` or the end of the `<body>` of the HTML file, such as:
To use an independent deployment of {{site.productname}}, add the `tinymceScriptSrc` prop to specify the path to the {{site.productname}} script, such as:
```jsx
<Editor tinymceScriptSrc="/path/to/tinymce.min.js" />
```
To use `tinymceScriptSrc` with the `create-react-app` project, put the {{site.productname}} distribution in `./public` folder
and reference the path to the `public` folder using the environment
variable `process.env.PUBLIC_URL`, such as:
```jsx
<Editor tinymceScriptSrc={process.env.PUBLIC_URL + '/tinymce/tinymce.min.js'}>
```
* **Deploy {{site.productname}} independent of the React application with a script tag**
An alternative method is to add a script to either the `<head>` or the
end of the `<body>` of the HTML file, such as:
```html
<script src="/path/to/tinymce.min.js"></script>
```
To use an independent deployment of {{site.productname}} with the create a React application, add the script to `/path/to/tinymce-react-demo/public/index.html`.
To use the independently sourced {{site.productname}} with create-react-app, add the script tag to `./public/index.html`.
For information on self-hosting {{site.productname}}, see: [Installing {{ site.productname }}]({{site.baseurl}}/general-configuration-guide/advanced-install/).
Normally the tinymce distribution would be put in the `public` folder
and referenced using the URL `%PUBLIC_URL%/tinymce/tinymce.min.js`, such as:
```html
<script src="%PUBLIC_URL%/tinymce/tinymce.min.js"></script>
```
For information on self-hosting {{site.productname}}, see: [Installing {{site.productname}}]({{site.baseurl}}/general-configuration-guide/advanced-install/).
* **Bundling {{site.productname}} with the React application using a module loader**
{{site.companyname}} does not recommend bundling `tinymce` and `tinymce-react` with a module loader. Bundling these packages can be complex and error prone.
To bundle {{site.productname}} using a module loader (such as Webpack and Browserify), see: [Usage with module loaders]({{site.baseurl}}/advanced/usage-with-module-loaders/).
7. Test the application using the Node.js development server.
Example of bundling:
```jsx
import { Editor } from '@tinymce/tinymce-react';
// TinyMCE so the global var exists
// eslint-disable-next-line no-unused-vars
import tinymce from 'tinymce/tinymce';
// Theme
import 'tinymce/themes/silver';
// Toolbar icons
import 'tinymce/icons/default';
// Editor styles
import 'tinymce/skins/ui/oxide/skin.min.css';
// importing the plugin js.
import 'tinymce/plugins/advlist';
import 'tinymce/plugins/autolink';
import 'tinymce/plugins/link';
import 'tinymce/plugins/image';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/charmap';
import 'tinymce/plugins/hr';
import 'tinymce/plugins/anchor';
import 'tinymce/plugins/spellchecker';
import 'tinymce/plugins/searchreplace';
import 'tinymce/plugins/wordcount';
import 'tinymce/plugins/code';
import 'tinymce/plugins/fullscreen';
import 'tinymce/plugins/insertdatetime';
import 'tinymce/plugins/media';
import 'tinymce/plugins/nonbreaking';
import 'tinymce/plugins/table';
import 'tinymce/plugins/template';
import 'tinymce/plugins/help';
// Content styles, including inline UI like fake cursors
/* eslint import/no-webpack-loader-syntax: off */
import contentCss from '!!raw-loader!tinymce/skins/content/default/content.min.css';
import contentUiCss from '!!raw-loader!tinymce/skins/ui/oxide/content.min.css';
export default function TinyEditorComponent(props) {
// note that skin and content_css is disabled to avoid the normal
// loading process and is instead loaded as a string via content_style
return (
<Editor
init={% raw %}{{{% endraw %}
skin: false,
content_css: false,
content_style: [contentCss, contentUiCss].join('\n'),
{% raw %}}}{% endraw %}
/>
);
}
```
6. Test the application using the Node.js development server.
* To start the development server, navigate to the `tinymce-react-demo` directory and run:
```sh

480
_includes/integrations/react-tech-ref.md

@ -2,9 +2,9 @@
**Covered in this section:**
- [Installing the TinyMCE React integration using the NPM](#installingthetinymcereactintegrationusingnpm)
- [Installing the TinyMCE React integration using NPM or Yarn](#installingthetinymcereactintegrationusingnpmoryarn)
- [Configuring the editor](#configuringtheeditor)
- [Available props](#availableprops)
- [`apiKey`](#apikey)
- [`cloudChannel`](#cloudchannel)
- [`disabled`](#disabled)
@ -13,18 +13,20 @@
- [`initialValue`](#initialvalue)
- [`inline`](#inline)
- [`onEditorChange`](#oneditorchange)
- [`outputFormat`](#outputformat)
- [`outputFormat` (*deprecated*)](#outputformat)
- [`plugins`](#plugins)
- [`scriptLoading`](#scriptloading)
- [`tagName`](#tagname)
- [`textareaName`](#textareaname)
- [`toolbar`](#toolbar)
- [`tinymceScriptSrc`](#tinymcescriptsrc)
- [`value`](#value)
- [Using the TinyMCE React component as a uncontrolled component](#usingthetinymcereactcomponentasauncontrolledcomponent)
- [Using the TinyMCE React component as a controlled component](#usingthetinymcereactcomponentasacontrolledcomponent)
- [Event binding](#eventbinding)
### Installing the TinyMCE React integration using NPM
### Installing the TinyMCE React integration using NPM or Yarn
To install the `tinymce-react` package and save it to your `package.json`.
@ -32,32 +34,95 @@ To install the `tinymce-react` package and save it to your `package.json`.
$ npm install --save @tinymce/tinymce-react
```
### Configuring the editor
The editor accepts the following properties:
or with Yarn
```jsx
<Editor
apiKey='your-api-key'
cloudChannel='{{site.productmajorversion}}-stable'
disabled={false}
id='uuid'
init= {% raw %}{{{% endraw %} {% raw %}}}{% endraw %}
initialValue=''
inline={false}
onEditorChange={}
plugins=''
tagName='div'
textareaName=''
toolbar=''
value=''
/>
```sh
$ yarn add @tinymce/tinymce-react
```
None of the configuration properties are **required** for `tinymce-react` to work. Specify a {{site.cloudname}} API key using `apiKey` to remove the `This domain is not registered...` warning message.
### Configuring the editor
The `tinymce-react` component provides props for:
- [Configuring editor source](#configuringeditorsource)
- [Configuring page elements](#configuringpageelements)
- [Configuring editor settings](#configuringeditorsettings)
- [Managing the editor](#managingtheeditor)
#### Configuring editor source
The `tinymce-react` integration will try to source {{site.productname}} in the following order:
1. The global `tinymce` will be used, if it is present on the page.
2. If the `tinymceScriptSrc` prop is provided, then a script tag will be added to the page to load {{site.productname}} from the given URL.
3. If none of the above conditions apply, then a script tag will be added to the page to load {{site.productname}} from {{site.cloudname}}.
These props are used to configure how the editor is sourced:
<dl>
<dt><a href="#apikey"><code>apiKey</code></a></dt>
<dd>The {{site.cloudname}} API key. When loading from {{site.cloudname}}, use this prop to remove the &quot;This domain is not registered...&quot; warning message.</dd>
<dt><a href="#cloudchannel"><code>cloudChannel</code></a></dt>
<dd>The channel of {{site.productname}} used when loading from {{site.cloudname}}.</dd>
<dt><a href="#scriptloading"><code>scriptLoading</code></a></dt>
<dd>The script loading behavior prop. Allows setting of the <code>async</code> and <code>defer</code> attributes, as well as adding an additional delay in milliseconds.</dd>
<dt><a href="#tinymcescriptsrc"><code>tinymceScriptSrc</code></a></dt>
<dd>The URL to use for sourcing {{site.productname}}, when loading a self-hosted version of {{site.productname}}.</dd>
</dl>
#### Configuring page elements
These props provide some control over the page elements that the integration creates:
<dl>
<dt><a href="#id"><code>id</code></a></dt>
<dd>The id attribute of the element that the editor is initialized on.</dd>
<dt><a href="#inline"><code>inline</code></a></dt>
<dd>Load the editor as part of the page&#59; sharing the page styles and selection.</dd>
<dt><a href="#tagname"><code>tagName</code></a></dt>
<dd>The tag used for creating an inline editor. Ignored for a classic (iframe) editor.</dd>
<dt><a href="#textareaname"><code>textareaName</code></a></dt>
<dd>The name attribute on the textarea tag (HTML element). Used for creating the classic (iframe) editor. Ignored for an inline editor.</dd>
</dl>
#### Configuring editor settings
These props are read when the editor is initialized. Changes after the editor has launched are ignored.
<dl>
<dt><a href="#init"><code>init</code></a></dt>
<dd>Additional options passed to {{site.productname}} when it is initialized.</dd>
<dt><a href="#plugins"><code>plugins</code></a></dt>
<dd>Specify the editor plugins. This will be <em>combined</em> with <code>plugins</code> in the <code>init</code> prop.</dd>
<dt><a href="#toolbar"><code>toolbar</code></a></dt>
<dd>Specify the editor toolbar. This will <strong>override</strong> the <code>toolbar</code> in the <code>init</code> prop.</dd>
</dl>
#### Managing the editor
These props can be updated after the editor is initialized. Note that there are [other events](#eventbinding) not mentioned here.
<dl>
<dt><a href="#disabled"><code>disabled</code></a></dt>
<dd>Should the editor be in read-only mode.</dd>
<dt><a href="#initialvalue"><code>initialValue</code></a></dt>
<dd>The starting value of the editor. Changing this value after the editor has loaded will reset the editor (including the editor content).</dd>
<dt><a href="#eventbinding"><code>onBeforeAddUndo</code></a></dt>
<dd>An event handler for notifying when the editor is about to create an undo level, and preventing it if required. This is important for controlled components that restrict the allowed values of the editor.</dd>
<dt><a href="#oneditorchange"><code>onEditorChange</code></a></dt>
<dd>An event handler for detecting editor changes. Useful when implementing {{site.productname}} as a controlled component.</dd>
<dt><a href="#eventbinding"><code>onInit</code></a></dt>
<dd>An event handler for notifying when the editor has initialized. Useful for getting the initial value of the editor or obtaining a reference to the editor that can be used for a uncontrolled component.</dd>
<dt><a href="#value"><code>value</code></a></dt>
<dd>Sets and enforces the value of the editor. Only used for a controlled component.</dd>
</dl>
### Available props
None of the configuration props are **required** for the {{site.productname}} React component; however, if the `apiKey` prop is not configured when loading from {{site.cloudname}}, a warning message will be shown in the editor. For guidance about which props to use, see: [Configuring the editor](#configuringtheeditor).
#### `apiKey`
{{site.cloudname}} API key. Required for deployments using the {{site.cloudname}} to provide the {{site.productname}} editor.
{{site.cloudname}} API key.
Required for deployments using the {{site.cloudname}} to provide the {{site.productname}} editor without the warning message "This domain is not registered...".
To register for a {{site.cloudname}} API key, visit the [sign-up page]({{site.accountsignup}}).
@ -75,15 +140,18 @@ To register for a {{site.cloudname}} API key, visit the [sign-up page]({{site.ac
#### `cloudChannel`
Changes the {{site.productname}} build used for the editor to either a specific version or a channel indicating a stability level.
**Default value:** `{{site.productmajorversion}}-stable`
**Possible values:** `{{site.productmajorversion}}-stable`, `{{site.productmajorversion}}-testing`, `{{site.productmajorversion}}-dev`
**Possible values:** `{{site.productmajorversion}}-stable`, `{{site.productmajorversion}}-testing`, `{{site.productmajorversion}}-dev`, `{{site.productminorversion}}`
Changes the {{site.productname}} build used for the editor to one of the following {{site.cloudname}} channels:
- `{{site.productmajorversion}}-stable` (**Default**): The current enterprise release of {{site.productname}}.
- `{{site.productmajorversion}}-testing`: The current release candidate for the next enterprise release of {{site.productname}}.
- `{{site.productmajorversion}}-dev`: The nightly-build version of {{site.productname}}.
- A version number such as `{{site.productminorversion}}`: The specific enterprise release version of {{site.productname}}.
Such as:
@ -94,10 +162,12 @@ Such as:
init={% raw %}{{{% endraw %} /* your other settings */ {% raw %}}}{% endraw %}
/>
```
For information {{site.productname}} development channels, see: [Specifying the {{site.productname}} editor version deployed from Cloud - dev, testing, and stable releases]({{site.baseurl}}/cloud-deployment-guide/editor-plugin-version/#devtestingandstablereleases).
#### `disabled`
The `disabled` property can dynamically switch the editor between a "disabled" (read-only) mode (`true`) and the standard editable mode (`false`).
The `disabled` prop can dynamically switch the editor between a "disabled" (read-only) mode (`true`) and the standard editable mode (`false`).
**Default value:** `false`
@ -112,7 +182,8 @@ The `disabled` property can dynamically switch the editor between a "disabled" (
```
#### `id`
An id for the editor. Used for retrieving the editor instance using the `tinymce.get('ID')` method. Defaults to an automatically generated [UUID](https://tools.ietf.org/html/rfc4122).
An id for the editor. Used for retrieving the editor instance using the `tinymce.get('ID')` method.
**Default value:** Automatically generated [UUID](https://tools.ietf.org/html/rfc4122).
@ -122,16 +193,21 @@ An id for the editor. Used for retrieving the editor instance using the `tinymce
```jsx
<Editor
id='uuid'
id='your-id'
/>
```
#### `init`
Object sent to the `tinymce.init` method used to initialize the editor.
For information on the {{site.productname}} selector (`tinymce.init`), see: [Basic setup]({{site.baseurl}}/general-configuration-guide/basic-setup/).
Additional settings passed to the `tinymce.init({...})` method used to initialize the editor.
For information on the {{site.productname}} `tinymce.init({...})` method, see: [Basic setup]({{site.baseurl}}/general-configuration-guide/basic-setup/).
When using `tinymce-react`:
- The `init` prop does not require the `selector` or `target` options
- If the `selector`, `target`, or `readonly` options are set using the `init` prop, they will be *overridden* by the integration.
**Default value:** `{% raw %}{{{% endraw %} {% raw %}}}{% endraw %}`
**Default value:** `{ }`
**Type:** Object
@ -140,7 +216,6 @@ For information on the {{site.productname}} selector (`tinymce.init`), see: [Bas
```jsx
<Editor
init={% raw %}{{{% endraw %}
selector: 'textarea#myTextArea',
plugins: [
'lists link image paste help wordcount'
],
@ -150,22 +225,45 @@ For information on the {{site.productname}} selector (`tinymce.init`), see: [Bas
```
#### `initialValue`
Initial content of the editor when the editor is initialized.
**Default value:** `' '`
The initial HTML content of the editor. This will reset the editor undo state and the cursor position when changed.
This may be set either before the editor loads, or soon afterwards by an asynchronous
process.
> **Important**: Ensure that this is **not** updated by `onEditorChange` or the editor will be unusable.
**Default value:** `''`
**Type:** String
##### Example: Using `initialValue`
##### Example: Using static `initialValue`
```jsx
<Editor
initialValue='Once upon a time...'
initialValue='<p>Once upon a time...</p>'
/>
```
##### Example: Using asynchronous `initialValue`
```jsx
const [initialValue, setInitialValue] = useState(undefined);
useEffect(() => {
// a real application might do a fetch request here to get the content
setTimeout(() => setInitialValue('<p>Once upon a time...</p>'), 500);
}, []);
return (
<Editor
initialValue={initialValue}
/>
);
```
#### `inline`
Used to set the editor to inline mode. Using `<Editor inline={true} />` is the same as setting `{inline: true}` in the {{site.productname}} selector (`tinymce.init`).
Used to set the editor to inline mode. Using `<Editor inline={true} />` is the same as setting `{inline: true}` in the {{site.productname}} `tinymce.init({...})` method.
For information on inline mode, see: [User interface options - `inline`]({{site.baseurl}}/configure/editor-appearance/#inline) and [Setup inline editing mode]({{site.baseurl}}/general-configuration-guide/use-tinymce-inline/).
@ -182,15 +280,33 @@ For information on inline mode, see: [User interface options - `inline`]({{site.
```
#### `onEditorChange`
Used to store the state of the editor outside the editor React component. This property is commonly used when using the {{site.productname}} React component as a controlled component. Use the [`outputFormat`](#outputformat) prop to specify the format of the content emitted.
For more information, see: [Using the {{site.productname}} React component as a controlled component](#usingthetinymcereactcomponentasacontrolledcomponent).
Used to store the state of the editor outside the {{site.productname}} React component.
This prop is commonly used when using the {{site.productname}} React component as a controlled component.
It is called with two arguments:
<dl>
<dt><code>value</code></dt>
<dd>The current value of the editor. This is normally HTML but can be text if the deprecated <a href="#outputformat"><code>outputFormat</code></a> prop is used.</dd>
<dt><code>editor</code></dt>
<dd>A reference to the editor.</dd>
</dl>
For detailed information on using `onEditorChange`, see: [Using the {{site.productname}} React component as a controlled component](#usingthetinymcereactcomponentasacontrolledcomponent).
**Type:** EventHandler
#### `outputFormat`
Used to specify the format of the content emitted via the [`onEditorChange`](#oneditorchange) event.
> **Important**: This option was deprecated with the release of the {{site.productname}}
React component 3.11.0. The `outputFormat` option will be removed in a future
release of the {{site.productname}} React component.
Used to specify the format of the content produced by the [`onEditorChange`](#oneditorchange) event.
This does not change the input format, so the editor must still be supplied HTML
in the `value` or `initialValue`, which makes this prop much harder to use
correctly than it initially seems.
**Type:** String
@ -201,13 +317,55 @@ Used to specify the format of the content emitted via the [`onEditorChange`](#on
##### Example: Using `outputFormat`
```jsx
<Editor
outputFormat='text'
/>
const textToHtml = (text) => {
const elem = document.createElement('div');
return text.split(/\n\n+/).map((paragraph) => {
return '<p>' + paragraph.split(/\n+/).map((line) => {
elem.textContent = line;
return elem.innerHTML;
}).join('<br/>') + '</p>';
}).join('');
};
const initialText = 'The quick brown fox jumps over the lazy dog';
const [text, setText] = useState(initialText);
return (
<>
<Editor
initialValue={textToHtml(initialText)}
outputFormat='text'
onEditorChange={(newText) => setText(newText)}
/>
<pre>{text}</pre>
</>
);
```
##### Example: Replacing usage of `outputFormat`
```jsx
const [value, setValue] = useState('<p>The quick brown fox jumps over the lazy dog</p>');
const [text, setText] = useState('');
return (
<>
<Editor
value={value}
onInit={(evt, editor) => {
setText(editor.getContent({format: 'text'}));
}}
onEditorChange={(newValue, editor) => {
setValue(newValue);
setText(editor.getContent({format: 'text'}));
}}
/>
<pre>{text}</pre>
</>
);
```
#### `plugins`
Used to include plugins for the editor. Using `<Editor plugins='lists' />` is the same as setting `{plugins: 'lists'}` in the {{site.productname}} selector (`tinymce.init`).
Used to include plugins for the editor. Using `<Editor plugins='lists' />` is the same as setting `{plugins: 'lists'}` in the {{site.productname}} `tinymce.init({...})` method.
For information on adding plugins to {{site.productname}}, see: [Add plugins to {{site.productname}}]({{site.baseurl}}/plugins/).
@ -221,7 +379,51 @@ For information on adding plugins to {{site.productname}}, see: [Add plugins to
/>
```
#### `scriptLoading`
Used to configure the script tag created to load {{site.productname}}.
Contains 3 settings:
<dl>
<dt><code>async</code></dt>
<dd>Sets the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-async"><code>async</code></a> attribute on the script tag created to load {{site.productname}}.
<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-async">For classic scripts, if the async attribute is present, then the classic script will be fetched in parallel to parsing and evaluated as soon as it is available.</blockquote>
<strong>Default value:</strong> <code>false</code>
</dd>
<dt><code>defer</code></dt>
<dd>Sets the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer"><code>defer</code></a> attribute on the script tag created to load {{site.productname}}.
<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer">This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed, but before firing DOMContentLoaded.</blockquote>
<strong>Default value:</strong> <code>false</code>
</dd>
<dt><code>delay</code></dt>
<dd>The script tag to load {{site.productname}} will be added after the specified delay in milliseconds.<br/>
<strong>Default value:</strong> <code>0</code>
</dd>
</dl>
**Type:** Object
```ts
{
async?: boolean;
defer?: boolean;
delay?: number;
}
```
##### Example: Loading {{site.productname}} asynchronously
```jsx
<Editor scriptLoading={% raw %}{{{% endraw %} async: true {% raw %}}}{% endraw %}>
```
##### Example: Delaying load of {{site.productname}} for 500 milliseconds
```jsx
<Editor scriptLoading={% raw %}{{{% endraw %} delay: 500 {% raw %}}}{% endraw %}>
```
#### `tagName`
Only valid when [`<Editor inline={true} />`](#inline). Used to define the HTML element for the editor in inline mode.
**Default value:** `div`
@ -233,27 +435,32 @@ Only valid when [`<Editor inline={true} />`](#inline). Used to define the HTML e
```jsx
<Editor
inline={true}
tagName='my-custom-tag'
tagName='section'
/>
```
#### `textareaName`
Sets the `name` attribute for the `textarea` element used for the editor in forms.
**Default value:** `' '`
Only valid when the editor is in classic (iframe) mode. Sets the `name` attribute for the `textarea` element used for the editor in forms.
**Default value:** `undefined`
**Type:** String
##### Example: Using `textareaName`
```jsx
<Editor
textareaName='myTextArea'
/>
<form method="post">
<Editor
textareaName='description'
/>
<button type="submit">Submit</button>
</form>
```
#### `toolbar`
Used to set the toolbar for the editor. Using `<Editor toolbar='bold' />` is the same as setting `{toolbar: 'bold'}` in the {{site.productname}} selector (`tinymce.init`).
Used to set the toolbar for the editor. Using `<Editor toolbar='bold' />` is the same as setting `{toolbar: 'bold'}` in the {{site.productname}} method `tinymce.init({...})`.
For information setting the toolbar for {{site.productname}}, see: [User interface options - toolbar]({{site.baseurl}}/configure/editor-appearance/#toolbar).
@ -271,7 +478,8 @@ For information setting the toolbar for {{site.productname}}, see: [User interfa
```
#### `tinymceScriptSrc`
Use the `tinymceScriptSrc` prop to specify an external version of TinyMCE to lazy load.
Use the `tinymceScriptSrc` prop to specify an external version of {{site.productname}} to lazy load.
**Type:** String
@ -284,33 +492,125 @@ Use the `tinymceScriptSrc` prop to specify an external version of TinyMCE to laz
```
#### `value`
This property allows the editor to be used as a controlled component by setting the `value` property and using the `onEditorChange` event.
For more information, see: [Using the {{site.productname}} React component as a controlled component](#usingthetinymcereactcomponentasacontrolledcomponent).
Sets the HTML content of the editor when operating as a controlled component.
When this prop is different to the current editor content, the editor content
will be changed to match (within 200 milliseconds) and an undo level will be created.
When the editor content changes by this mechanism, the editor will attempt to
retain the selection, however if the previous selection does not exist in the new
content, the cursor returns to the start of the document.
This prop allows the editor to be used as a controlled component by setting
the `value` prop and using the `onEditorChange` event to update the `value`.
For detailed information on using the `value` prop, see: [Using the {{site.productname}} React component as a controlled component](#usingthetinymcereactcomponentasacontrolledcomponent).
**Type:** String
### Using the TinyMCE React component as a controlled component
### Using the {{site.productname}} React component as a uncontrolled component
The {{site.productname}} React component is designed to be used as an uncontrolled component,
which allows the editor to perform well on larger documents.
When using the editor as an uncontrolled component, avoid using the `value`
and `onEditorChange` props. {{site.companyname}} recommends retrieving the editor content
when it is needed. The `onInit` event handler can be used to store a editor reference when the editor is loaded to assist with retrieving the content.
To provide visual feedback to the user when the content is ready
to be saved, use the `onDirty` event handler; combined with clearing
the editor's "dirty" state when saving the editor content.
{% include misc/concept-dirty-state.md %}
To use the editor as a [controlled component](https://reactjs.org/docs/forms.html#controlled-components), use the `onEditorChange` event instead of the `onChange` event, such as:
##### Example: Functional uncontrolled component with save button and dirty state
```jsx
function MyComponent({initialValue}) {
const editorRef = useRef(null);
const [dirty, setDirty] = useState(false);
useEffect(() => setDirty(false), [initialValue]);
const save = () => {
if (editorRef.current) {
const content = editorRef.current.getContent();
setDirty(false);
editorRef.current.setDirty(false);
// an application would save the editor content to the server here
console.log(content);
}
};
return (
<>
<Editor
initialValue={initialValue}
onInit={(evt, editor) => editorRef.current = editor}
onDirty={() => setDirty(true)}
/>
<button onClick={save} disabled={!dirty}>Save</button>
{dirty && <p>You have unsaved content!</p>}
</>
);
}
```
### Using the {{site.productname}} React component as a controlled component
> **Caution**: The controlled component can have performance problems on large
documents as it requires converting the entire document to a string on each
keystroke or modification.
To use the editor as a [controlled component](https://reactjs.org/docs/forms.html#controlled-components),
both the `value` and `onEditorChange` props are required.
The `value` prop is used to set and re-set the editor content. If it is not updated to the latest version of the editor content, the
editor will rollback any changes.
The `onEditorChange` prop is used to provide an event handler that will be run
when any change is made to the editor content. Changes to the editor must be applied to the
`value` prop within _200 milliseconds_ to prevent the changes being rolled back.
##### Example: Functional controlled component
```jsx
function MyComponent({initialValue}) {
const [value, setValue] = useState(initialValue ?? '');
useEffect(() => setValue(initialValue ?? ''), [initialValue]);
return (
<Editor
initialValue={initialValue}
value={value}
onEditorChange={(newValue, editor) => setValue(newValue)}
/>
);
}
```
##### Example: Class controlled component
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { content: '' };
this.state = { value: props.initialValue ?? '' };
this.handleEditorChange = this.handleEditorChange.bind(this);
}
handleEditorChange(content, editor) {
this.setState({ content });
componentDidUpdate(prevProps) {
if (this.props.initialValue !== prevProps.initialValue) {
this.setState({ value: this.props.initialValue ?? '' })
}
}
handleEditorChange(value, editor) {
this.setState({ value });
}
render() {
return (
<Editor
value={this.state.content}
initialValue={this.props.initialValue}
value={this.state.value}
onEditorChange={this.handleEditorChange}
/>
)
@ -318,6 +618,53 @@ class MyComponent extends React.Component {
}
```
When the editor must be restricted to avoid invalid states, such as exceeding a maximum length,
then a handler for `onBeforeAddUndo` must be added to avoid those states in the undo history.
##### Example: Limited length controlled component
```jsx
function MyComponent({initialValue, limit}) {
const sizeLimit = limit ?? 50;
const [ value, setValue ] = React.useState(initialValue ?? '');
const [ length, setLength ] = React.useState(0);
const handleInit = (evt, editor) => {
setLength(editor.getContent({ format: 'text' }).length);
};
const handleUpdate = (value, editor) => {
const length = editor.getContent({ format: 'text' }).length;
if (length <= sizeLimit) {
setValue(value);
setLength(length);
}
};
const handleBeforeAddUndo = (evt, editor) => {
const length = editor.getContent({ format: 'text' }).length;
// note that this is the opposite test as in handleUpdate
// because we are determining when to deny adding an undo level
if (length > sizeLimit) {
evt.preventDefault();
}
};
return (
<>
<Editor
initialValue={initialValue}
value={value}
onInit={handleInit}
onEditorChange={handleUpdate}
onBeforeAddUndo={handleBeforeAddUndo}
/>
<p>Remaining: {sizeLimit - length}</p>
</>
);
};
```
For information on controlled components in React, see: [React Docs - Controlled Components](https://reactjs.org/docs/forms.html#controlled-components).
### Event binding
@ -329,9 +676,12 @@ Functions can be bound to editor events, such as:
```
When the handler is called (**handlerFunction** in this example), it is called with two arguments:
* `event` - The TinyMCE event object.
* `editor` - A reference to the editor.
<dl>
<dt><code>event</code></dt>
<dd>The TinyMCE event object.</dd>
<dt><code>editor</code></dt>
<dd>A reference to the editor.</dd>
</dl>
The following events are available:
@ -396,4 +746,4 @@ The following events are available:
* `onShow`
* `onSubmit`
* `onUndo`
* `onVisualAid`
* `onVisualAid`

1
_includes/misc/concept-dirty-state.md

@ -0,0 +1 @@
> **Note**: The editor is "dirty" (or in a "dirty" state) when the user modifies editor content after initialization or the last `tinymce.editor.save()` call. This includes changes made using undo or redo.
Loading…
Cancel
Save