Major Releases

This page covers major breaking changes for Plate up to v48. For the latest migration guide, see Latest Migration. For patch and minor changes, refer to the individual package CHANGELOG.md files or visit the GitHub Releases page.

48.0.0

@udecode/[email protected]

  • #4281 by @zbeyens

    • PlateElement, PlateLeaf and PlateText HTML attributes are moved from top-level props to attributes prop, except className, style and as. Migration:
    // From
    <PlateElement
      {...props}
      ref={ref}
      contentEditable={false}
    >
      {children}
    </PlateElement>
     
    // To
    <PlateElement
      {...props}
      ref={ref}
      attributes={{
        ...props.attributes,
        contentEditable: false,
      }}
    >
      {children}
    </PlateElement>
    • Remove nodeProps prop from PlateElement, PlateLeaf, PlateText. It has been merged into attributes prop.
    • Plugin node.props should return the props directly instead of inside nodeProps object. Migration:
    // From
    node: {
      props: ({ element }) => ({
        nodeProps: {
          colSpan: element?.attributes?.colspan,
          rowSpan: element?.attributes?.rowspan,
        },
      });
    }
     
    // To
    node: {
      props: ({ element }) => ({
        colSpan: element?.attributes?.colspan,
        rowSpan: element?.attributes?.rowspan,
      });
    }
    • Remove asChild prop from PlateElement, PlateLeaf, PlateText. Use as prop instead.
    • Remove elementToAttributes, leafToAttributes, textToAttributes props from PlateElement, PlateLeaf, PlateText.
    • Remove DefaultElement, DefaultLeaf, DefaultText. Use PlateElement, PlateLeaf, PlateText instead.
    • Types: remove PlateRenderElementProps, PlateRenderLeafProps, PlateRenderTextProps. Use PlateElementProps, PlateLeafProps, PlateTextProps instead.

@udecode/[email protected]

  • #4281 by @zbeyens
    • Moved PlateElement, PlateLeaf, PlateText to @udecode/plate-core. No migration needed if you're importing from @udecode/plate.

@udecode/[email protected]

  • #4225 by @bbyiringiro

    • Add multi-provider support for improved collaboration: now supports both Hocuspocus and WebRTC simultaneously using a shared Y.Doc.
      • Migration: Replace hocuspocusProviderOptions with the new providers array. See examples below.

    Before:

    YjsPlugin.configure({
      options: {
        cursorOptions: {
          /* ... */
        },
        hocuspocusProviderOptions: {
          url: 'wss://hocuspocus.example.com',
          name: 'document-1',
          // ... other Hocuspocus options
        },
      },
    });

    After (Hocuspocus only):

    YjsPlugin.configure({
      options: {
        cursors: {
          /* ... */
        },
        providers: [
          {
            type: 'hocuspocus',
            options: {
              url: 'wss://hocuspocus.example.com',
              name: 'document-1',
              // ... other Hocuspocus options
            },
          },
        ],
      },
    });

    After (Hocuspocus + WebRTC):

    YjsPlugin.configure({
      options: {
        cursors: {
          /* ... */
        },
        providers: [
          {
            type: 'hocuspocus',
            options: {
              url: 'wss://hocuspocus.example.com',
              name: 'document-1',
            },
          },
          {
            type: 'webrtc',
            options: {
              roomName: 'document-1',
              // signaling: ['wss://signaling.example.com'], // Optional
            },
          },
        ],
      },
    });
    • Introduces UnifiedProvider interface that enables custom provider implementations (e.g., IndexedDB for offline persistence).
    • Renamed cursorOptions to cursors.
    • Merged yjsOptions into options.
      • Migration: Move options previously under yjsOptions directly into the main options object.
    • Removed YjsAboveEditable. You should now call init and destroy manually:
    React.useEffect(() => {
      if (!mounted) return;
     
      // Initialize Yjs connection and sync
      editor.getApi(YjsPlugin).yjs.init({
        id: roomName, // Or your document identifier
        value: INITIAL_VALUE, // Your initial editor content
      });
     
      // Destroy connection on component unmount
      return () => {
        editor.getApi(YjsPlugin).yjs.destroy();
      };
    }, [editor, mounted, roomName]); // Add relevant dependencies

47.0.0

@udecode/plate-markdown

  • #4174 by @felixfeng33 – #### New Features

    • Added support for math type deserialization
    • Added default underline mark serialization as <u>underline</u>
    • Improved serialization process:
      • Now uses a two-step process: slate nodes => MDAST nodes => markdown string
      • Previously: direct conversion from Slate nodes to markdown string
      • Results in more reliable and robust serialization
    • New node filtering options:
      • allowedNodes: Whitelist specific nodes
      • disallowedNodes: Blacklist specific nodes
      • allowNode: Custom function to filter nodes
    • New rules option for customizing serialization and deserialization rules, including custom mdx support
    • New remarkPlugins option to use remark plugins

    Breaking Changes

    Plugin Options

    Removed options:

    • elementRules use rules instead
    • textRules use rules instead
    • indentList now automatically detects if the IndentList plugin is used
    • splitLineBreaks deserialize only
    Deserialization
    • Removed elementRules and textRules options

    Example migration:

    export const markdownPlugin = MarkdownPlugin.configure({
      options: {
        disallowedNodes: [SuggestionPlugin.key],
        rules: {
          // For textRules
          [BoldPlugin.key]: {
            mark: true,
            deserialize: (mdastNode) => ({
              bold: true,
              text: node.value || '',
            }),
          },
          // For elementRules
          [EquationPlugin.key]: {
            deserialize: (mdastNode, options) => ({
              children: [{ text: '' }],
              texExpression: node.value,
              type: EquationPlugin.key,
            }),
          },
        },
        remarkPlugins: [remarkMath, remarkGfm],
      },
    });
    • Removed processor in editor.api.markdown.deserialize
      • Use remarkPlugins instead
    Serialization
    • Removed serializeMdNodes
      • Use editor.markdown.serialize({ value: nodes }) instead
    • Removed SerializeMdOptions due to new serialization process
      • Previous process: slate nodes => md
      • New process: slate nodes => md-ast => md
    • Removed options:
      • nodes
      • breakTag
      • customNodes
      • ignoreParagraphNewline
      • listDepth
      • markFormats
      • ulListStyleTypes
      • ignoreSuggestionType

    Migration example for SerializeMdOptions.customNodes and SerializeMdOptions.nodes:

    export const markdownPlugin = MarkdownPlugin.configure({
      options: {
        rules: {
          // Ignore all `insert` type suggestions
          [SuggestionPlugin.key]: {
            mark: true,
            serialize: (slateNode: TSuggestionText, options): mdast.Text => {
              const suggestionData = options.editor
                .getApi(SuggestionPlugin)
                .suggestion.suggestionData(node);
     
              return suggestionData?.type === 'insert'
                ? { type: 'text', value: '' }
                : { type: 'text', value: node.text };
            },
          },
          // For elementRules
          [EquationPlugin.key]: {
            serialize: (slateNode) => ({
              type: 'math',
              value: node.texExpression,
            }),
          },
        },
        remarkPlugins: [remarkMath, remarkGfm],
      },
    });

46.0.0

@udecode/[email protected]

  • #4122 by @zbeyens – Migrated from prismjs to highlight.js + lowlight for syntax highlighting.

    • Fix highlighting multi-lines tokens. Before, line tokens were computed line by line. Now, it's computed once for the whole block.
    • Bundle size much lower.
    • CodeBlockPlugin: remove prism option. Use lowlight option instead:
    import { all, createLowlight } from 'lowlight';
     
    const lowlight = createLowlight(all);
     
    CodeBlockPlugin.configure({
      options: {
        lowlight,
      },
    });
    • New option: defaultLanguage
    • Remove syntax option. Just omit lowlight option to disable syntax highlighting.
    • Remove syntaxPopularFirst option. Control this behavior in your own components.
    • Fix pasting code inside code blocks.
    • Remove useCodeBlockCombobox, useCodeBlockElement, useCodeSyntaxLeaf, useToggleCodeBlockButton. The logic has been moved to the components.

45.0.0

@udecode/[email protected]

  • #4064 by @felixfeng33 – This is a rewrite of the comments plugin removing UI logic (headless).

    Plugin Options

    • Removed configuration options from plugin options in favor of component-level control:
      • options.comments
      • options.myUserId
      • options.users

    Components

    • Removed legacy components:
      • CommentDeleteButton
      • CommentEditActions
      • CommentEditButton
      • CommentEditCancelButton
      • CommentEditSaveButton
      • CommentEditTextarea
      • CommentNewSubmitButton
      • CommentNewTextarea
      • CommentResolveButton
      • CommentsPositioner
      • CommentUserName

    API

    • Removed functions in favor of new API methods:
      • findCommentNodeapi.comment.node()
      • findCommentNodeByIdapi.comment.node({ id })
      • getCommentNodeEntriesapi.comment.nodes()
      • getCommentNodesByIdapi.comment.nodes({ id })
      • removeCommentMarktf.comment.remove()
      • unsetCommentNodesByIdtf.comment.unsetMark({ id })
    • Removed unused functions:
      • getCommentFragment
      • getCommentUrl
      • getElementAbsolutePosition
      • getCommentPosition
    • Updated getCommentCount to exclude draft comments

    State Management

    • Removed CommentProvider - users should implement their own state management – block-discussion.tsx
    • Moved useHooksComments to UI registry – comments-plugin.tsx
    • Removed hooks no longer needed with new UI:
      • useActiveCommentNode
      • useCommentsResolved
      • useCommentAddButton
      • useCommentItemContent
      • useCommentLeaf
      • useCommentsShowResolvedButton
      • useFloatingCommentsContentState
      • useFloatingCommentsState

    Types

    • Removed CommentUser
    • Moved TComment to UI registry – comment.tsx

@udecode/[email protected]

  • #4064 by @felixfeng33 – Note: This plugin is currently in an experimental phase and breaking changes may be introduced without a major version bump.

    • Add Suggestion UI
    • Remove: findSuggestionNode use findSuggestionProps.ts instead
    • Remove addSuggestionMark.ts
    • Remove useHooksSuggestion.ts as we've updated the activeId logic to no longer depend on useEditorSelector

44.0.1

@udecode/[email protected]

  • #4048 by @zbeyens

    • Support React 19
    • Upgraded to zustand-x@6
      • eventEditorSelectors -> EventEditorStore.get
      • eventEditorActions -> EventEditorStore.set
      • useEventEditorSelectors -> useEventEditorValue(key)
    • Upgraded to jotai-x@2
      • usePlateEditorStore -> usePlateStore
      • usePlateActions -> usePlateSet
      • Remove editor.setPlateState, use usePlateSet instead
      • usePlateSelectors -> usePlateValue
      • usePlateStates -> usePlateState
    • Moving plugin options hooks into standalone hooks to be compatible with React Compiler
      • editor.useOption, ctx.useOption -> usePluginOption(plugin, key, ...args)
      • editor.useOptions, ctx.useOptions -> usePluginOption(plugin, 'state')
      • New hook usePluginOptions(plugin, selector) to select plugin options (Zustand way).
    • We were supporting adding selectors to plugins using extendOptions. Those were mixed up with the options state, leading to potential conflicts and confusion.
      • The plugin method is renamed to extendSelectors
      • Selectors are now internally stored in plugin.selectors instead of plugin.options, but this does not change how you access those: using editor.getOption(plugin, 'selectorName'), ctx.getOption('selectorName') or above hooks.
      • Selector types are no longer in the 2nd generic type of PluginConfig, we're adding a 5th generic type for it.
    // Before:
    export type BlockSelectionConfig = PluginConfig<
      'blockSelection',
      { selectedIds?: Set<string>; } & BlockSelectionSelectors,
    >;
     
    // After:
    export type BlockSelectionConfig = PluginConfig<
      'blockSelection',
      { selectedIds?: Set<string>; },
      {}, // API
      {}, // Transforms
      BlockSelectionSelectors, // Selectors
    }>

@udecode/[email protected]

@udecode/[email protected]

  • #4048 by @zbeyens – Upgrade to zustand-x@2. Migration needed only if you use one of these stores:

    • ImagePreviewStore
    • FloatingMediaStore
  • #4048 by @zbeyens – Upgrade to jotai-x@2. Migration needed only if you use usePlaceholderStore

@udecode/[email protected]

@udecode/[email protected]

  • #4048 by @zbeyens – Move store state selectedCells and selectedTables from useTableStore to TablePlugin options store. This fixes the issue to get access to those state outside a table element (e.g. the toolbar)

  • #4048 by @zbeyens – Upgrade to jotai-x@2. Migration needed only if you use useTableStore

43.0.0

No breaking changes. Upgraded all dependencies to the latest version.

42.0.1

@udecode/[email protected]

  • #3920 by @zbeyens – AI plugins are now experimental: pin the dependency to avoid breaking changes. No breaking changes for this release.

@udecode/[email protected]

  • #3920 by @zbeyens – This package is now deprecated and will be renamed to @udecode/plate. Migration:

    • Remove @udecode/plate-common and install @udecode/plate
    • Replace all '@udecode/plate-common' with '@udecode/plate',

@udecode/[email protected]

  • #3920 by @zbeyens

    • Plugin normalizeInitialValue now returns void instead of Value. When mutating nodes, keep their references (e.g., use Object.assign instead of spread).

    • Editor methods have moved to editor.tf and editor.api. They still exist at the top level for slate backward compatibility, but are no longer redundantly typed. If you truly need the top-level method types, extend your editor type with LegacyEditorMethods (e.g. editor as Editor & LegacyEditorMethods). Since these methods can be overridden by extendEditor, with..., or slate plugins, consider migrating to the following approaches:

      // For overriding existing methods only:
      overrideEditor(({ editor, tf: { deleteForward }, api: { isInline } }) => ({
        transforms: {
          deleteForward(options) {
            // ...conditional override
            deleteForward(options);
          },
        },
        api: {
          isInline(element) {
            // ...conditional override
            return isInline(element);
          },
        },
      }));

    This was previously done in extendEditor using top-level methods, which still works but now throws a type error due to the move to editor.tf/editor.api. A workaround is to extend your editor with LegacyEditorMethods.

    Why? Having all methods at the top-level (next to children, marks, etc.) would clutter the editor interface. Slate splits transforms in three places (editor, Editor, and Transforms), which is also confusing. We've reorganized them into tf and api for better DX, but also to support transform-only middlewares in the future. This also lets us leverage extendEditorTransforms, extendEditorApi, and overrideEditor to modify those methods.

    Migration example:

    // From:
    export const withInlineVoid: ExtendEditor = ({ editor }) => {
      const { isInline, isSelectable, isVoid, markableVoid } = editor;
     
      const voidTypes: string[] = [];
      const inlineTypes: string[] = [];
     
      editor.pluginList.forEach((plugin) => {
        if (plugin.node.isInline) {
          inlineTypes.push(plugin.node.type);
        }
        if (plugin.node.isVoid) {
          voidTypes.push(plugin.node.type);
        }
      });
     
      editor.isInline = (element) => {
        return inlineTypes.includes(element.type as any)
          ? true
          : isInline(element);
      };
     
      editor.isVoid = (element) => {
        return voidTypes.includes(element.type as any) ? true : isVoid(element);
      };
     
      return editor;
    };
     
    export const InlineVoidPlugin = createSlatePlugin({
      key: 'inlineVoid',
      extendEditor: withInlineVoid,
    });
     
    // After (using overrideEditor since we're only overriding existing methods):
    export const withInlineVoid: OverrideEditor = ({
      api: { isInline, isSelectable, isVoid, markableVoid },
      editor,
    }) => {
      const voidTypes: string[] = [];
      const inlineTypes: string[] = [];
     
      editor.pluginList.forEach((plugin) => {
        if (plugin.node.isInline) {
          inlineTypes.push(plugin.node.type);
        }
        if (plugin.node.isVoid) {
          voidTypes.push(plugin.node.type);
        }
      });
     
      return {
        api: {
          isInline(element) {
            return inlineTypes.includes(element.type as any)
              ? true
              : isInline(element);
          },
          isVoid(element) {
            return voidTypes.includes(element.type as any)
              ? true
              : isVoid(element);
          },
        },
      };
    };
     
    export const InlineVoidPlugin = createSlatePlugin({
      key: 'inlineVoid',
    }).overrideEditor(withInlineVoid);
    • Move editor.redecorate to editor.api.redecorate

    Types:

    • Rename TRenderElementProps to RenderElementProps
    • Rename TRenderLeafProps to RenderLeafProps
    • Rename TEditableProps to EditableProps

@udecode/[email protected]

  • #3920 by @zbeyensThis package is now the new common package, so all plugin packages are being removed. Migration:

    • Add the following dependencies:
    "@udecode/plate-alignment": "42.0.0",
    "@udecode/plate-autoformat": "42.0.0",
    "@udecode/plate-basic-elements": "42.0.0",
    "@udecode/plate-basic-marks": "42.0.0",
    "@udecode/plate-block-quote": "42.0.0",
    "@udecode/plate-break": "42.0.0",
    "@udecode/plate-code-block": "42.0.0",
    "@udecode/plate-combobox": "42.0.0",
    "@udecode/plate-comments": "42.0.0",
    "@udecode/plate-csv": "42.0.0",
    "@udecode/plate-diff": "42.0.0",
    "@udecode/plate-docx": "42.0.0",
    "@udecode/plate-find-replace": "42.0.0",
    "@udecode/plate-floating": "42.0.0",
    "@udecode/plate-font": "42.0.0",
    "@udecode/plate-heading": "42.0.0",
    "@udecode/plate-highlight": "42.0.0",
    "@udecode/plate-horizontal-rule": "42.0.0",
    "@udecode/plate-indent": "42.0.0",
    "@udecode/plate-indent-list": "42.0.0",
    "@udecode/plate-kbd": "42.0.0",
    "@udecode/plate-layout": "42.0.0",
    "@udecode/plate-line-height": "42.0.0",
    "@udecode/plate-link": "42.0.0",
    "@udecode/plate-list": "42.0.0",
    "@udecode/plate-markdown": "42.0.0",
    "@udecode/plate-media": "42.0.0",
    "@udecode/plate-mention": "42.0.0",
    "@udecode/plate-node-id": "42.0.0",
    "@udecode/plate-normalizers": "42.0.0",
    "@udecode/plate-reset-node": "42.0.0",
    "@udecode/plate-resizable": "42.0.0",
    "@udecode/plate-select": "42.0.0",
    "@udecode/plate-selection": "42.0.0",
    "@udecode/plate-slash-command": "42.0.0",
    "@udecode/plate-suggestion": "42.0.0",
    "@udecode/plate-tabbable": "42.0.0",
    "@udecode/plate-table": "42.0.0",
    "@udecode/plate-toggle": "42.0.0",
    "@udecode/plate-trailing-block": "42.0.0"
    • Either replace all @udecode/plate imports with the individual package imports, or export the following in a new file (e.g. src/plate.ts):
    export * from '@udecode/plate-alignment';
    export * from '@udecode/plate-autoformat';
    export * from '@udecode/plate-basic-elements';
    export * from '@udecode/plate-basic-marks';
    export * from '@udecode/plate-block-quote';
    export * from '@udecode/plate-break';
    export * from '@udecode/plate-code-block';
    export * from '@udecode/plate-combobox';
    export * from '@udecode/plate-comments';
    export * from '@udecode/plate-diff';
    export * from '@udecode/plate-find-replace';
    export * from '@udecode/plate-font';
    export * from '@udecode/plate-heading';
    export * from '@udecode/plate-highlight';
    export * from '@udecode/plate-horizontal-rule';
    export * from '@udecode/plate-indent';
    export * from '@udecode/plate-indent-list';
    export * from '@udecode/plate-kbd';
    export * from '@udecode/plate-layout';
    export * from '@udecode/plate-line-height';
    export * from '@udecode/plate-link';
    export * from '@udecode/plate-list';
    export * from '@udecode/plate-media';
    export * from '@udecode/plate-mention';
    export * from '@udecode/plate-node-id';
    export * from '@udecode/plate-normalizers';
    export * from '@udecode/plate-reset-node';
    export * from '@udecode/plate-select';
    export * from '@udecode/plate-csv';
    export * from '@udecode/plate-docx';
    export * from '@udecode/plate-markdown';
    export * from '@udecode/plate-slash-command';
    export * from '@udecode/plate-suggestion';
    export * from '@udecode/plate-tabbable';
    export * from '@udecode/plate-table';
    export * from '@udecode/plate-toggle';
    export * from '@udecode/plate-trailing-block';
    export * from '@udecode/plate-alignment/react';
    export * from '@udecode/plate-autoformat/react';
    export * from '@udecode/plate-basic-elements/react';
    export * from '@udecode/plate-basic-marks/react';
    export * from '@udecode/plate-block-quote/react';
    export * from '@udecode/plate-break/react';
    export * from '@udecode/plate-code-block/react';
    export * from '@udecode/plate-combobox/react';
    export * from '@udecode/plate-comments/react';
    export * from '@udecode/plate-floating';
    export * from '@udecode/plate-font/react';
    export * from '@udecode/plate-heading/react';
    export * from '@udecode/plate-highlight/react';
    export * from '@udecode/plate-layout/react';
    export * from '@udecode/plate-slash-command/react';
    export * from '@udecode/plate-indent/react';
    export * from '@udecode/plate-indent-list/react';
    export * from '@udecode/plate-kbd/react';
    export * from '@udecode/plate-line-height/react';
    export * from '@udecode/plate-link/react';
    export * from '@udecode/plate-list/react';
    export * from '@udecode/plate-media/react';
    export * from '@udecode/plate-reset-node/react';
    export * from '@udecode/plate-selection';
    export * from '@udecode/plate-suggestion/react';
    export * from '@udecode/plate-tabbable/react';
    export * from '@udecode/plate-table/react';
    export * from '@udecode/plate-toggle/react';
    export * from '@udecode/plate-resizable';
    • Replace all '@udecode/plate' and '@udecode/plate/react' with '@/plate' in your codebase.

@udecode/[email protected]

  • #3920 by @zbeyens
    • Removed unused moveSelectionByOffset, getLastBlockDOMNode, useLastBlock, useLastBlockDOMNode

@udecode/[email protected]

  • #3920 by @zbeyens – Remove first parameter of editor.api.blockSelection.duplicate

