@edtr-io/plugin-text v3.0.2
Text plugin (TextEditor)
Table of contents
Usage
An example of how to use the Text plugin can be found in ./__fixtures__/index.ts.
Structure
The ./src/index.tsx file contains and exposes the Text plugin factory function and exposes the public types.
Additionally, there are:
components- React componentshooks- plugable hooks for configurationplugins- Slate plugin filestypes- TypeScript types used across the Text plugin (React component prop types are located in their respective component files)utils- utility functions used across the Text plugin
Technical decisions
Configuration
A config argument (of TextEditorConfig type) is passed to createTextPlugin factory, when creating a new Text plugin instance.
This argument is then passed to the useTextConfig hook, where it's merged with the default settings, as well as enriched with i18n and theming.
The config object received from the useTextConfig hook is then used as the source of truth for configuration across that instance of the Text plugin.
Controls (Text plugin plugins)
Currently used Slate version only allows Slate plugins to modify the editor object. To allow for the same functionality of plugins from the earlier version of serlo-editor/edtr-io, a hook approach was used (as recommended by the creator of Slate).
The useControls hook receives the config object and exposes three properties:
createTextEditor- a function that receives a Slate editor instance and wraps it in all the configured Slate pluginstoolbarControls- the configuration for Text plugin's toolbarhandleHotkeys- keyboard shortcut handlers for configured controls
This approach allows to simply pass an array of desired controls (as controls property of the config argument) when creating a Text plugin instance, thus making the controls easily configurable for the user of Text plugin.
Suggestions (serlo-editor/edtr-io plugins)
In order to easily transform a Text plugin into another serlo-editor/edtr-io plugin, the user can simply type / into an empty Text plugin, and they will be presented with a list of suggestions. A hook approach was used to make the suggestions easily configurable.
The useSuggestions hook receives:
- current
textcontent of the Text plugin - the
idof the Text plugin focusedandeditablestates of the Text plugin
and exposes:
showSuggestions- a flag controlling if the suggestions box should be shownsuggestionsProps- props for theSuggestionscomponenthotKeysProps- props for theHotKeyscomponenthandleHotkeys- keyboard shortcut handlers for configured controls
Saving state to Redux store
In order to enable global undo/redo behavior (TODO: and maybe other things?), any content changes are saved to the store, and previous values of Editor's value and selection are saved as refs withing the instance of Text plugin component.
If a portion of the content is selected and then replaced with some text, undo will restore the replaced content and the selection. Slate Editor's value prop is used only as an initial value and changing the bound value will not result in a rerender. Therefore, we have to manually assign the value to editor.children (as recommended by the Slate team).
Simple selection changes are not saved to the store, because we don't want to undo pure selection changes.
LinkControls workaround
The LinkControls component should only be shown if the selection is currently on a link inline. But, since we don't save pure selection changes to the store, LinkControls doesn't rerender on selection changes. To work around this problem, a simple useState hook is used:
hasSelectionChangedis passed toLinkControls, where it's used a dependency in auseEffecthook which takes care of showingLinkControlssetHasSelectionChangedis called whenever selection changes, which incrementshasSelectionChangedand makes sureLinkControlsvisibility will be updated
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago