Skip to content

Commit

Permalink
Merge pull request #3943 from udecode/import/html
Browse files Browse the repository at this point in the history
Import HTML exported by PlateStatic.
  • Loading branch information
felixfeng33 authored Jan 14, 2025
2 parents 0c9cc85 + b58d328 commit d1aaf4c
Show file tree
Hide file tree
Showing 61 changed files with 1,303 additions and 256 deletions.
12 changes: 12 additions & 0 deletions .changeset/few-points-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@udecode/plate-indent-list': patch
'@udecode/plate-line-height': patch
'@udecode/plate-code-block': patch
'@udecode/plate-comments': patch
'@udecode/plate-layout': patch
'@udecode/plate-media': patch
'@udecode/plate-table': patch
'@udecode/plate-docx': patch
---

Support deserialization from PlateStatic.
17 changes: 17 additions & 0 deletions .changeset/twenty-rivers-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@udecode/plate-core': patch
---

`editor.api.html.deserialize`: Support deserialization from PlateStatic.

New: `getEditorDOMFromHtmlString` returns the editor element in html string (the one with `data-slate-editor="true"`).

New utilities for checking Slate nodes in HTML:
- `isSlateVoid`: Check if an HTML element is a Slate void node
- `isSlateElement`: Check if an HTML element is a Slate element node
- `isSlateString`: Check if an HTML element is a Slate string node
- `isSlateLeaf`: Check if an HTML element is a Slate leaf node
- `isSlateNode`: Check if an HTML element is any type of Slate node
- `isSlatePluginElement`: Check if an HTML element is a Slate element node with a specific plugin key
- `isSlatePluginNode`: Check if an HTML element has a specific plugin key class
- `getSlateElements`: Get all Slate element nodes in an HTML element
4 changes: 2 additions & 2 deletions apps/www/content/docs/cn/html.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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/react';

