@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
text
content of the Text plugin - the
id
of the Text plugin focused
andeditable
states of the Text plugin
and exposes:
showSuggestions
- a flag controlling if the suggestions box should be shownsuggestionsProps
- props for theSuggestions
componenthotKeysProps
- props for theHotKeys
componenthandleHotkeys
- 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:
hasSelectionChanged
is passed toLinkControls
, where it's used a dependency in auseEffect
hook which takes care of showingLinkControls
setHasSelectionChanged
is called whenever selection changes, which incrementshasSelectionChanged
and makes sureLinkControls
visibility will be updated
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
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
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
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
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
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
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