@udecode/[email protected]

  • #3920 by @zbeyens

    • Remove slate, slate-dom, slate-react, slate-history and slate-hyperscript from your dependencies. It's now part of this package and @udecode/plate. All exports remain the same or have equivalents (see below).
    • Renamed createTEditor to createEditor.
    • createEditor now returns an editor (Editor) with all queries under editor.api and transforms under editor.tf. You can see or override them at a glance. For example, we now use editor.tf.setNodes instead of importing setNodes. This marks the completion of generic typing and the removal of error throws from slate, slate-dom, and slate-history queries/transforms, without forking implementations. We’ve also reduced the number of queries/transforms by merging a bunch of them.

    The following interfaces from slate and slate-dom are now part of Editor:

    • Editor, EditorInterface

    • Transforms

    • HistoryEditor (noop, unchanged), HistoryEditorInterface

    • DOMEditor (noop, unchanged), DOMEditorInterface

    • editor.findPath now returns DOMEditor.findPath (memo) and falls back to findNodePath (traversal, less performant) if not found.

    • Removed the first parameter (editor) from:

      • editor.hasEditableTarget
      • editor.hasSelectableTarget
      • editor.isTargetInsideNonReadonlyVoid
      • editor.hasRange
      • editor.hasTarget
    • editor.api.node(options) (previously findNode) at option is now at ?? editor.selection instead of at ?? editor.selection ?? []. That means if you want to lookup the entire document, you need to pass [] explicitly.

    • Removed setNode in favor of setNodes (you can now pass a TNode to at directly).

    • Removed setElements in favor of setNodes.

    • Removed unused isWordAfterTrigger, setBlockAboveNode, setBlockAboveTexts, setBlockNodes, getPointNextToVoid.

    • Replaced Path from slate with Path (type) and PathApi (static methods).

    • Replaced Operation from slate with Operation (type) and OperationApi (static methods).

    • Replaced Point from slate with Point (type) and PointApi (static methods).

    • Replaced Text from slate with TText (type) and TextApi (static methods). We also export Text type like slate but we don't recommend it as it's conflicting with the DOM type.

    • Replaced Range from slate with TRange (type) and RangeApi (static methods). We also export Range type like slate but we don't recommend it as it's conflicting with the DOM type.

    • Replaced Location from slate with TLocation (type) and LocationApi (static methods). We also export Location type like slate but we don't recommend it as it's conflicting with the DOM type.

    • Replaced Span from slate with Span (type) and SpanApi (static methods).

    • Replaced Node from slate with TNode (type) and NodeApi (static methods). We also export Node type like slate but we don't recommend it as it's conflicting with the DOM type.

    • Replaced Element from slate with TElement (type) and ElementApi (static methods). We also export Element type like slate but we don't recommend it as it's conflicting with the DOM type.

    • Signature change:

      • editor.tf.toggle.block({ type, ...options }) -> editor.tf.toggleBlock(type, options)
      • editor.tf.toggle.mark({ key, clear }) -> editor.tf.toggleMark(key, { remove: clear })
    • Moved editor functions:

      • addMark -> editor.tf.addMark
      • addRangeMarks -> editor.tf.setNodes(props, { at, marks: true })
      • blurEditor -> editor.tf.blur
      • collapseSelection -> editor.tf.collapse
      • createDocumentNode -> editor.api.create.value (core)
      • createNode -> editor.api.create.block
      • createPathRef -> editor.api.pathRef
      • createPointRef -> editor.api.pointRef
      • createRangeRef -> editor.api.rangeRef
      • deleteBackward({ unit }) -> editor.tf.deleteBackward(unit)
      • deleteForward({ unit }) -> editor.tf.deleteForward(unit)
      • deleteFragment -> editor.tf.deleteFragment
      • deleteText -> editor.tf.delete
      • deselect -> editor.tf.deselect
      • deselectEditor -> editor.tf.deselectDOM
      • duplicateBlocks -> editor.tf.duplicateNodes({ nodes })
      • findDescendant -> editor.api.descendant
      • findEditorDocumentOrShadowRoot -> editor.api.findDocumentOrShadowRoot
      • findEventRange -> editor.api.findEventRange
      • findNode(options) -> editor.api.node(options)
      • findNodeKey -> editor.api.findKey
      • findNodePath -> editor.api.findPath
      • findPath -> editor.api.findPath
      • focusEditor -> editor.tf.focus({ at })
      • focusEditorEdge -> editor.tf.focus({ at, edge: 'startEditor' | 'endEditor' })
      • getAboveNode -> editor.api.above
      • getAncestorNode -> editor.api.block({ highest: true })
      • getBlockAbove -> editor.api.block({ at, above: true }) or editor.api.block() if at is not a path
      • getBlocks -> editor.api.blocks
      • getEdgeBlocksAbove -> editor.api.edgeBlocks
      • getEdgePoints -> editor.api.edges
      • getEditorString -> editor.api.string
      • getEditorWindow -> editor.api.getWindow
      • getEndPoint -> editor.api.end
      • getFirstNode -> editor.api.first
      • getFragment -> editor.api.fragment
      • getFragmentProp(fragment, options) -> editor.api.prop({ nodes, ...options})
      • getLastNode -> editor.api.last
      • getLastNodeByLevel(level) -> editor.api.last([], { level })
      • getLeafNode -> editor.api.leaf
      • getLevels -> editor.api.levels
      • getMark -> editor.api.mark
      • getMarks -> editor.api.marks
      • getNextNode -> editor.api.next
      • getNextNodeStartPoint -> editor.api.start(at, { next: true })
      • getNodeEntries -> editor.api.nodes
      • getNodeEntry -> editor.api.node(at, options)
      • getNodesRange -> editor.api.nodesRange
      • getParentNode -> editor.api.parent
      • getPath -> editor.api.path
      • getPathRefs -> editor.api.pathRefs
      • getPoint -> editor.api.point
      • getPointAfter -> editor.api.after
      • getPointBefore -> editor.api.before
      • getPointBeforeLocation -> editor.api.before
      • getPointRefs -> editor.api.pointRefs
      • getPositions -> editor.api.positions
      • getPreviousBlockById -> editor.api.previous({ id, block: true })
      • getPreviousNode -> editor.api.previous
      • getPreviousNodeEndPoint -> editor.api.end({ previous: true })
      • getPreviousSiblingNode -> editor.api.previous({ at, sibling: true })
      • getRange -> editor.api.range
      • getRangeBefore -> editor.api.range('before', to, { before })
      • getRangeFromBlockStart -> editor.api.range('start', to)
      • getRangeRefs -> editor.api.rangeRefs
      • getSelectionFragment -> editor.api.fragment(editor.selection, { structuralTypes })
      • getSelectionText -> editor.api.string()
      • getStartPoint -> editor.api.start
      • getVoidNode -> editor.api.void
      • hasBlocks -> editor.api.hasBlocks
      • hasEditorDOMNode -> editor.api.hasDOMNode
      • hasEditorEditableTarget -> editor.api.hasEditableTarget
      • hasEditorSelectableTarget -> editor.api.hasSelectableTarget
      • hasEditorTarget -> editor.api.hasTarget
      • hasInlines -> editor.api.hasInlines
      • hasTexts -> editor.api.hasTexts
      • insertBreak -> editor.tf.insertBreak
      • insertData -> editor.tf.insertData
      • insertElements -> editor.tf.insertNodes<TElement>
      • insertEmptyElement -> editor.tf.insertNodes(editor.api.create.block({ type }))
      • insertFragment -> editor.tf.insertFragment
      • insertNode -> editor.tf.insertNode
      • insertNodes -> editor.tf.insertNodes
      • insertText -> editor.tf.insertText({ at }) or editor.tf.insertText({ marks: false }) without at
      • isAncestorEmpty -> editor.api.isEmpty
      • isBlock -> editor.api.isBlock
      • isBlockAboveEmpty -> editor.api.isEmpty(editor.selection, { block: true })
      • isBlockTextEmptyAfterSelection -> editor.api.isEmpty(editor.selection, { after: true })
      • isCollapsed(editor.selection) -> editor.api.isCollapsed()
      • isComposing -> editor.api.isComposing
      • isDocumentEnd -> editor.api.isEditorEnd
      • isEdgePoint -> editor.api.isEdge
      • isEditorEmpty -> editor.api.isEmpty()
      • isEditorFocused -> editor.api.isFocused
      • isEditorNormalizing -> editor.api.isNormalizing
      • isEditorReadOnly -> editor.api.isReadOnly
      • isElementEmpty -> editor.api.isEmpty
      • isElementReadOnly -> editor.api.elementReadOnly
      • isEndPoint -> editor.api.isEnd
      • isExpanded(editor.selection) -> editor.api.isCollapsed()
      • isInline -> editor.api.isInline
      • isMarkableVoid -> editor.api.markableVoid
      • isMarkActive -> editor.api.hasMark(key)
      • isPointAtWordEnd -> editor.api.isAt({ at, word: true, end: true })
      • isRangeAcrossBlocks -> editor.api.isAt({ at, blocks: true })
      • isRangeInSameBlock -> editor.api.isAt({ at, block: true })
      • isRangeInSingleText -> editor.api.isAt({ at, text: true })
      • isSelectionAtBlockEnd -> editor.api.isAt({ end: true })
      • isSelectionAtBlockStart -> editor.api.isAt({ start: true })
      • isSelectionCoverBlock -> editor.api.isAt({ block: true, start: true, end: true })
      • isSelectionExpanded -> editor.api.isExpanded()
      • isStartPoint -> editor.api.isStart
      • isTargetinsideNonReadonlyVoidEditor -> editor.api.isTargetInsideNonReadonlyVoid
      • isTextByPath -> editor.api.isText(at)
      • isVoid -> editor.api.isVoid
      • liftNodes -> editor.tf.liftNodes
      • mergeNodes -> editor.tf.mergeNodes
      • moveChildren -> editor.tf.moveNodes({ at, to, children: true, fromIndex, match: (node, path) => boolean })
      • moveNodes -> editor.tf.moveNodes
      • moveSelection -> editor.tf.move
      • normalizeEditor -> editor.tf.normalize
      • removeEditorMark -> editor.tf.removeMark
      • removeEditorText -> editor.tf.removeNodes({ text: true, empty: false })
      • removeEmptyPreviousBlock -> editor.tf.removeNodes({ previousEmptyBlock: true })
      • removeMark(options) -> editor.tf.removeMarks(keys, options)
      • removeNodeChildren -> editor.tf.removeNodes({ at, children: true })
      • removeNodes -> editor.tf.removeNodes
      • removeSelectionMark -> editor.tf.removeMarks()
      • replaceNode(editor, { nodes, insertOptions, removeOptions }) -> editor.tf.replaceNodes(nodes, { removeNodes, ...insertOptions })
      • select -> editor.tf.select
      • selectEndOfBlockAboveSelection -> editor.tf.select(editor.selection, { edge: 'end' })
      • selectNodes -> editor.tf.select(editor.api.nodesRange(nodes))
      • setFragmentData -> editor.tf.setFragmentData
      • setMarks(marks, clear) -> editor.tf.addMarks(marks, { remove: string | string[] })
      • setNodes -> editor.tf.setNodes
      • setPoint -> editor.tf.setPoint
      • setSelection -> editor.tf.setSelection
      • someNode -> editor.api.some(options)
      • splitNodes -> editor.tf.splitNodes
      • toDOMNode -> editor.api.toDOMNode
      • toDOMPoint -> editor.api.toDOMPoint
      • toDOMRange -> editor.api.toDOMRange
      • toggleWrapNodes -> editor.tf.toggleBlock(type, { wrap: true })
      • toSlateNode -> editor.api.toSlateNode
      • toSlatePoint -> editor.api.toSlatePoint
      • toSlateRange -> editor.api.toSlateRange
      • unhangCharacterRange -> editor.api.unhangRange(range, { character: true })
      • unhangRange -> editor.api.unhangRange
      • unsetNodes -> editor.tf.unsetNodes
      • unwrapNodes -> editor.tf.unwrapNodes
      • withoutNormalizing -> editor.tf.withoutNormalizing
      • wrapNodeChildren -> editor.tf.wrapNodes(element, { children: true })
      • wrapNodes -> editor.tf.wrapNodes
      • replaceNodeChildren -> editor.tf.replaceNodes({ at, children: true })
      • resetEditor -> editor.tf.reset
      • resetEditorChildren -> editor.tf.reset({ children: true })
      • selectEditor -> editor.tf.select([], { focus, edge })
      • selectSiblingNodePoint -> editor.tf.select(at, { next, previous })
    • Moved to NodeApi.:

      • getNextSiblingNodes(parentEntry, path) -> NodeApi.children(editor, path, { from: path.at(-1) + 1 })
      • getFirstNodeText -> NodeApi.firstText
      • getFirstChild([node, path]) -> NodeApi.firstChild(editor, path)
      • getLastChild([node, path]) -> NodeApi.lastChild(editor, path)
      • getLastChildPath([node, path]) -> NodeApi.lastChild(editor, path)
      • isLastChild([node, path], childPath) -> NodeApi.isLastChild(editor, childPath)
      • getChildren([node, path]) -> Array.from(NodeApi.children(editor, path))
      • getCommonNode -> NodeApi.common
      • getNode -> NodeApi.get
      • getNodeAncestor -> NodeApi.ancestor
      • getNodeAncestors -> NodeApi.ancestors
      • getNodeChild -> NodeApi.child
      • getNodeChildren -> NodeApi.children
      • getNodeDescendant -> NodeApi.descendant
      • getNodeDescendants -> NodeApi.descendants
      • getNodeElements -> NodeApi.elements
      • getNodeFirstNode -> NodeApi.first
      • getNodeFragment -> NodeApi.fragment
      • getNodeLastNode -> NodeApi.last
      • getNodeLeaf -> NodeApi.leaf
      • getNodeLevels -> NodeApi.levels
      • getNodeParent -> NodeApi.parent
      • getNodeProps -> NodeApi.extractProps
      • getNodes -> NodeApi.nodes
      • getNodeString -> NodeApi.string
      • getNodeTexts -> NodeApi.texts
      • hasNode -> NodeApi.has
      • hasSingleChild -> NodeApi.hasSingleChild
      • isAncestor -> NodeApi.isAncestor
      • isDescendant -> NodeApi.isDescendant
      • isEditor -> NodeApi.isEditor
      • isNode -> NodeApi.isNode
      • isNodeList -> NodeApi.isNodeList
      • nodeMatches -> NodeApi.matches
    • Moved to ElementApi.:

      • elementMatches -> ElementApi.matches
      • isElement -> ElementApi.isElement
      • isElementList -> ElementApi.isElementList
    • Moved to TextApi.:

      • isText -> TextApi.isText(at)
    • Moved to RangeApi.:

      • isCollapsed -> RangeApi.isCollapsed
      • isExpanded -> RangeApi.isExpanded
    • Moved to PathApi.:

      • isFirstChild -> !PathApi.hasPrevious
      • getPreviousPath -> PathApi.previous
    • Moved to PointApi.:

      • getPointFromLocation({ at, focus }) -> PointApi.get(at, { focus })
    • Moved from @udecode/plate/react to @udecode/plate:

      • Hotkeys
    • Upgraded to zustand@5 and zustand-x@5:

      • Replace createZustandStore('name')(initialState) with createZustandStore(initialState, { mutative: true, name: 'name' })
      • All plugin stores now use zustand-mutative for immutable state updates, which is faster than immer.

    Types:

    • Rename the following types:
      • TEditor -> Editor
      • TOperation -> Operation
      • TPath -> Path
      • TNodeProps -> NodeProps
      • TNodeChildEntry -> NodeChildEntry
      • TNodeEntry -> NodeEntry
      • TDescendant -> Descendant
      • TDescendantEntry -> DescendantEntry
      • TAncestor -> Ancestor
      • TAncestorEntry -> AncestorEntry
      • TElementEntry -> ElementEntry
      • TTextEntry -> TextEntry
    • Query/transform options now use generic V extends Value instead of E extends Editor.
    • getEndPoint, getEdgePoints, getFirstNode, getFragment, getLastNode, getLeafNode, getPath, getPoint, getStartPoint can return undefined if not found (suppressing error throws).
    • NodeApi.ancestor, NodeApi.child, NodeApi.common, NodeApi.descendant, NodeApi.first, NodeApi.get, NodeApi.last, NodeApi.leaf, NodeApi.parent, NodeApi.getIf, PathApi.previous return undefined if not found instead of throwing
    • Replace NodeOf type with DescendantOf in editor.tf.setNodes editor.tf.unsetNodes, editor.api.previous, editor.api.node, editor.api.nodes, editor.api.last
    • Enhanced editor.tf.setNodes:
      • Added marks option to handle mark-specific operations
      • When marks: true:
        • Only applies to text nodes in non-void nodes or markable void nodes
        • Automatically sets split: true and voids: true
        • Handles both expanded ranges and collapsed selections in markable voids
      • Replaces addRangeMarks functionality

@udecode/[email protected]

  • #3920 by @zbeyens – This package is now deprecated. Use @udecode/slate or @udecode/plate instead.

@udecode/[email protected]

  • #3920 by @zbeyens – This package is now deprecated. Use @udecode/slate or @udecode/plate instead.

@udecode/[email protected]

  • #3920 by @zbeyensMajor performance improvement: all table cells were re-rendering when a single cell changed. This is now fixed.

    • TablePlugin now depends on NodeIdPlugin.
    • Table merging is now enabled by default:
      • Renamed enableMerging to disableMerge.
      • Migration:
        • enableMerging: true → remove the option.
        • otherwise → TablePlugin.configure({ options: { disableMerge: true } })
    • Renamed unmergeTableCells to splitTableCell.
    • Renamed editor.api.create.cell to editor.api.create.tableCell.
    • In useTableMergeState, renamed canUnmerge to canSplit.
    • insertTableRow and insertTableColumn: removed disableSelect in favor of select. Migration: replace it with the opposite boolean.
    • getTableCellBorders: params (element, options)(editor, options); removed isFirstCell and isFirstRow.
    • Merged useTableCellElementState into useTableCellElement:
      • Removed its parameter.
      • Removed hovered and hoveredLeft returns (use CSS instead).
      • Renamed rowSize to minHeight.
      • Computes column sizes and returns width.
    • Merged useTableCellElementResizableState into useTableCellElementResizable:
      • Removed onHover and onHoverEnd props (use CSS instead).
    • Merged useTableElementState into useTableElement:
      • Removed its parameter.
      • No longer computes and returns colSizes, minColumnWidth, and colGroupProps.

41.0.2

@udecode/[email protected]

  • #3830 by @felixfeng33 – Rename findNodePath to findPath since the addition of findNodePath in the headless lib.

    We recommend using findPath mostly when subscribing to its value (e.g. in a React component) as it has O(path.length) complexity, compared to O(n) for the traversal-based findNodePath. This optimization is particularly important in:

    • Render functions of Plate components where using findNodePath would increase the initial render time by O(n²)
    • Key press handlers where using findNodePath would increase the handling time by O(n)

    where n is the number of nodes in the editor.

@udecode/[email protected]

  • #3861 by @zbeyens

    • Removed useDndBlock, useDragBlock, and useDropBlock hooks in favor of useDndNode, useDragNode, and useDropNode.
    • Removed DndProvider and useDraggableStore. Drop line state is now managed by DndPlugin as a single state object dropTarget containing both id and line.
    • useDropNode: removed onChangeDropLine and dropLine options

    Migration steps:

    • Remove DndProvider from your draggable component (e.g. draggable.tsx)
    • Replace useDraggableStore with useEditorPlugin(DndPlugin).useOption
    • Remove useDraggableState. Use const { isDragging, previewRef, handleRef } = useDraggable
    • Remove useDraggableGutter. Set contentEditable={false} to your gutter element
    • Remove props from useDropLine. Set contentEditable={false} to your drop line element
    • Remove withDraggable, useWithDraggable. Use DraggableAboveNodes instead

@udecode/[email protected]

  • #3830 by @felixfeng33
    • Move render.belowNodes from IndentListPlugin to BaseIndentListPlugin. Props type for listStyleTypes.liComponent and listStyleTypes.markerComponent options is now SlateRenderElementProps instead of PlateRenderElementProps
    • Move someIndentList, someIndentTodo from @udecode/plate-indent-list/react to @udecode/plate-indent-list

@udecode/[email protected]

  • #3878 by @zbeyens

    • insertColumnGroup: rename layout to columns
    • Remove setColumnWidth, useColumnState. Use setColumns instead

@udecode/[email protected]

  • #3830 by @felixfeng33 – Move from @udecode/plate-table/react to @udecode/plate-table:

    • deleteColumn
    • deleteColumnWhenExpanded
    • deleteRow
    • deleteRowWhenExpanded
    • getTableColumn
    • getTableGridAbove
    • getTableGridByRange
    • getTableRow
    • insertTable
    • mergeTableCells
    • moveSelectionFromCell
    • overrideSelectionFromCell
    • unmergeTableCells
    • withDeleteTable
    • withGetFragmentlable
    • withInsertFragmentTable
    • withInsertTextTable
    • withMarkTable
    • withSelectionTable
    • withSetFragmentDataTable
    • withTable

40.0.0

@udecode/[email protected]

  • #3744 by @zbeyens
    • Add slate-dom as a peer dependency.
    • Update slate-react peer dependency to >=0.111.0

@udecode/[email protected]

  • #3744 by @zbeyens
    • Remove scrollContainerSelector option in favor of useEditorContainerRef

@udecode/[email protected]

  • #3744 by @zbeyens
    • Remove scrollContainerSelector option in favor of useEditorContainerRef

@udecode/[email protected]

  • #3744 by @zbeyens
    • Remove toggleColumns in favor of toggleColumnGroup
    • Remove insertEmptyColumn in favor of insertColumn

39.0.0

@udecode/[email protected]

  • #3597 by @zbeyens – The following changes were made to improve performance:

    • Refactored useDraggable hook to focus on core dragging functionality:
      • Removed dropLine. Use useDropLine().dropLine instead.
      • Removed groupProps from the returned object – isHovered, and setIsHovered from the returned state. Use CSS instead.
      • Removed droplineProps, and gutterLeftProps from the returned object. Use useDropLine().props, useDraggableGutter().props instead.

@udecode/[email protected]

  • #3597 by @zbeyens – The following changes were made to improve performance:

    • Removed useHooksBlockSelection in favor of BlockSelectionAfterEditable
    • Removed slate-selected class from BlockSelectable. You can do it on your components using useBlockSelected() instead, or by using our new block-selection.tsx component.
    • Introduced useBlockSelectableStore for managing selectable state.

38.0.1

