-
- HTML deserializer:
- parent attributes does not override child leaf attributes anymore. For example, if a span has fontSize style = 16px, and its child span has fontSize style = 18px, it's now deserializing to 18px instead of 16px.
- Inject props:
- does not inject props when node value =
inject.props.defaultNodeValue
anymore.
- does not inject props when node value =
- HTML deserializer:
-
- fix link upsert on space
getPointBefore
: will return early if the point before is in another block. RemovedmultiPaths
option as it's not used anymore.
-
#1234 by @zbeyens – Breaking changes:
- removed
components
prop:
// Before <Plate plugins={plugins} components={components} />; // After // option 1: use the plugin factory let plugins = [ createParagraphPlugin({ component: ParagraphElement, }), ]; // option 2: use createPlugins plugins = createPlugins(plugins, { components: { [ELEMENT_PARAGRAPH]: ParagraphElement, }, }); <Plate plugins={plugins} />;
- removed
options
prop:
// Before <Plate plugins={plugins} options={options} />; // After // option 1: use the plugin factory let plugins = [ createParagraphPlugin({ type: 'paragraph', }), ]; // option 2: use createPlugins plugins = createPlugins(plugins, { overrideByKey: { [ELEMENT_PARAGRAPH]: { type: 'paragraph', }, }, }); <Plate plugins={plugins} />;
key
- replacing
pluginKey
- is now required: each plugin needs a key to be retrieved by key.
- replacing
- all handlers have
plugin
as a second parameter:
// Before export type X<T = {}> = (editor: PlateEditor<T>) => Y; // After export type X<T = {}, P = {}> = ( editor: PlateEditor<T>, plugin: WithPlatePlugin<T, P> ) => Y;
serialize
no longer haselement
andleaf
properties:
type SerializeHtml = RenderFunction< PlateRenderElementProps | PlateRenderLeafProps >;
Renamed:
injectParentComponent
toinject.aboveComponent
injectChildComponent
toinject.belowComponent
overrideProps
toinject.props
transformClassName
,transformNodeValue
,transformStyle
first parameter is no longereditor
as it's provided bythen
if needed.- the previously
getOverrideProps
is now the core behavior ifinject.props
is defined.
serialize
toserializeHtml
deserialize
todeserializeHtml
- can be an array
- the old deserializer options are merged to
deserializeHtml
type DeserializeHtml = { /** * List of HTML attribute names to store their values in `node.attributes`. */ attributeNames?: string[]; /** * Deserialize an element. * Use this instead of plugin.isElement if you don't want the plugin to renderElement. * @default plugin.isElement */ isElement?: boolean; /** * Deserialize a leaf. * Use this instead of plugin.isLeaf if you don't want the plugin to renderLeaf. * @default plugin.isLeaf */ isLeaf?: boolean; /** * Deserialize html element to slate node. */ getNode?: (element: HTMLElement) => AnyObject | undefined; query?: (element: HTMLElement) => boolean; /** * Deserialize an element: * - if this option (string) is in the element attribute names. * - if this option (object) values match the element attributes. */ validAttribute?: string | { [key: string]: string | string[] }; /** * Valid element `className`. */ validClassName?: string; /** * Valid element `nodeName`. * Set '*' to allow any node name. */ validNodeName?: string | string[]; /** * Valid element style values. * Can be a list of string (only one match is needed). */ validStyle?: Partial< Record<keyof CSSStyleDeclaration, string | string[] | undefined> >; /** * Whether or not to include deserialized children on this node */ withoutChildren?: boolean; };
- handlers starting by
on...
are moved tohandlers
field.
// Before onDrop: handler; // After handlers: { onDrop: handler; }
Removed:
renderElement
is favor of:isElement
is a boolean that enables element rendering.- the previously
getRenderElement
is now the core behavior.
renderLeaf
is favor of:isLeaf
is a boolean that enables leaf rendering.- the previously
getRenderLeaf
is now the core behavior.
inlineTypes
andvoidTypes
for:isInline
is a boolean that enables inline rendering.isVoid
is a boolean that enables void rendering.
plugins
is not a parameter anymore as it can be retrieved ineditor.plugins
withInlineVoid
is now using pluginsisInline
andisVoid
plugin fields.
Renamed:
getPlatePluginType
togetPluginType
getEditorOptions
togetPlugins
getPlatePluginOptions
togetPlugin
pipeOverrideProps
topipeInjectProps
getOverrideProps
topluginInjectProps
serializeHTMLFromNodes
toserializeHtml
getLeaf
toleafToHtml
getNode
toelementToHtml
xDeserializerId
toKEY_DESERIALIZE_X
deserializeHTMLToText
tohtmlTextNodeToString
deserializeHTMLToMarks
tohtmlElementToLeaf
andpipeDeserializeHtmlLeaf
deserializeHTMLToElement
tohtmlElementToElement
andpipeDeserializeHtmlElement
deserializeHTMLToFragment
tohtmlBodyToFragment
deserializeHTMLToDocumentFragment
todeserializeHtml
deserializeHTMLToBreak
tohtmlBrToNewLine
deserializeHTMLNode
todeserializeHtmlNode
deserializeHTMLElement
todeserializeHtmlElement
Removed:
usePlateKeys
,getPlateKeys
usePlateOptions
forgetPlugin
getPlateSelection
forgetPlateEditorRef().selection
flatMapByKey
getEditableRenderElement
andgetRenderElement
forpipeRenderElement
andpluginRenderElement
getEditableRenderLeaf
andgetRenderLeaf
forpipeRenderLeaf
andpluginRenderLeaf
getInlineTypes
getVoidTypes
getPlatePluginTypes
getPlatePluginWithOverrides
mapPlatePluginKeysToOptions
withDeserializeX
forPlatePlugin.editor.insertData
Changed types:
PlateEditor
:- removed
options
forpluginsByKey
- removed
WithOverride
is not returning an extended editor anymore (input and output editors are assumed to be the same types for simplicity).PlateState
- renamed
keyChange
tokeyEditor
- removed
plugins
foreditor.plugins
- removed
pluginKeys
- removed
selection
foreditor.selection
- actions:
- removed
setSelection
,setPlugins
,setPluginKeys
- removed
incrementKeyChange
for
- removed
- renamed
Renamed types:
XHTMLY
toXHtmlY
Deserialize
toDeseralizeHtml
Removed types:
PlatePluginOptions
:type
toPlatePlugin.type
component
toPlatePlugin.component
deserialize
toPlatePlugin.deserializeHtml
getNodeProps
toPlatePlugin.props.nodeProps
hotkey
toHotkeyPlugin
clear
toToggleMarkPlugin
defaultType
is hardcoded top.type
OverrideProps
forPlatePlugin.inject.props
Serialize
forPlatePlugin.serializeHtml
NodeProps
forAnyObject
OnKeyDownElementOptions
forHotkeyPlugin
OnKeyDownMarkOptions
forToggleMarkPlugin
WithInlineVoidOptions
GetNodeProps
forPlatePluginProps
DeserializeOptions
,GetLeafDeserializerOptions
,GetElementDeserializerOptions
,GetNodeDeserializerOptions
,GetNodeDeserializerRule
,DeserializeNode
forPlatePlugin.deserializeHtml
PlateOptions
RenderNodeOptions
DeserializedHTMLElement
- removed
-
#1234 by @zbeyens –
PlatePlugin
extended:- These fields are used by
withInsertData
plugin.
interface PlatePlugin { editor?: Nullable<{ insertData?: { /** * Format to get data. Example data types are text/plain and text/uri-list. */ format?: string; /** * Query to skip this plugin. */ query?: (options: PlatePluginInsertDataOptions) => boolean; /** * Deserialize data to fragment */ getFragment?: ( options: PlatePluginInsertDataOptions ) => TDescendant[] | undefined; // injected /** * Function called on `editor.insertData` just before `editor.insertFragment`. * Default: if the block above the selection is empty and the first fragment node type is not inline, * set the selected node type to the first fragment node type. * @return if true, the next handlers will be skipped. */ preInsert?: ( fragment: TDescendant[], options: PlatePluginInsertDataOptions ) => HandlerReturnType; /** * Transform the inserted data. */ transformData?: ( data: string, options: { dataTransfer: DataTransfer } ) => string; /** * Transform the fragment to insert. */ transformFragment?: ( fragment: TDescendant[], options: PlatePluginInsertDataOptions ) => TDescendant[]; }; }>; }
inject.pluginsByKey
:
interface PlatePlugin { inject?: { /** * Any plugin can use this field to inject code into a stack. * For example, if multiple plugins have defined * `inject.editor.insertData.transformData` for `key=KEY_DESERIALIZE_HTML`, * `insertData` plugin will call all of these `transformData` for `KEY_DESERIALIZE_HTML` plugin. * Differs from `overrideByKey` as this is not overriding any plugin. */ pluginsByKey?: Record<PluginKey, Partial<PlatePlugin<T>>>; }; }
options
: any plugin can use the second generic type to type this field. It means that each plugin can be extended using this field.type
is now optionalcomponent
: no longer need ofoptions
to customize the component.overrideByKey
: a plugin can override other plugins by key (deep merge).plugins
:- Can be used to pack multiple plugins, like the heading plugin.
- Plate eventually flats all the plugins into
editor.plugins
. - nesting support (recursive)
props
: Override nodecomponent
props. Props object or function with props parameters returning the new props. Previously done byoverrideProps
andgetNodeProps
options.then
: a function that is called after the plugin is loaded.- this is very powerful as it allows you to have plugin fields derived from the editor and/or the loaded plugin.
- nesting support (recursive)
interface PlatePlugin { /** * Recursive plugin merging. * Can be used to derive plugin fields from `editor`, `plugin`. * The returned value will be deeply merged to the plugin. */ then?: ( editor: PlateEditor<T>, plugin: WithPlatePlugin<T, P> ) => Partial<PlatePlugin<T, P>>; }
New plugins:
createEventEditorPlugin
(core)createInsertDataPlugin
withInsertData
- all plugins using
editor.insertData
field will be used here - it first gets the data with
format
- then it pipes
query
- then it pipes
transformData
- then it calls
getFragment
- then it pipes
transformFragment
- then it pipes
insertFragment
- all plugins using
New utils:
@udecode/plate-common
has been merged into this package as both packages were dependencies of the exact same packages.@udecode/plate-html-serializer
has been merged into this package.@udecode/plate-ast-serializer
has been merged into this package.@udecode/plate-serializer
has been merged into this package.createPlateEditor
: Create a plate editor with:createEditor
or customeditor
withPlate
- custom
components
createPluginFactory
: Create plugin factory with a default plugin.- The plugin factory:
- param 1
override
can be used to (deeply) override the default plugin. - param 2
overrideByKey
can be used to (deeply) override a nested plugin (in plugin.plugins) by key.
- param 1
- The plugin factory:
createPlugins
: Creates a new array of plugins by overriding the plugins in the original array.- Components can be overridden by key using
components
in the second param. - Any other properties can be overridden by key using
overrideByKey
in the second param.
- Components can be overridden by key using
findHtmlParentElement
flattenDeepPlugins
: Recursively mergeplugin.plugins
intoeditor.plugins
andeditor.pluginsByKey
mergeDeepPlugins
: Recursively merge nested plugins into the root plugins.getInjectedPlugins
:- Get all plugins having a defined
inject.pluginsByKey[plugin.key]
. - It includes
plugin
itself.
- Get all plugins having a defined
getPluginInjectProps
getPluginOptions
getPluginsByKey
mockPlugin
overridePluginsByKey
: Recursive deep merge of each plugin fromoverrideByKey
into plugin with same key (plugin
>plugin.plugins
).pipeInsertDataQuery
pipeInsertFragment
pipeTransformData
pipeTransformFragment
setDefaultPlugin
setPlatePlugins
: Flatten deep plugins then set editor.plugins and editor.pluginsByKeydeserializeHtmlNodeChildren
isHtmlComment
isHtmlElement
isHtmlText
pluginDeserializeHtml
New selectors:
usePlateKey
New types:
HotkeyPlugin
–hotkey
ToggleMarkPlugin
–hotkey
,mark
OverrideByKey
WithPlatePlugin
:PlatePlugin
with requiredtype
,options
,inject
andeditor
.Plate
will create default values if not defined.
Extended types:
PlateEditor
:plugins
: list of the editor pluginspluginsByKey
: map of the editor plugins
PlateState
:keyPlugins
: A key that is incremented on eacheditor.plugins
change.keySelection
: A key that is incremented on eacheditor.selection
change.
WithPlateOptions
:disableCorePlugins
- disable core plugins if you'd prefer to have more control over the plugins order.
- These fields are used by
- #1190 by @zbeyens –
- renamed:
SPEditor
toPEditor
(note thatPlateEditor
is the new default)SPRenderNodeProps
toPlateRenderNodeProps
SPRenderElementProps
toPlateRenderElementProps
SPRenderLeafProps
toPlateRenderLeafProps
useEventEditorId
tousePlateEventId
useStoreEditorOptions
tousePlateOptions
useStoreEditorRef
tousePlateEditorRef
useStoreEditorSelection
tousePlateSelection
useStoreEditorState
tousePlateEditorState
useStoreEditorValue
tousePlateValue
useStoreEnabled
tousePlateEnabled
useStorePlate
tousePlatePlugins
useStorePlatePluginKeys
tousePlateKeys
useStoreState
tousePlateState
getPlateId
: Get the last focused editor id, else get the last blurred editor id, else get the first editor id, elsenull
getPlateState
:- removed first parameter
state
- previously when giving no parameter, it was returning the first editor. Now it's returning the editor with id =
getPlateId()
. It meansuseEventEditorId('focus')
is no longer needed forusePlateEditorRef
usePlateEditorState
usePlateX
...
- removed first parameter
- renamed:
-
getEditableRenderElement
: now uses pluginsinjectChildComponent
to wrapchildren
(lowest)getEditableRenderElement
: now uses pluginsinjectParentComponent
to wrapcomponent
(highest)- new store selectors:
getPlateEditorRef
getPlateEnabled
getPlateKeys
getPlatePlugins
getPlateSelection
getPlateValue
getPlateEventId
Types:
PlatePlugin
,PlatePluginEditor
new fields:injectChildComponent
: Inject child component around any node children.injectParentComponent
: Inject parent component around any nodecomponent
.overrideProps
supports arrays.
SPRenderNodeProps
new fields:editor: PlateEditor
plugins: PlatePlugin
- new types:
PlateEditor<T = {}>
: default editor type used in Plate, assuming we all use history and react editors.InjectComponent
type InjectComponent = <T = AnyObject>( props: PlateRenderElementProps & T ) => RenderFunction<PlateRenderElementProps> | undefined;
87b133ce
by @zbeyens –- slate
DefaultLeaf
does not spread the props to the rendered span so we're using our ownDefaultLeaf
component which does it. It enables us to override the props leaves without having to register a component (e.g. fontColor)
- slate
-
#1154 by @zbeyens – generic type support:
getEditorOptions
getPlatePluginOptions
PlatePluginOptions
PlateOptions
-
#1150 by @jeffsee55 –
- Fixes dependencie issue for React<17 users by using the classic
React.createElement
function rather than the newerjsx-runtime
transform. - Per babel docs: https://babeljs.io/docs/en/babel-preset-react#with-a-configuration-file-recommended
- Fixes dependencie issue for React<17 users by using the classic
- #1126
7ee21356
Thanks @zbeyens! - feat:PlatePlugin
- new field:
overrideProps
- Overrides rendered node props (shallow merge).
- This enables controlling the props of any node component (use cases: indent, align,...).
- used by
pipeRenderElement
andpipeRenderLeaf
- new field:
getRenderElement
andgetRenderLeaf
:- pass the rest of the props to the component
getRenderNodeProps
:- computes slate class and
nodeProps
- computes slate class and
- new dependency:
clsx
- new types:
OverrideProps
PlatePluginEditor
PlatePluginSerialize
PlatePluginNode
PlatePluginElement
PlatePluginLeaf
- #1063
6af469cd
Thanks @ghingis! - addnormalizeInitialValue
prop toPlate
. Whentrue
, it will normalize the initial value passed to theeditor
once it's created. This is useful when adding normalization rules on already existing content. Default isfalse
.
- #1022
35caf35d
Thanks @zbeyens! -overrideProps
: new plate option used bygetRenderElement
andgetRenderLeaf
- If it's a function, its return value will override the component props.
- If it's an object, it will override the component props.
🎉 The Slate Plugins project has evolved to Plate 🎉
To migrate, find and replace all occurrences of:
slate-plugins
toplate
SlatePlugins
toPlate
SlatePlugin
toPlatePlugin
This is the last version of
@udecode/slate-plugins[-x]
, please install@udecode/plate[-x]
.
- #869
7c26cf32
Thanks @zbeyens! - - New plugin optiondeserialize.getFragment
: Function called oneditor.insertData
to filter the fragment to insert.- New plugin option
deserialize.preInsert
: Function called oneditor.insertData
just beforeeditor.insertFragment
. Default: if the block above the selection is empty and the first fragment node type is not inline, set the selected node type to the first fragment node type. If returns true, the next handlers will be skipped.
- New plugin option
- #855
75b39f18
Thanks @zbeyens! - Sometimes we want to preventDefault without stopping the handler pipeline, so we remove this check. In summary, to stop the pipeline, a handler has to returntrue
or runevent.stopPropagation()
- #853
abaf4a11
Thanks @zbeyens! - Before, the handlers had to returnfalse
to prevent the next handlers to be called. Now, we reuseisEventHandled
internally used by[email protected]
which has the opposite behavior: a handler has to returntrue
to stop the pipeline. Additionally, the pipeline stops if at any momentevent.isDefaultPrevented()
orevent.isPropagationStopped()
returnstrue
, except if the handler returnsfalse
. See the updated docs in "Creating Plugins".
- #840
42360b44
Thanks @zbeyens! - fix:- Plugin handlers are now run when a handler is passed to
editableProps
- If one handler returns
true
, slate internal corresponding handler is not called anymore
- Plugin handlers are now run when a handler is passed to
- #773
15048e6f
Thanks @zbeyens! - fix: before, store setValue was called at the start ofonChange
pipeline. Now, it's called at the end of the pipeline so we can make use of this value as the "previous value" in pluginsonChange
.
- #723
806e1632
Thanks @Aedron! - feat: newSlatePlugins
option -renderEditable
: CustomEditable
node
- #687
dfbde8bd
Thanks @zbeyens! - changes:- renamed:
useTSlate
touseEditorState
useTSlateStatic
touseEditorRef
useStoreEditor
touseStoreEditorRef
- removed:
useEditorId
in favor ofuseEditorRef().id
useEditorOptions
in favor ofuseEditorRef().options
useSlatePluginOptions
in favor ofgetSlatePluginOptions(useEditorRef(), pluginKey)
useSlatePluginType
in favor ofgetSlatePluginType(useEditorRef(), pluginKey)
pipeOnDOMBeforeInput
in favor ofpipeHandler
pipeOnKeyDown
in favor ofpipeHandler
- types:
- renamed:
SlatePluginsState
toSlatePluginsStates
State
toSlatePluginsState
- removed:
OnDOMBeforeInput
in favor ofDOMHandler<'onDOMBeforeInput'>
OnKeyDown
in favor ofKeyboardHandler
- renamed:
- renamed:
- #687
dfbde8bd
Thanks @zbeyens! - changes:useEditableProps
(used bySlatePlugins
):- new fields returned: all handler props from the plugins (if defined)
- new core plugins with the following fields:
onFocus: setEventEditorId('focus', id)
onBlur: setEventEditorId('blur', id)
- You can add your own handlers in a plugin
EditorStateEffect
: a new component used bySlatePlugins
to update the editor state.setEventEditorId
: a new action. Set an editor id by event key.eventEditorStore
,useEventEditorStore
: a new store. Store where the keys are event names and the values are editor ids.usePlateEventId
: a new selector. Get the editor id byevent
key.useStoreEditorSelection
: a new selector. Get the editor selection which is updated on editor change.useStoreEditorState
: a new selector. Get editor state which is updated on editor change. Similar touseSlate
.SlatePlugin
: the previous plugin could implement the following handlers:onChange
,onDOMBeforeInput
andonKeyDown
. The plugins now implement all DOM handlers: clipboard, composition, focus, form, image, keyboard, media, mouse, selection, touch, pointer, ui, wheel animation and transition events.SlatePluginsState
(store interface):- a new field
keyChange
incremented bySlatePlugins
onuseSlate
update. - a new field
selection = editor.selection
updated onuseSlate
update.
- a new field
pipeHandler
: a new function. Generic pipe for handlers.