diff --git a/src/components/editor/plugins/autoformat-kit.tsx b/src/components/editor/plugins/autoformat-kit.tsx index 97429051..6752335c 100644 --- a/src/components/editor/plugins/autoformat-kit.tsx +++ b/src/components/editor/plugins/autoformat-kit.tsx @@ -1,235 +1,78 @@ 'use client' -import type { AutoformatRule } from '@platejs/autoformat' import { - autoformatArrow, - autoformatLegal, - autoformatLegalHtml, - autoformatMath, - AutoformatPlugin, - autoformatPunctuation, - autoformatSmartQuotes, -} from '@platejs/autoformat' -import { insertEmptyCodeBlock } from '@platejs/code-block' -import { toggleList } from '@platejs/list' -import { KEYS } from 'platejs' - -const autoformatMarks: AutoformatRule[] = [ - { - match: '***', - mode: 'mark', - type: [KEYS.bold, KEYS.italic], - }, - { - match: '__*', - mode: 'mark', - type: [KEYS.underline, KEYS.italic], - }, - { - match: '__**', - mode: 'mark', - type: [KEYS.underline, KEYS.bold], - }, - { - match: '___***', - mode: 'mark', - type: [KEYS.underline, KEYS.bold, KEYS.italic], - }, - { - match: '**', - mode: 'mark', - type: KEYS.bold, - }, - { - match: '__', - mode: 'mark', - type: KEYS.underline, - }, - { - match: '*', - mode: 'mark', - type: KEYS.italic, - }, - { - match: '_', - mode: 'mark', - type: KEYS.italic, - }, - { - match: '~~', - mode: 'mark', - type: KEYS.strikethrough, - }, - { - match: '^', - mode: 'mark', - type: KEYS.sup, - }, - { - match: '~', - mode: 'mark', - type: KEYS.sub, - }, - { - match: '==', - mode: 'mark', - type: KEYS.highlight, - }, - { - match: '≡', - mode: 'mark', - type: KEYS.highlight, - }, - { - match: '`', - mode: 'mark', - type: KEYS.code, - }, -] - -const autoformatBlocks: AutoformatRule[] = [ - { - match: '# ', - mode: 'block', - type: KEYS.h1, - }, - { - match: '## ', - mode: 'block', - type: KEYS.h2, - }, - { - match: '### ', - mode: 'block', - type: KEYS.h3, - }, - { - match: '#### ', - mode: 'block', - type: KEYS.h4, - }, - { - match: '##### ', - mode: 'block', - type: KEYS.h5, - }, - { - match: '###### ', - mode: 'block', - type: KEYS.h6, - }, - { - match: '> ', - mode: 'block', - type: KEYS.blockquote, - }, - { - match: '```', - mode: 'block', - type: KEYS.codeBlock, - format: (editor) => { - insertEmptyCodeBlock(editor, { - defaultType: KEYS.p, - insertNodesOptions: { select: true }, - }) - }, - }, - // { - // match: '+ ', - // mode: 'block', - // preFormat: openNextToggles, - // type: KEYS.toggle, - // }, - { - match: ['---', '—-', '___ '], - mode: 'block', - type: KEYS.hr, - format: (editor) => { - editor.tf.setNodes({ type: KEYS.hr }) - editor.tf.insertNodes({ - children: [{ text: '' }], - type: KEYS.p, - }) - }, - }, -] + BlockquoteRules, + BoldRules, + CodeRules, + HighlightRules, + HorizontalRuleRules, + ItalicRules, + MarkComboRules, + StrikethroughRules, + SubscriptRules, + SuperscriptRules, + UnderlineRules, +} from '@platejs/basic-nodes' +import { CodeBlockRules } from '@platejs/code-block' +import { + BulletedListRules, + OrderedListRules, + TaskListRules, +} from '@platejs/list' +import { createSlatePlugin, KEYS } from 'platejs' -const autoformatLists: AutoformatRule[] = [ - { - match: ['* ', '- '], - mode: 'block', - type: 'list', - format: (editor) => { - toggleList(editor, { - listStyleType: KEYS.ul, - }) - }, - }, - { - match: [String.raw`^\d+\.$ `, String.raw`^\d+\)$ `], - matchByRegex: true, - mode: 'block', - type: 'list', - format: (editor, { matchString }) => { - toggleList(editor, { - listRestartPolite: Number(matchString) || 1, - listStyleType: KEYS.ol, - }) - }, - }, - { - match: ['[] '], - mode: 'block', - type: 'list', - format: (editor) => { - toggleList(editor, { - listStyleType: KEYS.listTodo, - }) - editor.tf.setNodes({ - checked: false, - listStyleType: KEYS.listTodo, - }) - }, - }, - { - match: ['[x] '], - mode: 'block', - type: 'list', - format: (editor) => { - toggleList(editor, { - listStyleType: KEYS.listTodo, - }) - editor.tf.setNodes({ - checked: true, - listStyleType: KEYS.listTodo, - }) - }, - }, -] +// Disable autoformat inside code blocks (preserves v52 query behavior). +const isNotInCodeBlock = (context: { + editor: { + api: { some: (options: { match: { type: string } }) => boolean } + getType: (key: string) => string + } +}) => + !context.editor.api.some({ + match: { type: context.editor.getType(KEYS.codeBlock) }, + }) export const AutoformatKit = [ - AutoformatPlugin.configure({ - options: { - enableUndoOnDelete: true, - rules: [ - ...autoformatBlocks, - ...autoformatMarks, - ...autoformatSmartQuotes, - ...autoformatPunctuation, - ...autoformatLegal, - ...autoformatLegalHtml, - ...autoformatArrow, - ...autoformatMath, - ...autoformatLists, - ].map( - (rule): AutoformatRule => ({ - ...rule, - query: (editor) => - !editor.api.some({ - match: { type: editor.getType(KEYS.codeBlock) }, - }), - }), - ), - }, + createSlatePlugin({ + key: 'markdownShortcuts', + inputRules: [ + BlockquoteRules.markdown({ enabled: isNotInCodeBlock }), + HorizontalRuleRules.markdown({ variant: '-', enabled: isNotInCodeBlock }), + HorizontalRuleRules.markdown({ variant: '_', enabled: isNotInCodeBlock }), + CodeBlockRules.markdown({ on: 'match', enabled: isNotInCodeBlock }), + MarkComboRules.markdown({ + variant: 'boldItalic', + enabled: isNotInCodeBlock, + }), + MarkComboRules.markdown({ + variant: 'boldUnderline', + enabled: isNotInCodeBlock, + }), + MarkComboRules.markdown({ + variant: 'italicUnderline', + enabled: isNotInCodeBlock, + }), + MarkComboRules.markdown({ + variant: 'boldItalicUnderline', + enabled: isNotInCodeBlock, + }), + BoldRules.markdown({ variant: '*', enabled: isNotInCodeBlock }), + BoldRules.markdown({ variant: '_', enabled: isNotInCodeBlock }), + ItalicRules.markdown({ variant: '*', enabled: isNotInCodeBlock }), + ItalicRules.markdown({ variant: '_', enabled: isNotInCodeBlock }), + UnderlineRules.markdown({ enabled: isNotInCodeBlock }), + StrikethroughRules.markdown({ enabled: isNotInCodeBlock }), + SubscriptRules.markdown({ enabled: isNotInCodeBlock }), + SuperscriptRules.markdown({ enabled: isNotInCodeBlock }), + HighlightRules.markdown({ variant: '==', enabled: isNotInCodeBlock }), + HighlightRules.markdown({ variant: '≡', enabled: isNotInCodeBlock }), + CodeRules.markdown({ enabled: isNotInCodeBlock }), + BulletedListRules.markdown({ variant: '*', enabled: isNotInCodeBlock }), + BulletedListRules.markdown({ variant: '-', enabled: isNotInCodeBlock }), + OrderedListRules.markdown({ variant: '.', enabled: isNotInCodeBlock }), + OrderedListRules.markdown({ variant: ')', enabled: isNotInCodeBlock }), + TaskListRules.markdown({ checked: false, enabled: isNotInCodeBlock }), + TaskListRules.markdown({ checked: true, enabled: isNotInCodeBlock }), + ], }), ] diff --git a/src/components/editor/plugins/basic-blocks-kit.tsx b/src/components/editor/plugins/basic-blocks-kit.tsx index 1c7d9682..51b853a9 100644 --- a/src/components/editor/plugins/basic-blocks-kit.tsx +++ b/src/components/editor/plugins/basic-blocks-kit.tsx @@ -1,5 +1,6 @@ 'use client' +import { HeadingRules } from '@platejs/basic-nodes' import { BlockquotePlugin, H1Plugin, @@ -10,6 +11,7 @@ import { H6Plugin, HorizontalRulePlugin, } from '@platejs/basic-nodes/react' +import { KEYS } from 'platejs' import { ParagraphPlugin } from 'platejs/react' import { BlockquoteElement } from '@/components/ui/blockquote-node' @@ -24,6 +26,17 @@ import { import { HrElement } from '@/components/ui/hr-node' import { ParagraphElement } from '@/components/ui/paragraph-node' +// Disable heading shortcuts inside code blocks (preserves v52 query behavior). +const isNotInCodeBlock = (context: { + editor: { + api: { some: (options: { match: { type: string } }) => boolean } + getType: (key: string) => string + } +}) => + !context.editor.api.some({ + match: { type: context.editor.getType(KEYS.codeBlock) }, + }) + export const BasicBlocksKit = [ ParagraphPlugin.withComponent(ParagraphElement), H1Plugin.configure({ @@ -34,6 +47,7 @@ export const BasicBlocksKit = [ break: { empty: 'reset' }, }, shortcuts: { toggle: { keys: 'mod+alt+1' } }, + inputRules: [HeadingRules.markdown({ enabled: isNotInCodeBlock })], }), H2Plugin.configure({ node: { @@ -43,6 +57,7 @@ export const BasicBlocksKit = [ break: { empty: 'reset' }, }, shortcuts: { toggle: { keys: 'mod+alt+2' } }, + inputRules: [HeadingRules.markdown({ enabled: isNotInCodeBlock })], }), H3Plugin.configure({ node: { @@ -52,6 +67,7 @@ export const BasicBlocksKit = [ break: { empty: 'reset' }, }, shortcuts: { toggle: { keys: 'mod+alt+3' } }, + inputRules: [HeadingRules.markdown({ enabled: isNotInCodeBlock })], }), H4Plugin.configure({ node: { @@ -61,6 +77,7 @@ export const BasicBlocksKit = [ break: { empty: 'reset' }, }, shortcuts: { toggle: { keys: 'mod+alt+4' } }, + inputRules: [HeadingRules.markdown({ enabled: isNotInCodeBlock })], }), H5Plugin.configure({ node: { @@ -70,6 +87,7 @@ export const BasicBlocksKit = [ break: { empty: 'reset' }, }, shortcuts: { toggle: { keys: 'mod+alt+5' } }, + inputRules: [HeadingRules.markdown({ enabled: isNotInCodeBlock })], }), H6Plugin.configure({ node: { @@ -79,6 +97,7 @@ export const BasicBlocksKit = [ break: { empty: 'reset' }, }, shortcuts: { toggle: { keys: 'mod+alt+6' } }, + inputRules: [HeadingRules.markdown({ enabled: isNotInCodeBlock })], }), BlockquotePlugin.configure({ node: { component: BlockquoteElement },