@udecode/[email protected]

  • #3506 by @zbeyens

    • Change plugin.options merging behavior from deep merge to shallow merge.
    • This affects .extend(), .configure(), and other methods that modify plugin options.
    • This update addresses a performance regression introduced in v37 that affected editor creation.

    Before:

    const plugin = createSlatePlugin({
      key: 'test',
      options: { nested: { a: 1 } },
    }).extend({
      options: { nested: { b: 1 } },
    });
     
    // Result: { nested: { a: 1, b: 1 } }

    After:

    const plugin = createSlatePlugin({
      key: 'test',
      options: { nested: { a: 1 } },
    }).extend(({ getOptions }) => ({
      options: {
        ...getOptions(),
        nested: { ...getOptions().nested, b: 1 },
      },
    }));
     
    // Result: { nested: { a: 1, b: 1 } }

    Migration:

    • If you're using nested options and want to preserve the previous behavior, you need to manually spread both the top-level options and the nested objects.
    • If you're not using nested options, no changes are required.
  • Rename all base plugins that have a React plugin counterpart to be prefixed with Base. This change improves clarity and distinguishes base implementations from potential React extensions. Use base plugins only for server-side environments or to extend your own DOM layer.

  • Import the following plugins from /react entry: AlignPlugin, CalloutPlugin, EquationPlugin, FontBackgroundColorPlugin, FontColorPlugin, FontFamilyPlugin, FontSizePlugin, FontWeightPlugin, InlineEquationPlugin, LineHeightPlugin, TextIndentPlugin, TocPlugin

37.0.0

Migration example: https://github.com/udecode/plate/pull/3480

We recommend to upgrade to @udecode/[email protected] in one-go.

@udecode/[email protected]

  • #3420 by @zbeyens
    • createAlignPlugin -> AlignPlugin
    • setAlign: remove key option

@udecode/[email protected]

  • #3420 by @zbeyens
    • createAutoformatPlugin -> AutoformatPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createBasicElementPlugins -> BasicElementsPlugin
    • createBlockquotePlugin -> BlockquotePlugin
    • createCodeBlockPlugin -> CodeBlockPlugin
    • createHeadingPlugin -> HeadingPlugin
    • Move paragraph plugin to @udecode/plate-core

@udecode/[email protected]

  • #3420 by @zbeyens
    • createBasicMarksPlugins -> BasicMarksPlugin
    • createBoldPlugin -> BoldPlugin
    • createCodePlugin -> CodePlugin
    • createItalicPlugin -> ItalicPlugin
    • createStrikethroughPlugin -> StrikethroughPlugin
    • createSubscriptPlugin -> SubscriptPlugin
    • createSuperscriptPlugin -> SuperscriptPlugin
    • createUnderlinePlugin -> UnderlinePlugin
    • All mark plugins removed hotkey option. Use plugin.shortcuts instead (see plate-core)

@udecode/[email protected]

  • #3420 by @zbeyens
    • createBlockquotePlugin -> BlockquotePlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createSoftBreakPlugin -> SoftBreakPlugin
    • createExitBreakPlugin -> ExitBreakPlugin
    • createSingleLinePlugin -> SingleLinePlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createCaptionPlugin -> CaptionPlugin
    • CaptionPlugin options:
      • Rename pluginKeys to plugins
      • Rename focusEndCaptionPath to focusEndPath
      • Rename focusStartCaptionPath to focusStartPath
      • Rename showCaptionId to visibleId
      • Rename isShow to isVisible
    • Move captionGlobalStore to CaptionPlugin

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createCodeBlockPlugin -> CodeBlockPlugin
    • NEW CodeLinePlugin
    • NEW CodeSyntaxPlugin
    • Remove getCodeLineType, use editor.getType(CodeLinePlugin) instead

@udecode/[email protected]

  • #3420 by @zbeyens
    • Split build into @udecode/plate-combobox and @udecode/plate-combobox/react.

@udecode/[email protected]

  • #3420 by @zbeyens
    • createCommentsPlugin -> CommentsPlugin
    • Move commentsStore to CommentsPlugin
    • Remove CommentsProvider and its hooks
    • Remove useCommentsStates (replaced by direct option access)
    • Remove useCommentsSelectors (replaced by option selectors)
    • Remove useCommentsActions (replaced by api methods)
    • Replace useUpdateComment with api.comment.updateComment
    • Replace useAddRawComment with api.comment.addRawComment
    • Replace useAddComment with api.comment.addComment
    • Replace useRemoveComment with api.comment.removeComment
    • Replace useResetNewCommentValue with api.comment.resetNewCommentValue
    • Replace useNewCommentText with options.newText
    • Replace useMyUser with options.myUser
    • Replace useUserById with options.userById
    • Replace useCommentById with options.commentById
    • Replace useActiveComment with options.activeComment
    • Replace useAddCommentMark with insert.comment

@udecode/[email protected]

  • #3420 by @zbeyens
    • Split build into @udecode/plate-common and @udecode/plate-common/react.
    • NEW /react exports @udecode/react-hotkeys

@udecode/[email protected]

  • #3420 by @zbeyensPlugin System:

    Decoupling React in all packages:

    • Split build into @udecode/plate-core and @udecode/plate-core/react
    • NEW SlatePlugin as the foundation for all plugins
    • PlatePlugin extends SlatePlugin with React-specific plugin features

    Plugin Creation:

    • Remove createPluginFactory
    • NEW createSlatePlugin: vanilla
    • NEW createTSlatePlugin: vanilla explicitly typed
    • NEW createPlatePlugin: React
    • NEW createTPlatePlugin: React explicitly typed
    • NEW toPlatePlugin: extend a vanilla plugin into a React plugin
    • NEW toTPlatePlugin: extend a vanilla plugin into a React plugin explicitly typed
    • Rename all plugins starting with createNamePlugin() to NamePlugin

    Before:

    const MyPluginFactory = createPluginFactory({
      key: 'myPlugin',
      isElement: true,
      component: MyComponent,
    });
    const plugin = MyPluginFactory();

    After:

    const plugin = createSlatePlugin({
      key: 'myPlugin',
      node: {
        isElement: true,
        component: MyComponent,
      },
    });
    const reactPlugin = toPlatePlugin(plugin);

    Plugin Configuration:

    • Remove all NamePlugin option types, use NameConfig instead.
    • NameConfig as the new naming convention for plugin configurations.

    Before:

    createPluginFactory<HotkeyPlugin>({
      handlers: {
        onKeyDown: onKeyDownToggleElement,
      },
      options: {
        hotkey: ['mod+opt+0', 'mod+shift+0'],
      },
    });

    After:

    export const ParagraphPlugin = createPlatePlugin({
      key: 'p',
      node: { isElement: true },
    }).extend({ editor, type }) => ({
      shortcuts: {
        toggleParagraph: {
          handler: () => {
            editor.tf.toggle.block({ type });
          },
          keys: [
            [Key.Mod, Key.Alt, '0'],
            [Key.Mod, Key.Shift, '0'],
          ],
          preventDefault: true,
        },
      },
    })
    • toggleParagraph is now a shortcut for editor.tf.toggle.block({ type: 'p' }) for the given keys
    • Multiple shortcuts can be defined per plugin, and any shortcut can be disabled by setting shortcuts.toggleParagraph = null
    • Note the typing support using Key

    Plugin Properties:

    Rename SlatePlugin / PlatePlugin properties:

    • type -> node.type
    • isElement -> node.isElement
    • isLeaf -> node.isLeaf
    • isInline -> node.isInline
    • isMarkableVoid -> node.isMarkableVoid
    • isVoid -> node.isVoid
    • component -> node.component or render.node
    • props -> node.props
    • overrideByKey -> override.plugins
    • renderAboveEditable -> render.aboveEditable
    • renderAboveSlate -> render.aboveSlate
    • renderAfterEditable -> render.afterEditable
    • renderBeforeEditable -> render.beforeEditable
    • inject.props -> inject.nodeProps
    • inject.props.validTypes -> inject.targetPlugins
    • inject.aboveComponent -> render.aboveNodes
    • inject.belowComponent -> render.belowNodes
    • inject.pluginsByKey -> inject.plugins
    • editor.insertData -> parser
      • NEW parser.format now supports string[]
      • NEW parser.mimeTypes: string[]
    • deserializeHtml -> parsers.html.deserializer
    • deserializeHtml.getNode -> parsers.html.deserializer.parse
    • serializeHtml -> parsers.htmlReact.serializer
    • withOverride -> extendEditor
    • All methods now have a single parameter: SlatePluginContext<C> or PlatePluginContext<C>, in addition to the method specific options. Some of the affected methods are:
      • decorate
      • handlers, including onChange. Returns ({ event, ...ctx }) => void instead of (editor, plugin) => (event) => void
      • handlers.onChange: ({ value, ...ctx }) => void instead of (editor, plugin) => (value) => void
      • normalizeInitialValue
      • editor.insertData.preInsert
      • editor.insertData.transformData
      • editor.insertData.transformFragment
      • deserializeHtml.getNode
      • deserializeHtml.query
      • inject.props.query
      • inject.props.transformProps
      • useHooks
      • withOverrides

    NEW SlatePlugin properties:

    • api: API methods provided by this plugin
    • dependencies: An array of plugin keys that this plugin depends on
    • node: Node-specific configuration for this plugin
    • parsers: Now accept string keys to add custom parsers
    • priority: Plugin priority for registration and execution order
    • shortcuts: Plugin-specific hotkeys
    • inject.targetPluginToInject: Function to inject plugin config into other plugins specified by inject.targetPlugins

    Before:

    export const createAlignPlugin = createPluginFactory({
      key: KEY_ALIGN,
      inject: {
        props: {
          defaultNodeValue: 'start',
          nodeKey: KEY_ALIGN,
          styleKey: 'textAlign',
          validNodeValues: ['start', 'left', 'center', 'right', 'end', 'justify'],
          validTypes: ['p'],
        },
      },
      then: (_, plugin) =>
        mapInjectPropsToPlugin(editor, plugin, {
          deserializeHtml: {
            getNode: (el, node) => {
              if (el.style.textAlign) {
                node[plugin.key] = el.style.textAlign;
              }
            },
          },
        }),
    });

    After:

    export const AlignPlugin = createSlatePlugin({
      inject: {
        nodeProps: {
          defaultNodeValue: 'start',
          nodeKey: 'align',
          styleKey: 'textAlign',
          validNodeValues: ['start', 'left', 'center', 'right', 'end', 'justify'],
        },
        targetPluginToInject: ({ editor, plugin }) => ({
          parsers: {
            html: {
              deserializer: {
                parse: ({ element, node }) => {
                  if (element.style.textAlign) {
                    node[editor.getType(plugin)] = element.style.textAlign;
                  }
                },
              },
            },
          },
        }),
        targetPlugins: [ParagraphPlugin.key],
      },
      key: 'align',
    });

    Plugin Shortcuts:

    • NEW shortcuts to add custom hotkeys to a plugin.
    • Remove hotkey option from all plugins

    Before:

    type LinkPlugin = {
      hotkey?: string;
    };

    After:

    type LinkConfig = PluginConfig<
      // key
      'p',
      // options
      { defaultLinkAttributes?: any },
      // api
      { link: { getAttributes: (editor: PlateEditor) => LinkAttributes } },
      // transforms
      { floatingLink: { hide: () => void } }
    >;

    Shortcuts API:

    • handler is called with the editor, event, and event details.
    • keys is an array of keys to trigger the shortcut.
    • priority is the priority of the shortcut over other shortcuts.
    • ...HotkeysOptions from @udecode/react-hotkeys

    Plugin Types:

    • Update SlatePlugin, PlatePlugin generics. P, V, E -> C extends AnyPluginConfig = PluginConfig
    • Remove PluginOptions
    • Remove PlatePluginKey
    • Remove HotkeyPlugin, ToggleMarkPlugin in favor of plugin.shortcuts
    • WithPlatePlugin -> EditorPlugin, EditorPlatePlugin
    • PlatePluginComponent -> NodeComponent
    • InjectComponent* -> NodeWrapperComponent*
    • PlatePluginInsertData -> Parser
    • PlatePluginProps -> NodeProps
    • RenderAfterEditable -> EditableSiblingComponent
    • WithOverride -> ExtendEditor
    • SerializeHtml -> HtmlReactSerializer

    Plugin Store:

    • NEW each plugin has its own store, accessible via plugin.optionsStore and plugin.useOptionsStore
    • editor has many methods to get, set and subscribe to plugin options

    Plugin Methods:

    • All plugin methods return a new plugin instance with the extended types.
    • Remove then, use extend instead
    • NEW extend method to deep merge a plugin configuration
      • If you pass an object, it will be directly merged with the plugin config.
      • If you pass a function, it will be called with the plugin config once the editor is resolved and should return the new plugin config.
      • Object extensions always have the priority over function extensions.
      • Extend multiple times to derive from the result of the previous extension.
    • NEW configure method to configure the properties of existing plugins. The difference with extend is that configure with not add new properties to the plugin, it will only modify existing ones.
    • NEW extendPlugin method to extend a nested plugin configuration.
    • NEW configurePlugin method to configure the properties of a nested plugin.
    • NEW extendApi method to extend the plugin API. The API is then merged into editor.api[plugin.key].
    • NEW extendTransforms method to extend the plugin transforms. The transforms is then merged into editor.transforms[plugin.key].
    • NEW extendEditorApi method to extend the editor API. The API is then merged into editor.api. Use this to add or override top-level methods to the editor.
    • NEW extendEditorTransforms method to extend the editor transforms. The transforms is then merged into editor.transforms.
    • NEW extendOptions method to extend the plugin options with selectors. Use editor.useOption(plugin, 'optionKey') to subscribe to an (extended) option.
    • NEW withComponent to replace plugin.node.component

    Plugin Context

    Each plugin method now receive the plugin context created with getEditorPlugin(editor, plugin) as parameter:

    • api
    • editor
    • getOption
    • getOptions
    • plugin
    • setOption
    • setOptions
    • tf
    • type
    • useOption

    Core Plugins:

    • NEW ParagraphPlugin is now part of core
    • NEW DebugPlugin is now part of core
      • NEW api.debug.log, api.debug.info, api.debug.warn, api.debug.error methods
      • options.isProduction to control logging in production environments
      • options.logLevel to set the minimum log level
      • options.logger to customize logging behavior
      • options.throwErrors to control error throwing behavior, by default a PlateError will be thrown on api.debug.error
    • NEW - You can now override a core plugin by adding it to editor.plugins. Last plugin wins.
    • createDeserializeHtmlPlugin -> HtmlPlugin
      • NEW api.html.deserialize
    • createEventEditorPlugin -> EventEditorPlugin
      • eventEditorStore -> EventEditorStore
    • createDeserializeAstPlugin -> AstPlugin
    • createEditorProtocolPlugin -> SlateNextPlugin
      • NEW editor.tf.toggle.block
      • NEW editor.tf.toggle.mark
      • Remove createNodeFactoryPlugin, included in SlateNextPlugin.
      • Remove createPrevSelectionPlugin, included in SlateNextPlugin.
    • createHistoryPlugin -> HistoryPlugin
    • createInlineVoidPlugin -> InlineVoidPlugin
    • createInsertDataPlugin -> ParserPlugin
    • createLengthPlugin -> LengthPlugin
    • createReactPlugin -> ReactPlugin

    Editor Creation:

    NEW withSlate:

    • Extends an editor into a vanilla Plate editor
    • NEW rootPlugin option for configuring the root plugin

    NEW withPlate:

    • Extends an editor into a React Plate editor
    • Now extends withSlate with React-specific enhancements
    • NEW useOptions and useOption methods to the editor

    NEW createSlateEditor:

    • Create a vanilla Plate editor with server-side support

    createPlateEditor:

    • Plugin replacement mechanism: using plugins, any plugin with the same key that a previous plugin will replace it. That means you can now override core plugins that way, like ReactPlugin

    • root plugin is now created from createPlateEditor option as a quicker way to configure the editor than passing plugins. Since plugins can have nested plugins (think as a recursive tree), plugins option will be passed to root plugin plugins option.

    • Centralized editor resolution. Before, both createPlateEditor and Plate component were resolving the editor. Now, only createPlateEditor takes care of that. That means id, value, and other options are now controlled by createPlateEditor.

    • Remove createPlugins, pass plugins directly:

      • components -> override.components
      • overrideByKey -> override.plugins

    createPlateEditor options:

    • Rename normalizeInitialValue option to shouldNormalizeEditor
    • Move components to override.components to override components by key
    • Move overrideByKey to override.plugins to override plugins by key
    • Remove disableCorePlugins, use override.enabled instead
    • NEW value to set the initial value of the editor.
    • NEW autoSelect?: 'end' | 'start' | boolean to auto select the start of end of the editor. This is decoupled from autoFocus.
    • NEW selection to control the initial selection.
    • NEW override.enabled to disable plugins by key
    • NEW rootPlugin?: (plugin: AnyPlatePlugin) => AnyPlatePlugin to configure the root plugin. From here, you can for example call configurePlugin to configure any plugin.
    • NEW api, decorate, extendEditor, handlers, inject, normalizeInitialValue, options, override, priority, render, shortcuts, transforms, useHooks. These options will be passed to the very first rootPlugin.

    NEW usePlateEditor() hook to create a PlateEditor in a React component:

    • Uses createPlateEditor and useMemo to avoid re-creating the editor on every render.
    • Dependencies can be added to the hook to re-create the editor on demand. id option is always used as dependency.

    Editor Methods:

    editor: PlateEditor:

    • Move redecorate to editor.api.redecorate
    • Move reset to editor.tf.reset
    • Move plate.set to editor.setPlateState
    • Move blockFactory to editor.api.create.block
    • Move childrenFactory to editor.api.create.value
    • Rename plugins to pluginList
    • Rename pluginsByKey to plugins
    • NEW getApi() to get the editor API
    • NEW getTransforms() to get the editor transforms
    • Remove getPlugin(editor, key), use editor.getPlugin(plugin) or editor.getPlugin({ key })
    • Remove getPluginType, use editor.getType(plugin) to get node type
    • Remove getPluginInjectProps(editor, key), use editor.getPlugin(plugin).inject.props
    • NEW getOptionsStore() to get a plugin options store
    • Remove getPluginOptions, use getOptions()
    • NEW getOption() to get a plugin option
    • NEW setOption() to set a plugin option
    • NEW setOptions() to set multiple plugin options. Pass a function to use Immer. Pass an object to merge the options.
    • NEW useOption to subscribe to a plugin option in a React component
    • NEW useOptions to subscribe to a plugin options store in a React component
    • Remove getPlugins, use editor.pluginList
    • Remove getPluginsByKey, use editor.plugins
    • Remove mapInjectPropsToPlugin

    Editor Types:

    The new generic types are:

    • V extends Value = Value, P extends AnyPluginConfig = PlateCorePlugin
    • That means this function will infer all plugin configurations from the options passed to it:
      • key
      • options
      • api
      • transforms
    • Can't infer for some reason? Use createTPlateEditor for explicit typing.
    const editor = createPlateEditor({ plugins: [TablePlugin] });
    editor.api.htmlReact.serialize(); // core plugin is automatically inferred
    editor.tf.insert.tableRow(); // table plugin is automatically inferred

    Plate Component

    PlateProps:

    • editor is now required. If null, Plate will not render anything. As before, Plate remounts on id change.
    • Remove id, plugins, maxLength, pass these to createPlateEditor instead
    • Remove initialValue, value, pass value to createPlateEditor instead
    • Remove editorRef
    • Remove disableCorePlugins, override plugins in createPlateEditor instead

    Utils:

    • Remove useReplaceEditor since editor is now always controlled
    • NEW useEditorPlugin to get the editor and the plugin context.

    Types:

    • PlateRenderElementProps, PlateRenderLeafProps generics: V, N -> N, C

    Plate Store:

    • Remove plugins and rawPlugins, use useEditorRef().plugins instead, or listen to plugin changes with editor.useOption(plugin, <optionKey>)
    • Remove value, use useEditorValue() instead
    • Remove editorRef, use useEditorRef() instead

    Miscellaneous Changes

    • slate >=0.103.0 peer dependency
    • slate-react >=0.108.0 peer dependency
    • New dependency @udecode/react-hotkeys
    • Remove ELEMENT_, MARK_ and KEY_ constants. Use NamePlugin.key instead.
    • Replace ELEMENT_DEFAULT with ParagraphPlugin.key.
    • Remove getTEditor
    • Rename withTReact to withPlateReact
    • Rename withTHistory to withPlateHistory
    • Rename usePlateId to useEditorId
    • Remove usePlateSelectors().id(), usePlateSelectors().value(), usePlateSelectors().plugins(), use instead useEditorRef().<key>
    • Rename toggleNodeType to toggleBlock
    • toggleBlock options:
      • Rename activeType to type
      • Rename inactiveType to defaultType
    • Remove react-hotkeys-hook re-exports. Use @udecode/react-hotkeys instead.

    Types:

    • Move TEditableProps, TRenderElementProps to @udecode/slate-react
    • Remove <V extends Value> generic in all functions where not used
    • Remove PlatePluginKey
    • Remove OverrideByKey
    • Remove PlateId

