From c8f71fdd3c6d9da99b1d824cae0035c454f5cee7 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Wed, 1 Jan 2025 20:29:18 +0800 Subject: [PATCH 01/25] docs --- apps/www/content/docs/cn/html.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/www/content/docs/cn/html.mdx b/apps/www/content/docs/cn/html.mdx index 2402830824..986e31375f 100644 --- a/apps/www/content/docs/cn/html.mdx +++ b/apps/www/content/docs/cn/html.mdx @@ -191,14 +191,14 @@ const html = await serializeHtml(editor, { components }); ### 使用方法 -The `editor.api.html.deserialize` function allows you to convert HTML content into Slate value: +`editor.api.html.deserialize` 函数允许你将 HTML 内容转换为 Slate 值: ```typescript import { createPlateEditor } from '@udecode/plate-common/react'; const editor = createPlateEditor({ plugins: [ - // all plugins that you want to deserialize + // 所有你想要反序列化的插件 ] }) editor.children = editor.api.html.deserialize('

Hello, world!

') From 680142a2365926322589a910e41257a178f22015 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Wed, 1 Jan 2025 20:29:35 +0800 Subject: [PATCH 02/25] Fix paste code block --- apps/www/src/app/(app)/dev/client.tsx | 35 ++++++++++++++ apps/www/src/app/(app)/dev/layout.tsx | 7 +++ apps/www/src/app/(app)/dev/page.tsx | 13 ++++++ .../default/block/slate-to-html/page.tsx | 17 +++++++ .../code-block/src/lib/BaseCodeBlockPlugin.ts | 2 +- .../htmlDeserializerCodeBlock.ts | 16 ++++++- .../htmlDeserializerCodeBlockStatic.ts | 46 +++++++++++++++++++ .../code-block/src/lib/deserializer/index.ts | 6 +++ packages/code-block/src/lib/index.ts | 2 +- .../src/lib/static/deserialize/checkUtils.ts | 39 ++++++++++++++++ .../core/src/lib/static/deserialize/index.ts | 5 ++ packages/core/src/lib/static/index.ts | 1 + 12 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 apps/www/src/app/(app)/dev/client.tsx create mode 100644 apps/www/src/app/(app)/dev/layout.tsx create mode 100644 apps/www/src/app/(app)/dev/page.tsx rename packages/code-block/src/lib/{ => deserializer}/htmlDeserializerCodeBlock.ts (70%) create mode 100644 packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts create mode 100644 packages/code-block/src/lib/deserializer/index.ts create mode 100644 packages/core/src/lib/static/deserialize/checkUtils.ts create mode 100644 packages/core/src/lib/static/deserialize/index.ts diff --git a/apps/www/src/app/(app)/dev/client.tsx b/apps/www/src/app/(app)/dev/client.tsx new file mode 100644 index 0000000000..7fba1296eb --- /dev/null +++ b/apps/www/src/app/(app)/dev/client.tsx @@ -0,0 +1,35 @@ +'use client'; + +import { Plate } from '@udecode/plate-core/react'; + +import { useCreateEditor } from '@/registry/default/components/editor/use-create-editor'; +import { linkValue } from '@/registry/default/example/values/link-value'; +import { Button } from '@/registry/default/plate-ui/button'; +import { Editor, EditorContainer } from '@/registry/default/plate-ui/editor'; + +export function ClientComponent() { + // console.log(linkValue, 'fj'); + + const editor = useCreateEditor({ + value: linkValue, + }); + + const handleFileSelect = () => { + const r = editor.api.html.deserialize({ + element: `

fj
fj

+

fj

