Autoformat
'use client';
import React from 'react';
import { Plate } from '@udecode/plate/react';
import { editorPlugins } from '@/components/editor/plugins/editor-plugins';
import { useCreateEditor } from '@/components/editor/use-create-editor';
import { Editor, EditorContainer } from '@/components/plate-ui/editor';
import { DEMO_VALUES } from './values/demo-values';
export default function Demo({ id }: { id: string }) {
const editor = useCreateEditor({
plugins: [...editorPlugins],
value: DEMO_VALUES[id],
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Features
- Enables quick content formatting via shortcodes.
- Offers markdown-like inline codes for real-time typing.
- Enhances and simplifies editing by avoiding toolbar buttons and shortcuts for common formatting.
- Auto conversion feature (e.g.,
#
to H1). - Provides predefined formatting rules.
Shortcodes
text*
for bold text._text_
for italicized text.~~text~~
for strikethrough text.- ... and more.
Installation
npm install @udecode/plate-autoformat
Usage
import { AutoformatPlugin } from '@udecode/plate-autoformat/react';
const plugins = [
// ...otherPlugins,
AutoformatPlugin.configure({
options: {
rules: autoformatRules,
enableUndoOnDelete: true,
},
}),
];
Examples
autoformatRules
'use client';
import type { SlateEditor } from '@udecode/plate';
import type { AutoformatRule } from '@udecode/plate-autoformat';
import { ElementApi, isType } from '@udecode/plate';
import { ParagraphPlugin } from '@udecode/plate/react';
import {
autoformatArrow,
autoformatLegal,
autoformatLegalHtml,
autoformatMath,
autoformatPunctuation,
autoformatSmartQuotes,
} from '@udecode/plate-autoformat';
import { AutoformatPlugin } from '@udecode/plate-autoformat/react';
import {
BoldPlugin,
CodePlugin,
ItalicPlugin,
StrikethroughPlugin,
SubscriptPlugin,
SuperscriptPlugin,
UnderlinePlugin,
} from '@udecode/plate-basic-marks/react';
import { BlockquotePlugin } from '@udecode/plate-block-quote/react';
import { insertEmptyCodeBlock } from '@udecode/plate-code-block';
import {
CodeBlockPlugin,
CodeLinePlugin,
} from '@udecode/plate-code-block/react';
import { HEADING_KEYS } from '@udecode/plate-heading';
import { HighlightPlugin } from '@udecode/plate-highlight/react';
import { HorizontalRulePlugin } from '@udecode/plate-horizontal-rule/react';
import {
INDENT_LIST_KEYS,
ListStyleType,
toggleIndentList,
} from '@udecode/plate-indent-list';
import { TogglePlugin, openNextToggles } from '@udecode/plate-toggle/react';
export const format = (editor: SlateEditor, customFormatting: any) => {
if (editor.selection) {
const parentEntry = editor.api.parent(editor.selection);
if (!parentEntry) return;
const [node] = parentEntry;
if (
ElementApi.isElement(node) &&
!isType(editor, node, CodeBlockPlugin.key) &&
!isType(editor, node, CodeLinePlugin.key)
) {
customFormatting();
}
}
};
export const autoformatMarks: AutoformatRule[] = [
{
match: '***',
mode: 'mark',
type: [BoldPlugin.key, ItalicPlugin.key],
},
{
match: '__*',
mode: 'mark',
type: [UnderlinePlugin.key, ItalicPlugin.key],
},
{
match: '__**',
mode: 'mark',
type: [UnderlinePlugin.key, BoldPlugin.key],
},
{
match: '___***',
mode: 'mark',
type: [UnderlinePlugin.key, BoldPlugin.key, ItalicPlugin.key],
},
{
match: '**',
mode: 'mark',
type: BoldPlugin.key,
},
{
match: '__',
mode: 'mark',
type: UnderlinePlugin.key,
},
{
match: '*',
mode: 'mark',
type: ItalicPlugin.key,
},
{
match: '_',
mode: 'mark',
type: ItalicPlugin.key,
},
{
match: '~~',
mode: 'mark',
type: StrikethroughPlugin.key,
},
{
match: '^',
mode: 'mark',
type: SuperscriptPlugin.key,
},
{
match: '~',
mode: 'mark',
type: SubscriptPlugin.key,
},
{
match: '==',
mode: 'mark',
type: HighlightPlugin.key,
},
{
match: '≡',
mode: 'mark',
type: HighlightPlugin.key,
},
{
match: '`',
mode: 'mark',
type: CodePlugin.key,
},
];
export const autoformatBlocks: AutoformatRule[] = [
{
match: '# ',
mode: 'block',
type: HEADING_KEYS.h1,
},
{
match: '## ',
mode: 'block',
type: HEADING_KEYS.h2,
},
{
match: '### ',
mode: 'block',
type: HEADING_KEYS.h3,
},
{
match: '#### ',
mode: 'block',
type: HEADING_KEYS.h4,
},
{
match: '##### ',
mode: 'block',
type: HEADING_KEYS.h5,
},
{
match: '###### ',
mode: 'block',
type: HEADING_KEYS.h6,
},
{
match: '> ',
mode: 'block',
type: BlockquotePlugin.key,
},
{
format: (editor) => {
insertEmptyCodeBlock(editor, {
defaultType: ParagraphPlugin.key,
insertNodesOptions: { select: true },
});
},
match: '```',
mode: 'block',
triggerAtBlockStart: false,
type: CodeBlockPlugin.key,
},
{
match: '+ ',
mode: 'block',
preFormat: openNextToggles,
type: TogglePlugin.key,
},
{
format: (editor) => {
editor.tf.setNodes({ type: HorizontalRulePlugin.key });
editor.tf.insertNodes({
children: [{ text: '' }],
type: ParagraphPlugin.key,
});
},
match: ['---', '—-', '___ '],
mode: 'block',
type: HorizontalRulePlugin.key,
},
];
export const autoformatIndentLists: AutoformatRule[] = [
{
format: (editor) => {
toggleIndentList(editor, {
listStyleType: ListStyleType.Disc,
});
},
match: ['* ', '- '],
mode: 'block',
type: 'list',
},
{
format: (editor) =>
toggleIndentList(editor, {
listStyleType: ListStyleType.Decimal,
}),
match: [String.raw`^\d+\.$ `, String.raw`^\d+\)$ `],
matchByRegex: true,
mode: 'block',
type: 'list',
},
{
format: (editor) => {
toggleIndentList(editor, {
listStyleType: INDENT_LIST_KEYS.todo,
});
editor.tf.setNodes({
checked: false,
listStyleType: INDENT_LIST_KEYS.todo,
});
},
match: ['[] '],
mode: 'block',
type: 'list',
},
{
format: (editor) => {
toggleIndentList(editor, {
listStyleType: INDENT_LIST_KEYS.todo,
});
editor.tf.setNodes({
checked: true,
listStyleType: INDENT_LIST_KEYS.todo,
});
},
match: ['[x] '],
mode: 'block',
type: 'list',
},
];
export const autoformatPlugin = AutoformatPlugin.configure({
options: {
enableUndoOnDelete: true,
rules: [
...autoformatBlocks,
...autoformatMarks,
...autoformatSmartQuotes,
...autoformatPunctuation,
...autoformatLegal,
...autoformatLegalHtml,
...autoformatArrow,
...autoformatMath,
...autoformatIndentLists,
],
},
});
autoformatBlocks
autoformatIndentLists
If using the Indent List plugin, you can use the following rules:
autoformatLists
If using the List plugin, you can use the following rules:
autoformatMarks
autoformatUtils
Plugins
AutoformatPlugin
Rules
You can import the following rules:
Name | Description |
---|---|
autoformatSmartQuotes | Converts "text" to "text" . |
Converts 'text' to 'text' . | |
autoformatPunctuation | Converts -- to — . |
Converts ... to … . | |
Converts >> to » . | |
Converts << to « . | |
autoformatArrow | Converts -> to → . |
Converts <- to ← . | |
Converts => to ⇒ . | |
Converts <= and ≤= to ⇐ . | |
autoformatLegal | Converts (tm) and (TM) to ™ . |
Converts (r) and (R) to ® . | |
Converts (c) and (C) to © . | |
autoformatLegalHtml | Converts ™ to ™ . |
Converts ® to ® . | |
Converts © to © . | |
Converts § to § . | |
autoformatComparison | Converts !> to !> . |
Converts !< to ≮ . | |
Converts >= to ≥ . | |
Converts <= to ≤ . | |
Converts !>= to ≱ . | |
Converts !<= to ≰ . | |
autoformatEquality | Converts != to ≠ . |
Converts == to ≡ . | |
Converts !== and ≠= to ≢ . | |
Converts ~= to ≈ . | |
Converts !~= to ≉ . | |
autoformatFraction | Converts 1/2 to ½ . |
Converts 1/3 to ⅓ . | |
... | |
Converts 7/8 to ⅞ . | |
autoformatDivision | Converts // to ÷ . |
autoformatOperation | Converts +- to ± . |
Converts %% to ‰ . | |
Converts %%% and ‰% to `‱. | |
autoformatDivision rules. | |
autoformatSubscriptNumbers | Converts ~0 to ₀ . |
Converts ~1 to ₁ . | |
... | |
Converts ~9 to ₉ . | |
autoformatSubscriptSymbols | Converts ~+ to ₊ . |
Converts ~- to ₋ . | |
autoformatSuperscriptNumbers | Converts ^0 to ⁰ . |
Converts ^1 to ¹ . | |
... | |
Converts ^9 to ⁹ . | |
autoformatSuperscriptSymbols | Converts ^+ to ° . |
Converts ^- to ⁺ . | |
autoformatMath | autoformatComparison rules |
autoformatEquality rules | |
autoformatOperation rules | |
autoformatFraction rules | |
autoformatSubscriptNumbers rules | |
autoformatSubscriptSymbols rules | |
autoformatSuperscriptNumbers rules | |
autoformatSuperscriptSymbols rules |
Types
AutoformatCommonRule
An interface for the common structure of autoformat rules, regardless of their mode.
- For
mode: 'block'
: lookup for the end match(es) before the cursor. - For
mode: 'text'
: lookup for the end match(es) before the cursor. Ifformat
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. MatchRange
:- Default:
false
The rule applies when the trigger and the text just before the cursor matches.
Triggering character to autoformat.
If true, insert the triggering character after autoformatting.
AutoformatBlockRule
An interface for autoformat rules for block mode.
- Default:
true
- Default:
false
Block mode: set block type or custom format.
Pattern to match for the autoformat rule.
Block type to set. Ignored if format
is defined.
Whether trigger should be at block start.
Whether to allow autoformat with same block type above.
Function called before format
. Used to reset selected block.
Custom formatting function.
AutoformatMarkRule
An interface for autoformat rules for mark mode.
AutoformatTextRule
An interface for autoformat rules for text mode.