@udecode/[email protected]

@udecode/[email protected]

@udecode/[email protected]

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createDndPlugin -> DndPlugin
    • Remove editor.isDragging, use editor.getOptions(DndPlugin).isDragging instead
    • Move dndStore to DndPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createDeserializeDocxPlugin -> DocxPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createEmojiPlugin -> EmojiPlugin
    • NEW EmojiInputPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createExcalidrawPlugin -> ExcalidrawPlugin
    • insertExcalidraw remove key option

@udecode/[email protected]

  • #3420 by @zbeyens
    • createFindReplacePlugin -> FindReplacePlugin

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createFontBackgroundColorPlugin -> FontBackgroundColorPlugin
    • createFontColorPlugin -> FontColorPlugin
    • createFontSizePlugin -> FontSizePlugin
    • createFontFamilyPlugin -> FontFamilyPlugin
    • createFontWeightPlugin -> FontWeightPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createHeadingPlugin -> HeadingPlugin
    • Replace ELEMENT_H1 with HEADING_KEYS.H1
    • Replace KEYS_HEADING with HEADING_LEVELS

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createHorizontalRulePlugin -> HorizontalRulePlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createDeserializeHtmlPlugin -> HtmlPlugin
    • Rename deserializeHtml plugin to html
    • Rename deserializeHtml.getNode to parse

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createIndentListPlugin -> IndentListPlugin
    • Rename injectIndentListComponent to renderIndentListBelowNodes
    • Replace normalizeIndentList with withNormalizeIndentList
    • Replace deleteBackwardIndentList with withDeleteBackwardIndentList
    • Replace insertBreakIndentList with withInsertBreakIndentList
    • Remove types: LiFC (use PlateRenderElementProps), MarkerFC (use Omit<PlateRenderElementProps, 'children'>)

@udecode/[email protected]

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createColumnPlugin -> ColumnPlugin
    • NEW ColumnItemPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createLineHeightPlugin -> LineHeightPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createLinkPlugin -> LinkPlugin
    • Move floatingLinkStore to LinkPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createListPlugin -> ListPlugin
    • NEW BulletedListPlugin
    • NEW NumberedListPlugin
    • NEW ListItemPlugin
    • NEW ListItemContentPlugin
    • NEW list transforms: toggle.list, toggle.bulletedList, toggle.numberedList
    • Remove type utils: getListItemType, getUnorderedListType, getOrderedListType, getListItemContentType
    • Replace insertBreakList(editor) with withInsertBreakList(ctx)
    • Replace insertFragmentList(editor) with withInsertFragmentList(ctx)
    • Replace insertBreakTodoList(editor) with withInsertBreakTodoList(ctx)
    • Replace deleteForwardList(editor) with withdeleteForwardList(ctx)
    • Replace deleteBackwardList(editor) with withdeleteBackwardList(ctx)
    • Move list options from ul and ol to list plugin
    • toggleList options are now { type: string }

@udecode/[email protected]

  • #3420 by @zbeyens
    • createDeserializeMdPlugin -> MarkdownPlugin

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createMediaPlugin -> MediaPlugin
    • FloatingMediaUrlInput, submitFloatingMedia rename option pluginKey -> plugin
    • insertMediaEmbed remove key option

@udecode/[email protected]

  • #3420 by @zbeyens
    • createMentionPlugin -> MentionPlugin
    • NEW MentionInputPlugin
    • Remove createMentionNode option, override api.insert.mention instead

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createNormalizersPlugin -> NormalizersPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • NEW @udecode/plate-layout
    • NEW /react exports @udecode/react-hotkeys
    • Split build into @udecode/plate and @udecode/plate/react.
    • Remove @udecode/plate-paragraph
    • All stores now start with a capital letter

@udecode/[email protected]

  • #3420 by @zbeyens
    • Remove onKeyDownToggleElement, use shortcuts instead.
    • Remove onKeyDownToggleMark, use shortcuts instead.

@udecode/[email protected]

  • #3473 by @12joan – New package for integrating Plate with Playwright tests

@udecode/[email protected]

@udecode/[email protected]

@udecode/[email protected]

  • #3420 by @zbeyens
    • createSelectOnBackspacePlugin -> SelectOnBackspacePlugin
    • createDeletePlugin -> DeletePlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • Rename createSelectionPlugin to BlockSelectionPlugin
    • Remove isNodeBlockSelected, isBlockSelected, hasBlockSelected, useBlockSelected functions
      • Use editor.getOptions(BlockSelectionPlugin) or editor.useOptions(BlockSelectionPlugin) instead
    • Remove addSelectedRow function
      • Use editor.api.blockSelection.addSelectedRow instead
    • Remove withSelection HOC
    • Rename onCloseBlockSelection to onChangeBlockSelection
    • Moved blockSelectionStore to BlockSelectionPlugin
    • Moved blockContextMenuStore to BlockContextMenuPlugin
    • Remove BlockStartArea and BlockSelectionArea components
      • Use areaOptions in BlockSelectionPlugin for configuration instead
    • Remove dependency on @viselect/vanilla package
      • Forked and integrated selection functionality locally
    • Add BlockContextMenuPlugin, which is now used by BlockSelectionPlugin
      • No need to add it manually
    • Fix scroll-related bugs in the selection functionality
    • Improve performance and reliability of block selection

@udecode/[email protected]

  • #3420 by @zbeyens
    • createSlashPlugin -> SlashPlugin
    • NEW SlashInputPlugin

@udecode/[email protected]

  • #3420 by @zbeyenscreateTEditor:

    • Implement default methods for slate-react and slate-history in createTEditor
    • Add noop function to provide default implementations for unimplemented editor methods

    Types:

    • Merge ReactEditor and HistoryEditor interfaces into TEditor, removing TReactEditor and THistoryEditor
    • Remove Value generic type parameter from function signatures and type definitions
    • Replace V extends Value with E extends TEditor for improved type inference
    • Simplify TEditor<V> to TEditor in many places
    • Refactor element-related types, where E extends TEditor in all cases:
      • EElement<V> to ElementOf<E>
      • EText<V> to TextOf<E>
      • ENode<V> to NodeOf<E>
      • EDescendant<V> to DescendantOf<E>
      • EAncestor<V> to AncestorOf<E>
      • EElementOrText<V> to ElementOrTextOf<E>
    • Update TNodeEntry related types:
      • ENodeEntry<V> to NodeEntryOf<E>
      • EElementEntry<V> to ElementEntryOf<E>
      • ETextEntry<V> to TextEntryOf<E>
      • EAncestorEntry<V> to AncestorEntryOf<E>
      • EDescendantEntry<V> to DescendantEntryOf<E>
    • Remove unused types:
      • EElementEntry<V>
      • ETextEntry<V>
      • EDescendantEntry<V>

@udecode/[email protected]

  • #3420 by @zbeyens – Types:

    • Remove TReactEditor type, as it's now integrated into the main TEditor type in @udecode/slate. Use TEditor instead.
    • Replace V extends Value with E extends TEditor for improved type inference
    • NEW TEditableProps, TRenderElementProps

@udecode/[email protected]

  • #3420 by @zbeyens – Types:

    • Replace V extends Value with E extends TEditor for improved type inference

@udecode/[email protected]

  • #3420 by @zbeyens
    • createSuggestionPlugin -> SuggestionPlugin
    • Move suggestionStore to SuggestionPlugin
    • Remove SuggestionProvider and its hooks
    • Remove useSuggestionStates (replaced by direct option access)
    • Remove useSuggestionSelectors (replaced by option selectors)
    • Remove useSuggestionActions (replaced by api methods)
    • Replace useUpdateSuggestion with api.suggestion.updateSuggestion
    • Replace useAddSuggestion with api.suggestion.addSuggestion
    • Replace useRemoveSuggestion with api.suggestion.removeSuggestion
    • Replace useSuggestionById with options.suggestionById
    • Replace useSuggestionUserById with options.suggestionUserById
    • Replace useCurrentSuggestionUser with options.currentSuggestionUser
    • Remove editor.activeSuggestionId, use plugin option
    • Remove useSetIsSuggesting, use editor.setOption
    • Remove useSetActiveSuggestionId, use editor.setOption
    • Remove editor.isSuggesting, use plugin option
    • Remove SuggestionEditorProps type

@udecode/[email protected]

  • #3420 by @zbeyens
    • createTabbablePlugin -> TabbablePlugin
    • TabbablePlugin option isTabbable: remove first editor parameter

@udecode/[email protected]

  • #3420 by @zbeyens
    • createTablePlugin -> TablePlugin
    • NEW TableRowPlugin, TableCellPlugin, TableCellHeaderPlugin
    • Replace insertTableColumn with editor.insert.tableColumn
    • Replace insertTableRow with editor.insert.tableRow
    • Move cellFactory option to create.cell api
    • Move getCellChildren option to table.getCellChildren api

@udecode/[email protected]

  • #3420 by @zbeyens
    • createTogglePlugin -> TogglePlugin
    • Move toggleControllerStore to TogglePlugin
    • Remove setOpenIds option
    • Replace isToggleOpen with option isOpen
    • Rename injectToggle to renderToggleAboveNodes

@udecode/[email protected]

  • #3420 by @zbeyens
    • createTrailingBlockPlugin -> TrailingBlockPlugin

@udecode/[email protected]

  • #3420 by @zbeyens
    • createYjsPlugin -> YjsPlugin
    • Move yjsStore to YjsPlugin
    • Move editor.yjs.provider to options.provider
    • Rename RenderAboveEditableYjs to YjsAboveEditable

