All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.
Until 1.0.0 is released, breaking changes will be added as minor or patch version bumps.
withListis now needed for nested list (back again). MovedonKeyDownListhandler for Enter and Backspace toinsertBreakanddeleteBackward.
- queries:
isSelectionInListItem
- transforms:
moveListItemDownmoveListItemUpinsertListItem
- Could not use IME in nested lists, fixed using
withList.
- Add
editoras deps inEditableonKeyDown,decorateandonDOMBeforeInput. Sometimes the editor reference can change, e.g. when resetting the editor.
EditablePlugins:onKeyDownPlugins: RunonKeyDownListthenonKeyDownof each plugin. Stop if one handler returns false. It's a way to "stop propagation". By doing so, you should carefully order your plugins.
isBlockTextEmptyAfterSelection: Is there empty text after the selection. If there is no leaf after the selected leaf, returnEditor.isEnd. Else, check if the next leaves are empty.getNextSiblingNodes: Get the next sibling nodes after a path.
- When a link was inserted at the end of a list item, we could not add a new list item after it.
- Stopping the propagation in mention
onKeyDownso pressingEnterin a list item will not insert a new list item when selecting a mention.
- markdown deserializer is now fixed by using
remark-slate
onKeyDownList: missing options fixed.
onKeyDownList: fixed a bug when inserting break at the start of a list item.
-
removed:
withResetBlockType,withBreakEmptyReset,withDeleteStartResetin favor of `ResetBlo ### Breaking Changes
-
removed:
withResetBlockType,withBreakEmptyReset,withDeleteStartResetin favor ofResetBlockTypePlugin.withList: its logic has been moved intoListPlugin(onKeyDownList).isTable,isTableRow,isTableCellin favor ofgetAboveByType.
- new plugin
ResetBlockTypePluginreplacingwithResetBlockTypeonKeyDownResetBlockType
- new editor plugin:
withRemoveEmptyNodes: Remove nodes with empty text.optionsaccepts node types where the rule applies.
- queries:
getAboveByType: Get the block above a location (default: selection) by type.isAncestorEmpty: Is an ancestor empty (empty text and no inline children).isBlockAboveEmpty: Is the block above the selection empty.
- new normalizer:
withRemoveEmptyNodes:- Remove nodes with empty text.
- Option
typeto specify which node types are targeted.
linkplugin:isUrloption with default tois-urlpackage.- Paste a string inside a link element will edit its children text but not its url.
- Uses
withRemoveEmptyNodes.
getRenderLeafis now passingleafto the component props.
- Pasting some urls was freezing the editor.
list: delete at the start of a list item will move it up.ckTypePlugin`.withList: its logic has been moved intoListPlugin(onKeyDownList).isTable,isTableRow,isTableCellin favor ofgetAboveByType.
- new plugin
ResetBlockTypePluginreplacingwithResetBlockTypeonKeyDownResetBlockType
- new editor plugin:
withRemoveEmptyNodes: Remove nodes with empty text.optionsaccepts node types where the rule applies.
- queries:
getAboveByType: Get the block above a location (default: selection) by type.isAncestorEmpty: Is an ancestor empty (empty text and no inline children).isBlockAboveEmpty: Is the block above the selection empty.
- new normalizer:
withRemoveEmptyNodes:- Remove nodes with empty text.
- Option
typeto specify which node types are targeted.
linkplugin:isUrloption with default tois-urlpackage.- Paste a string inside a link element will edit its children text but not its url.
- Uses
withRemoveEmptyNodes.
getRenderLeafis now passingleafto the component props.
- Pasting some urls was freezing the editor.
list: delete at the start of a list item will move it up.
- improved typing of
EditablePlugins
- renamed
setPropsToNodestomergeDeepToNodes
- new utils:
applyDeepToNodesdefaultsDeepToNodes
withNodeID: usedefaultsDeepToNodesinstead ofmergeDeepToNodesas we don't want to override any existing id.- missing export
- update
EditablePluginsPropsinterface.
attributeswas missing in the element plugins
- tree-shaking support for
lodash - export
isExpanded
- Removed:
styled-componentsfrom peerDependenciesAlignElementDeserializeElementin favor ofDeserializeNodeDeserializeLeafin favor ofDeserializeNodegetElementComponentin favor ofgetRenderElementHeadingEelementsListElements
- Renamed:
ActionItemtoTodoList.- Node types, full list:
ELEMENT_PARAGRAPH
ELEMENT_MENTION
ELEMENT_BLOCKQUOTE
ELEMENT_CODE_BLOCK
ELEMENT_LINK
ELEMENT_IMAGE
ELEMENT_MEDIA_EMBED
ELEMENT_TODO_LI
ELEMENT_H1
ELEMENT_H2
ELEMENT_H3
ELEMENT_H4
ELEMENT_H5
ELEMENT_H6
ELEMENT_ALIGN_LEFT
ELEMENT_ALIGN_CENTER
ELEMENT_ALIGN_RIGHT
ELEMENT_UL
ELEMENT_OL
ELEMENT_LI
ELEMENT_TABLE
ELEMENT_TH
ELEMENT_TR
ELEMENT_TD
MARK_BOLD
MARK_ITALIC
MARK_UNDERLINE
MARK_STRIKETHROUGH
MARK_CODE
MARK_SUBSCRIPT
MARK_SUPERSCRIPT
MARK_HIGHLIGHT
MARK_SEARCH_HIGHLIGHT- Plugin options follow a new structure:
For getRenderElement:
const options: ParagraphRenderElementOptions = {
// Use a unique key for each slate node.
p: {
// Give a React component or HTML tag (e.g. 'div') to render the element.
component: StyledElement,
// Give a unique type for each element.
type: ELEMENT_PARAGRAPH,
// Give props to the root of the React component.
rootProps: {
// Give a className to the React component. Give an empty string to remove the className.
className: 'slate-p',
// When using a styled component, specify the root tag to render.
as: 'p',
// Customize styled components: https://github.com/microsoft/fluentui/wiki/Component-Styling
styles: {
root: {
margin: 0,
}
}
},
},
}
For getRenderLeaf:
const options: BoldRenderLeafOptions = {
// Use a unique key for each slate node.
bold: {
// Give a React component or HTML tag (e.g. 'span') to render the leaf.
component: StyledLeaf,
// Give a unique string for each mark.
type: MARK_BOLD,
// Specify the hotkey to toggle this mark.
hotkey: 'mod+b',
// Specify the marks to clear when toggling this mark.
clear: '',
// Give props to the root of the React component.
rootProps: {
// Give a className to the React component. Give an empty string to remove the className.
className: 'slate-bold',
// When using a styled component, specify the root tag to render.
as: 'strong',
// Customize styled components: https://github.com/microsoft/fluentui/wiki/Component-Styling
styles: {
root: {
fontWeight: 600,
}
}
},
},
}
onKeyDownMarksignature updated:
// from
(
type: string,
hotkey: undefined,
options?: MarkOnKeyDownOptions
)
// to
(options: MarkOnKeyDownOptions)
HighlightPlugin:- Removed
bgoption in favor ofstylesprops.
- Removed
- Updated
getLeafDeserializer,getElementDeserializerandgetNodeDeserializer - Updated
deserializeHTMLToMarks. - Updated default hotkeys:
code:mod+estrikethrough:mod+shift+s
getNodeDeserializer- returns a list of deserializers
- options:
- updated:
node(renamed fromcreateNode): Slate node creator from HTML element. - new:
rules: List of rules the element needs to follow to be deserialized to a slate node:- updated:
nodeNames(renamed fromtagNames): Required node names to deserialize the element. Set '*' to allow any node name. - new:
className: Required className to deserialized the element. - new:
style: Required style to deserialize the element. Each value should be a (list of) string.
- updated:
- updated:
- ...
- Centralized default options for each plugin (
defaults.ts):
DEFAULTS_PARAGRAPH
DEFAULTS_MENTION
DEFAULTS_BLOCKQUOTE
DEFAULTS_CODE_BLOCK
DEFAULTS_LINK
DEFAULTS_IMAGE
DEFAULTS_MEDIA_EMBED
DEFAULTS_TODO_LIST
DEFAULTS_TABLE
DEFAULTS_LIST
DEFAULTS_HEADING
DEFAULTS_ALIGN- All element and leaf plugins use a default
className: useful for serialization. - Components:
- New:
StyledComponentStyledElementStyledLeaf
- Updated:
strikethrough:<s>tag instead of<span>with styles
- New:
- New utils:
setDefaultsβ Deep merge the default object properties that are not defined in the destination object. Used to set the default options.getRenderLeafDefaultonKeyDownMarkDefault
- Hotkeys:
- New:
highlight:mod+shift+h
- Updated:
code:mod+estrikethrough:mod+shift+s
- New:
- HTML Deserializers:
- added style deserializing for:
- superscript:
vertical-align: sub - subscript:
vertical-align: super - code:
word-wrap: break-word
- superscript:
- added style deserializing for:
- Styles updated:
blockquotecodecode-blocktable
- Decorate code block using Prismjs. It's using javascript language by default (WIP).
align: deserialize
getSelectionNodesByTyperenamed togetNodesByType- new option:
at
- new option:
isNodeInSelectionrenamed toisNodeTypeIn- new option:
at
- new option:
getBlockAboveSelectionrenamed togetBlockAbove- new option:
at
- new option:
getTextFromBlockStartToAnchorrenamed togetRangeFromBlockStart- new option:
at
- new option:
- removed
getSelectionNodesArrayByType - replaced
insertLinkbyupsertLinkAtSelection wrapLinkis now only wrapping the link (without unwrapping).@udecode/corepackage renamed to@udecode/slate-plugins-core.
AlignPluginβ new plugin for alignment.getPointBefore- new options:
multiPathsafterMatch(replacingbeforeMatch)skipInvalid
- support for multiple characters lookup.
- new options:
getRangeBeforeβ Get range fromgetPointBeforeto the end point ofat.withAutoformat:- new option type:
WithAutoformatOptions - Configurable markup to trigger the autoformatting.
- Configurable character to trigger the autoformatting.
- Configurable option to enable autoformatting in the middle of a block by inserting a block instead of updating.
- Configurable option to enable inline formatting.
- new option type:
wrapNodesβ new transform extendingTransforms.wrapNodes. Options:unhangβ to unhang range before wrapping.
getNodesβ same forEditor.nodes
withLinkβ space key should wrap the previous url with a link at the start of a block.wrapNodesβ fixed a bug where selecting an entire node then callingwrapNodeswas wrapping also the next node.
getPointBeforeβ Editor.before with additional options, useful to look for a point before a location using match options.withLinkβ Insert space after a url to wrap a link. There should be a space before the url. TODO: it's not working when the url is at the start of the block.LinkElement:- styles updated.
- supports
styles.
- when using
withLink, inserting '#' was adding a link element.
- Split the core functionality to
@udecode/slate-plugins-core
Note: Version bump only for package slate-plugins
Note: Version bump only for package slate-plugins
Note: Version bump only for package slate-plugins
Note: Version bump only for package slate-plugins
- renamed
withDeserializeHtmltowithDeserializeHTML. - changed signature of
withDeserializeHTMLto({ plugins }) - renamed most of utils in
deserialize-html, includinghtmlDeserializetodeserializeHTMLToDocumentFragment - renamed
htmlSerializetoserializeHTMLFromNodes. - removed
ToolbarCodeBlockin favor ofToolbarElementinstead. withBreakEmptyResetandwithDeleteStartResetβ renamed optionp.typetodefaultType.withToggleTypeβ renamed optionp.typetodefaultTypewithTableβ removedinsertBreakhandler that prevented to insert break inside table cells, you should now useSoftBreakPluginto allow inserting soft breaks instead.
- new types, including
SlateDocumentto enforce a valid structure to be used in<Slate> - added
inlineTypesandvoidTypesproperties to theSlatePlugininterface.EditablePluginswill setisInlineandisVoidto each provided type. withVoidandwithInlinehave been replaced bywithInlineVoid.withResetBlockTypeβ combineswithBreakEmptyResetandwithDeleteStartReset.SoftBreakPluginβ configurable rules.ExitBreakPlugin.
deserializeHTMLToDocumentFragmentcould return a fragment with emptychildren, crashing the editor. It has been fixed so all elements have at least one children (empty text) by usingSlateDocumenttype.withDeserializeHTMLwas buggy when the first inserted node is an inline element (e.g. mention element).
htmlSerializeβ function for serializing content from Slate format to HTML format.
htmlSerializeβ improved the plugin identification and also added a branch for missing types in top levels.withNodeIDβinsertNodeoperation was not creating new ids.
htmlSerializeβ function for serializing content from Slate format to HTML format.
- correctly export the React component types.
- export
withNodeID.
- renamed
withBlocktowithToggleTypeas it just toggles the type of an element (inline or not). - renamed
withImagetowithImageUpload. - renamed
VideoPluginand its atoms toMediaEmbedPlugin. - renamed
VIDEOtype toMEDIA_EMBEDand changed its value fromvideotomedia_embed. - renamed
withShortcutstowithAutoformat. - renamed
HoveringToolbartoBalloonToolbar. - renamed
MarkdownPreviewPlugintoPreviewPluginas it will be configurable to support other languages. - removed
heightprops inToolbar, usestylesinstead. - renamed
ToolbarBlocktoToolbarElement. - renamed
ToolbarTableProps.actiontoToolbarTableProps.transform.
- New plugin
BasicElementPlugins - New props
stylesinToolbar - New props
stylesinHeadingToolbar - New props in
ToolbarButton:stylestooltip
- New props in
BalloonToolbar:stylesdirectionhiddenDelaythemearrow
Toolbar,HeadingToolbarandBalloonToolbarrestyled.- New queries:
getSelectionTextgetTextisCollapsedisExpandedisSelectionExpanded
useMention:- removed
MentionSelectComponentfrom return
- removed
onChangeMention:- signature changed from
({ editor }: { editor: Editor })to(editor: Editor)
- signature changed from
MentionSelect:- props renaming:
- from
mentionablestooptions - from
indextovalueIndex - from
targettoat
- from
- props renaming:
MentionNodeinterface: replacedmentionablebyvalue. You can add more fields to the element interface instead of adding them tomentionableonKeyDownMark:- signature changed from
({ clear, type, hotkey, }: MarkOnKeyDownOptions)to(type: string, hotkey: string, { clear }: MarkOnKeyDownOptions = {})
- signature changed from
- removed
withForcedLayoutin favor ofwithTypeRules(more generic) - changed
CODEtype value fromcodetocode_block - renamed
CodePlugintoCodeBlockPluginandInlineCodePlugintoCodePlugin
getLastNode(editor: Editor, level: number): new query to get the last node at a specific level/depthwithTypeRules: new normalizer plugin to force any node to have a specific typeutils:getPreviousIndexgetNextIndex
queries:isPointAtWordEndisWordAfterTriggergetNode: same thanNode.getbut returns null if not the node is not found at the given path.
useMention:optionsis now optional
MentionPlugin,renderElementMention:- added
prefixoption - added
onClickoption
- added
MentionSelect:- added props:
styles, see Component Styling
- added props:
getRenderElement- added a 3rd argument:
optionsthat will be passed to the component as props. You should use that for static props (same value for all instances). And you should mutate the element when it's dynamic.
- added a 3rd argument:
MentionElement:- attribute
data-slate-characterrenamed todata-slate-value
- attribute
mention:- signature of
onChangeMentionchanged - signature of
useMentionchanged
- signature of
// from
useMention({
characters: CHARACTERS,
}
// to
useMention(CHARACTERS, {
maxSuggestions: 10,
trigger: '@',
prefix: ''
});mention:- changed mention representation from string to object (more useful later for storing other information then just the string, like ids)
- added an options parameter to useMention, adding trigger and prefix to maxSuggestions
- improved typing where seemed appropriate
deserializer-html:- export
withDeserializeHtml
- export
- previous build was broken because of tests not being excluded
- refactored:
toggleCodetotoggleWrapNodes(generic).
- removed:
clearMarkin favor ofEditor.removeMark.
pipe: new helper to avoid the wrapper hell when usingwithPlugins. You can now have an array of pluginswithPlugins.EditablePlugins: new props for adding your dependencies to the correspondinguseCallback.decorateDepsrenderElementDepsrenderLeafDepsonDOMBeforeInputDepsonKeyDownDeps
toggleMark: new optional parameterclear: marks to clear when adding mark.- helpers:
createDefaultHandler
- there was a big performance gap between the official slate
Editablecomponent and ourEditablePluginscomponent. This has been resolved by usinguseCallback.
deserializeLink: should work with slate fragments.withForcedLayoutwas normalizing on each change.
withNodeID: renamedidGeneratortoidCreator
withNodeID: new options:filterTextfilterallowexclude
setPropsToNodes: helper to set props to nodes and its children (recursively), with many options to filter the nodes that will receive the props (e.g. only Element, only Text, only nodes of type Paragraph, etc.).
withNodeIDshould now work with history undos/redos
- renamed:
withPasteHtmltowithDeserializeHtmlwithPasteMdtowithDeserializeMdonKeyDownMark.marktoonKeyDownMark.type
- refactored:
onKeyDownMentionandonChangeMentionare now returned byuseMentionisBlockActiveandisLinkActivehave been removed in favor ofisNodeInSelection
- new options for mark plugins: type (
typeBold,typeItalic, etc.) . withDeserializeHtml:- the deserializer is now using
data-slate-typeattribute of each HTML element. So copy/pasting slate fragments should now work. - when pasting a value, the type of the first node will replace the
type of the selected node (using
Transforms.setNodes).
- the deserializer is now using
withTransforms:- extends
editorwith transforms (only one for now).
- extends
withNodeID:- Set an id to the new
Elementand/orTextnodes.
- Set an id to the new
deserializeMentiondeserializeActionItemdeserializeIframedeserializeHighlightgetSelectionNodesArrayByTypegetSelectionNodesByTypeisAncestorunwrapNodesByType- unit testing
- a lot of refactoring
HeadingPlugin:- styling change (from h1 to h6)
EditablePlugins:styleprops is now overridable
withDeserializeHtml: fixCannot read property 'children' of nullwithForcedLayout: the previous behavior was forcing to have paragraph nodes after the title. New behavior: first node should be a title (otherwise insert/edit) and second node should exist (otherwise insert a paragraph by default). We will see how to generalize this plugin in a future release.Toolbar: changeheighttomin-heightfor dynamic height.
- refactor
getElementtogetElementComponent - refactor elements types to reflect the html tags. Also avoiding
-as it's not valid in GraphQL enums.action-item->action_itemblock-quote->blockquoteheading-one->h1(untilh6)link->anumbered-list->olbulleted-list->ullist-item->liparagraph->ptable-row->trtable-cell->tdIf you already saved elements in your database, you will need to migrate or override the types with the previous ones:
// you can add nodeTypes to any element plugin
export const nodeTypes = {
p.type: PARAGRAPH,
typeMention: MENTION,
blockquote.type: BLOCKQUOTE,
typeCode: CODE_BLOCK,
typeLink: LINK,
typeImg: IMAGE,
typeVideo: MEDIA_EMBED,
todo_li.type: TODO_LIST,
typeTable: TableType.TABLE,
typeTr: TableType.ROW,
typeTd: TableType.CELL,
ul.type: ListType.UL,
ol.type: ListType.OL,
typeLi: ListType.LI,
h1.type: HeadingType.H1,
h2.type: HeadingType.H2,
h3.type: HeadingType.H3,
h4.type: HeadingType.H4,
h5.type: HeadingType.H5,
h6.type: HeadingType.H6,
typeEditableVoid: EDITABLE_VOID,
};
- Ordered lists supported in
withShortcuts(Markdown Shortcuts) by typing1.. - Option type to all elements. Not yet for the marks.
getRenderElements
- queries:
isRangeAtRoot(point: Point)to check if anchor or focus of a range is at the root.
- use
isRangeAtRoot(point: Point)before eachEditor.parentcall.
- queries:
isPointAtRoot(point: Point)to check if a point is at the root.
- plugins:
withVoidto set a list of element types to void.withInlineto set a list of element types to inline.
plugin-list: fixed a bug where toggling the list throws an error when a paragraph has few leafs
plugin-marks: New plugins for HTML<sub>and<sup>tags: superscript and subscript plugins. Included in the "Marks" story.
- Deserializer: pasting html or markdown with Elements inside Text tags works correctly now.
paste-md:- markdown can be pasted into the editor
plugin-list:- make sure list item is removed when unwrapping.
- if multiple paragraphs are selected when pressing toggle - they should end up as separate list items.
- The default toggleBlock function creates several code blocks if there are multiple paragraphs selected. This fix creates a toggleCode function that just wraps the whole selection in a code block - or unwraps if it is already in a block.
plugin-table:- Insert table
- Delete table
- Add/delete row
- Add/delete cell
plugin-list:- Each list item now has a paragraph child.
plugin-list:- Supports nested lists:
- Press
Tabon a list item (except the first one) to indent the current list. - Press
Shift+Tab,EnterorBackspaceto unindent the current list.
- Press
- Supports nested lists:
- styles:
line-heightof heading
- plugins:
withListhas been removed and its logic is now insidewithBlockwith the new optionunwrapTypes.withShortcuts: removeddeleteBackwardlogic as its covered bywithDeleteStartReset.
ptag was the default if notypewas provided. The new default isdiv.
- plugins:
withDeleteStartReset: on delete at the start of an empty block in types, replace it with a new paragraph.withBreakEmptyReset: on insert break at the start of an empty block in types, replace it with a new paragraph.
- queries:
isList
- styles
- action item.
- removed the element styling from
globalStyleas it is not exported. - a lot of spacing changes.