`, + }); + console.log(r, 'result'); + }; + + return ( +
+ + + + + + +
+ ); +} diff --git a/apps/www/src/app/(app)/dev/layout.tsx b/apps/www/src/app/(app)/dev/layout.tsx new file mode 100644 index 0000000000..a2d1853dcc --- /dev/null +++ b/apps/www/src/app/(app)/dev/layout.tsx @@ -0,0 +1,7 @@ +export default function DevLayout({ children }: { children: React.ReactNode }) { + return ( +
+
{children}
+
+ ); +} diff --git a/apps/www/src/app/(app)/dev/page.tsx b/apps/www/src/app/(app)/dev/page.tsx new file mode 100644 index 0000000000..4b880f83f4 --- /dev/null +++ b/apps/www/src/app/(app)/dev/page.tsx @@ -0,0 +1,13 @@ +import { ClientComponent } from './client'; + +export default function DevPage() { + // Get all the marks from a leaf element + + // const htmlJson = html2Slate(basicHtmlString); + + return ( +
+ +
+ ); +} diff --git a/apps/www/src/registry/default/block/slate-to-html/page.tsx b/apps/www/src/registry/default/block/slate-to-html/page.tsx index 8d653bc549..f99646e84d 100644 --- a/apps/www/src/registry/default/block/slate-to-html/page.tsx +++ b/apps/www/src/registry/default/block/slate-to-html/page.tsx @@ -334,6 +334,23 @@ export default async function SlateToHtmlBlock() { theme, }); + // const html2Slate = async (html: string) => { + // const { JSDOM } = await import('jsdom'); + // const dom = new JSDOM(html); + // const document = dom.window.document; + + // // 获取

元素 + // const pElement = document.querySelector('p'); + + // if (pElement) { + // console.log('🚀 ~ html2Slate ~ pElement:', pElement.textContent); // 获取

内容 + // } else { + // console.log('No

element found!'); + // } + // }; + + // await html2Slate('

some HTML

'); + return (
diff --git a/packages/code-block/src/lib/BaseCodeBlockPlugin.ts b/packages/code-block/src/lib/BaseCodeBlockPlugin.ts index 0edb8ef107..f2ea5717b5 100644 --- a/packages/code-block/src/lib/BaseCodeBlockPlugin.ts +++ b/packages/code-block/src/lib/BaseCodeBlockPlugin.ts @@ -10,7 +10,7 @@ import type { Prism } from './types'; import { withCodeBlock } from '../lib/withCodeBlock'; import { decorateCodeLine } from './decorateCodeLine'; -import { htmlDeserializerCodeBlock } from './htmlDeserializerCodeBlock'; +import { htmlDeserializerCodeBlock } from './deserializer/htmlDeserializerCodeBlock'; export type CodeBlockConfig = PluginConfig< 'code_block', diff --git a/packages/code-block/src/lib/htmlDeserializerCodeBlock.ts b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts similarity index 70% rename from packages/code-block/src/lib/htmlDeserializerCodeBlock.ts rename to packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts index 1877591503..73531bf117 100644 --- a/packages/code-block/src/lib/htmlDeserializerCodeBlock.ts +++ b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts @@ -1,9 +1,22 @@ import type { HtmlDeserializer } from '@udecode/plate-common'; -import { BaseCodeBlockPlugin, BaseCodeLinePlugin } from './BaseCodeBlockPlugin'; +import { + BaseCodeBlockPlugin, + BaseCodeLinePlugin, +} from '../BaseCodeBlockPlugin'; +import { + htmlDeserializerCodeBlockStatic, + rulesStaticCodeBlock, +} from './htmlDeserializerCodeBlockStatic'; export const htmlDeserializerCodeBlock: HtmlDeserializer = { parse: ({ element }) => { + const staticCodeBlock = htmlDeserializerCodeBlockStatic(element); + + if (staticCodeBlock) { + return staticCodeBlock; + } + const languageSelectorText = [...element.childNodes].find( (node: ChildNode) => node.nodeName === 'SELECT' @@ -38,5 +51,6 @@ export const htmlDeserializerCodeBlock: HtmlDeserializer = { fontFamily: 'Consolas', }, }, + ...(rulesStaticCodeBlock as any), ], }; diff --git a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts new file mode 100644 index 0000000000..d6ab055ea5 --- /dev/null +++ b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts @@ -0,0 +1,46 @@ +import { + type HtmlDeserializer, + getSlateElements, + isPluginStatic, +} from '@udecode/plate-common'; + +import { + BaseCodeBlockPlugin, + BaseCodeLinePlugin, +} from '../BaseCodeBlockPlugin'; + +export const rulesStaticCodeBlock: HtmlDeserializer['rules'] = [ + { + validClassName: 'slate-code_block', + validNodeName: 'DIV', + }, +]; + +export const htmlDeserializerCodeBlockStatic = (element: HTMLElement) => { + if (isPluginStatic(element, BaseCodeBlockPlugin.key)) { + const languageClass = Array.from(element.classList).find((className) => + className.startsWith('language-') + ); + + const lang = languageClass?.replace('language-', ''); + + const staticCodeLines = getSlateElements(element).filter((el) => + isPluginStatic(el, BaseCodeLinePlugin.key) + ); + + if (staticCodeLines) { + const codeLines = staticCodeLines.map((line) => { + return { + children: [{ text: line.textContent }], + type: BaseCodeLinePlugin.key, + }; + }); + + return { + children: codeLines, + lang, + type: BaseCodeBlockPlugin.key, + }; + } + } +}; diff --git a/packages/code-block/src/lib/deserializer/index.ts b/packages/code-block/src/lib/deserializer/index.ts new file mode 100644 index 0000000000..7b8d56f8f0 --- /dev/null +++ b/packages/code-block/src/lib/deserializer/index.ts @@ -0,0 +1,6 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './htmlDeserializerCodeBlock'; +export * from './htmlDeserializerCodeBlockStatic'; diff --git a/packages/code-block/src/lib/index.ts b/packages/code-block/src/lib/index.ts index 780ccdebb9..4b898bf7df 100644 --- a/packages/code-block/src/lib/index.ts +++ b/packages/code-block/src/lib/index.ts @@ -4,11 +4,11 @@ export * from './BaseCodeBlockPlugin'; export * from './decorateCodeLine'; -export * from './htmlDeserializerCodeBlock'; export * from './insertDataCodeBlock'; export * from './insertFragmentCodeBlock'; export * from './types'; export * from './withCodeBlock'; +export * from './deserializer/index'; export * from './normalizers/index'; export * from './queries/index'; export * from './transforms/index'; diff --git a/packages/core/src/lib/static/deserialize/checkUtils.ts b/packages/core/src/lib/static/deserialize/checkUtils.ts new file mode 100644 index 0000000000..be1b67605e --- /dev/null +++ b/packages/core/src/lib/static/deserialize/checkUtils.ts @@ -0,0 +1,39 @@ +export const isElementStatic = (element: HTMLElement) => { + return ( + 'dataset' in element && + Object.hasOwn(element.dataset, 'slateNode') && + element.dataset.slateNode === 'element' + ); +}; + +export const isTextStatic = (element: HTMLElement) => { + return ( + 'dataset' in element && + Object.hasOwn(element.dataset, 'slateNode') && + element.dataset.slateNode === 'text' + ); +}; + +export const isLeafStatic = (element: HTMLElement) => { + return ( + 'dataset' in element && + Object.hasOwn(element.dataset, 'slateLeaf') && + element.dataset.slateLeaf === 'true' + ); +}; + +export const isStringStatic = (element: HTMLElement) => { + return ( + 'dataset' in element && + Object.hasOwn(element.dataset, 'slateString') && + element.dataset.slateString === 'true' + ); +}; + +export const isPluginStatic = (element: HTMLElement, key: string) => { + return element.classList.contains(`slate-${key}`); +}; + +export const getSlateElements = (element: HTMLElement): HTMLElement[] => { + return Array.from(element.querySelectorAll('[data-slate-node="element"]')); +}; diff --git a/packages/core/src/lib/static/deserialize/index.ts b/packages/core/src/lib/static/deserialize/index.ts new file mode 100644 index 0000000000..0c0363aa6b --- /dev/null +++ b/packages/core/src/lib/static/deserialize/index.ts @@ -0,0 +1,5 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './checkUtils'; diff --git a/packages/core/src/lib/static/index.ts b/packages/core/src/lib/static/index.ts index 2e0c6e3f16..8ed19d8a2a 100644 --- a/packages/core/src/lib/static/index.ts +++ b/packages/core/src/lib/static/index.ts @@ -8,4 +8,5 @@ export * from './pluginRenderLeafStatic'; export * from './serializeHtml'; export * from './types'; export * from './components/index'; +export * from './deserialize/index'; export * from './utils/index'; From 527e3d584d6e7bca3b9e2bff6f39f9b3d79cdf16 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Mon, 6 Jan 2025 22:56:33 +0800 Subject: [PATCH 03/25] paste p --- .../src/lib/deserializer/htmlDeserializerCodeBlock.ts | 4 ++-- .../src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts | 2 +- .../core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts index 73531bf117..28e22c8e14 100644 --- a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts +++ b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts @@ -6,7 +6,7 @@ import { } from '../BaseCodeBlockPlugin'; import { htmlDeserializerCodeBlockStatic, - rulesStaticCodeBlock, + staticRules, } from './htmlDeserializerCodeBlockStatic'; export const htmlDeserializerCodeBlock: HtmlDeserializer = { @@ -51,6 +51,6 @@ export const htmlDeserializerCodeBlock: HtmlDeserializer = { fontFamily: 'Consolas', }, }, - ...(rulesStaticCodeBlock as any), + ...(staticRules as any), ], }; diff --git a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts index d6ab055ea5..582b26079f 100644 --- a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts +++ b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts @@ -9,7 +9,7 @@ import { BaseCodeLinePlugin, } from '../BaseCodeBlockPlugin'; -export const rulesStaticCodeBlock: HtmlDeserializer['rules'] = [ +export const staticRules: HtmlDeserializer['rules'] = [ { validClassName: 'slate-code_block', validNodeName: 'DIV', diff --git a/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts b/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts index d62fc5b929..22a0a3565d 100644 --- a/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts +++ b/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts @@ -13,6 +13,10 @@ export const BaseParagraphPlugin = createSlatePlugin({ { validNodeName: 'P', }, + { + validClassName: 'slate-p', + validNodeName: 'DIV', + }, ], }, }, From d61bdcbc416cd4a0c535a8a87970991d8cbc3f5c Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Wed, 8 Jan 2025 19:28:03 +0800 Subject: [PATCH 04/25] toc & file --- packages/heading/src/lib/BaseTocPlugin.ts | 12 +++++++++++ packages/media/src/lib/BaseFilePlugin.ts | 25 ++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/heading/src/lib/BaseTocPlugin.ts b/packages/heading/src/lib/BaseTocPlugin.ts index 84d1fcda93..738766273e 100644 --- a/packages/heading/src/lib/BaseTocPlugin.ts +++ b/packages/heading/src/lib/BaseTocPlugin.ts @@ -22,4 +22,16 @@ export const BaseTocPlugin = createTSlatePlugin({ isScroll: true, topOffset: 80, }, + parsers: { + html: { + deserializer: { + rules: [ + { + validClassName: 'slate-toc', + validNodeName: 'DIV', + }, + ], + }, + }, + }, }); diff --git a/packages/media/src/lib/BaseFilePlugin.ts b/packages/media/src/lib/BaseFilePlugin.ts index 9872257c0c..689d9dcf67 100644 --- a/packages/media/src/lib/BaseFilePlugin.ts +++ b/packages/media/src/lib/BaseFilePlugin.ts @@ -1,4 +1,4 @@ -import { createSlatePlugin } from '@udecode/plate-common'; +import { createSlatePlugin, isPluginStatic } from '@udecode/plate-common'; import type { TMediaElement } from './media'; @@ -7,4 +7,27 @@ export interface TFileElement extends TMediaElement {} export const BaseFilePlugin = createSlatePlugin({ key: 'file', node: { isElement: true, isVoid: true }, + parsers: { + html: { + deserializer: { + parse: ({ element }) => { + if (!isPluginStatic(element, BaseFilePlugin.key)) return; + + const a = element.querySelector('a')!; + + return { + name: a.getAttribute('download'), + type: 'file', + url: a.getAttribute('href'), + }; + }, + rules: [ + { + validClassName: 'slate-file', + validNodeName: 'DIV', + }, + ], + }, + }, + }, }); From 4fd248097eb0de6fc14e6e69479c09dd4ef459c9 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Wed, 8 Jan 2025 20:13:01 +0800 Subject: [PATCH 05/25] wip --- apps/www/src/app/(app)/dev/client.tsx | 297 +++++++++++++++++- .../deserialize/htmlStringToEditorDOM.ts | 13 + .../core/src/lib/static/deserialize/index.ts | 1 + 3 files changed, 305 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/lib/static/deserialize/htmlStringToEditorDOM.ts diff --git a/apps/www/src/app/(app)/dev/client.tsx b/apps/www/src/app/(app)/dev/client.tsx index 7fba1296eb..b723c48289 100644 --- a/apps/www/src/app/(app)/dev/client.tsx +++ b/apps/www/src/app/(app)/dev/client.tsx @@ -1,30 +1,315 @@ 'use client'; +import { withProps } from '@udecode/cn'; +import { BaseAlignPlugin } from '@udecode/plate-alignment'; +import { + BaseBoldPlugin, + BaseCodePlugin, + BaseItalicPlugin, + BaseStrikethroughPlugin, + BaseSubscriptPlugin, + BaseSuperscriptPlugin, + BaseUnderlinePlugin, +} from '@udecode/plate-basic-marks'; +import { BaseBlockquotePlugin } from '@udecode/plate-block-quote'; +import { + BaseCodeBlockPlugin, + BaseCodeLinePlugin, + BaseCodeSyntaxPlugin, +} from '@udecode/plate-code-block'; +import { BaseCommentsPlugin } from '@udecode/plate-comments'; +import { + BaseParagraphPlugin, + SlateLeaf, + createSlateEditor, + getEditorDOMFromHtmlString, + insertNodes, + serializeHtml, +} from '@udecode/plate-common'; import { Plate } from '@udecode/plate-core/react'; +import { BaseDatePlugin } from '@udecode/plate-date'; +import { + BaseFontBackgroundColorPlugin, + BaseFontColorPlugin, + BaseFontSizePlugin, +} from '@udecode/plate-font'; +import { + BaseHeadingPlugin, + BaseTocPlugin, + HEADING_KEYS, + HEADING_LEVELS, +} from '@udecode/plate-heading'; +import { BaseHighlightPlugin } from '@udecode/plate-highlight'; +import { BaseHorizontalRulePlugin } from '@udecode/plate-horizontal-rule'; +import { BaseIndentPlugin } from '@udecode/plate-indent'; +import { BaseIndentListPlugin } from '@udecode/plate-indent-list'; +import { BaseKbdPlugin } from '@udecode/plate-kbd'; +import { BaseColumnItemPlugin, BaseColumnPlugin } from '@udecode/plate-layout'; +import { BaseLineHeightPlugin } from '@udecode/plate-line-height'; +import { BaseLinkPlugin } from '@udecode/plate-link'; +import { + BaseEquationPlugin, + BaseInlineEquationPlugin, +} from '@udecode/plate-math'; +import { + BaseAudioPlugin, + BaseFilePlugin, + BaseImagePlugin, + BaseMediaEmbedPlugin, + BaseVideoPlugin, +} from '@udecode/plate-media'; +import { BaseMentionPlugin } from '@udecode/plate-mention'; +import { + BaseTableCellHeaderPlugin, + BaseTableCellPlugin, + BaseTablePlugin, + BaseTableRowPlugin, +} from '@udecode/plate-table'; +import { BaseTogglePlugin } from '@udecode/plate-toggle'; +import Prism from 'prismjs'; import { useCreateEditor } from '@/registry/default/components/editor/use-create-editor'; +import { basicNodesValue } from '@/registry/default/example/values/basic-nodes-value'; import { linkValue } from '@/registry/default/example/values/link-value'; +import { BlockquoteElementStatic } from '@/registry/default/plate-ui/blockquote-element-static'; import { Button } from '@/registry/default/plate-ui/button'; +import { CodeBlockElementStatic } from '@/registry/default/plate-ui/code-block-element-static'; +import { CodeLeafStatic } from '@/registry/default/plate-ui/code-leaf-static'; +import { CodeLineElementStatic } from '@/registry/default/plate-ui/code-line-element-static'; +import { CodeSyntaxLeafStatic } from '@/registry/default/plate-ui/code-syntax-leaf-static'; +import { ColumnElementStatic } from '@/registry/default/plate-ui/column-element-static'; +import { ColumnGroupElementStatic } from '@/registry/default/plate-ui/column-group-element-static'; +import { CommentLeafStatic } from '@/registry/default/plate-ui/comment-leaf-static'; +import { DateElementStatic } from '@/registry/default/plate-ui/date-element-static'; import { Editor, EditorContainer } from '@/registry/default/plate-ui/editor'; +import { EditorStatic } from '@/registry/default/plate-ui/editor-static'; +import { EquationElementStatic } from '@/registry/default/plate-ui/equation-element-static'; +import { HeadingElementStatic } from '@/registry/default/plate-ui/heading-element-static'; +import { HighlightLeafStatic } from '@/registry/default/plate-ui/highlight-leaf-static'; +import { HrElementStatic } from '@/registry/default/plate-ui/hr-element-static'; +import { ImageElementStatic } from '@/registry/default/plate-ui/image-element-static'; +import { + FireLiComponent, + FireMarker, +} from '@/registry/default/plate-ui/indent-fire-marker'; +import { + TodoLiStatic, + TodoMarkerStatic, +} from '@/registry/default/plate-ui/indent-todo-marker-static'; +import { InlineEquationElementStatic } from '@/registry/default/plate-ui/inline-equation-element-static'; +import { KbdLeafStatic } from '@/registry/default/plate-ui/kbd-leaf-static'; +import { LinkElementStatic } from '@/registry/default/plate-ui/link-element-static'; +import { MediaAudioElementStatic } from '@/registry/default/plate-ui/media-audio-element-static'; +import { MediaFileElementStatic } from '@/registry/default/plate-ui/media-file-element-static'; +import { MediaVideoElementStatic } from '@/registry/default/plate-ui/media-video-element-static'; +import { MentionElementStatic } from '@/registry/default/plate-ui/mention-element-static'; +import { ParagraphElementStatic } from '@/registry/default/plate-ui/paragraph-element-static'; +import { + TableCellElementStatic, + TableCellHeaderStaticElement, +} from '@/registry/default/plate-ui/table-cell-element-static'; +import { TableElementStatic } from '@/registry/default/plate-ui/table-element-static'; +import { TableRowElementStatic } from '@/registry/default/plate-ui/table-row-element-static'; +import { TocElementStatic } from '@/registry/default/plate-ui/toc-element-static'; +import { ToggleElementStatic } from '@/registry/default/plate-ui/toggle-element-static'; + +const siteUrl = 'https://platejs.org'; export function ClientComponent() { // console.log(linkValue, 'fj'); const editor = useCreateEditor({ - value: linkValue, + value: [...linkValue, ...basicNodesValue], }); + const exportToHtml = async () => { + const components = { + [BaseAudioPlugin.key]: MediaAudioElementStatic, + [BaseBlockquotePlugin.key]: BlockquoteElementStatic, + [BaseBoldPlugin.key]: withProps(SlateLeaf, { as: 'strong' }), + [BaseCodeBlockPlugin.key]: CodeBlockElementStatic, + [BaseCodeLinePlugin.key]: CodeLineElementStatic, + [BaseCodePlugin.key]: CodeLeafStatic, + [BaseCodeSyntaxPlugin.key]: CodeSyntaxLeafStatic, + [BaseColumnItemPlugin.key]: ColumnElementStatic, + [BaseColumnPlugin.key]: ColumnGroupElementStatic, + [BaseCommentsPlugin.key]: CommentLeafStatic, + [BaseDatePlugin.key]: DateElementStatic, + [BaseEquationPlugin.key]: EquationElementStatic, + [BaseFilePlugin.key]: MediaFileElementStatic, + [BaseHighlightPlugin.key]: HighlightLeafStatic, + [BaseHorizontalRulePlugin.key]: HrElementStatic, + [BaseImagePlugin.key]: ImageElementStatic, + [BaseInlineEquationPlugin.key]: InlineEquationElementStatic, + [BaseItalicPlugin.key]: withProps(SlateLeaf, { as: 'em' }), + [BaseKbdPlugin.key]: KbdLeafStatic, + [BaseLinkPlugin.key]: LinkElementStatic, + // [BaseMediaEmbedPlugin.key]: MediaEmbedElementStatic, + [BaseMentionPlugin.key]: MentionElementStatic, + [BaseParagraphPlugin.key]: ParagraphElementStatic, + [BaseStrikethroughPlugin.key]: withProps(SlateLeaf, { as: 'del' }), + [BaseSubscriptPlugin.key]: withProps(SlateLeaf, { as: 'sub' }), + [BaseSuperscriptPlugin.key]: withProps(SlateLeaf, { as: 'sup' }), + [BaseTableCellHeaderPlugin.key]: TableCellHeaderStaticElement, + [BaseTableCellPlugin.key]: TableCellElementStatic, + [BaseTablePlugin.key]: TableElementStatic, + [BaseTableRowPlugin.key]: TableRowElementStatic, + [BaseTocPlugin.key]: TocElementStatic, + [BaseTogglePlugin.key]: ToggleElementStatic, + [BaseUnderlinePlugin.key]: withProps(SlateLeaf, { as: 'u' }), + [BaseVideoPlugin.key]: MediaVideoElementStatic, + [HEADING_KEYS.h1]: withProps(HeadingElementStatic, { variant: 'h1' }), + [HEADING_KEYS.h2]: withProps(HeadingElementStatic, { variant: 'h2' }), + [HEADING_KEYS.h3]: withProps(HeadingElementStatic, { variant: 'h3' }), + [HEADING_KEYS.h4]: withProps(HeadingElementStatic, { variant: 'h4' }), + [HEADING_KEYS.h5]: withProps(HeadingElementStatic, { variant: 'h5' }), + [HEADING_KEYS.h6]: withProps(HeadingElementStatic, { variant: 'h6' }), + }; + + const editorStatic = createSlateEditor({ + plugins: [ + BaseColumnPlugin, + BaseColumnItemPlugin, + BaseTocPlugin, + BaseVideoPlugin, + BaseAudioPlugin, + BaseParagraphPlugin, + BaseHeadingPlugin, + BaseMediaEmbedPlugin, + BaseBoldPlugin, + BaseCodePlugin, + BaseItalicPlugin, + BaseStrikethroughPlugin, + BaseSubscriptPlugin, + BaseSuperscriptPlugin, + BaseUnderlinePlugin, + BaseBlockquotePlugin, + BaseDatePlugin, + BaseEquationPlugin, + BaseInlineEquationPlugin, + BaseCodeBlockPlugin.configure({ + options: { + prism: Prism, + }, + }), + BaseIndentPlugin.extend({ + inject: { + targetPlugins: [ + BaseParagraphPlugin.key, + BaseBlockquotePlugin.key, + BaseCodeBlockPlugin.key, + ], + }, + }), + BaseIndentListPlugin.extend({ + inject: { + targetPlugins: [ + BaseParagraphPlugin.key, + ...HEADING_LEVELS, + BaseBlockquotePlugin.key, + BaseCodeBlockPlugin.key, + BaseTogglePlugin.key, + ], + }, + options: { + listStyleTypes: { + fire: { + liComponent: FireLiComponent, + markerComponent: FireMarker, + type: 'fire', + }, + todo: { + liComponent: TodoLiStatic, + markerComponent: TodoMarkerStatic, + type: 'todo', + }, + }, + }, + }), + BaseLinkPlugin, + BaseTableRowPlugin, + BaseTablePlugin, + BaseTableCellPlugin, + BaseHorizontalRulePlugin, + BaseFontColorPlugin, + BaseFontBackgroundColorPlugin, + BaseFontSizePlugin, + BaseKbdPlugin, + BaseAlignPlugin.extend({ + inject: { + targetPlugins: [ + BaseParagraphPlugin.key, + BaseMediaEmbedPlugin.key, + ...HEADING_LEVELS, + BaseImagePlugin.key, + ], + }, + }), + BaseLineHeightPlugin, + BaseHighlightPlugin, + BaseFilePlugin, + BaseImagePlugin, + BaseMentionPlugin, + BaseCommentsPlugin, + BaseTogglePlugin, + ], + value: editor.children, + }); + + const editorHtml = await serializeHtml(editorStatic, { + components, + editorComponent: EditorStatic, + props: { style: { padding: '0 calc(50% - 350px)', paddingBottom: '' } }, + }); + + const prismCss = ``; + const tailwindCss = ``; + const katexCss = ``; + + const html = ` + + + + + + + + + ${tailwindCss} + ${prismCss} + ${katexCss} + + + + ${editorHtml} + + `; + + return html; + }; + + const handleFileSelect = async () => { + const html = await exportToHtml(); + + const editorNode = getEditorDOMFromHtmlString(html); - const handleFileSelect = () => { const r = editor.api.html.deserialize({ - element: `