36.0.0

No breaking changes

35.0.0

@udecode/[email protected]

  • #3282 by @12joan – Make the dependency on prismjs optional

    New usage:

    // Import Prism with your supported languages
    import Prism from 'prismjs';
     
    import 'prismjs/components/prism-antlr4.js';
    import 'prismjs/components/prism-bash.js';
    import 'prismjs/components/prism-c.js';
    // ...
     
    const plugins = createPlugins([
      createCodeBlockPlugin({
        options: {
          prism: Prism,
        },
      }),
    ]);

34.0.0

@udecode/[email protected]

  • Breaking Change: The selectedColor option for BlockSelectable has been deprecated. Please use useBlockSelected to customize the style of each node component.

  • #3241 by @felixfeng33 – Add logic for the block-context-menu and improved the user experience for block-selection, such as interactions related to keyboard shortcuts, bug fixes.

  • Starting from this version, a single Cmd+A will no longer select the entire document but will select the entire block instead. Double Cmd+A will use the blockSelection plugin to select all blocks. To disable this behavior, pass handlers: { onKeyDown: null }.

33.0.0

@udecode/[email protected]

  • #3125 by @zbeyens
    • serializeMd: remove nodes option. editor.children is now serialized

32.0.0

None (CI release issue)

31.0.0

None (CI release issue)

30.0.0

@udecode/[email protected]

  • #2867 by @12joan – Fix: in v28, TableProvider was incorrectly shared by all tables in the editor. TableProvider must now be rendered as part of TableElement.

29.0.0

@udecode/[email protected]

  • #2829 by @zbeyens
    • Moved withProps to @udecode/cn
    • Moved PortalBody, Text, Box, createPrimitiveComponent, createSlotComponent, withProviders to @udecode/react-utils
    • Removed getRootProps (unused)

28.0.0

@udecode/[email protected]

  • 822f6f56b by @12joan
    • Remove { fn: ... } workaround for jotai stores that contain functions
    • Breaking change: usePlateSelectors, usePlateActions and usePlateStates no longer accept generic type arguments. If custom types are required, cast the resulting values at the point of use, or use hooks like useEditorRef that still provide generics.

27.0.0

@udecode/[email protected]

  • #2763 by @12joan
    • Migrate store to jotai@2
    • Revert the breaking changes to @udecode/plate-comments made in 26.0.0

@udecode/[email protected]

  • #2763 by @12joan
    • Migrate store from jotai@1 to jotai@2
      • New dependency: jotai-x. See https://github.com/udecode/jotai-x
      • Accessing a store without an explicit provider component is no longer supported. Attempting to do so will result in a warning in the console: Tried to access jotai store '${storeName}' outside of a matching provider.
    • Upgraded from zustand@3 to zustand@4
    • Rename zustand-x exports
      • StateActions -> ZustandStateActions
      • StoreApi -> ZustandStoreApi
      • createStore -> createZustandStore
      • Note that these exports are deprecated and should not be used in new code. They may be removed in a future version of Plate.

@udecode/[email protected]

  • #2763 by @12joan
    • Migrate store to jotai@2
    • Resizable components must now be wrapped inside a ResizableProvider

26.0.0

@udecode/[email protected]

  • #2760 by @12joan
    • Renamed the comments prop on CommentsProvider to initialComments to reflect the fact that updating its value after the initial render has no effect
    • Removed the following props from CommentsProvider, since they represent the internal state of the comments plugin and should not be controlled externally:
      • activeCommentId
      • addingCommentId
      • newValue
      • focusTextarea
    • The following props on CommentsProvider can now be updated after the initial render (whereas prior to this version, doing so had no effect):
      • myUserId
      • users
      • onCommentAdd
      • onCommentUpdate
      • onCommentDelete

@udecode/[email protected]

  • #2733 by @dimaanj
    • [Breaking] serializeHtml: replaced option slateProps by plateProps.

25.0.1

@udecode/[email protected]

  • #2729 by @12joanThis is a breaking change meant to be part of v25, hence the patch. On deserializeHtml, replace stripWhitespace with collapseWhiteSpace, defaulting to true. The collapseWhiteSpace option aims to parse white space in HTML according to the HTML specification, ensuring greater accuracy when pasting HTML from browsers.

@udecode/[email protected]

  • #2725 by @EandrewJones – Remove useCommentValue, which was redundant with the hooks applied automatically in CommentEditTextarea.tsx.

24.0.0

@udecode/[email protected]

  • #2629 by @zbeyens

    • [Breaking] Rename Plate to PlateContent.
    • [Breaking] Rename PlateProvider to Plate.
    • [Breaking] Rendering PlateContent is now required in Plate. This allows you to choose where to render the editor next to other components like toolbar. Example:
    // Before
    <Plate />
    // or
    <PlateProvider>
      <Plate />
    </PlateProvider>
     
    // After
    <Plate>
      <PlateContent />
    </Plate>
    • [Breaking] Remove provider props such as plugins from PlateContent. These props should be passed to Plate.
    • [Breaking] Remove editableProps prop from PlateContent. Move these asPlateContent props.
    • [Breaking] Remove children prop from PlateContent. Render instead these components after PlateContent.
    • [Breaking] Remove firstChildren prop from PlateContent. Render instead these components before PlateContent.
    • [Breaking] Remove editableRef prop from PlateContent. Use ref instead.
    • [Breaking] Remove withPlateProvider.
    • [Breaking] Rename usePlateEditorRef to useEditorRef.
    • [Breaking] Rename usePlateEditorState to useEditorState.
    • [Breaking] Rename usePlateReadOnly to useEditorReadOnly. This hook can be used below Plate while useReadOnly can only be used in node components.
    • [Breaking] Rename usePlateSelection to useEditorSelection.
    • [Breaking] Rename store attributes keyDecorate, keyEditor and keySelection to versionDecorate, versionEditor and versionSelection. These are now numbers incremented on each change.
    • [Breaking] Rename store attribute isRendered to isMounted.

23.0.0

@udecode/[email protected]

  • #2537 by @haydencarlsonMediaEmbedElement is now more headless with a smaller bundle size. Update the following components:

    • npx shadcn@canary add media-embed-element
      • now uses react-lite-youtube-embed for YouTube videos.
      • now uses react-tweet for Twitter tweets.
    • npx shadcn@canary add image-element

    Breaking changes:

    • Moved Resizable to @udecode/plate-resizable
    • Moved Caption, CaptionTextarea to @udecode/plate-caption
    • Removed useMediaEmbed, MediaEmbedVideo, MediaEmbedTweet, Tweet, parseMediaUrl, mediaStore
    • Removed @udecode/resizable, scriptjs, react-textarea-autosize dependencies
    • MediaPlugin
      • removed rules. Use parsers option instead.
      • removed disableCaption. Use createCaptionPlugin instead.
    • Caption is now a separate plugin. Install @udecode/plate-caption and add it to your plugins:
    import { ELEMENT_IMAGE, ELEMENT_MEDIA_EMBED } from '@udecode/plate-media';
     
    createCaptionPlugin({
      options: { pluginKeys: [ELEMENT_IMAGE, ELEMENT_MEDIA_EMBED] },
    });

@udecode/[email protected]

  • #2541 by @zbeyens
    • Package renamed to @udecode/plate-resizable.
    • ResizeHandle is now fully headless: no style is applied by default. Add your own Resizable, ResizeHandle components:
      • npx shadcn@canary add resizable

@udecode/[email protected]

  • Removed TableCellElementResizable. Use useTableCellElementResizableState and useTableCellElementResizable instead.

22.0.0

Headless UI.

@udecode/[email protected]

Migration:

  • Manual installation.
  • For each unresolved import not listed in the following major changes (components from @udecode/plate-ui-x), generate the component using the CLI.

@udecode/[email protected]

  • #2471 by @zbeyens – Removed:
    • AccountCircleIcon
    • CheckIcon
    • MoreVertIcon
    • RefreshIcon
    • AvatarImage
    • CommentLinkButton
    • CommentLinkDialog
    • CommentLinkDialogCloseButton
    • CommentLinkDialogCopyLink
    • CommentLinkDialogInput
    • PlateCommentLeaf for useCommentLeafState

@udecode/[email protected]

  • #2471 by @zbeyens – Removed:
    • Draggable
    • DraggableBlock
    • DraggableBlockToolbar
    • DraggableBlockToolbarWrapper
    • DraggableDropline
    • DraggableGutterLeftProps
    • DraggableRoot
    • DragHandle

@udecode/[email protected]

  • #2471 by @zbeyens – Removed:
    • FloatingLink
    • FloatingLinkEditButton
    • FloatingLinkTextInput
    • UnlinkButton
    • LaunchIcon
    • Link
    • LinkIcon
    • LinkOffIcon
    • ShortTextIcon

@udecode/[email protected]

@udecode/[email protected]

  • #2471 by @zbeyens – Plate 2.0 – Headless UI. Read the docs about the new UI pattern: https://platejs.org/docs/components.

    • Removed @udecode/plate-ui dependency.
    • Removed @udecode/plate-emoji dependency. You can install it separately.
    • Removed styled-components peerDependency.

    Replaced @udecode/plate-headless dependency (deprecated) by:

    • @udecode/plate-alignment
    • @udecode/plate-autoformat
    • @udecode/plate-basic-elements
    • @udecode/plate-basic-marks
    • @udecode/plate-block-quote
    • @udecode/plate-break
    • @udecode/plate-code-block
    • @udecode/plate-combobox
    • @udecode/plate-comments
    • @udecode/plate-common
    • @udecode/plate-find-replace
    • @udecode/plate-floating
    • @udecode/plate-font
    • @udecode/plate-heading
    • @udecode/plate-highlight
    • @udecode/plate-horizontal-rule
    • @udecode/plate-indent
    • @udecode/plate-indent-list
    • @udecode/plate-kbd
    • @udecode/plate-line-height
    • @udecode/plate-link
    • @udecode/plate-list
    • @udecode/plate-media
    • @udecode/plate-mention
    • @udecode/plate-node-id
    • @udecode/plate-normalizers
    • @udecode/plate-paragraph
    • @udecode/plate-reset-node
    • @udecode/plate-select
    • @udecode/plate-serializer-csv
    • @udecode/plate-serializer-docx
    • @udecode/plate-serializer-html
    • @udecode/plate-serializer-md
    • @udecode/plate-suggestion
    • @udecode/plate-tabbable
    • @udecode/plate-table
    • @udecode/plate-trailing-block
    • @udecode/resizable

@udecode/[email protected]

  • #2471 by @zbeyens – Upgraded peer dependencies:
    • slate-react: >=0.95.0 Removed:
    • useElementPrpos
    • useWrapElement
    • createComponentAs
    • createElementAs

@udecode/[email protected]

  • #2471 by @zbeyens – Removed:
    • TableCellElement
    • TableCellElementResizableWrapper
    • TableCellElementRoot
    • TableElement
    • TableElementCol
    • TableElementColGroup
    • TableElementRoot
    • TableElementTBody
    • TableRowElement
    • ArrowDropDownCircleIcon
    • BorderAllIcon
    • BorderBottomIcon
    • BorderLeftIcon
    • BorderNoneIcon
    • BorderOuterIcon
    • BorderRightIcon
    • BorderTopIcon

21.0.0

@udecode/[email protected]

20.0.0

@udecode/[email protected]

  • 0077402 by @zbeyens
    • This package has been split into multiple packages for separation of concerns and decoupled versioning:
      • @udecode/utils is a collection of miscellaneous utilities. Can be used by any project.
      • @udecode/slate is a collection of slate experimental features and bug fixes that may be moved into slate one day. It's essentially composed of the generic types. Can be used by vanilla slate consumers without plate.
      • @udecode/slate-react is a collection of slate-react experimental features and bug fixes that that may be moved into slate-react one day. It's essentially composed of the generic types. Can be used by vanilla slate-react consumers without plate.
      • @udecode/plate-core is the minimalistic core of plate. It essentially includes Plate, PlateProvider and their dependencies. Note this package is not dependent on the *-utils packages.
      • @udecode/slate-utils is a collection of utils depending on @udecode/slate. Can be used by vanilla slate consumers without plate.
      • @udecode/plate-utils is a collection of utils depending on @udecode/slate-react and @udecode/plate-core
      • @udecode/plate-common re-exports the 6 previous packages and is a dependency of all the other packages. It's basically replacing @udecore/plate-core as a bundle.
    • Removed getPreventDefaultHandler since it is no longer needed. Migration:
      • If using @udecode/plate or @udecode/plate-headless: none
      • Else: find & replace @udecode/plate-core by @udecode/plate-common

@udecode/[email protected]

  • #2240 by @OliverWales
    • Add allowedSchemes plugin option
      • Any URL schemes other than http(s), mailto and tel must be added to allowedSchemes, otherwise they will not be included in links

@udecode/[email protected]

  • #2251 by @zbeyens
    • TablePlugin option disableUnsetSingleColSize has been renamed and inverted into enableUnsetSingleColSize. New default is disabled. Migration:
      • if using disableUnsetSingleColSize: true, the option can be removed
      • if using disableUnsetSingleColSize: false, use enableUnsetSingleColSize: true
    • getTableColumnIndex second parameter type is now: cellNode: TElement

@udecode/[email protected]

  • #2237 by @tmorane – Unstyled logic has been moved to @udecode/plate-dnd

    // before
    import { createDndPlugin } from '@udecode/plate-ui-dnd';
     
    // after
    import { createDndPlugin } from '@udecode/plate-dnd';

    Only withPlateDraggable, withPlateDraggables and PlateDraggable are left in @udecode/plate-ui-dnd. Renamed:

    • withDraggables -> withPlateDraggables. In the second parameter, draggable props options have been moved under draggableProps:
    // before
    {
      onRenderDragHandle: () => {}
      styles,
    }
     
    // after
    {
      draggableProps: {
        onRenderDragHandle: () => {}
        styles,
      },
    }

@udecode/[email protected]

  • #2251 by @zbeyens – Headless components and hooks moved to @udecode/plate-table, so the following components have been renamed:
    • TableElement -> PlateTableElement
      • removed table border to set it at the cell level
      • margin-left: 1px to support cell borders
      • if all columns have a fixed size, the table will have a dynamic width instead of always 100%
    • TableRowElement -> PlateTableRowElement
    • TableCellElement -> PlateTableCellElement
      • removed td border in favor of td::before. The latter is responsible of having the border and the selected background color.
      • z-index: td is 0, td::before is 10, td::before in selected state is 20, handle is 30, handle resize is 40.
      • removed selectedCell div in favor of ::before
    • TablePopover -> PlateTablePopover Styled props have been removed.

19.0.0

@udecode/[email protected]

  • #2097 by @zbeyens
    • upgrade deps, including typescript support for the new editor methods:
    // from
    "slate": "0.78.0",
    "slate-history": "0.66.0",
    "slate-react": "0.79.0"
    // to
    "slate": "0.87.0",
    "slate-history": "0.86.0",
    "slate-react": "0.88.0"

