diff --git a/apps/www/public/r/autoformat-classic-kit.json b/apps/www/public/r/autoformat-classic-kit.json index afcbff9cde..0eb9c9ff1e 100644 --- a/apps/www/public/r/autoformat-classic-kit.json +++ b/apps/www/public/r/autoformat-classic-kit.json @@ -14,7 +14,7 @@ "files": [ { "path": "src/registry/components/editor/plugins/autoformat-classic-kit.tsx", - "content": "'use client';\n\nimport type { AutoformatBlockRule, AutoformatRule } from '@platejs/autoformat';\nimport type { SlateEditor } from 'platejs';\n\nimport {\n autoformatArrow,\n autoformatLegal,\n autoformatLegalHtml,\n autoformatMath,\n AutoformatPlugin,\n autoformatPunctuation,\n autoformatSmartQuotes,\n} from '@platejs/autoformat';\nimport { insertEmptyCodeBlock } from '@platejs/code-block';\nimport { toggleList, unwrapList } from '@platejs/list-classic';\nimport { ElementApi, isType, KEYS } from 'platejs';\n\nconst preFormat: AutoformatBlockRule['preFormat'] = (editor) =>\n unwrapList(editor);\n\nconst format = (editor: SlateEditor, customFormatting: any) => {\n if (editor.selection) {\n const parentEntry = editor.api.parent(editor.selection);\n\n if (!parentEntry) return;\n\n const [node] = parentEntry;\n\n if (ElementApi.isElement(node) && !isType(editor, node, KEYS.codeBlock)) {\n customFormatting();\n }\n }\n};\n\nconst formatList = (editor: SlateEditor, elementType: string) => {\n format(editor, () =>\n toggleList(editor, {\n type: elementType,\n })\n );\n};\n\nconst autoformatMarks: AutoformatRule[] = [\n {\n match: '***',\n mode: 'mark',\n type: [KEYS.bold, KEYS.italic],\n },\n {\n match: '__*',\n mode: 'mark',\n type: [KEYS.underline, KEYS.italic],\n },\n {\n match: '__**',\n mode: 'mark',\n type: [KEYS.underline, KEYS.bold],\n },\n {\n match: '___***',\n mode: 'mark',\n type: [KEYS.underline, KEYS.bold, KEYS.italic],\n },\n {\n match: '**',\n mode: 'mark',\n type: KEYS.bold,\n },\n {\n match: '__',\n mode: 'mark',\n type: KEYS.underline,\n },\n {\n match: '*',\n mode: 'mark',\n type: KEYS.italic,\n },\n {\n match: '_',\n mode: 'mark',\n type: KEYS.italic,\n },\n {\n match: '~~',\n mode: 'mark',\n type: KEYS.strikethrough,\n },\n {\n match: '^',\n mode: 'mark',\n type: KEYS.sup,\n },\n {\n match: '~',\n mode: 'mark',\n type: KEYS.sub,\n },\n {\n match: '==',\n mode: 'mark',\n type: KEYS.highlight,\n },\n {\n match: '≡',\n mode: 'mark',\n type: KEYS.highlight,\n },\n {\n match: '`',\n mode: 'mark',\n type: KEYS.code,\n },\n];\n\nconst autoformatBlocks: AutoformatRule[] = [\n {\n match: '# ',\n mode: 'block',\n preFormat,\n type: KEYS.h1,\n },\n {\n match: '## ',\n mode: 'block',\n preFormat,\n type: KEYS.h2,\n },\n {\n match: '### ',\n mode: 'block',\n preFormat,\n type: KEYS.h3,\n },\n {\n match: '#### ',\n mode: 'block',\n preFormat,\n type: KEYS.h4,\n },\n {\n match: '##### ',\n mode: 'block',\n preFormat,\n type: KEYS.h5,\n },\n {\n match: '###### ',\n mode: 'block',\n preFormat,\n type: KEYS.h6,\n },\n {\n match: '> ',\n mode: 'block',\n preFormat,\n type: KEYS.blockquote,\n },\n {\n match: '```',\n mode: 'block',\n preFormat,\n type: KEYS.codeBlock,\n format: (editor) => {\n insertEmptyCodeBlock(editor, {\n defaultType: KEYS.p,\n insertNodesOptions: { select: true },\n });\n },\n },\n // {\n // match: '+ ',\n // mode: 'block',\n // preFormat: openNextToggles,\n // type: KEYS.toggle,\n // },\n {\n match: ['---', '—-', '___ '],\n mode: 'block',\n type: KEYS.hr,\n format: (editor) => {\n editor.tf.setNodes({ type: KEYS.hr });\n editor.tf.insertNodes({\n children: [{ text: '' }],\n type: KEYS.p,\n });\n },\n },\n];\n\nconst autoformatLists: AutoformatRule[] = [\n {\n match: ['* ', '- '],\n mode: 'block',\n preFormat,\n type: KEYS.li,\n format: (editor) => formatList(editor, KEYS.ulClassic),\n },\n {\n match: [String.raw`^\\d+\\.$ `, String.raw`^\\d+\\)$ `],\n matchByRegex: true,\n mode: 'block',\n preFormat,\n type: KEYS.li,\n format: (editor) => formatList(editor, KEYS.olClassic),\n },\n {\n match: '[] ',\n mode: 'block',\n type: KEYS.listTodoClassic,\n },\n {\n match: '[x] ',\n mode: 'block',\n type: KEYS.listTodoClassic,\n format: (editor) =>\n editor.tf.setNodes(\n { checked: true, type: KEYS.listTodoClassic },\n {\n match: (n) => editor.api.isBlock(n),\n }\n ),\n },\n];\n\nexport const AutoformatKit = [\n AutoformatPlugin.configure({\n options: {\n enableUndoOnDelete: true,\n rules: [\n ...autoformatBlocks,\n ...autoformatMarks,\n ...autoformatSmartQuotes,\n ...autoformatPunctuation,\n ...autoformatLegal,\n ...autoformatLegalHtml,\n ...autoformatArrow,\n ...autoformatMath,\n ...autoformatLists,\n ].map((rule) => ({\n ...rule,\n query: (editor) =>\n !editor.api.some({\n match: { type: editor.getType(KEYS.codeBlock) },\n }),\n })),\n },\n }),\n];\n", + "content": "'use client';\n\nimport type { AutoformatBlockRule, AutoformatRule } from '@platejs/autoformat';\nimport type { SlateEditor } from 'platejs';\n\nimport {\n autoformatArrow,\n autoformatLegal,\n autoformatLegalHtml,\n autoformatMath,\n AutoformatPlugin,\n autoformatPunctuation,\n autoformatSmartQuotes,\n} from '@platejs/autoformat';\nimport { insertEmptyCodeBlock } from '@platejs/code-block';\nimport { toggleList, toggleTaskList, unwrapList } from '@platejs/list-classic';\nimport { ElementApi, isType, KEYS } from 'platejs';\n\nconst preFormat: AutoformatBlockRule['preFormat'] = (editor) =>\n unwrapList(editor);\n\nconst format = (editor: SlateEditor, customFormatting: any) => {\n if (editor.selection) {\n const parentEntry = editor.api.parent(editor.selection);\n\n if (!parentEntry) return;\n\n const [node] = parentEntry;\n\n if (ElementApi.isElement(node) && !isType(editor, node, KEYS.codeBlock)) {\n customFormatting();\n }\n }\n};\n\nconst formatTaskList = (editor: SlateEditor, defaultChecked = false) => {\n format(editor, () => toggleTaskList(editor, defaultChecked));\n};\n\nconst formatList = (editor: SlateEditor, elementType: string) => {\n format(editor, () =>\n toggleList(editor, {\n type: elementType,\n })\n );\n};\n\nconst autoformatMarks: AutoformatRule[] = [\n {\n match: '***',\n mode: 'mark',\n type: [KEYS.bold, KEYS.italic],\n },\n {\n match: '__*',\n mode: 'mark',\n type: [KEYS.underline, KEYS.italic],\n },\n {\n match: '__**',\n mode: 'mark',\n type: [KEYS.underline, KEYS.bold],\n },\n {\n match: '___***',\n mode: 'mark',\n type: [KEYS.underline, KEYS.bold, KEYS.italic],\n },\n {\n match: '**',\n mode: 'mark',\n type: KEYS.bold,\n },\n {\n match: '__',\n mode: 'mark',\n type: KEYS.underline,\n },\n {\n match: '*',\n mode: 'mark',\n type: KEYS.italic,\n },\n {\n match: '_',\n mode: 'mark',\n type: KEYS.italic,\n },\n {\n match: '~~',\n mode: 'mark',\n type: KEYS.strikethrough,\n },\n {\n match: '^',\n mode: 'mark',\n type: KEYS.sup,\n },\n {\n match: '~',\n mode: 'mark',\n type: KEYS.sub,\n },\n {\n match: '==',\n mode: 'mark',\n type: KEYS.highlight,\n },\n {\n match: '≡',\n mode: 'mark',\n type: KEYS.highlight,\n },\n {\n match: '`',\n mode: 'mark',\n type: KEYS.code,\n },\n];\n\nconst autoformatBlocks: AutoformatRule[] = [\n {\n match: '# ',\n mode: 'block',\n preFormat,\n type: KEYS.h1,\n },\n {\n match: '## ',\n mode: 'block',\n preFormat,\n type: KEYS.h2,\n },\n {\n match: '### ',\n mode: 'block',\n preFormat,\n type: KEYS.h3,\n },\n {\n match: '#### ',\n mode: 'block',\n preFormat,\n type: KEYS.h4,\n },\n {\n match: '##### ',\n mode: 'block',\n preFormat,\n type: KEYS.h5,\n },\n {\n match: '###### ',\n mode: 'block',\n preFormat,\n type: KEYS.h6,\n },\n {\n match: '> ',\n mode: 'block',\n preFormat,\n type: KEYS.blockquote,\n },\n {\n match: '```',\n mode: 'block',\n preFormat,\n type: KEYS.codeBlock,\n format: (editor) => {\n insertEmptyCodeBlock(editor, {\n defaultType: KEYS.p,\n insertNodesOptions: { select: true },\n });\n },\n },\n // {\n // match: '+ ',\n // mode: 'block',\n // preFormat: openNextToggles,\n // type: KEYS.toggle,\n // },\n {\n match: ['---', '—-', '___ '],\n mode: 'block',\n type: KEYS.hr,\n format: (editor) => {\n editor.tf.setNodes({ type: KEYS.hr });\n editor.tf.insertNodes({\n children: [{ text: '' }],\n type: KEYS.p,\n });\n },\n },\n];\n\nconst autoformatLists: AutoformatRule[] = [\n {\n match: ['* ', '- '],\n mode: 'block',\n preFormat,\n type: KEYS.li,\n format: (editor) => formatList(editor, KEYS.ulClassic),\n },\n {\n match: [String.raw`^\\d+\\.$ `, String.raw`^\\d+\\)$ `],\n matchByRegex: true,\n mode: 'block',\n preFormat,\n type: KEYS.li,\n format: (editor) => formatList(editor, KEYS.olClassic),\n },\n {\n match: '[] ',\n mode: 'block',\n type: KEYS.taskList,\n format: (editor) => formatTaskList(editor, false),\n },\n {\n match: '[x] ',\n mode: 'block',\n type: KEYS.taskList,\n format: (editor) => formatTaskList(editor, true),\n },\n];\n\nexport const AutoformatKit = [\n AutoformatPlugin.configure({\n options: {\n enableUndoOnDelete: true,\n rules: [\n ...autoformatBlocks,\n ...autoformatMarks,\n ...autoformatSmartQuotes,\n ...autoformatPunctuation,\n ...autoformatLegal,\n ...autoformatLegalHtml,\n ...autoformatArrow,\n ...autoformatMath,\n ...autoformatLists,\n ].map((rule) => ({\n ...rule,\n query: (editor) =>\n !editor.api.some({\n match: { type: editor.getType(KEYS.codeBlock) },\n }),\n })),\n },\n }),\n];\n", "type": "registry:component" } ] diff --git a/apps/www/public/r/code-block-node.json b/apps/www/public/r/code-block-node.json index 02c8b53493..c5a44cc6f1 100644 --- a/apps/www/public/r/code-block-node.json +++ b/apps/www/public/r/code-block-node.json @@ -16,12 +16,12 @@ "files": [ { "path": "src/registry/ui/code-block-node.tsx", - "content": "'use client';\n\nimport * as React from 'react';\n\nimport { formatCodeBlock, isLangSupported } from '@platejs/code-block';\nimport { BracesIcon, Check, CheckIcon, CopyIcon } from 'lucide-react';\nimport { type TCodeBlockElement, type TCodeSyntaxLeaf, NodeApi } from 'platejs';\nimport {\n type PlateElementProps,\n type PlateLeafProps,\n PlateElement,\n PlateLeaf,\n} from 'platejs/react';\nimport { useEditorRef, useElement, useReadOnly } from 'platejs/react';\n\nimport { Button } from '@/components/ui/button';\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/ui/command';\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover';\nimport { cn } from '@/lib/utils';\n\nexport function CodeBlockElement(props: PlateElementProps) {\n const { editor, element } = props;\n\n return (\n \n
\n
\n          {props.children}\n        
\n\n \n {isLangSupported(element.lang) && (\n formatCodeBlock(editor, { element })}\n title=\"Format code\"\n >\n \n \n )}\n\n \n\n NodeApi.string(element)}\n />\n
\n \n \n );\n}\n\nfunction CodeBlockCombobox() {\n const [open, setOpen] = React.useState(false);\n const readOnly = useReadOnly();\n const editor = useEditorRef();\n const element = useElement();\n const value = element.lang || 'plaintext';\n const [searchValue, setSearchValue] = React.useState('');\n\n const items = React.useMemo(\n () =>\n languages.filter(\n (language) =>\n !searchValue ||\n language.label.toLowerCase().includes(searchValue.toLowerCase())\n ),\n [searchValue]\n );\n\n if (readOnly) return null;\n\n return (\n \n \n \n {languages.find((language) => language.value === value)?.label ??\n 'Plain Text'}\n \n \n setSearchValue('')}\n >\n \n setSearchValue(value)}\n placeholder=\"Search language...\"\n />\n No language found.\n\n \n \n {items.map((language) => (\n {\n editor.tf.setNodes(\n { lang: value },\n { at: element }\n );\n setSearchValue(value);\n setOpen(false);\n }}\n >\n \n {language.label}\n \n ))}\n \n \n \n \n \n );\n}\n\nfunction CopyButton({\n value,\n ...props\n}: { value: (() => string) | string } & Omit<\n React.ComponentProps,\n 'value'\n>) {\n const [hasCopied, setHasCopied] = React.useState(false);\n\n React.useEffect(() => {\n setTimeout(() => {\n setHasCopied(false);\n }, 2000);\n }, [hasCopied]);\n\n return (\n {\n void navigator.clipboard.writeText(\n typeof value === 'function' ? value() : value\n );\n setHasCopied(true);\n }}\n {...props}\n >\n Copy\n {hasCopied ? (\n \n ) : (\n \n )}\n \n );\n}\n\nexport function CodeLineElement(props: PlateElementProps) {\n return ;\n}\n\nexport function CodeSyntaxLeaf(props: PlateLeafProps) {\n const tokenClassName = props.leaf.className as string;\n\n return ;\n}\n\nconst languages: { label: string; value: string }[] = [\n { label: 'Auto', value: 'auto' },\n { label: 'Plain Text', value: 'plaintext' },\n { label: 'ABAP', value: 'abap' },\n { label: 'Agda', value: 'agda' },\n { label: 'Arduino', value: 'arduino' },\n { label: 'ASCII Art', value: 'ascii' },\n { label: 'Assembly', value: 'x86asm' },\n { label: 'Bash', value: 'bash' },\n { label: 'BASIC', value: 'basic' },\n { label: 'BNF', value: 'bnf' },\n { label: 'C', value: 'c' },\n { label: 'C#', value: 'csharp' },\n { label: 'C++', value: 'cpp' },\n { label: 'Clojure', value: 'clojure' },\n { label: 'CoffeeScript', value: 'coffeescript' },\n { label: 'Coq', value: 'coq' },\n { label: 'CSS', value: 'css' },\n { label: 'Dart', value: 'dart' },\n { label: 'Dhall', value: 'dhall' },\n { label: 'Diff', value: 'diff' },\n { label: 'Docker', value: 'dockerfile' },\n { label: 'EBNF', value: 'ebnf' },\n { label: 'Elixir', value: 'elixir' },\n { label: 'Elm', value: 'elm' },\n { label: 'Erlang', value: 'erlang' },\n { label: 'F#', value: 'fsharp' },\n { label: 'Flow', value: 'flow' },\n { label: 'Fortran', value: 'fortran' },\n { label: 'Gherkin', value: 'gherkin' },\n { label: 'GLSL', value: 'glsl' },\n { label: 'Go', value: 'go' },\n { label: 'GraphQL', value: 'graphql' },\n { label: 'Groovy', value: 'groovy' },\n { label: 'Haskell', value: 'haskell' },\n { label: 'HCL', value: 'hcl' },\n { label: 'HTML', value: 'html' },\n { label: 'Idris', value: 'idris' },\n { label: 'Java', value: 'java' },\n { label: 'JavaScript', value: 'javascript' },\n { label: 'JSON', value: 'json' },\n { label: 'Julia', value: 'julia' },\n { label: 'Kotlin', value: 'kotlin' },\n { label: 'LaTeX', value: 'latex' },\n { label: 'Less', value: 'less' },\n { label: 'Lisp', value: 'lisp' },\n { label: 'LiveScript', value: 'livescript' },\n { label: 'LLVM IR', value: 'llvm' },\n { label: 'Lua', value: 'lua' },\n { label: 'Makefile', value: 'makefile' },\n { label: 'Markdown', value: 'markdown' },\n { label: 'Markup', value: 'markup' },\n { label: 'MATLAB', value: 'matlab' },\n { label: 'Mathematica', value: 'mathematica' },\n { label: 'Mermaid', value: 'mermaid' },\n { label: 'Nix', value: 'nix' },\n { label: 'Notion Formula', value: 'notion' },\n { label: 'Objective-C', value: 'objectivec' },\n { label: 'OCaml', value: 'ocaml' },\n { label: 'Pascal', value: 'pascal' },\n { label: 'Perl', value: 'perl' },\n { label: 'PHP', value: 'php' },\n { label: 'PowerShell', value: 'powershell' },\n { label: 'Prolog', value: 'prolog' },\n { label: 'Protocol Buffers', value: 'protobuf' },\n { label: 'PureScript', value: 'purescript' },\n { label: 'Python', value: 'python' },\n { label: 'R', value: 'r' },\n { label: 'Racket', value: 'racket' },\n { label: 'Reason', value: 'reasonml' },\n { label: 'Ruby', value: 'ruby' },\n { label: 'Rust', value: 'rust' },\n { label: 'Sass', value: 'scss' },\n { label: 'Scala', value: 'scala' },\n { label: 'Scheme', value: 'scheme' },\n { label: 'SCSS', value: 'scss' },\n { label: 'Shell', value: 'shell' },\n { label: 'Smalltalk', value: 'smalltalk' },\n { label: 'Solidity', value: 'solidity' },\n { label: 'SQL', value: 'sql' },\n { label: 'Swift', value: 'swift' },\n { label: 'TOML', value: 'toml' },\n { label: 'TypeScript', value: 'typescript' },\n { label: 'VB.Net', value: 'vbnet' },\n { label: 'Verilog', value: 'verilog' },\n { label: 'VHDL', value: 'vhdl' },\n { label: 'Visual Basic', value: 'vbnet' },\n { label: 'WebAssembly', value: 'wasm' },\n { label: 'XML', value: 'xml' },\n { label: 'YAML', value: 'yaml' },\n];\n", + "content": "'use client';\n\nimport * as React from 'react';\n\nimport { formatCodeBlock, isLangSupported } from '@platejs/code-block';\nimport { BracesIcon, Check, CheckIcon, CopyIcon } from 'lucide-react';\nimport { type TCodeBlockElement, type TCodeSyntaxLeaf, NodeApi } from 'platejs';\nimport {\n type PlateElementProps,\n type PlateLeafProps,\n PlateElement,\n PlateLeaf,\n} from 'platejs/react';\nimport { useEditorRef, useElement, useReadOnly } from 'platejs/react';\n\nimport { Button } from '@/components/ui/button';\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/ui/command';\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover';\nimport { cn } from '@/lib/utils';\n\nexport function CodeBlockElement(props: PlateElementProps) {\n const { editor, element } = props;\n\n return (\n \n
\n
\n          {props.children}\n        
\n\n \n {isLangSupported(element.lang) && (\n formatCodeBlock(editor, { element })}\n title=\"Format code\"\n >\n \n \n )}\n\n \n\n NodeApi.string(element)}\n />\n
\n \n
\n );\n}\n\nfunction CodeBlockCombobox() {\n const [open, setOpen] = React.useState(false);\n const readOnly = useReadOnly();\n const editor = useEditorRef();\n const element = useElement();\n const value = element.lang || 'plaintext';\n const [searchValue, setSearchValue] = React.useState('');\n\n const items = React.useMemo(\n () =>\n languages.filter(\n (language) =>\n !searchValue ||\n language.label.toLowerCase().includes(searchValue.toLowerCase())\n ),\n [searchValue]\n );\n\n if (readOnly) return null;\n\n return (\n \n \n \n {languages.find((language) => language.value === value)?.label ??\n 'Plain Text'}\n \n \n setSearchValue('')}\n >\n \n setSearchValue(value)}\n placeholder=\"Search language...\"\n />\n No language found.\n\n \n \n {items.map((language) => (\n {\n editor.tf.setNodes(\n { lang: value },\n { at: element }\n );\n setSearchValue(value);\n setOpen(false);\n }}\n >\n \n {language.label}\n \n ))}\n \n \n \n \n \n );\n}\n\nfunction CopyButton({\n value,\n ...props\n}: { value: (() => string) | string } & Omit<\n React.ComponentProps,\n 'value'\n>) {\n const [hasCopied, setHasCopied] = React.useState(false);\n\n React.useEffect(() => {\n setTimeout(() => {\n setHasCopied(false);\n }, 2000);\n }, [hasCopied]);\n\n return (\n {\n void navigator.clipboard.writeText(\n typeof value === 'function' ? value() : value\n );\n setHasCopied(true);\n }}\n {...props}\n >\n Copy\n {hasCopied ? (\n \n ) : (\n \n )}\n \n );\n}\n\nexport function CodeLineElement(props: PlateElementProps) {\n return ;\n}\n\nexport function CodeSyntaxLeaf(props: PlateLeafProps) {\n const tokenClassName = props.leaf.className as string;\n\n return ;\n}\n\nconst languages: { label: string; value: string }[] = [\n { label: 'Auto', value: 'auto' },\n { label: 'Plain Text', value: 'plaintext' },\n { label: 'ABAP', value: 'abap' },\n { label: 'Agda', value: 'agda' },\n { label: 'Arduino', value: 'arduino' },\n { label: 'ASCII Art', value: 'ascii' },\n { label: 'Assembly', value: 'x86asm' },\n { label: 'Bash', value: 'bash' },\n { label: 'BASIC', value: 'basic' },\n { label: 'BNF', value: 'bnf' },\n { label: 'C', value: 'c' },\n { label: 'C#', value: 'csharp' },\n { label: 'C++', value: 'cpp' },\n { label: 'Clojure', value: 'clojure' },\n { label: 'CoffeeScript', value: 'coffeescript' },\n { label: 'Coq', value: 'coq' },\n { label: 'CSS', value: 'css' },\n { label: 'Dart', value: 'dart' },\n { label: 'Dhall', value: 'dhall' },\n { label: 'Diff', value: 'diff' },\n { label: 'Docker', value: 'dockerfile' },\n { label: 'EBNF', value: 'ebnf' },\n { label: 'Elixir', value: 'elixir' },\n { label: 'Elm', value: 'elm' },\n { label: 'Erlang', value: 'erlang' },\n { label: 'F#', value: 'fsharp' },\n { label: 'Flow', value: 'flow' },\n { label: 'Fortran', value: 'fortran' },\n { label: 'Gherkin', value: 'gherkin' },\n { label: 'GLSL', value: 'glsl' },\n { label: 'Go', value: 'go' },\n { label: 'GraphQL', value: 'graphql' },\n { label: 'Groovy', value: 'groovy' },\n { label: 'Haskell', value: 'haskell' },\n { label: 'HCL', value: 'hcl' },\n { label: 'HTML', value: 'html' },\n { label: 'Idris', value: 'idris' },\n { label: 'Java', value: 'java' },\n { label: 'JavaScript', value: 'javascript' },\n { label: 'JSON', value: 'json' },\n { label: 'Julia', value: 'julia' },\n { label: 'Kotlin', value: 'kotlin' },\n { label: 'LaTeX', value: 'latex' },\n { label: 'Less', value: 'less' },\n { label: 'Lisp', value: 'lisp' },\n { label: 'LiveScript', value: 'livescript' },\n { label: 'LLVM IR', value: 'llvm' },\n { label: 'Lua', value: 'lua' },\n { label: 'Makefile', value: 'makefile' },\n { label: 'Markdown', value: 'markdown' },\n { label: 'Markup', value: 'markup' },\n { label: 'MATLAB', value: 'matlab' },\n { label: 'Mathematica', value: 'mathematica' },\n { label: 'Mermaid', value: 'mermaid' },\n { label: 'Nix', value: 'nix' },\n { label: 'Notion Formula', value: 'notion' },\n { label: 'Objective-C', value: 'objectivec' },\n { label: 'OCaml', value: 'ocaml' },\n { label: 'Pascal', value: 'pascal' },\n { label: 'Perl', value: 'perl' },\n { label: 'PHP', value: 'php' },\n { label: 'PowerShell', value: 'powershell' },\n { label: 'Prolog', value: 'prolog' },\n { label: 'Protocol Buffers', value: 'protobuf' },\n { label: 'PureScript', value: 'purescript' },\n { label: 'Python', value: 'python' },\n { label: 'R', value: 'r' },\n { label: 'Racket', value: 'racket' },\n { label: 'Reason', value: 'reasonml' },\n { label: 'Ruby', value: 'ruby' },\n { label: 'Rust', value: 'rust' },\n { label: 'Sass', value: 'scss' },\n { label: 'Scala', value: 'scala' },\n { label: 'Scheme', value: 'scheme' },\n { label: 'SCSS', value: 'scss' },\n { label: 'Shell', value: 'shell' },\n { label: 'Smalltalk', value: 'smalltalk' },\n { label: 'Solidity', value: 'solidity' },\n { label: 'SQL', value: 'sql' },\n { label: 'Swift', value: 'swift' },\n { label: 'TOML', value: 'toml' },\n { label: 'TypeScript', value: 'typescript' },\n { label: 'VB.Net', value: 'vbnet' },\n { label: 'Verilog', value: 'verilog' },\n { label: 'VHDL', value: 'vhdl' },\n { label: 'Visual Basic', value: 'vbnet' },\n { label: 'WebAssembly', value: 'wasm' },\n { label: 'XML', value: 'xml' },\n { label: 'YAML', value: 'yaml' },\n];\n", "type": "registry:ui" }, { "path": "src/registry/ui/code-block-node-static.tsx", - "content": "import * as React from 'react';\n\nimport {\n type SlateElementProps,\n type SlateLeafProps,\n type TCodeBlockElement,\n SlateElement,\n SlateLeaf,\n} from 'platejs';\n\nexport function CodeBlockElementStatic(\n props: SlateElementProps\n) {\n return (\n \n
\n
\n          {props.children}\n        
\n
\n \n );\n}\n\nexport function CodeLineElementStatic(props: SlateElementProps) {\n return ;\n}\n\nexport function CodeSyntaxLeafStatic(props: SlateLeafProps) {\n const tokenClassName = props.leaf.className as string;\n\n return ;\n}\n", + "content": "import * as React from 'react';\n\nimport {\n type SlateElementProps,\n type SlateLeafProps,\n type TCodeBlockElement,\n SlateElement,\n SlateLeaf,\n} from 'platejs';\n\nexport function CodeBlockElementStatic(\n props: SlateElementProps\n) {\n return (\n \n
\n
\n          {props.children}\n        
\n
\n
\n );\n}\n\nexport function CodeLineElementStatic(props: SlateElementProps) {\n return ;\n}\n\nexport function CodeSyntaxLeafStatic(props: SlateLeafProps) {\n const tokenClassName = props.leaf.className as string;\n\n return ;\n}\n", "type": "registry:ui" } ], diff --git a/apps/www/public/r/components-changelog-docs.json b/apps/www/public/r/components-changelog-docs.json index 4854b90c55..c1724f9c2c 100644 --- a/apps/www/public/r/components-changelog-docs.json +++ b/apps/www/public/r/components-changelog-docs.json @@ -7,7 +7,7 @@ "files": [ { "path": "../../docs/components/changelog.mdx", - "content": "---\ntitle: Changelog\ndescription: Latest component updates and announcements.\ntoc: true\n---\n\nSince Plate UI is not a component library, a changelog is maintained here.\n\nUse the [CLI](https://platejs.org/docs/components/cli) to install the latest version of the components.\n\n## June 2025 #23\n\n### June 29 #23.9\n- `link-node`: Remove `useLink`\n- `link-node-static`: missing `getLinkAttributes`\n- `media-image-node`: `attributes.alt` type casting\n\n### June 26 #23.7\n- `inline-combobox`: Fixed combobox not closing when clicking outside the editor\n\n### June 24 #23.6\n- `transform.ts`: add `toggleCodeBlock` to `setBlockMap`. Fix the structural error of the code_block created by `turn-into-toolbar-button.tsx`.\n\n### June 20 #23.5\n- [Drag and drop improvements](https://github.com/udecode/plate/pull/4385)\n- `block-draggable`: Fixed drag and drop functionality with multiple selected blocks and resolved drop positioning issues on margins.\n- `block-selection-kit`: It is now possible to select the entire table (table), but the rows (tr) will only be selected if your selection box is within the table.\n- `table-node`: Add block selection styles to the table.\n\n### June 18 #23.4\n\n- `table-node`: Fix bug affecting cursor position and improve performance\n\n### June 16 #23.3\n\n- `block-draggable`: use `getPluginByType` instead of `getContainerTypes`\n\n### June 13 #23.2\n\n- `editor`: Fix placeholder positioning `**:data-slate-placeholder:!top-1/2 **:data-slate-placeholder:-translate-y-1/2`.\n- `block-placeholder-kit`: Change placeholder color to `text-muted-foreground/80` to match `editor` one.\n\n### June 9 #23.1\n\n**Plate 49**\n\nMerging files, using a more consistent naming convention, and removing unused `export` statements.\n\nComponents:\n\n- Now that basic nodes have a default HTML element, you can remove `withProps(..., { as: '...' })` plugin components.\n- To improve decoupling, plugins are not imported anymore only for their keys. Import `KEYS` from `@udecode/plate` instead, as a unified source of keys.\n - `ParagraphPlugin.key` -> `KEYS.p`\n - `INDENT_LIST_KEYS.listStyleType` -> `KEYS.listType`\n - `ListStyleType.Decimal` -> `KEYS.ol`\n - `ListStyleType.Disc` -> `KEYS.ul`\n - `list` (classic) -> `KEYS.listClassic`\n - `ol` (classic) -> `KEYS.olClassic`\n - `ul` (classic) -> `KEYS.ulClassic`\n - `li` (classic) -> `KEYS.liClassic`\n - `action_item` (classic) -> `KEYS.listTodoClassic`\n- Rename all `*-element`, `*-leaf` files to `*-node` (and static versions)\n- Removed `ai-anchor-element`, merged into `ai-node`\n- Removed `ai-loading-bar`, merged into `ai-menu`\n- Removed `ai-menu-items`, merged into `ai-menu`\n- Renamed `align-dropdown-menu` to `align-toolbar-button`, `AlignDropdownMenu` to `AlignToolbarButton`\n- Renamed `api-ai` to `ai-api`\n- Renamed `api-uploadthing` to `media-uploadthing-api`\n- `BlockSelection`: fix block selection for tables\n- Removed `code-block-combobox`, merged into `code-block-node`\n- Removed `code-line-element`, merged into `code-block-node` (and static version)\n- Removed `code-syntax-leaf`, merged into `code-block-node` (and static version)\n- Rename `color-toolbar-button` to `font-color-toolbar-button`, `ColorDropdownMenu` to `FontColorToolbarButton`\n- Removed all `color-*` files, merged into `font-color-toolbar-button`\n - Rename `color-dropdown-menu` to `font-color-toolbar-button`\n- Removed `column-group-element`, merged into `column-node` (and static version)\n- Removed `comment-create-form`, merged into `comment`\n- Renamed `draggable` to `block-draggable`, `DraggableAboveNodes` to `BlockDraggable`\n- Renamed `emoji-input-element` to `emoji-node`\n- Removed all `emoji-*` files (except `emoji-input-node`), merged into `emoji-toolbar-button`\n - Rename `EmojiToolbarDropdown` to `EmojiPopover`, `EmojiDropdownMenu` to `EmojiToolbarButton`\n - `EmojiPicker` `icons` prop is now optional and defaulted to `emojiCategoryIcons` and `emojiSearchIcons`\n- Renamed `image-preview` to `media-preview-dialog`, `ImagePreview` to `MediaPreviewDialog`\n- Renamed `image-element` to `media-image-node`\n - Renamed `MediaFileElement` to `FileElement` (and static version)\n - Renamed `MediaAudioElement` to `AudioElement` (and static version)\n - Renamed `MediaVideoElement` to `VideoElement` (and static version)\n- Renamed `indent-list-toolbar-button` to `list-toolbar-button`\n - Renamed `BulletedIndentListToolbarButton` to `BulletedListToolbarButton`\n - Renamed `NumberedIndentListToolbarButton` to `NumberedListToolbarButton`\n- Renamed `indent-todo-marker` to `block-list`\n- Removed `indent-fire-marker`\n- Removed `indent-todo-toolbar-button`, merged into `list-toolbar-button`\n- Renamed `IndentTodoToolbarButton` into `TodoListToolbarButton`\n- Removed `inline-equation-element` and `equation-popover`, merged into `equation-node` (and static version)\n- Removed `inline-equation-toolbar-button`, merged into `equation-toolbar-button`\n- Renamed `insert-dropdown-menu` to `insert-toolbar-button`, `InsertDropdownMenu` to `InsertToolbarButton`\n- Renamed `line-height-dropdown-menu` to `line-height-toolbar-button`, `LineHeightDropdownMenu` to `LineHeightToolbarButton`\n- Rename `link-floating-toolbar` to `link-toolbar`\n- Removed `list-indent-toolbar-button`, merged into `list-classic-toolbar-button`\n- Renamed `ListIndentToolbarButton` to `IndentToolbarButton`\n- Renamed `list-node` to `list-classic-node`\n- Renamed `media-popover` to `media-toolbar`, `MediaPopover` to `MediaToolbar`\n- Renamed `mode-dropdown-menu` to `mode-toolbar-button`, `ModeDropdownMenu` to `ModeToolbarButton`\n- Renamed `more-dropdown-menu` to `more-toolbar-button`, `MoreDropdownMenu` to `MoreToolbarButton`\n- Removed `outdent-toolbar-button`, merged into `indent-toolbar-button`\n- `table-icons`: rename `Border*` to `Border*Icon`\n- Renamed `slash-input-element` to `slash-input-node`\n- Renamed `SuggestionBelowNodes` to `SuggestionLineBreak`\n- Removed `table-cell-element`, merged into `table-node` (and static version)\n- Removed `table-row-element`, merged into `table-node` (and static version)\n- Renamed `table-dropdown-menu` to `table-toolbar-button`, `TableDropdownMenu` to `TableToolbarButton`\n- Removed `todo-list-node`, merged into `list-classic-node`\n- Renamed `turn-into-dropdown-menu` to `turn-into-toolbar-button`, `TurnIntoDropdownMenu` to `TurnIntoToolbarButton`\n- `export-toolbar-button`, `indent-list-plugins`: remove fire from `listStyleTypes`\n- `useCommentEditor`: `usePlateEditor` instead of `useCreateEditor`\n- Removed `placeholder`, `withPlaceholder`. Migration: use `block-placeholder-kit`, `BlockPlaceholderPlugin` instead.\n- `line-height-toolbar-button`: remove `useLineHeightDropdownMenu` hook.\n- `font-color-toolbar-button`: remove `useColorInput` hook.\n\nPlugins:\n\n- Renamed all `*-plugin`, `*-plugins` files to `-kit`, and `*Plugin`, `*Plugins` to `*Kit`. A **plugin kit** is a collection of configured plugins.\n - Renamed `editor-plugins` to `editor-kit`\n - Renamed `equation-plugins` to `math-kit`, `equationPlugins` to `MathKit`\n - Renamed `indent-list-plugins` to `list-kit`, `indentListPlugins` to `ListKit`\n - Added `BlockList` component to `block-list`, used in `list-kit`\n - Removed `use-create-editor`, use `usePlateEditor` instead\n- `ai-kit`: add `show` shortcut. Remove `useHotkeys('mod+j')` from `ai-menu`\n- `comment-kit`: add `setDraft` transform, shortcut\n- `basic-marks-kit`, `basic-blocks-kit`: add shortcuts\n\n- `transforms`, `block-draggable`: remove `STRUCTURE_TYPES`, those are now inferred from `plugin.node.isContainer`. Use instead `editor.meta.containerTypes`.\n- Remove `structuralTypes` from `useSelectionFragmentProp` usages.\n\n## May 2025 #22\n\n### May 26 #22.7\n\n- [Fix combobox closing issue](https://github.com/udecode/plate/pull/4322)\n- `inline-combobox`: fix `insertPoint` not being updated when the combobox is closed.\n\n### May 15 #22.6\n\n- [Fix inline math keyboard behavior and style](https://github.com/udecode/plate/pull/4305)\n- `equation-popover`: Focus back to the editor when the popover is closed.\n- `inline-equation-element`: When selecting it should be highlighted.\n\n### May 11-12 #22.5\n\n- [Templates migration to Plate 48](https://github.com/udecode/plate/pull/4298/files)\n- Migration to shadcn v4: \n - Plate had a forked version of shadcn/ui primitives that could conflict with your existing components. Our components now **fully depend** on the original shadcn/ui primitives, easing the integration of Plate into your existing shadcn/ui set of components.\n - All components updated to [Tailwind v4](https://ui.shadcn.com/docs/tailwind-v4). \n - See the updated [installation guide](/docs/components/installation).\n- Migration to React 19. If you're using React 18, you may need to use `React.forwardRef` in a few places.\n- Migration to [shadcn CLI](https://ui.shadcn.com/docs/cli):\n - Remove `registries` from `components.json`\n - Use `npx shadcn` instead of `npx shadcx`\n- [MCP support](/docs/mcp)\n- Remove `withRef` from all components\n- Import `cn` from `@/lib/utils` instead of `@udecode/cn` to stay consistent with shadcn/ui\n- Remove unused `className`, `style` props from all element and leaf components\n- `draggable`:\n - Fix dnd in Firefox\n- `media-placeholder-element`: refactor to use `use-upload-file` hook instead of `uploadthing`\n - Migration: `npx shadcn@latest add https://platejs.org/r/api-uploadthing`\n\n### May 6 #22.3\n\n- `ai-chat-editor`: support none-standard markdown nodes.\n- `slash-input-element`: add callout support.\n- `block-selection-plugins.tsx`: fix block selection not working.\n\n### May 4 #22.2\n\n- `ai/command`: forked smoothStream from `ai` package now uses 30ms delay by default (only code blocks and tables use 100ms delay).\n\nv48 migration:\n- `PlateElement`, `PlateLeaf` and `PlateText` HTML attributes are moved from top-level props to `attributes` prop.\n- Remove `nodeProps` prop from `PlateElement`, `PlateLeaf`, `PlateText`. Use `attributes` prop instead.\n- Migrated components: \n - `block-discussion`\n - `comment-leaf`\n - `date-element`\n - `draggable`\n - `excalidraw-element`\n - `hr-element` + `-static`\n - `image-element` + `-static`\n - `link-element`\n - `media-audio-element`\n - `media-file-element`\n - `media-placeholder-element`\n - `media-video-element`\n - `mention-element`\n - `placeholder`\n - `suggestion-leaf`\n - `table-cell-element` + `-static`\n - `table-element`\n - `tag-element`\n\n### May 2 #22.1\n- `use-chat`: add `_abortFakeStream`.\n- `ai-menu`: Fix menu items are displayed incorrectly.\n- `ai-loading-bar`: Move esc keydown handler to `ai-menu`.\n- `ai/command`: add chunking delay to 100ms (Temporary workaround with performance issue).\n\n\n## April 2025 #21\n\n### April 30 #21.3\n\n- `autoformat-plugin`: allow starting a new indent list with numbers other than 1\n\n### April 29 #21.2\n\n- `ai-leaf`: add `aiIndicatorVariants` to display loading state.\n- `cursor-overlay`: hide when ai is streaming.\n- `api/ai/command`: fix chunking issue.\n\nAdd `discussion-plugin`:\n- add `discussionPlugin` to `editor-plugins`, remove `configure` from `suggestionPlugin`\n- refactor `block-suggestion`, `comment` to use `discussionPlugin`\n- fix `comment-create-form` to create discussion when none exists\n- style changes in `suggestion-leaf`\n- fix `link-floating-toolbar` to support internal links, and placement top when suggestion or comment is active\n\n### April 19 #21.1\n\n- `ai-anchor-element`: add `ai-anchor-element` component that is inserted before streaming, removed after streaming, and used for positioning the ai-menu\n- `ai-loading-bar`: add `ai-loading-bar` component that is used to display the loading progress of the insert mode streaming\n- `ai-menu`: migrate to latest `ai` package\n- `ai-menu-items`: add `generateMarkdownSample`\n- `ai-plugins`: Remove the single-paragraph limit from prompts\n- `editor`: introduce `PlateContainer` component\n\n### April 2 #21.1\n\n- `export-toolbar-button`: fix pdf export issue with `html2canvas-pro`\n- `import-toolbar-button`: fix sometimes unable to select the file\n\n## March 2025 #20\n\n### March 12 2025 #20.4\n\n- `ai-toolbar-button`: add missing `@udecode/plate-ai` dependency.\n- `comment-toolbar-button`: add missing `comments-plugin` registry dependency.\n- `font-size-toolbar-button`: add missing `popover` registry dependency.\n- `tooltip`: add missing `button` registry dependency.\n\n### March 10 #20.3\n- `block-context-menu`: Prevent opening context menu in read-only mode\n\n### March 2 #20.2\n\n- `block-suggestion`: fix styles\n- `suggestion-leaf-static`: add static versions\n\n### March 1 #20.1\n\nPlate 46 - new code block\n\n- Migrated from Prism.js to lowlight for syntax highlighting\n - `code-block-element-static`, `code-block-element`, `code-block-combobox`: Updated to use lowlight classes. Default to github theme.\n - `code-syntax-leaf-static`, `code-syntax-leaf`: Updated to use lowlight token classes\n - Removed `prismjs` dependency and related styles\n - Use `lowlight` plugin option instead of `prism` option\n - `code-block-combobox`: add `Auto` language option, change language values to match lowlight\n- `autoformat-plugin`: prevent autoformat on code blocks\n\n```tsx\nimport { all, createLowlight } from 'lowlight';\n\nconst lowlight = createLowlight(all);\n\nCodeBlockPlugin.configure({\n options: {\n lowlight,\n },\n});\n```\n\n### Feburary 21 #19.3\n\n- `image-preview`: prevent block menu on image preivew mask\n- `media-popover`: hide media popover when image preivew is open\n\n### February 18 #19.2\n\nPlate 45 - new comments & suggestions UI\n\n- NEW `block-discussion` as the main container, used in `plate-element`\n- NEW `comment` for individual comment display\n- NEW `comment-create-form` with minimal Plate editor for input\n- Removed legacy components:\n - `comments-popover`\n - `comment-avatar`\n - `comment-reply-items`\n - `comment-value`\n - `comment-resolve-button`\n- NEW `block-suggestion`\n- NEW `suggestion-leaf`\n- NEW `suggestion-line-break`\n- Remove `plate-element`, import `PlateElement` from `@udecode/plate/react` instead. Add in `block-selection-plugins`:\n```tsx\nrender: {\n belowRootNodes: (props) => {\n if (!props.className?.includes('slate-selectable')) return null;\n\n return ;\n },\n},\n```\n\n### February 3 #19.1\n\n- React 19\n- TailwindCSS 4\n- Plate 45\n- Jotai 2\n- Zustand 6\n- `comment-more-dropdown`: remove `useCommentEditButtonState`, `useCommentDeleteButtonState`\n- `image-element`, `media-embed-element`, `media-video-element`, `mode-dropdown-menu`\n - use `const width = useResizableValue('width')`\n- `image-preview`: remove `useScaleInputState`, `useImagePreviewState`\n- `floating-toolbar`: \n - replace `useEventEditorSelectors` with `useEventEditorValue`\n- `media-popover`: \n - replace `floatingMediaActions` with `FloatingMediaStore.set`, \n - replace `useFloatingMediaSelectors` with `useFloatingMediaValue`\n\n## January 2025 #18\n\n### January 23 #18.8\n\n- `table-element`: fix styles, show table border controls when collapsed\n- `table-row-element`: refactor\n- `table-cell-element`: selection bg-brand\n\n### January 21 #18.7\n\n- `table-element`, `table-row-element`: support row dnd and selection\n- `plate-element`: add `blockSelectionClassName` prop\n- `editor`: z-50 for selection area\n- `draggable`: \n - Replace `editor.api.blockSelection.replaceSelectedIds` with `editor.api.blockSelection.clear`\n - Use `TooltipButton` for drag handle\n - Block select on drag handle click\n - Hide drag handle in table cells\n- `column-element`, `table-cell-element`: add `isSelectionAreaVisible` check\n- `block-selection`: hide if dragging\n- Replace `editor.api.blockSelection.addSelectedRow` with `editor.api.blockSelection.set`:\n - `ai-menu`\n - `equation-popover`\n- `align-dropdown-menu`: deprecate \n\n\n### January 18 #18.6\n\n- `inline-equation-element` and `equation-popover`: Fix: When selecting an inline equation, the popover should not open, as it causes the selection to be lost.\n\n### January 17 #18.5\n\n- `emoji-picker-search-bar`: add `autoFocus`\n\n### January 16 #18.4\n\n- `import-toolbar-button` and `export-toolbar-button`: add `markdown` support\n\n### January 14 #18.3\n- `fixed-toolbar-buttons`: add `import-toolbar-button`\n- `indent-fire-marker.tsx` Add `data-plate-prevent-deserialization` to prevent deserialization of the fire marker. Change the `span` tag to `li`.\n- `indent-todo-marker.tsx` change the `span` tag to `li`.\n- `image-element-static.tsx` and `hr-element-static.tsx`: Fix `nodeProps` not being passed to `SlateElement`.\n- `ai-chat-editor`:\n```tsx\nconst aiEditor = usePlateEditor({ plugins });\nuseAIChatEditor(aiEditor, content);\n```\n\n### January 12 #18.2\n\n- `ai-plugins`: remove `createAIEditor`, it's now created in `ai-chat-editor`\n- `ai-chat-editor`: just use `useAIChatEditor` (v42.1)\n- `ai-menu`: avoid collisions, remove `aiEditorRef`\n- `command`: add `focus-visible:outline-none`\n- `editor-static`: update `aiChat` padding\n- `transforms`: fix `insertBlock` used by slash commands: it should insert a new block if the newly inserted block is of the same type as the command.\n- `block-selection-plugins`: update `BlockSelectionPlugin`\n\n```tsx\nBlockSelectionPlugin.configure(({ editor }) => ({\n options: {\n enableContextMenu: true,\n isSelectable: (element, path) => {\n return (\n !['code_line', 'column', 'td'].includes(element.type) &&\n !editor.api.block({ above: true, at: path, match: { type: 'tr' } })\n );\n },\n },\n}))\n```\n\n \n### January 8 #18.1\n\n- v42 migration\n- `table-element`, `table-element-static`\n - Move icons to `table-icons`\n - Remove `colgroup`, col width is now set in `table-cell-element`\n- `table-row-element`: remove `hideBorder` prop\n- `table-cell-element`, `table-cell-element-static`: \n - column hover/resizing state is now using Tailwind instead of JS\n - **Major performance improvement**: all table cells were re-rendering on a single cell change. This is now fixed.\n - React.memo\n- `table-dropdown-menu`:\n - dynamic table insert\n - merge/split cells\n - insert row/col before\n- `tooltip`: add `TooltipButton`\n- `indent-list-toolbar-button`: Remove `IndentListToolbarButton` use `NumberedIndentListToolbarButton` and `BulletedIndentListToolbarButton` instead.\n- `table-dropdown-menu`: new insert table interface.\n- `column-group-element`: fix `ColumnFloatingToolbar` onColumnChange\n\n## December 2024 #17\n\n### December 28 #17.8\n\n- `export-toolbar-button`: add `katex` support\n- `plate-element`: remove `relative` className\n- All components using the `PlateElement` have had redundant `relative` class names removed.\n### December 27 #17.7\n\n- `fixed-toolbar-buttons`: add `font-size-toolbar-button`\n- `floating-toolbar`: add `inline-equation-toolbar-button`\n- `turn-into-dropdown-menu`: Fix: after turn into other block, the editor should regain focus.\n- `insert-dropdown-menu`: add `inline equation` and `equation` & fix the focus issue\n- `slash-input-element`: add `equation` and `inline equation`\n\n### December 23 #17.5\n\n- `table-element`: fix selection\n- before: `isSelectingCell && '[&_*::selection]:bg-none'`\n- after: `isSelectingCell && '[&_*::selection]:!bg-transparent'`\n\n\n### December 21 #17.4\n\nUpdate `tailwind.config.cjs` for better font support in the HTML export:\n\n```ts\nfontFamily: {\n heading: [\n 'var(--font-heading)',\n 'ui-sans-serif',\n '-apple-system',\n 'BlinkMacSystemFont',\n 'Segoe UI Variable Display',\n 'Segoe UI',\n 'Helvetica',\n 'Apple Color Emoji',\n 'Arial',\n 'sans-serif',\n 'Segoe UI Emoji',\n 'Segoe UI Symbol',\n 'Noto Color Emoji',\n ],\n mono: ['var(--font-mono)', ...fontFamily.mono],\n sans: [\n 'var(--font-sans)',\n 'ui-sans-serif',\n '-apple-system',\n 'BlinkMacSystemFont',\n 'Segoe UI Variable Display',\n 'Segoe UI',\n 'Helvetica',\n 'Apple Color Emoji',\n 'Arial',\n 'sans-serif',\n 'Segoe UI Emoji',\n 'Segoe UI Symbol',\n 'Noto Color Emoji',\n ],\n```\n\n\n### December 20 #17.3\n\n- `insertColumnGroup`, `toggleColumnGroup`: use `columns` option instead of `layout` \n- Remove `with-draggables`. Add [`DraggableAboveNodes`](https://github.com/udecode/plate/pull/3878/files#diff-493c12ebed9c3ef9fd8c3a723909b18ad439a448c0132d2d93e5341ee0888ad2) to `draggable`. Add to `DndPlugin` config:\n```tsx\nDndPlugin.configure({ render: { aboveNodes: DraggableAboveNodes } }),\n```\n- `column-element`, `image-element`, `media-video-element`: Remove `useDraggableState`. Use `const { isDragging, previewRef, handleRef } = useDraggable`\n- `column-group-element`: Remove `useColumnState`. Use instead:\n```tsx\nconst columnGroupElement = useElement(ColumnPlugin.key);\n\nconst onColumnChange = (widths: string[]) => {\n setColumns(editor, {\n at: findNodePath(editor, columnGroupElement),\n widths,\n });\n};\n```\n- `export-toolbar-button`: add `exportToHtml`\n\n### December 19 #17.2\n\nPlate 41\n\n- New RSC components for element and leaf components, filename ending with `-static.tsx`. Those are now added along with the default client components.\n- `editor`: add `select-text` to `editorVariants`\n- `date-element`: remove popover when read-only\n- `indent-todo-marker`: use `SlateRenderElementProps` type instead of `PlateRenderElementProps`\n- `hr-element`, `media-audio-element`, `media-embed-element`, `mention-element`: improve cursor styling\n- `media-file-element`: use `` instead of `div` + `onClick`\n- all element and leaf components: `className` prop is now placed before inline prop.\n\n### December 16 #17.1\n\n- `column-element`:\n - Add drag and drop support for columns\n - Add drag handle with tooltip\n - Fix column spacing and padding\n\n- `column-group-element`:\n - Remove gap between columns\n - Remove margin top\n\n- `draggable`:\n - Remove `DraggableProvider` HOC\n - Remove `DropLine` children prop\n\n## November 2024 #16\n\n### November 26 #16.9\n\nhttps://github.com/udecode/plate/pull/3809/files\n- Add `select-editor`, `tag-element`, `label`, `form`\n- Replace `cmdk` dependency with `@udecode/cmdk`. It's a controllable version of `cmdk`.\n- `command`: add variants\n- `editor`: add `select` variant\n- `popover`: add `animate` variant\n\nhttps://github.com/udecode/plate/pull/3807/files\n- `toc-element`: remove `