fj
fj

-

fj

`, + element: editorNode, }); - console.log(r, 'result'); + + insertNodes(editor, r); }; return (
- + diff --git a/packages/core/src/lib/static/deserialize/htmlStringToEditorDOM.ts b/packages/core/src/lib/static/deserialize/htmlStringToEditorDOM.ts new file mode 100644 index 0000000000..a26a590b6e --- /dev/null +++ b/packages/core/src/lib/static/deserialize/htmlStringToEditorDOM.ts @@ -0,0 +1,13 @@ +/** + * Convert HTML string exported from Plate into HTML element. + * + * @param html - The HTML string to convert exported from Plate. + * @returns The Editor element without head and body. + */ +export const getEditorDOMFromHtmlString = (html: string) => { + const node = document.createElement('body'); + node.innerHTML = html; + const editorNode = node.querySelector('[data-slate-editor="true"]'); + + return editorNode as HTMLElement; +}; diff --git a/packages/core/src/lib/static/deserialize/index.ts b/packages/core/src/lib/static/deserialize/index.ts index 0c0363aa6b..2146572559 100644 --- a/packages/core/src/lib/static/deserialize/index.ts +++ b/packages/core/src/lib/static/deserialize/index.ts @@ -3,3 +3,4 @@ */ export * from './checkUtils'; +export * from './htmlStringToEditorDOM'; \ No newline at end of file From 9c1a17b3ed5220114c79092beebc32d44a9adfb4 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Wed, 8 Jan 2025 20:14:17 +0800 Subject: [PATCH 06/25] fix --- .../default/block/slate-to-html/page.tsx | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/apps/www/src/registry/default/block/slate-to-html/page.tsx b/apps/www/src/registry/default/block/slate-to-html/page.tsx index f99646e84d..8d653bc549 100644 --- a/apps/www/src/registry/default/block/slate-to-html/page.tsx +++ b/apps/www/src/registry/default/block/slate-to-html/page.tsx @@ -334,23 +334,6 @@ export default async function SlateToHtmlBlock() { theme, }); - // const html2Slate = async (html: string) => { - // const { JSDOM } = await import('jsdom'); - // const dom = new JSDOM(html); - // const document = dom.window.document; - - // // 获取

元素 - // const pElement = document.querySelector('p'); - - // if (pElement) { - // console.log('🚀 ~ html2Slate ~ pElement:', pElement.textContent); // 获取

内容 - // } else { - // console.log('No

element found!'); - // } - // }; - - // await html2Slate('

some HTML

'); - return (
From def42c5dfb7a40b5a2a991f3dded2cf1a001dad1 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Thu, 9 Jan 2025 20:02:50 +0800 Subject: [PATCH 07/25] indent list --- apps/www/src/app/(app)/dev/client.tsx | 16 ++++++-- .../default/example/values/link-value.tsx | 5 ++- .../default/plate-ui/indent-fire-marker.tsx | 9 ++++- .../plate-ui/indent-todo-marker-static.tsx | 10 ++++- .../default/plate-ui/indent-todo-marker.tsx | 6 ++- .../deserializer/htmlDeserializerCodeBlock.ts | 6 +-- .../htmlDeserializerCodeBlockStatic.ts | 22 ++++------- .../html/utils/htmlTextNodeToString.ts | 2 + .../html/utils/pluginDeserializeHtml.ts | 38 ++++++++++++++++++- .../plugins/paragraph/BaseParagraphPlugin.ts | 4 -- .../lib/static/components/SlateElement.tsx | 5 +++ packages/docx/src/lib/DocxPlugin.ts | 23 +++++++++++ packages/heading/src/lib/BaseTocPlugin.ts | 12 ------ .../src/lib/BaseIndentListPlugin.ts | 20 +++++++--- .../src/lib/renderIndentListBelowNodes.tsx | 7 +++- packages/media/src/lib/BaseFilePlugin.ts | 6 --- 16 files changed, 130 insertions(+), 61 deletions(-) diff --git a/apps/www/src/app/(app)/dev/client.tsx b/apps/www/src/app/(app)/dev/client.tsx index b723c48289..c3a8358e0f 100644 --- a/apps/www/src/app/(app)/dev/client.tsx +++ b/apps/www/src/app/(app)/dev/client.tsx @@ -66,11 +66,14 @@ import { BaseTableRowPlugin, } from '@udecode/plate-table'; import { BaseTogglePlugin } from '@udecode/plate-toggle'; +import { isEqual } from 'lodash'; import Prism from 'prismjs'; import { useCreateEditor } from '@/registry/default/components/editor/use-create-editor'; import { basicNodesValue } from '@/registry/default/example/values/basic-nodes-value'; +import { indentListValue } from '@/registry/default/example/values/indent-list-value'; import { linkValue } from '@/registry/default/example/values/link-value'; +import { tableValue } from '@/registry/default/example/values/table-value'; import { BlockquoteElementStatic } from '@/registry/default/plate-ui/blockquote-element-static'; import { Button } from '@/registry/default/plate-ui/button'; import { CodeBlockElementStatic } from '@/registry/default/plate-ui/code-block-element-static'; @@ -114,12 +117,13 @@ import { TocElementStatic } from '@/registry/default/plate-ui/toc-element-static import { ToggleElementStatic } from '@/registry/default/plate-ui/toggle-element-static'; const siteUrl = 'https://platejs.org'; +const createValue = () => { + return [...basicNodesValue, ...indentListValue, ...linkValue, ...tableValue]; +}; export function ClientComponent() { - // console.log(linkValue, 'fj'); - const editor = useCreateEditor({ - value: [...linkValue, ...basicNodesValue], + value: createValue(), }); const exportToHtml = async () => { const components = { @@ -295,6 +299,8 @@ export function ClientComponent() { return html; }; + console.log(createValue(), 'A'); + const handleFileSelect = async () => { const html = await exportToHtml(); @@ -304,6 +310,10 @@ export function ClientComponent() { element: editorNode, }); + console.log(r, 'B'); + + console.log(isEqual(r, createValue()), 'fj'); + insertNodes(editor, r); }; diff --git a/apps/www/src/registry/default/example/values/link-value.tsx b/apps/www/src/registry/default/example/values/link-value.tsx index e9404d3fda..13b6772aca 100644 --- a/apps/www/src/registry/default/example/values/link-value.tsx +++ b/apps/www/src/registry/default/example/values/link-value.tsx @@ -8,7 +8,10 @@ export const linkValue: any = ( Link - Add hyperlinks{' '} + Add{' '} + + hyperlinks + {' '} within your text to reference external sources or provide additional information using the Link plugin. diff --git a/apps/www/src/registry/default/plate-ui/indent-fire-marker.tsx b/apps/www/src/registry/default/plate-ui/indent-fire-marker.tsx index 8f834fcc63..cc775b9b45 100644 --- a/apps/www/src/registry/default/plate-ui/indent-fire-marker.tsx +++ b/apps/www/src/registry/default/plate-ui/indent-fire-marker.tsx @@ -10,7 +10,12 @@ export const FireMarker = ( return (
- + {(element as TIndentElement).indent % 2 === 0 ? '🔥' : '🚀'}
@@ -20,5 +25,5 @@ export const FireMarker = ( export const FireLiComponent = (props: SlateRenderElementProps) => { const { children } = props; - return {children}; + return
  • {children}
  • ; }; diff --git a/apps/www/src/registry/default/plate-ui/indent-todo-marker-static.tsx b/apps/www/src/registry/default/plate-ui/indent-todo-marker-static.tsx index 4bc0071ed7..ae8857924d 100644 --- a/apps/www/src/registry/default/plate-ui/indent-todo-marker-static.tsx +++ b/apps/www/src/registry/default/plate-ui/indent-todo-marker-static.tsx @@ -24,12 +24,18 @@ export const TodoLiStatic = ({ element, }: SlateRenderElementProps) => { return ( - {children} - + ); }; diff --git a/apps/www/src/registry/default/plate-ui/indent-todo-marker.tsx b/apps/www/src/registry/default/plate-ui/indent-todo-marker.tsx index 48643b21aa..9363cadcd2 100644 --- a/apps/www/src/registry/default/plate-ui/indent-todo-marker.tsx +++ b/apps/www/src/registry/default/plate-ui/indent-todo-marker.tsx @@ -35,12 +35,14 @@ export const TodoLi = (props: SlateRenderElementProps) => { const { children, element } = props; return ( - {children} - + ); }; diff --git a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts index 28e22c8e14..cab197d146 100644 --- a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts +++ b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.ts @@ -4,10 +4,7 @@ import { BaseCodeBlockPlugin, BaseCodeLinePlugin, } from '../BaseCodeBlockPlugin'; -import { - htmlDeserializerCodeBlockStatic, - staticRules, -} from './htmlDeserializerCodeBlockStatic'; +import { htmlDeserializerCodeBlockStatic } from './htmlDeserializerCodeBlockStatic'; export const htmlDeserializerCodeBlock: HtmlDeserializer = { parse: ({ element }) => { @@ -51,6 +48,5 @@ export const htmlDeserializerCodeBlock: HtmlDeserializer = { fontFamily: 'Consolas', }, }, - ...(staticRules as any), ], }; diff --git a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts index 582b26079f..c2517c2fd3 100644 --- a/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts +++ b/packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlockStatic.ts @@ -1,21 +1,10 @@ -import { - type HtmlDeserializer, - getSlateElements, - isPluginStatic, -} from '@udecode/plate-common'; +import { getSlateElements, isPluginStatic } from '@udecode/plate-common'; import { BaseCodeBlockPlugin, BaseCodeLinePlugin, } from '../BaseCodeBlockPlugin'; -export const staticRules: HtmlDeserializer['rules'] = [ - { - validClassName: 'slate-code_block', - validNodeName: 'DIV', - }, -]; - export const htmlDeserializerCodeBlockStatic = (element: HTMLElement) => { if (isPluginStatic(element, BaseCodeBlockPlugin.key)) { const languageClass = Array.from(element.classList).find((className) => @@ -31,15 +20,18 @@ export const htmlDeserializerCodeBlockStatic = (element: HTMLElement) => { if (staticCodeLines) { const codeLines = staticCodeLines.map((line) => { return { - children: [{ text: line.textContent }], type: BaseCodeLinePlugin.key, + // eslint-disable-next-line perfectionist/sort-objects + children: [{ text: line.textContent }], }; }); return { - children: codeLines, - lang, type: BaseCodeBlockPlugin.key, + // eslint-disable-next-line perfectionist/sort-objects + lang, + // eslint-disable-next-line perfectionist/sort-objects + children: codeLines, }; } } diff --git a/packages/core/src/lib/plugins/html/utils/htmlTextNodeToString.ts b/packages/core/src/lib/plugins/html/utils/htmlTextNodeToString.ts index 0b0cb9b619..3d17e006d7 100644 --- a/packages/core/src/lib/plugins/html/utils/htmlTextNodeToString.ts +++ b/packages/core/src/lib/plugins/html/utils/htmlTextNodeToString.ts @@ -3,6 +3,8 @@ import { isHtmlText } from './isHtmlText'; export const htmlTextNodeToString = (node: ChildNode | HTMLElement) => { if (isHtmlText(node)) { + if (node.parentElement?.dataset.platePreventDeserialization) return ''; + return node.textContent || ''; } }; diff --git a/packages/core/src/lib/plugins/html/utils/pluginDeserializeHtml.ts b/packages/core/src/lib/plugins/html/utils/pluginDeserializeHtml.ts index 92a4735ea0..9f017b7647 100644 --- a/packages/core/src/lib/plugins/html/utils/pluginDeserializeHtml.ts +++ b/packages/core/src/lib/plugins/html/utils/pluginDeserializeHtml.ts @@ -11,6 +11,41 @@ import type { Nullable } from '../../../types'; import { getEditorPlugin } from '../../../plugin'; import { getInjectedPlugins } from '../../../utils/getInjectedPlugins'; +/** + * Get a deserializer and add default rules for deserializing plate static + * elements + */ +const getDeserializedWithStaticRules = (plugin: AnyEditorPlugin) => { + const isElement = plugin.node.isElement; + + let deserializer = plugin.parsers?.html?.deserializer; + + if (!isElement) return deserializer; + + const rules = deserializer?.rules ?? []; + + // Check if rules already contain slate-xxx className + const hasSlateRule = rules.some((rule) => + rule.validClassName?.includes(`slate-${plugin.key}`) + ); + + const staticRules = hasSlateRule + ? rules + : [ + { + validClassName: `slate-${plugin.key}`, + validNodeName: 'DIV', + }, + ...rules, + ]; + + if (!deserializer) deserializer = { rules: staticRules }; + + deserializer.rules = staticRules; + + return deserializer; +}; + /** Get a deserializer by type, node names, class names and styles. */ export const pluginDeserializeHtml = ( editor: SlateEditor, @@ -22,10 +57,9 @@ export const pluginDeserializeHtml = ( ): (Nullable & { node: AnyObject }) | undefined => { const { node: { isElement: isElementRoot, isLeaf: isLeafRoot, type }, - parsers, } = plugin; - const deserializer = parsers?.html?.deserializer; + const deserializer = getDeserializedWithStaticRules(plugin); if (!deserializer) return; diff --git a/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts b/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts index 22a0a3565d..d62fc5b929 100644 --- a/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts +++ b/packages/core/src/lib/plugins/paragraph/BaseParagraphPlugin.ts @@ -13,10 +13,6 @@ export const BaseParagraphPlugin = createSlatePlugin({ { validNodeName: 'P', }, - { - validClassName: 'slate-p', - validNodeName: 'DIV', - }, ], }, }, diff --git a/packages/core/src/lib/static/components/SlateElement.tsx b/packages/core/src/lib/static/components/SlateElement.tsx index 6f31e9e2f9..58200aaf79 100644 --- a/packages/core/src/lib/static/components/SlateElement.tsx +++ b/packages/core/src/lib/static/components/SlateElement.tsx @@ -29,7 +29,12 @@ export const SlateElement = (props: SlateElementProps) => { ...nodeProps, ...elementToAttributes?.(element), className: clsx(props.className, nodeProps?.className), + // deserialize 'data-block-id': block ? element.id : undefined, + 'data-slate-checked': element.checked, + 'data-slate-indent': element.indent, + 'data-slate-list-start': element.listStart, + 'data-slate-list-style-type': element.listStyleType, style: { position: 'relative', ...props.style, diff --git a/packages/docx/src/lib/DocxPlugin.ts b/packages/docx/src/lib/DocxPlugin.ts index 0acac117c0..5cb6224dd5 100644 --- a/packages/docx/src/lib/DocxPlugin.ts +++ b/packages/docx/src/lib/DocxPlugin.ts @@ -16,11 +16,34 @@ import { getTextListStyleType } from './docx-cleaner/utils/getTextListStyleType' import { isDocxContent } from './docx-cleaner/utils/isDocxContent'; import { isDocxList } from './docx-cleaner/utils/isDocxList'; +const isIndentListStatic = (element: HTMLElement) => { + return !!element.dataset.slateListStyleType; +}; + const getParse = (type: string): HtmlDeserializer['parse'] => ({ element }) => { const node: any = { type }; + if (isIndentListStatic(element)) { + const { slateChecked, slateIndent, slateListStart, slateListStyleType } = + element.dataset; + + if (slateChecked !== undefined) { + node.checked = slateChecked === 'true'; + } + if (slateIndent !== undefined) { + node.indent = Number(slateIndent); + } + if (slateListStart !== undefined) { + node.listStart = Number(slateListStart); + } + if (slateListStyleType !== undefined) { + node.listStyleType = slateListStyleType; + } + + return node; + } if (isDocxList(element)) { node.indent = getDocxListIndent(element); diff --git a/packages/heading/src/lib/BaseTocPlugin.ts b/packages/heading/src/lib/BaseTocPlugin.ts index 738766273e..84d1fcda93 100644 --- a/packages/heading/src/lib/BaseTocPlugin.ts +++ b/packages/heading/src/lib/BaseTocPlugin.ts @@ -22,16 +22,4 @@ export const BaseTocPlugin = createTSlatePlugin({ isScroll: true, topOffset: 80, }, - parsers: { - html: { - deserializer: { - rules: [ - { - validClassName: 'slate-toc', - validNodeName: 'DIV', - }, - ], - }, - }, - }, }); diff --git a/packages/indent-list/src/lib/BaseIndentListPlugin.ts b/packages/indent-list/src/lib/BaseIndentListPlugin.ts index 309c076fa2..3d4f8143f2 100644 --- a/packages/indent-list/src/lib/BaseIndentListPlugin.ts +++ b/packages/indent-list/src/lib/BaseIndentListPlugin.ts @@ -91,12 +91,20 @@ export const BaseIndentListPlugin = createTSlatePlugin({ html: { deserializer: { isElement: true, - parse: ({ editor, element, getOptions }) => ({ - // gdoc uses aria-level attribute - indent: Number(element.getAttribute('aria-level')), - listStyleType: getOptions().getListStyleType?.(element), - type: editor.getType(BaseParagraphPlugin), - }), + parse: ({ editor, element, getOptions }) => { + const parent = element.parentElement; + + const isPlateStatic = parent?.dataset.slateIndentList === 'true'; + + if (isPlateStatic) return; + + return { + // gdoc uses aria-level attribute + indent: Number(element.getAttribute('aria-level')), + listStyleType: getOptions().getListStyleType?.(element), + type: editor.getType(BaseParagraphPlugin), + }; + }, rules: [ { validNodeName: 'LI', diff --git a/packages/indent-list/src/lib/renderIndentListBelowNodes.tsx b/packages/indent-list/src/lib/renderIndentListBelowNodes.tsx index ccc8880f76..4651d10cb7 100644 --- a/packages/indent-list/src/lib/renderIndentListBelowNodes.tsx +++ b/packages/indent-list/src/lib/renderIndentListBelowNodes.tsx @@ -61,7 +61,12 @@ export const renderIndentListBelowNodes: NodeStaticWrapperComponent = ( listOptions; return ( - + {/* FIX: cursor position issue */} {Li ?
  • {children}
  • :
  • {children}
  • } diff --git a/packages/media/src/lib/BaseFilePlugin.ts b/packages/media/src/lib/BaseFilePlugin.ts index 689d9dcf67..5a9ef2f636 100644 --- a/packages/media/src/lib/BaseFilePlugin.ts +++ b/packages/media/src/lib/BaseFilePlugin.ts @@ -21,12 +21,6 @@ export const BaseFilePlugin = createSlatePlugin({ url: a.getAttribute('href'), }; }, - rules: [ - { - validClassName: 'slate-file', - validNodeName: 'DIV', - }, - ], }, }, }, From 21a51df890ca9d9507782f9aaed687a655466aba Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Thu, 9 Jan 2025 21:40:17 +0800 Subject: [PATCH 08/25] table --- apps/www/src/app/(app)/dev/client.tsx | 6 ++---- .../default/plate-ui/table-element-static.tsx | 16 ++++++++++++++-- packages/table/src/lib/BaseTablePlugin.ts | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/apps/www/src/app/(app)/dev/client.tsx b/apps/www/src/app/(app)/dev/client.tsx index c3a8358e0f..d4fd031743 100644 --- a/apps/www/src/app/(app)/dev/client.tsx +++ b/apps/www/src/app/(app)/dev/client.tsx @@ -71,8 +71,6 @@ import Prism from 'prismjs'; import { useCreateEditor } from '@/registry/default/components/editor/use-create-editor'; import { basicNodesValue } from '@/registry/default/example/values/basic-nodes-value'; -import { indentListValue } from '@/registry/default/example/values/indent-list-value'; -import { linkValue } from '@/registry/default/example/values/link-value'; import { tableValue } from '@/registry/default/example/values/table-value'; import { BlockquoteElementStatic } from '@/registry/default/plate-ui/blockquote-element-static'; import { Button } from '@/registry/default/plate-ui/button'; @@ -118,7 +116,7 @@ import { ToggleElementStatic } from '@/registry/default/plate-ui/toggle-element- const siteUrl = 'https://platejs.org'; const createValue = () => { - return [...basicNodesValue, ...indentListValue, ...linkValue, ...tableValue]; + return [...tableValue, ...basicNodesValue]; }; export function ClientComponent() { @@ -320,7 +318,7 @@ export function ClientComponent() { return (
    - + console.log(v, 'Update')} editor={editor}> diff --git a/apps/www/src/registry/default/plate-ui/table-element-static.tsx b/apps/www/src/registry/default/plate-ui/table-element-static.tsx index 42aa43f64f..097b658571 100644 --- a/apps/www/src/registry/default/plate-ui/table-element-static.tsx +++ b/apps/www/src/registry/default/plate-ui/table-element-static.tsx @@ -14,21 +14,33 @@ export const TableElementStatic = ({ const { colSizes } = props.element as TTableElement; return ( - + - + {colSizes?.map((width, index) => ( ))} + {children} diff --git a/packages/table/src/lib/BaseTablePlugin.ts b/packages/table/src/lib/BaseTablePlugin.ts index 4c8e8f10bb..bf7b7510c5 100644 --- a/packages/table/src/lib/BaseTablePlugin.ts +++ b/packages/table/src/lib/BaseTablePlugin.ts @@ -3,6 +3,7 @@ import { bindFirst, createSlatePlugin, createTSlatePlugin, + isPluginStatic, } from '@udecode/plate-common'; import type { TableApi, TableConfig } from './types'; @@ -84,6 +85,22 @@ export const BaseTablePlugin = createTSlatePlugin({ parsers: { html: { deserializer: { + parse: ({ element, type }) => { + if (isPluginStatic(element, type)) { + const colSizes = JSON.parse(element.dataset.colSizes as string); + + return { colSizes, marginLeft: 20, type }; + } + // prevent table static elements from being parsed multiple times + if ( + isPluginStatic(element.parentElement!, type) && + element.tagName === 'TABLE' + ) { + return; + } + + return { type }; + }, rules: [{ validNodeName: 'TABLE' }], }, }, From 03a29a3cb3db4413770039349fb374f122c809d9 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Thu, 9 Jan 2025 21:53:54 +0800 Subject: [PATCH 09/25] hr --- apps/www/src/app/(app)/dev/client.tsx | 12 +++++++++--- .../registry/default/plate-ui/hr-element-static.tsx | 7 ++++++- .../default/plate-ui/table-element-static.tsx | 1 + .../plugins/html/utils/pipeDeserializeHtmlElement.ts | 2 ++ packages/table/src/lib/BaseTablePlugin.ts | 12 ++++++------ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/apps/www/src/app/(app)/dev/client.tsx b/apps/www/src/app/(app)/dev/client.tsx index d4fd031743..c0b3eaad79 100644 --- a/apps/www/src/app/(app)/dev/client.tsx +++ b/apps/www/src/app/(app)/dev/client.tsx @@ -70,8 +70,7 @@ import { isEqual } from 'lodash'; import Prism from 'prismjs'; import { useCreateEditor } from '@/registry/default/components/editor/use-create-editor'; -import { basicNodesValue } from '@/registry/default/example/values/basic-nodes-value'; -import { tableValue } from '@/registry/default/example/values/table-value'; +import { mediaPlaceholderValue } from '@/registry/default/example/values/media-value'; import { BlockquoteElementStatic } from '@/registry/default/plate-ui/blockquote-element-static'; import { Button } from '@/registry/default/plate-ui/button'; import { CodeBlockElementStatic } from '@/registry/default/plate-ui/code-block-element-static'; @@ -116,7 +115,14 @@ import { ToggleElementStatic } from '@/registry/default/plate-ui/toggle-element- const siteUrl = 'https://platejs.org'; const createValue = () => { - return [...tableValue, ...basicNodesValue]; + return [ + // ...basicNodesValue, + // ...indentListValue, + // ...linkValue, + // ...tableValue, + // ...horizontalRuleValue, + ...mediaPlaceholderValue, + ]; }; export function ClientComponent() { diff --git a/apps/www/src/registry/default/plate-ui/hr-element-static.tsx b/apps/www/src/registry/default/plate-ui/hr-element-static.tsx index d3bc75c9dc..1fa6103b5f 100644 --- a/apps/www/src/registry/default/plate-ui/hr-element-static.tsx +++ b/apps/www/src/registry/default/plate-ui/hr-element-static.tsx @@ -13,8 +13,13 @@ export function HrElementStatic({ }: SlateElementProps) { return ( -
    +

    {colSizes?.map((width, index) => ( diff --git a/packages/core/src/lib/plugins/html/utils/pipeDeserializeHtmlElement.ts b/packages/core/src/lib/plugins/html/utils/pipeDeserializeHtmlElement.ts index 5e0a136a1d..46364e34a0 100644 --- a/packages/core/src/lib/plugins/html/utils/pipeDeserializeHtmlElement.ts +++ b/packages/core/src/lib/plugins/html/utils/pipeDeserializeHtmlElement.ts @@ -10,6 +10,8 @@ export const pipeDeserializeHtmlElement = ( editor: SlateEditor, element: HTMLElement ) => { + if (element.dataset.platePreventDeserialization) return; + let result: (Nullable & { node: AnyObject }) | undefined; [...editor.pluginList].reverse().some((plugin) => { diff --git a/packages/table/src/lib/BaseTablePlugin.ts b/packages/table/src/lib/BaseTablePlugin.ts index bf7b7510c5..111358c838 100644 --- a/packages/table/src/lib/BaseTablePlugin.ts +++ b/packages/table/src/lib/BaseTablePlugin.ts @@ -92,12 +92,12 @@ export const BaseTablePlugin = createTSlatePlugin({ return { colSizes, marginLeft: 20, type }; } // prevent table static elements from being parsed multiple times - if ( - isPluginStatic(element.parentElement!, type) && - element.tagName === 'TABLE' - ) { - return; - } + // if ( + // isPluginStatic(element.parentElement!, type) && + // element.tagName === 'TABLE' + // ) { + // return; + // } return { type }; }, From abf038504c2a043a0e0b55ff9d5b1bf02ecab667 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Thu, 9 Jan 2025 23:16:09 +0800 Subject: [PATCH 10/25] media --- .../plate-ui/media-audio-element-static.tsx | 11 ++++-- .../plate-ui/media-file-element-static.tsx | 8 +++-- .../plate-ui/media-video-element-static.tsx | 4 +++ packages/media/src/lib/BaseAudioPlugin.ts | 32 ++++++++++++++++- packages/media/src/lib/BaseFilePlugin.ts | 35 ++++++++++++++----- packages/media/src/lib/BaseVideoPlugin.ts | 32 ++++++++++++++++- 6 files changed, 108 insertions(+), 14 deletions(-) diff --git a/apps/www/src/registry/default/plate-ui/media-audio-element-static.tsx b/apps/www/src/registry/default/plate-ui/media-audio-element-static.tsx index 397951fdbf..735fd2c413 100644 --- a/apps/www/src/registry/default/plate-ui/media-audio-element-static.tsx +++ b/apps/www/src/registry/default/plate-ui/media-audio-element-static.tsx @@ -11,13 +11,20 @@ export function MediaAudioElementStatic({ className, ...props }: SlateElementProps) { - const { url } = props.element as TAudioElement; + const { align, isUpload, url, width } = props.element as TAudioElement; return (
    -
    {children} diff --git a/apps/www/src/registry/default/plate-ui/media-file-element-static.tsx b/apps/www/src/registry/default/plate-ui/media-file-element-static.tsx index f80dfe5ae0..8b1cbc514e 100644 --- a/apps/www/src/registry/default/plate-ui/media-file-element-static.tsx +++ b/apps/www/src/registry/default/plate-ui/media-file-element-static.tsx @@ -12,12 +12,16 @@ export const MediaFileElementStatic = ({ className, ...props }: SlateElementProps) => { - const { name, url } = props.element as TFileElement; + const { align, isUpload, name, url, width } = props.element as TFileElement; return ( -
    {name}
    +
    {name}
    {/*
    diff --git a/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx b/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx index 91cdbf3cba..f54e9dc340 100644 --- a/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx +++ b/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx @@ -15,6 +15,7 @@ export function MediaVideoElementStatic({ const { align = 'center', caption, + isUpload, url, width, } = props.element as TVideoElement & @@ -31,6 +32,9 @@ export function MediaVideoElementStatic({ > diff --git a/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx b/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx index f54e9dc340..91cdbf3cba 100644 --- a/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx +++ b/apps/www/src/registry/default/plate-ui/media-video-element-static.tsx @@ -15,7 +15,6 @@ export function MediaVideoElementStatic({ const { align = 'center', caption, - isUpload, url, width, } = props.element as TVideoElement & @@ -32,9 +31,6 @@ export function MediaVideoElementStatic({ >