@udecode/[email protected]

  • #2097 by @zbeyens
    • due to esm issues, dnd plugin is not part of plate package anymore. To use it, install @udecode/plate-ui-dnd
    // before
    import { createDndPlugin } from '@udecode/plate';
    // after
    import { createDndPlugin } from '@udecode/plate-ui-dnd';
    • upgrade peerDeps:
    // from
    "slate": ">=0.78.0",
    "slate-history": ">=0.66.0",
    "slate-react": ">=0.79.0"
    // to
    "slate": ">=0.87.0",
    "slate-history": ">=0.86.0",
    "slate-react": ">=0.88.0"

18.0.0

@udecode/[email protected]

  • #1889 by @zbeyens
    • @udecode/plate-selection package moved out from @udecode/plate because of https://github.com/Simonwep/selection/issues/124
    • Migration:
      • If not using createBlockSelectionPlugin, no migration is needed.
      • Otherwise, install @udecode/plate-selection and import createBlockSelectionPlugin from that package.

17.0.0

@udecode/[email protected]

  • #1871 by @zbeyens

    • usePlateStore:
      • Plate no longer has a global store containing all the editor states (zustand). Each editor store is now defined in a React context tree (jotai). If you need to access all the editor states at once (as you could do before), you'll need to build that layer yourself.
      • Plate store is now accessible only below PlateProvider or Plate (provider-less mode). It means it's no longer accessible outside of a Plate React tree. If you have such use-case, you'll need to build your own layer to share the state between your components.
      • You can nest many PlateProvider with different scopes (id prop). Default scope is PLATE_SCOPE
      • Hook usage:
        • const value = usePlateSelectors(id).value()
        • const setValue = usePlateActions(id).value()
        • const [value, setValue] = usePlateStates(id).value()
      • removed from the store:
        • editableProps, use the props instead
        • enabled, use conditional rendering instead
        • isReady, no point anymore as it's now directly ready
      • useEventPlateId is still used to get the last focused editor id.
      • Functions are stored in an object { fn: <here> }
        • const setOnChange = usePlateActions(id).onChange()
        • setOnChange({ fn: newOnChange })
    • Plate
      • if rendered below PlateProvider, it will render PlateSlate > PlateEditable
      • if rendered without PlateProvider, it will render PlateProvider > PlateSlate > PlateEditable
      • default id is no longer main, it's now PLATE_SCOPE
    • PlateProvider
      • Each provider has an optional scope, so you can have multiple providers in the same React tree and use the plate hooks with the corresponding scope.
      • Plate effects are now run in PlateProvider
        • initialValue, value, editor, normalizeInitialValue, normalizeEditor are no longer defined in an effect (SSR support)
      • Props:
        • now extends the previous Plate props
        • if using PlateProvider, set the provider props on it instead of Plate. Plate would only need editableProps and PlateEditableExtendedProps
        • if not using it, set the provider props on Plate
    // Before
    <PlateProvider>
      <Toolbar>
        <AlignToolbarButtons />
      </Toolbar>
     
      <Plate<MyValue> editableProps={editableProps} <MyValue> initialValue={alignValue} plugins={plugins} />
    </PlateProvider>
     
    // After
    <PlateProvider<MyValue> initialValue={alignValue} plugins={plugins}>
      <Toolbar>
        <AlignToolbarButtons />
      </Toolbar>
     
      <Plate<MyValue> editableProps={editableProps} />
    </PlateProvider>
     
    // After (provider-less mode)
    <Plate<MyValue> editableProps={editableProps} initialValue={alignValue} plugins={plugins} />
    • types:
      • store editor is no longer nullable
      • store value is no longer nullable
      • id type is now PlateId
    • renamed:
      • SCOPE_PLATE to PLATE_SCOPE
      • getEventEditorId to getEventPlateId
      • getPlateActions().resetEditor to useResetPlateEditor()
    • removed:
      • plateIdAtom
      • usePlateId for usePlateSelectors().id()
      • EditablePlugins for PlateEditable
      • SlateChildren
      • PlateEventProvider for PlateProvider
      • withPlateEventProvider for withPlateProvider
      • usePlate
      • usePlatesStoreEffect
      • useEventEditorId for useEventPlateId
      • platesStore, platesActions, platesSelectors, usePlatesSelectors
      • getPlateActions for usePlateActions
      • getPlateSelectors for usePlateSelectors
      • getPlateEditorRef for usePlateEditorRef
      • getPlateStore, usePlateStore
      • EditorId for PlateId

@udecode/[email protected]

  • #1871 by @zbeyens
    • Removed these imports because of build errors:
      • prismjs/components/prism-django
      • prismjs/components/prism-ejs
      • prismjs/components/prism-php

@udecode/[email protected]

  • #1871 by @zbeyens
    • Removed [ELEMENT_CODE_BLOCK]: CodeBlockElement from Plate UI. You can define it in your app.

16.0.0

@udecode/[email protected]

@udecode/[email protected]

  • #1721 by @zbeyens
    • deprecate @udecode/plate-image and @udecode/plate-media-embed, those got merged into @udecode/plate-media

@udecode/[email protected]

  • #1721 by @zbeyens
    • removed:
      • useImageElement for useElement
      • MediaEmbedUrlInput for FloatingMediaUrlInput
      • parseEmbedUrl for parseMediaUrl
      • EmbedProviders
    • renamed:
      • ImageImg to Image
      • ImageCaptionTextarea to CaptionTextarea
      • useImageCaptionString to useCaptionString
      • ImageResizable to Resizable

@udecode/[email protected]

  • #1721 by @zbeyens
  • TableElementBase props:
    • replace onRenderContainer by floatingOptions or by replacing ELEMENT_TABLE in the createPlateUI function.
  • TablePopover is now a floating instead of tippy
  • deps:
    • replaced plate-ui-popover by plate-floating

@udecode/[email protected]

  • #1721 by @zbeyens
  • deprecate @udecode/plate-ui-popover for @udecode/plate-floating

15.0.0

@udecode/[email protected]

  • #1677 by @zbeyens
    • deps:
      • replaced @udecode/plate-ui-popper by @udecode/plate-floating
    • comboboxStore:
      • removed popperContainer, use floatingOptions instead
      • removed popperOptions, use floatingOptions instead

@udecode/[email protected]

  • #1677 by @zbeyens
    • createLinkPlugin
      • removed onKeyDownLink for floating link
      • removed hotkey for triggerFloatingLinkHotkeys
    • removed:
      • getAndUpsertLink for upsertLink
      • upsertLinkAtSelection for upsertLink
    • LinkToolbarButton:
      • onClick now calls triggerFloatingLink

@udecode/[email protected]

  • #1677 by @zbeyens
  • remove addRow for insertTableRow
  • remove addColumn for insertTableColumn

@udecode/[email protected]

  • #1677 by @zbeyens
    • remove @udecode/plate-ui-popper dep for @udecode/plate-floating

@udecode/[email protected]

  • #1677 by @zbeyens
    • moved Button to @udecode/plate-button
    • Button is now unstyled

@udecode/[email protected]

  • #1677 by @zbeyens
  • deprecated, use instead @udecode/plate-floating

@udecode/[email protected]

  • #1677 by @zbeyens
  • remove @udecode/plate-ui-popper and react-popper deps for @udecode/plate-floating
  • BalloonToolbarProps:
    • removed popperOptions for floatingOptions
  • remove useBalloonToolbarPopper for useFloatingToolbar

14.0.0

@udecode/[email protected]

  • #1633 by @tjramage – Moved serializeHtml and its utils to @udecode/plate-serializer-html as it has a new dependency: html-entities.
    • If you're using @udecode/plate, no migration is needed
    • Otherwise, import it from @udecode/plate-serializer-html

13.0.0

@udecode/[email protected]

  • Plate children are now rendered as last children of Slate (previously first children). To reproduce the previous behavior, move children to firstChildren

@udecode/[email protected]

@udecode/[email protected]

  • #1585 by @zbeyens – Removed @udecode/plate-juice from @udecode/plate. Install it if using @udecode/plate-serializer-docx:
    yarn install @udecode/plate-juice

@udecode/[email protected]

@udecode/[email protected]

@udecode/[email protected]

  • #1585 by @zbeyens – Moved react-dnd react-dnd-html5-backend deps to peer-dependencies. Install these if using @udecode/plate-ui-dnd:
    yarn install react-dnd react-dnd-html5-backend

12.0.0

@udecode/[email protected]

  • #1579 by @zbeyens – renamed:
  • useDndBlock options:
    • blockRef -> nodeRef
    • removePreview -> preview.disable
  • useDropBlockOnEditor -> useDropBlock
  • useDropBlock options:
    • blockRef -> nodeRef
    • setDropLine -> onChangeDropLine signature change:
  • getHoverDirection:
// before
(
  dragItem: DragItemBlock,
  monitor: DropTargetMonitor,
  ref: any,
  hoverId: string
)
// after
{
  dragItem,
  id,
  monitor,
  nodeRef,
}: GetHoverDirectionOptions

11.0.0

@udecode/[email protected]

  • #1500 by @zbeyens – Thanks @ianstormtaylor for the initial work on https://github.com/ianstormtaylor/slate/pull/4177.

    This release includes major changes to plate and slate types:

    • Changing the TEditor type to be TEditor<V> where V represents the "value" being edited by Slate. In the most generic editor, V would be equivalent to TElement[] (since that is what is accepted as children of the editor). But in a custom editor, you might have TEditor<Array<Paragraph | Quote>>.
    • Other TEditor-and-TNode-related methods have been also made generic, so for example if you use getLeafNode(editor, path) it knows that the return value is a TText node. But more specifically, it knows that it is the text node of the type you've defined in your custom elements (with any marks you've defined).
    • This replaces the declaration merging approach, and provides some benefits. One of the drawbacks to declaration merging was that it was impossible to know whether you were dealing with an "unknown" or "known" element, since the underlying type was changed. Similarly, having two editors on the page with different schemas wasn't possible to represent. Hopefully this approach with generics will be able to smoothly replace the declaration merging approach. (While being easy to migrate to, since you can pass those same custom element definitions into TEditor still.)

Define your custom types

Slate types

Those Slate types should be replaced by the new types:

  • Editor -> TEditor<V extends Value = Value>
    • Note that TEditor methods are not typed based on Value as it would introduce a circular dependency. You can use getTEditor(editor) to get the editor with typed methods.
  • ReactEditor -> TReactEditor<V extends Value = Value>
  • HistoryEditor -> THistoryEditor<V extends Value = Value>
  • EditableProps -> TEditableProps<V extends Value = Value>
  • Node -> TNode
  • Element -> TElement
  • Text -> TText
  • NodeEntry -> TNodeEntry
  • NodeProps -> TNodeProps

Slate functions

Those Slate functions should be replaced by the new typed ones:

  • As the new editor type is not matching the slate ones, all Transforms, Editor, Node, Element, Text, HistoryEditor, ReactEditor functions should be replaced: The whole API has been typed into Plate core. See https://github.com/udecode/plate/packages/core/src/slate
  • createEditor -> createTEditor
  • withReact -> withTReact
  • withHistory -> withTHistory

Generic types

  • <T = {}> could be used to extend the editor type. It is now replaced by <E extends PlateEditor<V> = PlateEditor<V>> to customize the whole editor type.

  • When the plugin type is customizable, these generics are used: <P = PluginOptions, V extends Value = Value, E extends PlateEditor<V> = PlateEditor<V>>, where P is the plugin options type.

  • Editor functions are using <V extends Value> generic, where V can be a custom editor value type used in PlateEditor<V>.

  • Editor functions returning a node are using <N extends ENode<V>, V extends Value = Value> generics, where N can be a custom returned node type.

  • Editor callbacks (e.g. a plugin option) are using <V extends Value = Value, E extends PlateEditor<V> = PlateEditor<V>> generics, where E can be a custom editor type.

  • Node functions returning a node are using <N extends Node, R extends TNode = TNode> generics.

  • These generics are used by <V extends Value, K extends keyof EMarks<V>>: getMarks, isMarkActive, removeMark, setMarks, ToggleMarkPlugin, addMark, removeEditorMark

  • WithOverride is a special type case as it can return a new editor type:

    // before
    export type WithOverride<T = {}, P = {}> = (
      editor: PlateEditor<T>,
      plugin: WithPlatePlugin<T, P>
    ) => PlateEditor<T>;
     
    // after - where E is the Editor type (input), and EE is the Extended Editor type (output)
    export type WithOverride<
      P = PluginOptions,
      V extends Value = Value,
      E extends PlateEditor<V> = PlateEditor<V>,
      EE extends E = E,
    > = (editor: E, plugin: WithPlatePlugin<P, V, E>) => EE;
  • type TEditor<V extends Value>

  • type PlateEditor<V extends Value>

Renamed functions

  • getAbove -> getAboveNode
  • getParent -> getParentNode
  • getText -> getEditorString
  • getLastNode -> getLastNodeByLevel
  • getPointBefore -> getPointBeforeLocation
  • getNodes -> getNodeEntries
  • isStart -> isStartPoint
  • isEnd -> isEndPoint

Replaced types

Removing node props types in favor of element types (same props + extends TElement). You can use TNodeProps to get the node data (props).

  • LinkNodeData -> TLinkElement
  • ImageNodeData -> TImageElement
  • TableNodeData -> TTableElement
  • MentionNodeData -> TMentionElement
  • MentionNode -> TMentionElement
  • MentionInputNodeData -> TMentionInputElement
  • MentionInputNode -> TMentionInputElement
  • CodeBlockNodeData -> TCodeBlockElement
  • MediaEmbedNodeData -> TMediaEmbedElement
  • TodoListItemNodeData -> TTodoListItemElement
  • ExcalidrawNodeData -> TExcalidrawElement

Utils

  • match signature change:
<T extends TNode>(
  obj: T,
  path: TPath,
  predicate?: Predicate<T>
)
  • deleteFragment is now using Editor.deleteFragment

@udecode/[email protected]

  • getEmptyTableNode default options changed. Migration:
// From (0 row count and col count, previously it was 2)
getEmptyTableNode(editor);
// To
getEmptyTableNode(editor, { rowCount: 2, colCount: 2 });

@udecode/[email protected]

Generic types

  • type StyledElementProps<V extends Value, N extends TElement = EElement<V>, TStyles = {}>

10.0.0

@udecode/[email protected]

  • #1377 by @zbeyens – Before, BalloonToolbar could be outside Plate. Now, BallonToolbar should be a child of Plate to support multiple editors.

9.0.0

@udecode/[email protected]

  • #1303 by @zbeyens
    • Plate
      • editor prop can now be fully controlled: Plate is not applying withPlate on it anymore
    • PlatePlugin.deserializeHtml
      • can't be an array anymore
      • moved validAttribute, validClassName, validNodeName, validStyle to deserializeHtml.rules property
    • renamed plateStore to platesStore
    • platesStore is now a zustood store
    • eventEditorStore is now a zustood store
    • getPlateId now gets the last editor id if not focused or blurred
      • used by usePlateEditorRef and usePlateEditorState
    • removed:
      • usePlateEnabled for usePlateSelectors(id).enabled()
      • usePlateValue for usePlateSelectors(id).value()
      • usePlateActions:
        • resetEditor for getPlateActions(id).resetEditor()
        • clearState for platesActions.unset()
        • setInitialState for platesActions.set(id)
        • setEditor for getPlateActions(id).editor(value)
        • setEnabled for getPlateActions(id).enabled(value)
        • setValue for getPlateActions(id).value(value)
      • getPlateState
      • usePlateState
      • usePlateKey