const editor = createPlateEditor({
plugins: [
// all plugins that you want to deserialize
// 所有你想要反序列化的插件
]
})
editor.children = editor.api.html.deserialize('<p>Hello, world!</p>')
Expand Down
28 changes: 28 additions & 0 deletions apps/www/public/r/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -1922,6 +1922,34 @@
],
"type": "registry:ui"
},
{
"dependencies": [],
"doc": {
"description": "A toolbar button to import editor content from a file.",
"docs": [
{
"route": "/docs/import",
"title": "Import"
}
],
"examples": [
"basic-nodes-demo"
],
"label": "New",
"title": "Import Toolbar Button"
},
"files": [
{
"path": "plate-ui/import-toolbar-button.tsx",
"type": "registry:ui"
}
],
"name": "import-toolbar-button",
"registryDependencies": [
"toolbar"
],
"type": "registry:ui"
},
{
"dependencies": [
"@udecode/plate-caption"
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/styles/default/comments-demo.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"type": "registry:example"
},
{
"content": "import type { Value } from '@udecode/plate';\n\nexport const commentsValue: Value = [\n {\n children: [{ text: 'Comments' }],\n type: 'h2',\n },\n {\n children: [\n {\n text: 'Add ',\n },\n {\n comment: true,\n comment_1: true,\n text: 'comments to your content',\n },\n { text: ' to provide additional context, insights, or ' },\n {\n comment: true,\n comment_2: true,\n text: 'collaborate',\n },\n {\n text: ' with others',\n },\n ],\n type: 'p',\n },\n];\n",
"content": "import type { Value } from '@udecode/plate';\n\nexport const commentsValue: Value = [\n {\n children: [{ text: 'Comments' }],\n type: 'h2',\n },\n {\n children: [\n {\n text: 'Add ',\n },\n {\n comment: true,\n comment_1: true,\n text: 'comments to your content',\n },\n { text: ' to provide additional context, insights, or ' },\n {\n comment: true,\n comment_2: true,\n text: 'collaborate',\n },\n {\n text: ' with others',\n },\n ],\n type: 'p',\n },\n];\n",
"path": "example/values/comments-value.tsx",
"target": "components/comments-value.tsx",
"type": "registry:example"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"files": [
{
"content": "'use client';\n\nimport React from 'react';\n\nimport { useEditorReadOnly } from '@udecode/plate/react';\nimport {\n BoldPlugin,\n CodePlugin,\n ItalicPlugin,\n StrikethroughPlugin,\n UnderlinePlugin,\n} from '@udecode/plate-basic-marks/react';\nimport {\n FontBackgroundColorPlugin,\n FontColorPlugin,\n} from '@udecode/plate-font/react';\nimport { HighlightPlugin } from '@udecode/plate-highlight/react';\nimport {\n AudioPlugin,\n FilePlugin,\n ImagePlugin,\n VideoPlugin,\n} from '@udecode/plate-media/react';\nimport {\n ArrowUpToLineIcon,\n BaselineIcon,\n BoldIcon,\n Code2Icon,\n HighlighterIcon,\n ItalicIcon,\n PaintBucketIcon,\n StrikethroughIcon,\n UnderlineIcon,\n WandSparklesIcon,\n} from 'lucide-react';\n\nimport { MoreDropdownMenu } from '@/components/plate-ui/more-dropdown-menu';\n\nimport { AIToolbarButton } from './ai-toolbar-button';\nimport { AlignDropdownMenu } from './align-dropdown-menu';\nimport { ColorDropdownMenu } from './color-dropdown-menu';\nimport { CommentToolbarButton } from './comment-toolbar-button';\nimport { EmojiDropdownMenu } from './emoji-dropdown-menu';\nimport { ExportToolbarButton } from './export-toolbar-button';\nimport { FontSizeToolbarButton } from './font-size-toolbar-button';\nimport { RedoToolbarButton, UndoToolbarButton } from './history-toolbar-button';\nimport {\n BulletedIndentListToolbarButton,\n NumberedIndentListToolbarButton,\n} from './indent-list-toolbar-button';\nimport { IndentTodoToolbarButton } from './indent-todo-toolbar-button';\nimport { IndentToolbarButton } from './indent-toolbar-button';\nimport { InsertDropdownMenu } from './insert-dropdown-menu';\nimport { LineHeightDropdownMenu } from './line-height-dropdown-menu';\nimport { LinkToolbarButton } from './link-toolbar-button';\nimport { MarkToolbarButton } from './mark-toolbar-button';\nimport { MediaToolbarButton } from './media-toolbar-button';\nimport { ModeDropdownMenu } from './mode-dropdown-menu';\nimport { OutdentToolbarButton } from './outdent-toolbar-button';\nimport { TableDropdownMenu } from './table-dropdown-menu';\nimport { ToggleToolbarButton } from './toggle-toolbar-button';\nimport { ToolbarGroup } from './toolbar';\nimport { TurnIntoDropdownMenu } from './turn-into-dropdown-menu';\n\nexport function FixedToolbarButtons() {\n const readOnly = useEditorReadOnly();\n\n return (\n <div className=\"flex w-full\">\n {!readOnly && (\n <>\n <ToolbarGroup>\n <UndoToolbarButton />\n <RedoToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <AIToolbarButton tooltip=\"AI commands\">\n <WandSparklesIcon />\n </AIToolbarButton>\n </ToolbarGroup>\n\n <ToolbarGroup>\n <ExportToolbarButton>\n <ArrowUpToLineIcon />\n </ExportToolbarButton>\n </ToolbarGroup>\n\n <ToolbarGroup>\n <InsertDropdownMenu />\n <TurnIntoDropdownMenu />\n <FontSizeToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <MarkToolbarButton nodeType={BoldPlugin.key} tooltip=\"Bold (⌘+B)\">\n <BoldIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton\n nodeType={ItalicPlugin.key}\n tooltip=\"Italic (⌘+I)\"\n >\n <ItalicIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton\n nodeType={UnderlinePlugin.key}\n tooltip=\"Underline (⌘+U)\"\n >\n <UnderlineIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton\n nodeType={StrikethroughPlugin.key}\n tooltip=\"Strikethrough (⌘+⇧+M)\"\n >\n <StrikethroughIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton nodeType={CodePlugin.key} tooltip=\"Code (⌘+E)\">\n <Code2Icon />\n </MarkToolbarButton>\n\n <ColorDropdownMenu\n nodeType={FontColorPlugin.key}\n tooltip=\"Text color\"\n >\n <BaselineIcon />\n </ColorDropdownMenu>\n\n <ColorDropdownMenu\n nodeType={FontBackgroundColorPlugin.key}\n tooltip=\"Background color\"\n >\n <PaintBucketIcon />\n </ColorDropdownMenu>\n </ToolbarGroup>\n\n <ToolbarGroup>\n <AlignDropdownMenu />\n\n <NumberedIndentListToolbarButton />\n <BulletedIndentListToolbarButton />\n <IndentTodoToolbarButton />\n <ToggleToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <LinkToolbarButton />\n <TableDropdownMenu />\n <EmojiDropdownMenu />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <MediaToolbarButton nodeType={ImagePlugin.key} />\n <MediaToolbarButton nodeType={VideoPlugin.key} />\n <MediaToolbarButton nodeType={AudioPlugin.key} />\n <MediaToolbarButton nodeType={FilePlugin.key} />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <LineHeightDropdownMenu />\n <OutdentToolbarButton />\n <IndentToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <MoreDropdownMenu />\n </ToolbarGroup>\n </>\n )}\n\n <div className=\"grow\" />\n\n <ToolbarGroup>\n <MarkToolbarButton nodeType={HighlightPlugin.key} tooltip=\"Highlight\">\n <HighlighterIcon />\n </MarkToolbarButton>\n <CommentToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <ModeDropdownMenu />\n </ToolbarGroup>\n </div>\n );\n}\n",
"content": "'use client';\n\nimport React from 'react';\n\nimport { useEditorReadOnly } from '@udecode/plate/react';\nimport {\n BoldPlugin,\n CodePlugin,\n ItalicPlugin,\n StrikethroughPlugin,\n UnderlinePlugin,\n} from '@udecode/plate-basic-marks/react';\nimport {\n FontBackgroundColorPlugin,\n FontColorPlugin,\n} from '@udecode/plate-font/react';\nimport { HighlightPlugin } from '@udecode/plate-highlight/react';\nimport {\n AudioPlugin,\n FilePlugin,\n ImagePlugin,\n VideoPlugin,\n} from '@udecode/plate-media/react';\nimport {\n ArrowUpToLineIcon,\n BaselineIcon,\n BoldIcon,\n Code2Icon,\n HighlighterIcon,\n ItalicIcon,\n PaintBucketIcon,\n StrikethroughIcon,\n UnderlineIcon,\n WandSparklesIcon,\n} from 'lucide-react';\n\nimport { MoreDropdownMenu } from '@/components/plate-ui/more-dropdown-menu';\n\nimport { AIToolbarButton } from './ai-toolbar-button';\nimport { AlignDropdownMenu } from './align-dropdown-menu';\nimport { ColorDropdownMenu } from './color-dropdown-menu';\nimport { CommentToolbarButton } from './comment-toolbar-button';\nimport { EmojiDropdownMenu } from './emoji-dropdown-menu';\nimport { ExportToolbarButton } from './export-toolbar-button';\nimport { FontSizeToolbarButton } from './font-size-toolbar-button';\nimport { RedoToolbarButton, UndoToolbarButton } from './history-toolbar-button';\nimport { ImportToolbarButton } from './import-toolbar-button';\nimport {\n BulletedIndentListToolbarButton,\n NumberedIndentListToolbarButton,\n} from './indent-list-toolbar-button';\nimport { IndentTodoToolbarButton } from './indent-todo-toolbar-button';\nimport { IndentToolbarButton } from './indent-toolbar-button';\nimport { InsertDropdownMenu } from './insert-dropdown-menu';\nimport { LineHeightDropdownMenu } from './line-height-dropdown-menu';\nimport { LinkToolbarButton } from './link-toolbar-button';\nimport { MarkToolbarButton } from './mark-toolbar-button';\nimport { MediaToolbarButton } from './media-toolbar-button';\nimport { ModeDropdownMenu } from './mode-dropdown-menu';\nimport { OutdentToolbarButton } from './outdent-toolbar-button';\nimport { TableDropdownMenu } from './table-dropdown-menu';\nimport { ToggleToolbarButton } from './toggle-toolbar-button';\nimport { ToolbarGroup } from './toolbar';\nimport { TurnIntoDropdownMenu } from './turn-into-dropdown-menu';\n\nexport function FixedToolbarButtons() {\n const readOnly = useEditorReadOnly();\n\n return (\n <div className=\"flex w-full\">\n {!readOnly && (\n <>\n <ToolbarGroup>\n <UndoToolbarButton />\n <RedoToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <AIToolbarButton tooltip=\"AI commands\">\n <WandSparklesIcon />\n </AIToolbarButton>\n </ToolbarGroup>\n\n <ToolbarGroup>\n <ExportToolbarButton>\n <ArrowUpToLineIcon />\n </ExportToolbarButton>\n\n <ImportToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <InsertDropdownMenu />\n <TurnIntoDropdownMenu />\n <FontSizeToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <MarkToolbarButton nodeType={BoldPlugin.key} tooltip=\"Bold (⌘+B)\">\n <BoldIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton\n nodeType={ItalicPlugin.key}\n tooltip=\"Italic (⌘+I)\"\n >\n <ItalicIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton\n nodeType={UnderlinePlugin.key}\n tooltip=\"Underline (⌘+U)\"\n >\n <UnderlineIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton\n nodeType={StrikethroughPlugin.key}\n tooltip=\"Strikethrough (⌘+⇧+M)\"\n >\n <StrikethroughIcon />\n </MarkToolbarButton>\n\n <MarkToolbarButton nodeType={CodePlugin.key} tooltip=\"Code (⌘+E)\">\n <Code2Icon />\n </MarkToolbarButton>\n\n <ColorDropdownMenu\n nodeType={FontColorPlugin.key}\n tooltip=\"Text color\"\n >\n <BaselineIcon />\n </ColorDropdownMenu>\n\n <ColorDropdownMenu\n nodeType={FontBackgroundColorPlugin.key}\n tooltip=\"Background color\"\n >\n <PaintBucketIcon />\n </ColorDropdownMenu>\n </ToolbarGroup>\n\n <ToolbarGroup>\n <AlignDropdownMenu />\n\n <NumberedIndentListToolbarButton />\n <BulletedIndentListToolbarButton />\n <IndentTodoToolbarButton />\n <ToggleToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <LinkToolbarButton />\n <TableDropdownMenu />\n <EmojiDropdownMenu />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <MediaToolbarButton nodeType={ImagePlugin.key} />\n <MediaToolbarButton nodeType={VideoPlugin.key} />\n <MediaToolbarButton nodeType={AudioPlugin.key} />\n <MediaToolbarButton nodeType={FilePlugin.key} />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <LineHeightDropdownMenu />\n <OutdentToolbarButton />\n <IndentToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <MoreDropdownMenu />\n </ToolbarGroup>\n </>\n )}\n\n <div className=\"grow\" />\n\n <ToolbarGroup>\n <MarkToolbarButton nodeType={HighlightPlugin.key} tooltip=\"Highlight\">\n <HighlighterIcon />\n </MarkToolbarButton>\n <CommentToolbarButton />\n </ToolbarGroup>\n\n <ToolbarGroup>\n <ModeDropdownMenu />\n </ToolbarGroup>\n </div>\n );\n}\n",
"path": "plate-ui/fixed-toolbar-buttons.tsx",
"target": "components/plate-ui/fixed-toolbar-buttons.tsx",
"type": "registry:ui"
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/styles/default/horizontal-rule-demo.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"type": "registry:example"
},
{
"content": "import { BaseHorizontalRulePlugin } from '@udecode/plate-horizontal-rule';\nimport { jsx } from '@udecode/plate-test-utils';\n\njsx;\n\nexport const horizontalRuleValue: any = (\n <fragment>\n <hh2>Horizontal Rule</hh2>\n <hp>\n Add horizontal rules to visually separate sections and content within your\n document.\n </hp>\n <element type={BaseHorizontalRulePlugin.key}>\n <htext />\n </element>\n </fragment>\n);\n",
"content": "import { BaseHorizontalRulePlugin } from '@udecode/plate-horizontal-rule';\nimport { jsx } from '@udecode/plate-test-utils';\n\njsx;\n\nexport const horizontalRuleValue: any = (\n <fragment>\n <hh2>Horizontal Rule</hh2>\n {/* <hp>\n Add horizontal rules to visually separate sections and content within your\n document.\n </hp> */}\n <element type={BaseHorizontalRulePlugin.key}>\n <htext />\n </element>\n </fragment>\n);\n",
"path": "example/values/horizontal-rule-value.tsx",
"target": "components/horizontal-rule-value.tsx",
"type": "registry:example"
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/styles/default/hr-element.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"type": "registry:ui"
},
{
"content": "import React from 'react';\n\nimport type { SlateElementProps } from '@udecode/plate';\n\nimport { cn } from '@udecode/cn';\nimport { SlateElement } from '@udecode/plate';\n\nexport function HrElementStatic({\n children,\n className,\n nodeProps,\n ...props\n}: SlateElementProps) {\n return (\n <SlateElement className={className} {...props}>\n <div className=\"cursor-text py-6\" contentEditable={false}>\n <hr\n {...nodeProps}\n className={cn(\n 'h-0.5 rounded-sm border-none bg-muted bg-clip-content'\n )}\n />\n </div>\n {children}\n </SlateElement>\n );\n}\n",
"content": "import React from 'react';\n\nimport type { SlateElementProps } from '@udecode/plate';\n\nimport { cn } from '@udecode/cn';\nimport { SlateElement } from '@udecode/plate';\n\nexport function HrElementStatic({\n children,\n className,\n nodeProps,\n ...props\n}: SlateElementProps) {\n return (\n <SlateElement className={className} nodeProps={nodeProps} {...props}>\n <div className=\"cursor-text py-6\" contentEditable={false}>\n <hr\n {...nodeProps}\n className={cn(\n 'h-0.5 rounded-sm border-none bg-muted bg-clip-content'\n )}\n />\n </div>\n {children}\n </SlateElement>\n );\n}\n",
"path": "plate-ui/hr-element-static.tsx",
"target": "components/plate-ui/hr-element-static.tsx",
"type": "registry:ui"
Expand Down
Loading

0 comments on commit d1aaf4c

Please sign in to comment.