@udecode/[email protected]

  • #1303 by @zbeyens
  • renamed plate-x-ui to plate-ui-x: all packages depending on styled-components has plate-ui prefix
  • renamed plate-x-serializer to plate-serializer-x
  • is now exporting only these (new) packages:
    • @udecode/plate-headless: all unstyled packages
    • @udecode/plate-ui: all styled packages
  • renamed PlateState to PlateStoreState

8.0.0

@udecode/[email protected]

  • #1234 by @zbeyens – Removed:

    • IndentListPluginOptions for PlatePlugin

    Rename:

    • getIndentListInjectComponent to injectIndentListComponent

@udecode/[email protected]

  • #1234 by @zbeyens – Breaking changes:

    Plate

    • 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} />;

    PlatePlugin

    • key
      • replacing pluginKey
      • is now required: each plugin needs a key to be retrieved by key.
    • 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 has element and leaf properties:
    type SerializeHtml = RenderFunction<
      PlateRenderElementProps | PlateRenderLeafProps
    >;

    Renamed:

    • injectParentComponent to inject.aboveComponent
    • injectChildComponent to inject.belowComponent
    • overrideProps to inject.props
      • transformClassName, transformNodeValue, transformStyle first parameter is no longer editor as it's provided by then if needed.
      • the previously getOverrideProps is now the core behavior if inject.props is defined.
    • serialize to serializeHtml
    • deserialize to deserializeHtml
      • 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 to handlers property.
    // 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 and voidTypes for:
      • isInline is a boolean that enables inline rendering.
      • isVoid is a boolean that enables void rendering.

    General

    • the following plugins are now part of the core plugins, so you need to remove these from your plugins prop:
    const corePlugins = [
      createReactPlugin(),
      createHistoryPlugin(),
      createEventEditorPlugin(),
      createInlineVoidPlugin(),
      createInsertDataPlugin(),
      createDeserializeAstPlugin(),
      createDeserializeHtmlPlugin(),
    ];
    • plugins is not a parameter anymore as it can be retrieved in editor.plugins
    • withInlineVoid is now using plugins isInline and isVoid plugin properties.

    Renamed:

    • getPlatePluginType to getPluginType
    • getEditorOptions to getPlugins
    • getPlatePluginOptions to getPlugin
    • pipeOverrideProps to pipeInjectProps
    • getOverrideProps to pluginInjectProps
    • serializeHTMLFromNodes to serializeHtml
      • getLeaf to leafToHtml
      • getNode to elementToHtml
    • xDeserializerId to KEY_DESERIALIZE_X
    • deserializeHTMLToText to htmlTextNodeToString
    • deserializeHTMLToMarks to htmlElementToLeaf and pipeDeserializeHtmlLeaf
    • deserializeHTMLToElement to htmlElementToElement and pipeDeserializeHtmlElement
    • deserializeHTMLToFragment to htmlBodyToFragment
    • deserializeHTMLToDocumentFragment to deserializeHtml
    • deserializeHTMLToBreak to htmlBrToNewLine
    • deserializeHTMLNode to deserializeHtmlNode
    • deserializeHTMLElement to deserializeHtmlElement

    Removed:

    • usePlateKeys, getPlateKeys
    • usePlateOptions for getPlugin
    • getPlateSelection for getPlateEditorRef().selection
    • flatMapByKey
    • getEditableRenderElement and getRenderElement for pipeRenderElement and pluginRenderElement
    • getEditableRenderLeaf and getRenderLeaf for pipeRenderLeaf and pluginRenderLeaf
    • getInlineTypes
    • getVoidTypes
    • getPlatePluginTypes
    • getPlatePluginWithOverrides
    • mapPlatePluginKeysToOptions
    • withDeserializeX for PlatePlugin.editor.insertData

    Changed types:

    • PlateEditor:
      • removed options for pluginsByKey
    • WithOverride is not returning an extended editor anymore (input and output editors are assumed to be the same types for simplicity).
    • PlateState
      • renamed keyChange to keyEditor
      • removed plugins for editor.plugins
      • removed pluginKeys
      • removed selection for editor.selection
      • actions:
        • removed setSelection, setPlugins, setPluginKeys
        • removed incrementKeyChange for

    Renamed types:

    • XHTMLY to XHtmlY
    • Deserialize to DeseralizeHtml

    Removed types:

    • PlatePluginOptions:
      • type to PlatePlugin.type
      • component to PlatePlugin.component
      • deserialize to PlatePlugin.deserializeHtml
      • getNodeProps to PlatePlugin.props.nodeProps
      • hotkey to HotkeyPlugin
      • clear to ToggleMarkPlugin
      • defaultType is hardcoded to p.type
    • OverrideProps for PlatePlugin.inject.props
    • Serialize for PlatePlugin.serializeHtml
    • NodeProps for AnyObject
    • OnKeyDownElementOptions for HotkeyPlugin
    • OnKeyDownMarkOptions for ToggleMarkPlugin
    • WithInlineVoidOptions
    • GetNodeProps for PlatePluginProps
    • DeserializeOptions, GetLeafDeserializerOptions, GetElementDeserializerOptions, GetNodeDeserializerOptions, GetNodeDeserializerRule, DeserializeNode for PlatePlugin.deserializeHtml
    • PlateOptions
    • RenderNodeOptions
    • DeserializedHTMLElement

@udecode/[email protected]

  • #1234 by @zbeyens – Removed:
    • useFindReplacePlugin for createFindReplacePlugin

@udecode/[email protected]

  • #1234 by @zbeyens
    • setAlign
      • moved param 3 to param 2 as setNodesOptions

@udecode/[email protected]

  • #1234 by @zbeyens
    • renamed createBasicElementPlugins to createBasicElementsPlugin

@udecode/[email protected]

  • #1234 by @zbeyens – Removed:
    • getCodeBlockPluginOptions for getPlugin
    • getCodeLinePluginOptions for getPlugin

@udecode/[email protected]

  • #1234 by @zbeyens – Renamed:
    • HeadingPluginOptions to HeadingsPlugin

@udecode/[email protected]

  • #1234 by @zbeyens – Removed:
    • getMentionInputPluginOptions for getPlugin
    • getMentionInputType for getPluginType
    • COMBOBOX_TRIGGER_MENTION

@udecode/[email protected]

  • #1234 by @zbeyens
    • renamed createBasicMarkPlugins to createBasicMarksPlugin

@udecode/[email protected]

  • #1234 by @zbeyens – Breaking changes:

    • all plugins options are now defined in the plugin itself
    • plugins which now have nested plugins instead of array:
      • createBasicElementsPlugin
      • createCodeBlockPlugin
      • createHeadingPlugin
      • createListPlugin
      • createTablePlugin
      • createBasicMarksPlugin

    Removed:

    • createEditorPlugins for createPlateEditor (without components) and createPlateEditorUI (with Plate components)
    • createPlateOptions for createPlugins
    • all DEFAULTS_X: these are defined in the plugins
    • all getXDeserialize: these are defined in the plugins
    • all WithXOptions for extended plugins
    • all getXRenderElement
    • some plugin option types are removed for PlatePlugin

    Renamed:

    • createPlateComponents to createPlateUI
    • all getXY handlers to yX (e.g. getXOnKeyDown to onKeyDownX)
    • all XPluginOptions to XPlugin
    • all pluginKey parameter to key except in components

    Renamed types:

    • DecorateSearchHighlightOptions to FindReplacePlugin

    Updated deps:

    • "slate": "0.70.0"
    • "slate-react": "0.70.1"

    Removed deps (merged to core):

    • plate-common
    • plate-ast-serializer
    • plate-html-serializer
    • plate-serializer

@udecode/[email protected]

  • #1234 by @zbeyens – Renamed:
    • createDeserializeCSVPlugin to createDeserializeCsvPlugin
    • deserializeCSV to deserializeCsv

@udecode/[email protected]

  • #1234 by @zbeyens

    • createDeserializeMdPlugin:
      • is now disabled if there is html data in the data transfer.

    Renamed:

    • createDeserializeMDPlugin to createDeserializeMdPlugin
    • deserializeMD to deserializeMd

7.0.0

@udecode/plate-core

  • renamed:
    • SPEditor to PEditor (note that PlateEditor is the new default)
    • SPRenderNodeProps to PlateRenderNodeProps
    • SPRenderElementProps to PlateRenderElementProps
    • SPRenderLeafProps to PlateRenderLeafProps
    • useEventEditorId to usePlateEventId
    • useStoreEditorOptions to usePlateOptions
    • useStoreEditorRef to usePlateEditorRef
    • useStoreEditorSelection to usePlateSelection
    • useStoreEditorState to usePlateEditorState
    • useStoreEditorValue to usePlateValue
    • useStoreEnabled to usePlateEnabled
    • useStorePlate to usePlatePlugins
    • useStorePlatePluginKeys to usePlateKeys
    • useStoreState to usePlateState
  • getPlateId: Get the last focused editor id, else get the last blurred editor id, else get the first editor id, else null
  • 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 means useEventEditorId('focus') is no longer needed for
      • usePlateEditorRef
      • usePlateEditorState
      • usePlateX...

@udecode/plate-alignment

  • setAlign: option align renamed to value
  • removed getAlignOverrideProps() in favor of getOverrideProps(KEY_ALIGN)

@udecode/plate-indent

  • removed getIndentOverrideProps() in favor of getOverrideProps(KEY_INDENT)
  • rename onKeyDownHandler to getIndentOnKeyDown()
  • IndentPluginOptions
    • rename types to validTypes
    • rename cssPropName to styleKey
    • rename transformCssValue to transformNodeValue

@udecode/plate-line-height

  • setLineHeight: option lineHeight renamed to value
  • removed getLineHeightOverrideProps in favor of getOverrideProps(KEY_LINE_HEIGHT)

@udecode/plate-mention

  • getMentionOnSelectItem:
    • removed createMentionNode in favor of plugin options
    • removed insertSpaceAfterMention in favor of plugin options

@udecode/plate-mention-ui

  • MentionCombobox props:
    • removed trigger in favor of plugin options
    • removed insertSpaceAfterMention in favor of plugin options
    • removed createMentionNode in favor of plugin options

@udecode/plate-x-ui

  • renamed ToolbarAlign to AlignToolbarButton
  • renamed ToolbarCodeBlock to CodeBlockToolbarButton
  • renamed ToolbarElement to BlockToolbarButton
  • renamed ToolbarImage to ImageToolbarButton
  • renamed ToolbarLink to LinkToolbarButton
  • renamed ToolbarList to ListToolbarButton
  • renamed ToolbarLineHeight to LineHeightToolbarDropdown
  • renamed ToolbarMark to MarkToolbarButton
  • renamed ToolbarMediaEmbed to MediaEmbedToolbarButton
  • renamed ToolbarSearchHighlight to SearchHighlightToolbar
  • renamed ToolbarTable to TableToolbarButton

6.0.0

@udecode/plate-alignment

The align plugin is no longer wrapping a block, but instead setting an align property to an existing block.

  • createAlignPlugin:
    • removed pluginKeys, renderElement and deserialize
  • removed:
    • ELEMENT_ALIGN_LEFT
    • ELEMENT_ALIGN_CENTER
    • ELEMENT_ALIGN_RIGHT
    • ELEMENT_ALIGN_JUSTIFY
    • KEYS_ALIGN in favor of KEY_ALIGN
    • getAlignDeserialize
    • upsertAlign in favor of setAlign

Migration (normalizer):

  • for each node:
    • run parent = getParent(editor, path), if parent[0].type is one of the alignment values:
      • run setAlign(editor, { align }, { at: path })
      • run unwrapNodes(editor, { at: path })

@udecode/plate-alignment-ui

  • ToolbarAlignProps:
    • removed type in favor of align
    • removed unwrapTypes
    • added align

5.0.0

@udecode/plate-mention

The mention plugin is now using the combobox.

  • removed useMentionPlugin in favor of createMentionPlugin
    • migration: replace useMentionPlugin().plugin by createMentionPlugin()
  • removed options:
    • mentionableSearchPattern
    • insertSpaceAfterMention
    • maxSuggestions: moved to comboboxStore
    • trigger: moved to comboboxStore
    • mentionables: moved to items in comboboxStore
    • mentionableFilter: moved to filter in comboboxStore
  • removed matchesTriggerAndPattern in favor of getTextFromTrigger
  • removed MentionNodeData in favor of ComboboxItemData
export interface ComboboxItemData {
  /** Unique key. */
  key: string;
  /** Item text. */
  text: any;
  /**
   * Whether the item is disabled.
   *
   * @default false
   */
  disabled?: boolean;
  /** Data available to `onRenderItem`. */
  data?: unknown;
}

@udecode/plate-mention-ui

  • removed MentionSelect in favor of MentionCombobox

@udecode/plate-toolbar

  • removed setPositionAtSelection in favor of useBalloonToolbarPopper
  • removed useBalloonMove in favor of useBalloonToolbarPopper
  • removed usePopupPosition in favor of useBalloonToolbarPopper
  • removed useBalloonShow in favor of useBalloonToolbarPopper BalloonToolbar props:
  • removed direction in favor of popperOptions.placement
  • renamed scrollContainer to popperContainer

4.0.0

@udecode/plate-toolbar

  • BalloonToolbar: removed hiddenDelay prop.

3.0.0

All UI packages

There was multiple instances of styled-components across all the packages. So we moved styled-components from dependencies to peer dependencies.

Before

styled-components was not listed in your dependencies

After

Add styled-components to your dependencies

2.0.0

@udecode/plate-autoformat

  • autoformatBlock:
    • signatude changed
// Before
(
  editor: TEditor,
  type: string,
  at: Location,
  options: Pick<AutoformatRule, 'preFormat' | 'format'>
)
// After
(editor: TEditor, options: AutoformatBlockOptions)
  • moved the checks from withAutoformat
  • autoformatInline:
    • renamed to autoformatMark
    • signatured changed
// Before
(
  editor: TEditor,
  options: Pick<AutoformatRule, 'type' | 'between' | 'markup' | 'ignoreTrim'>
)
// After
(
  editor: TEditor,
  options: AutoformatMarkOptions
)
  • AutoformatRule is now AutoformatBlockRule | AutoformatMarkRule | AutoformatTextRule;
    • mode: 'inline' renamed to mode: 'mark'
    • markup and between have been replaced by match: string | string[] | MatchRange | MatchRange[]: The rule applies when the trigger and the text just before the cursor matches. For mode: 'block': lookup for the end match(es) before the cursor. For mode: 'text': lookup for the end match(es) before the cursor. If format is an array, also lookup for the start match(es). For mode: 'mark': lookup for the start and end matches. Note: '_*', ['_*'] and { start: '_*', end: '*_' } are equivalent.
    • trigger now defaults to the last character of match or match.end (previously ' ')
  • the plugin now checks that there is no character before the start match to apply autoformatting. For example, nothing will happen by typing a*text*.