From 660828b83541d3e30e85aa9f5272b70425dce919 Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 18:34:56 +0100 Subject: [PATCH 1/7] [DEV-19130] Add plate and plate-common as dependencies to the root package --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 4cf331efb..62a7e2364 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "dependencies": { "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", + "@udecode/plate": "^42.1.2", + "@udecode/plate-common": "^42.0.0", "react": "^18.3.0", "react-dom": "^18.3.0" }, From 4b3c38711b0966cb4bbe117af12755e6850dbefb Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 18:48:35 +0100 Subject: [PATCH 2/7] [DEV-19130] Make `createEditor` responsible for creating the PlateEditor instance too --- .../InputPlaceholderElement.stories.tsx | 2 +- .../components/PlaceholderElement.stories.tsx | 2 +- .../AttachmentPlaceholderElement.stories.tsx | 2 +- .../ContactPlaceholderElement.stories.tsx | 2 +- .../EmbedPlaceholderElement.stories.tsx | 2 +- .../GalleryPlaceholderElement.stories.tsx | 2 +- .../ImagePlaceholderElement.stories.tsx | 2 +- .../MediaPlaceholderElement.stories.tsx | 2 +- .../SocialPostPlaceholderElement.stories.tsx | 2 +- ...toryBookmarkPlaceholderElement.stories.tsx | 2 +- .../StoryEmbedPlaceholderElement.stories.tsx | 2 +- .../VideoPlaceholderElement.stories.tsx | 2 +- .../WebBookmarkPlaceholderElement.stories.tsx | 2 +- packages/slate-editor/src/hyperscript.ts | 6 ++- .../src/modules/editor/createEditor.ts | 49 +++++++++++++++---- .../editor/lib/isEditorValueEqual.test.ts | 6 +-- .../src/modules/editor/test-utils.ts | 9 ++-- .../src/modules/editor/useCreateEditor.ts | 10 +--- 18 files changed, 67 insertions(+), 39 deletions(-) diff --git a/packages/slate-editor/src/extensions/placeholders/components/InputPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/components/InputPlaceholderElement.stories.tsx index b43ff5c37..df25ecb2f 100644 --- a/packages/slate-editor/src/extensions/placeholders/components/InputPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/components/InputPlaceholderElement.stories.tsx @@ -13,7 +13,7 @@ import { PlaceholdersManager } from '../PlaceholdersManager'; import { InputPlaceholderElement } from './InputPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.EMBED, diff --git a/packages/slate-editor/src/extensions/placeholders/components/PlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/components/PlaceholderElement.stories.tsx index 6365bdfbd..eabddc14c 100644 --- a/packages/slate-editor/src/extensions/placeholders/components/PlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/components/PlaceholderElement.stories.tsx @@ -12,7 +12,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { PlaceholderElement } from './PlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.ATTACHMENT, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/AttachmentPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/AttachmentPlaceholderElement.stories.tsx index 9fe1b4e7d..be87c3005 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/AttachmentPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/AttachmentPlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { AttachmentPlaceholderElement } from './AttachmentPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.ATTACHMENT, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/ContactPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/ContactPlaceholderElement.stories.tsx index 163d25f16..a6eff7286 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/ContactPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/ContactPlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { ContactPlaceholderElement } from './ContactPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.CONTACT, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/EmbedPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/EmbedPlaceholderElement.stories.tsx index 862b50adb..8160b5b58 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/EmbedPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/EmbedPlaceholderElement.stories.tsx @@ -11,7 +11,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { EmbedPlaceholderElement } from './EmbedPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.EMBED, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/GalleryPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/GalleryPlaceholderElement.stories.tsx index 966a5c074..a2f2ef9d4 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/GalleryPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/GalleryPlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { GalleryPlaceholderElement } from './GalleryPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.GALLERY, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/ImagePlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/ImagePlaceholderElement.stories.tsx index 3987bcd3c..8c202e0cd 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/ImagePlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/ImagePlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { ImagePlaceholderElement } from './ImagePlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.IMAGE, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/MediaPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/MediaPlaceholderElement.stories.tsx index 8165a1199..5e5600f58 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/MediaPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/MediaPlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { MediaPlaceholderElement } from './MediaPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.MEDIA, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/SocialPostPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/SocialPostPlaceholderElement.stories.tsx index 38b841440..f9b3d6763 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/SocialPostPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/SocialPostPlaceholderElement.stories.tsx @@ -11,7 +11,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { SocialPostPlaceholderElement } from './SocialPostPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.SOCIAL_POST, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/StoryBookmarkPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/StoryBookmarkPlaceholderElement.stories.tsx index 96cf3b591..8912959a9 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/StoryBookmarkPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/StoryBookmarkPlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { StoryBookmarkPlaceholderElement } from './StoryBookmarkPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.STORY_BOOKMARK, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/StoryEmbedPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/StoryEmbedPlaceholderElement.stories.tsx index 1fe43bef2..1ed1a8464 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/StoryEmbedPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/StoryEmbedPlaceholderElement.stories.tsx @@ -10,7 +10,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { StoryEmbedPlaceholderElement } from './StoryEmbedPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.STORY_EMBED, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/VideoPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/VideoPlaceholderElement.stories.tsx index f49ac0018..d8ad458ba 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/VideoPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/VideoPlaceholderElement.stories.tsx @@ -11,7 +11,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { VideoPlaceholderElement } from './VideoPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.VIDEO, diff --git a/packages/slate-editor/src/extensions/placeholders/elements/WebBookmarkPlaceholderElement.stories.tsx b/packages/slate-editor/src/extensions/placeholders/elements/WebBookmarkPlaceholderElement.stories.tsx index 107ef5045..d582df062 100644 --- a/packages/slate-editor/src/extensions/placeholders/elements/WebBookmarkPlaceholderElement.stories.tsx +++ b/packages/slate-editor/src/extensions/placeholders/elements/WebBookmarkPlaceholderElement.stories.tsx @@ -11,7 +11,7 @@ import { PlaceholderNode } from '../PlaceholderNode'; import { WebBookmarkPlaceholderElement } from './WebBookmarkPlaceholderElement'; const extensions = [PlaceholdersExtension()]; -const editor = createEditor(createPlateEditor(), () => extensions); +const editor = createEditor({ editor: createPlateEditor(), getExtensions: () => extensions }); const placeholder: PlaceholderNode = { type: PlaceholderNode.Type.WEB_BOOKMARK, diff --git a/packages/slate-editor/src/hyperscript.ts b/packages/slate-editor/src/hyperscript.ts index b24fc039e..0ff897fa9 100644 --- a/packages/slate-editor/src/hyperscript.ts +++ b/packages/slate-editor/src/hyperscript.ts @@ -124,7 +124,11 @@ const extensions = [ const creators: Record = { editor: createEditorFactory(() => - createEditor(createSlateEditor(), () => extensions, [withReact, withHistory]), + createEditor({ + editor: createSlateEditor(), + getExtensions: () => extensions, + withOverrides: [withReact, withHistory], + }), ), 'editor-pure': createEditorFactory(() => withReact(createSlateEditor())), 'h:text': createText, diff --git a/packages/slate-editor/src/modules/editor/createEditor.ts b/packages/slate-editor/src/modules/editor/createEditor.ts index 11b5a9abf..1f5a814ba 100644 --- a/packages/slate-editor/src/modules/editor/createEditor.ts +++ b/packages/slate-editor/src/modules/editor/createEditor.ts @@ -8,7 +8,9 @@ import { import type { Extension, WithOverrides } from '@prezly/slate-commons'; import { isNotUndefined } from '@technically/is-not-undefined'; import { flow } from '@technically/lodash'; -import type { SlateEditor } from '@udecode/plate-common'; +import { type Editor } from '@udecode/plate'; +import { createPlateEditor } from '@udecode/plate/react'; +import { type PlatePlugin } from '@udecode/plate/react'; import { createParagraph } from '#extensions/paragraphs'; import { withNodesHierarchy, hierarchySchema } from '#modules/nodes-hierarchy'; @@ -19,18 +21,41 @@ import { withElementsEqualityCheck, withRichBlocks, } from './plugins'; +import { type Value } from './types'; -export function createEditor( - baseEditor: SlateEditor, - getExtensions: () => Extension[], - plugins: WithOverrides[] = [], -) { - const overrides = getExtensions() - .map(({ withOverrides }) => withOverrides) +type Params = { + initialValue?: Value; + plugins?: PlatePlugin[]; + editor?: Editor; + /** + * @deprecated It is planned to migrate extensions to become Plate Plugins + */ + getExtensions?: () => Extension[]; + /** + * @deprecated It is recommended to migrate these overrides to become Plate Plugins + */ + withOverrides?: WithOverrides[]; +}; + +export function createEditor({ + initialValue, + plugins = [], + editor, + getExtensions = noExtensions, + withOverrides = [], +}: Params) { + const baseEditor = createPlateEditor({ + editor, + plugins, + value: initialValue, + }); + + const extensionsOverrides = getExtensions() + .map((extension) => extension.withOverrides) .filter(isNotUndefined); return flow([ - ...plugins, + ...withOverrides, withNodesHierarchy(hierarchySchema), withBreaksOnExpandedSelection, withBreaksOnVoidNodes, @@ -41,6 +66,10 @@ export function createEditor( withDeserializeHtml(getExtensions), withRichBlocks(getExtensions), withElementsEqualityCheck, - ...overrides, + ...extensionsOverrides, ])(baseEditor); } + +function noExtensions(): Extension[] { + return []; +} diff --git a/packages/slate-editor/src/modules/editor/lib/isEditorValueEqual.test.ts b/packages/slate-editor/src/modules/editor/lib/isEditorValueEqual.test.ts index b339d8942..51ddf0792 100644 --- a/packages/slate-editor/src/modules/editor/lib/isEditorValueEqual.test.ts +++ b/packages/slate-editor/src/modules/editor/lib/isEditorValueEqual.test.ts @@ -6,7 +6,7 @@ import { isEditorValueEqual } from './isEditorValueEqual'; describe('isEditorValueEqual', () => { it('should return true for equivalent values', () => { - const editor = createEditor(createSlateEditor(), () => []); + const editor = createEditor({ editor: createSlateEditor() }); const a = [ { @@ -25,7 +25,7 @@ describe('isEditorValueEqual', () => { }); it('should return false for non-equivalent values', () => { - const editor = createEditor(createSlateEditor(), () => []); + const editor = createEditor({ editor: createSlateEditor() }); const a = [ { @@ -44,7 +44,7 @@ describe('isEditorValueEqual', () => { }); it('should consider structural equality', () => { - const editor = createEditor(createSlateEditor(), () => []); + const editor = createEditor({ editor: createSlateEditor() }); const a = [ { diff --git a/packages/slate-editor/src/modules/editor/test-utils.ts b/packages/slate-editor/src/modules/editor/test-utils.ts index a46efaf68..074de0988 100644 --- a/packages/slate-editor/src/modules/editor/test-utils.ts +++ b/packages/slate-editor/src/modules/editor/test-utils.ts @@ -103,8 +103,9 @@ export function getAllExtensions() { } export function createEditor(input: JSX.Element) { - return createBaseEditor(input as unknown as SlateEditor, getAllExtensions, [ - withReact, - withHistory, - ]); + return createBaseEditor({ + editor: input as unknown as SlateEditor, + getExtensions: getAllExtensions, + withOverrides: [withReact, withHistory], + }); } diff --git a/packages/slate-editor/src/modules/editor/useCreateEditor.ts b/packages/slate-editor/src/modules/editor/useCreateEditor.ts index 13a80ea63..fbc430d11 100644 --- a/packages/slate-editor/src/modules/editor/useCreateEditor.ts +++ b/packages/slate-editor/src/modules/editor/useCreateEditor.ts @@ -1,6 +1,5 @@ import { type Extension, type OnKeyDown } from '@prezly/slate-commons'; import type { PlateEditor, PlatePlugin } from '@udecode/plate-common/react'; -import { createPlateEditor } from '@udecode/plate-common/react'; import type { KeyboardEvent } from 'react'; import { useCallback, useMemo } from 'react'; @@ -42,13 +41,8 @@ export function useCreateEditor({ const extensionsRef = useLatest(extensions); const getExtensions = useCallback(() => extensionsRef.current, [extensionsRef]); const editor = useMemo(() => { - const plateEditor = createPlateEditor({ - plugins: plugins, - value: initialValue, - }); - - return createEditor(plateEditor, getExtensions); - }, [getExtensions, plugins]); + return createEditor({ initialValue, plugins, getExtensions }); + }, [plugins, getExtensions]); return { editor, From 039d4f515ae94fb7047ec834bc9f2a131e808d27 Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 18:58:30 +0100 Subject: [PATCH 3/7] [DEV-19130] Make `withRichBlocks` a Plate Plugin --- packages/slate-editor/src/index.ts | 7 +--- .../src/modules/editor/createEditor.ts | 10 +++-- .../slate-editor/src/modules/editor/index.ts | 7 +--- .../editor/plugins/RichBlocksPlugin.ts | 37 +++++++++++++++++++ .../src/modules/editor/plugins/index.ts | 2 +- .../modules/editor/plugins/withRichBlocks.ts | 22 ----------- 6 files changed, 47 insertions(+), 38 deletions(-) create mode 100644 packages/slate-editor/src/modules/editor/plugins/RichBlocksPlugin.ts delete mode 100644 packages/slate-editor/src/modules/editor/plugins/withRichBlocks.ts diff --git a/packages/slate-editor/src/index.ts b/packages/slate-editor/src/index.ts index a543e4b44..faa4d8918 100644 --- a/packages/slate-editor/src/index.ts +++ b/packages/slate-editor/src/index.ts @@ -27,17 +27,12 @@ import type { BaseEditor } from 'slate'; import type { HistoryEditor } from 'slate-history'; import type { FlashEditor } from '#extensions/flash-nodes'; -import type { - DefaultTextBlockEditor, - ElementsEqualityCheckEditor, - RichBlocksAwareEditor, -} from '#modules/editor'; +import type { DefaultTextBlockEditor, ElementsEqualityCheckEditor } from '#modules/editor'; type Editor = BaseEditor & HistoryEditor & DefaultTextBlockEditor & ElementsEqualityCheckEditor & - RichBlocksAwareEditor & FlashEditor; declare module 'slate' { diff --git a/packages/slate-editor/src/modules/editor/createEditor.ts b/packages/slate-editor/src/modules/editor/createEditor.ts index 1f5a814ba..0c6bbd93e 100644 --- a/packages/slate-editor/src/modules/editor/createEditor.ts +++ b/packages/slate-editor/src/modules/editor/createEditor.ts @@ -19,7 +19,7 @@ import { withDefaultTextBlock, withDeserializeHtml, withElementsEqualityCheck, - withRichBlocks, + RichBlocksPlugin, } from './plugins'; import { type Value } from './types'; @@ -46,7 +46,12 @@ export function createEditor({ }: Params) { const baseEditor = createPlateEditor({ editor, - plugins, + plugins: [ + ...plugins, + RichBlocksPlugin.configure({ + options: { getExtensions }, + }), + ], value: initialValue, }); @@ -64,7 +69,6 @@ export function createEditor({ withNormalization(getExtensions), withUserFriendlyDeleteBehavior, withDeserializeHtml(getExtensions), - withRichBlocks(getExtensions), withElementsEqualityCheck, ...extensionsOverrides, ])(baseEditor); diff --git a/packages/slate-editor/src/modules/editor/index.ts b/packages/slate-editor/src/modules/editor/index.ts index ac1745aa7..cdfe168d8 100644 --- a/packages/slate-editor/src/modules/editor/index.ts +++ b/packages/slate-editor/src/modules/editor/index.ts @@ -1,12 +1,7 @@ export { Editor } from './Editor'; export { createEditor } from './createEditor'; export { createEmptyValue } from './lib'; -export { - withDefaultTextBlock, - withDeserializeHtml, - withElementsEqualityCheck, - withRichBlocks, -} from './plugins'; +export { withDefaultTextBlock, withDeserializeHtml, withElementsEqualityCheck } from './plugins'; export type { DefaultTextBlockEditor, ElementsEqualityCheckEditor, diff --git a/packages/slate-editor/src/modules/editor/plugins/RichBlocksPlugin.ts b/packages/slate-editor/src/modules/editor/plugins/RichBlocksPlugin.ts new file mode 100644 index 000000000..a0b0d1dc7 --- /dev/null +++ b/packages/slate-editor/src/modules/editor/plugins/RichBlocksPlugin.ts @@ -0,0 +1,37 @@ +import type { Extension } from '@prezly/slate-commons'; +import type { Node } from '@udecode/plate'; +import { createPlatePlugin, type PlatePlugin } from '@udecode/plate/react'; + +type Configuration = { + key: 'RichBlocks'; + options: { + getExtensions(): Extension[]; + }; + api: never; + transforms: never; +}; + +export const RichBlocksPlugin: PlatePlugin = createPlatePlugin< + Configuration['key'], + Configuration['options'], + Configuration['api'], + Configuration['transforms'] +>({ + key: 'RichBlocks', + options: { + getExtensions: () => [], + }, +}).overrideEditor(({ getOptions }) => { + const { getExtensions } = getOptions(); + function isRichBlock(node: Node) { + for (const extension of getExtensions()) { + if (extension.isRichBlock?.(node)) return true; + } + return false; + } + return { + api: { + isRichBlock, + }, + }; +}); diff --git a/packages/slate-editor/src/modules/editor/plugins/index.ts b/packages/slate-editor/src/modules/editor/plugins/index.ts index 4acb31d67..5a9eda00c 100644 --- a/packages/slate-editor/src/modules/editor/plugins/index.ts +++ b/packages/slate-editor/src/modules/editor/plugins/index.ts @@ -4,4 +4,4 @@ export { type ElementsEqualityCheckEditor, withElementsEqualityCheck, } from './withElementsEqualityCheck'; -export { type RichBlocksAwareEditor, withRichBlocks } from './withRichBlocks'; +export { RichBlocksPlugin } from './RichBlocksPlugin'; diff --git a/packages/slate-editor/src/modules/editor/plugins/withRichBlocks.ts b/packages/slate-editor/src/modules/editor/plugins/withRichBlocks.ts deleted file mode 100644 index 7b3b173e3..000000000 --- a/packages/slate-editor/src/modules/editor/plugins/withRichBlocks.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Extension } from '@prezly/slate-commons'; -import type { SlateEditor } from '@udecode/plate-common'; -import type { Node } from 'slate'; - -export interface RichBlocksAwareEditor { - isRichBlock(node: Node): boolean; -} - -export function withRichBlocks(getExtensions: () => Extension[]) { - return function (editor: T): T & RichBlocksAwareEditor { - function isRichBlock(node: Node) { - for (const extension of getExtensions()) { - if (extension.isRichBlock?.(node)) return true; - } - return false; - } - - return Object.assign(editor, { - isRichBlock, - }); - }; -} From 9ca2049b4ac82731341d741a9bc02f93aefdb1fe Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 19:18:19 +0100 Subject: [PATCH 4/7] [DEV-19130] Make `withDefaultTextBlock` a Plate Plugin --- packages/slate-editor/src/index.ts | 10 +++----- .../src/modules/editor/createEditor.ts | 8 +++++-- .../slate-editor/src/modules/editor/index.ts | 8 ++----- .../editor/plugins/DefaultTextBlockPlugin.ts | 24 +++++++++++++++++++ .../src/modules/editor/plugins/index.ts | 2 +- .../editor/plugins/withDefaultTextBlock.ts | 18 -------------- 6 files changed, 36 insertions(+), 34 deletions(-) create mode 100644 packages/slate-editor/src/modules/editor/plugins/DefaultTextBlockPlugin.ts delete mode 100644 packages/slate-editor/src/modules/editor/plugins/withDefaultTextBlock.ts diff --git a/packages/slate-editor/src/index.ts b/packages/slate-editor/src/index.ts index faa4d8918..d7558005f 100644 --- a/packages/slate-editor/src/index.ts +++ b/packages/slate-editor/src/index.ts @@ -22,18 +22,14 @@ export { type ResultPromise, type UploadcareOptions, withUploadcare } from './mo // Editor type -import type { ElementNode, ParagraphNode, TextNode } from '@prezly/slate-types'; +import type { ElementNode, TextNode } from '@prezly/slate-types'; import type { BaseEditor } from 'slate'; import type { HistoryEditor } from 'slate-history'; import type { FlashEditor } from '#extensions/flash-nodes'; -import type { DefaultTextBlockEditor, ElementsEqualityCheckEditor } from '#modules/editor'; +import type { ElementsEqualityCheckEditor } from '#modules/editor'; -type Editor = BaseEditor & - HistoryEditor & - DefaultTextBlockEditor & - ElementsEqualityCheckEditor & - FlashEditor; +type Editor = BaseEditor & HistoryEditor & ElementsEqualityCheckEditor & FlashEditor; declare module 'slate' { interface CustomTypes { diff --git a/packages/slate-editor/src/modules/editor/createEditor.ts b/packages/slate-editor/src/modules/editor/createEditor.ts index 0c6bbd93e..92eb38653 100644 --- a/packages/slate-editor/src/modules/editor/createEditor.ts +++ b/packages/slate-editor/src/modules/editor/createEditor.ts @@ -16,7 +16,7 @@ import { createParagraph } from '#extensions/paragraphs'; import { withNodesHierarchy, hierarchySchema } from '#modules/nodes-hierarchy'; import { - withDefaultTextBlock, + DefaultTextBlockPlugin, withDeserializeHtml, withElementsEqualityCheck, RichBlocksPlugin, @@ -48,6 +48,11 @@ export function createEditor({ editor, plugins: [ ...plugins, + DefaultTextBlockPlugin.configure({ + options: { + createDefaultTextBlock: createParagraph, + }, + }), RichBlocksPlugin.configure({ options: { getExtensions }, }), @@ -64,7 +69,6 @@ export function createEditor({ withNodesHierarchy(hierarchySchema), withBreaksOnExpandedSelection, withBreaksOnVoidNodes, - withDefaultTextBlock(createParagraph), withInlineVoid(getExtensions), withNormalization(getExtensions), withUserFriendlyDeleteBehavior, diff --git a/packages/slate-editor/src/modules/editor/index.ts b/packages/slate-editor/src/modules/editor/index.ts index cdfe168d8..e11500fd4 100644 --- a/packages/slate-editor/src/modules/editor/index.ts +++ b/packages/slate-editor/src/modules/editor/index.ts @@ -1,11 +1,7 @@ export { Editor } from './Editor'; export { createEditor } from './createEditor'; export { createEmptyValue } from './lib'; -export { withDefaultTextBlock, withDeserializeHtml, withElementsEqualityCheck } from './plugins'; -export type { - DefaultTextBlockEditor, - ElementsEqualityCheckEditor, - RichBlocksAwareEditor, -} from './plugins'; +export { DefaultTextBlockPlugin, withDeserializeHtml, withElementsEqualityCheck } from './plugins'; +export type { ElementsEqualityCheckEditor } from './plugins'; export type { EditorRef, EditorProps, Value } from './types'; export { useEditorEvents } from './useEditorEvents'; diff --git a/packages/slate-editor/src/modules/editor/plugins/DefaultTextBlockPlugin.ts b/packages/slate-editor/src/modules/editor/plugins/DefaultTextBlockPlugin.ts new file mode 100644 index 000000000..ec425f6d7 --- /dev/null +++ b/packages/slate-editor/src/modules/editor/plugins/DefaultTextBlockPlugin.ts @@ -0,0 +1,24 @@ +import { type TElement } from '@udecode/plate'; +import { createPlatePlugin } from '@udecode/plate/react'; + +type TextBlockFactory = (props?: Partial) => T; + +type Options = { + createDefaultTextBlock(): TextBlockFactory; +}; + +export const DefaultTextBlockPlugin = { + configure(config: { options: Options }) { + return createPlatePlugin<'DefaultTextBlock', Options>({ + key: 'DefaultTextBlock', + options: config.options, + }).overrideEditor(({ getOptions }) => { + const { createDefaultTextBlock } = getOptions(); + return { + api: { + createDefaultTextBlock, + }, + }; + }); + }, +}; diff --git a/packages/slate-editor/src/modules/editor/plugins/index.ts b/packages/slate-editor/src/modules/editor/plugins/index.ts index 5a9eda00c..c0a182984 100644 --- a/packages/slate-editor/src/modules/editor/plugins/index.ts +++ b/packages/slate-editor/src/modules/editor/plugins/index.ts @@ -1,4 +1,4 @@ -export { type DefaultTextBlockEditor, withDefaultTextBlock } from './withDefaultTextBlock'; +export { DefaultTextBlockPlugin } from './DefaultTextBlockPlugin'; export { withDeserializeHtml } from './withDeserializeHtml'; export { type ElementsEqualityCheckEditor, diff --git a/packages/slate-editor/src/modules/editor/plugins/withDefaultTextBlock.ts b/packages/slate-editor/src/modules/editor/plugins/withDefaultTextBlock.ts deleted file mode 100644 index cd3b13179..000000000 --- a/packages/slate-editor/src/modules/editor/plugins/withDefaultTextBlock.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { SlateEditor } from '@udecode/plate-common'; -import type { Element } from 'slate'; - -type TextBlockFactory = (props?: Partial) => T; - -export interface DefaultTextBlockEditor { - createDefaultTextBlock: TextBlockFactory; -} - -export function withDefaultTextBlock( - createDefaultTextBlock: TextBlockFactory, -) { - return function (editor: E): E & DefaultTextBlockEditor { - return Object.assign(editor, { - createDefaultTextBlock, - }); - }; -} From e05f4c3e28e01cb15294176e41a4d7024a6b3834 Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 19:23:31 +0100 Subject: [PATCH 5/7] [DEV-19130] Make `withElementsEqualityCheck` a Plate Plugin --- packages/slate-editor/src/index.ts | 3 +- .../src/modules/editor/createEditor.ts | 4 +-- .../slate-editor/src/modules/editor/index.ts | 2 -- ...heck.ts => ElementsEqualityCheckPlugin.ts} | 33 +++++++------------ .../src/modules/editor/plugins/index.ts | 7 ++-- 5 files changed, 16 insertions(+), 33 deletions(-) rename packages/slate-editor/src/modules/editor/plugins/{withElementsEqualityCheck.ts => ElementsEqualityCheckPlugin.ts} (84%) diff --git a/packages/slate-editor/src/index.ts b/packages/slate-editor/src/index.ts index d7558005f..a7de7a05e 100644 --- a/packages/slate-editor/src/index.ts +++ b/packages/slate-editor/src/index.ts @@ -27,9 +27,8 @@ import type { BaseEditor } from 'slate'; import type { HistoryEditor } from 'slate-history'; import type { FlashEditor } from '#extensions/flash-nodes'; -import type { ElementsEqualityCheckEditor } from '#modules/editor'; -type Editor = BaseEditor & HistoryEditor & ElementsEqualityCheckEditor & FlashEditor; +type Editor = BaseEditor & HistoryEditor & FlashEditor; declare module 'slate' { interface CustomTypes { diff --git a/packages/slate-editor/src/modules/editor/createEditor.ts b/packages/slate-editor/src/modules/editor/createEditor.ts index 92eb38653..ca863fffe 100644 --- a/packages/slate-editor/src/modules/editor/createEditor.ts +++ b/packages/slate-editor/src/modules/editor/createEditor.ts @@ -18,8 +18,8 @@ import { withNodesHierarchy, hierarchySchema } from '#modules/nodes-hierarchy'; import { DefaultTextBlockPlugin, withDeserializeHtml, - withElementsEqualityCheck, RichBlocksPlugin, + ElementsEqualityCheckPlugin, } from './plugins'; import { type Value } from './types'; @@ -53,6 +53,7 @@ export function createEditor({ createDefaultTextBlock: createParagraph, }, }), + ElementsEqualityCheckPlugin, RichBlocksPlugin.configure({ options: { getExtensions }, }), @@ -73,7 +74,6 @@ export function createEditor({ withNormalization(getExtensions), withUserFriendlyDeleteBehavior, withDeserializeHtml(getExtensions), - withElementsEqualityCheck, ...extensionsOverrides, ])(baseEditor); } diff --git a/packages/slate-editor/src/modules/editor/index.ts b/packages/slate-editor/src/modules/editor/index.ts index e11500fd4..4299e70a8 100644 --- a/packages/slate-editor/src/modules/editor/index.ts +++ b/packages/slate-editor/src/modules/editor/index.ts @@ -1,7 +1,5 @@ export { Editor } from './Editor'; export { createEditor } from './createEditor'; export { createEmptyValue } from './lib'; -export { DefaultTextBlockPlugin, withDeserializeHtml, withElementsEqualityCheck } from './plugins'; -export type { ElementsEqualityCheckEditor } from './plugins'; export type { EditorRef, EditorProps, Value } from './types'; export { useEditorEvents } from './useEditorEvents'; diff --git a/packages/slate-editor/src/modules/editor/plugins/withElementsEqualityCheck.ts b/packages/slate-editor/src/modules/editor/plugins/ElementsEqualityCheckPlugin.ts similarity index 84% rename from packages/slate-editor/src/modules/editor/plugins/withElementsEqualityCheck.ts rename to packages/slate-editor/src/modules/editor/plugins/ElementsEqualityCheckPlugin.ts index aa238e549..c829c2632 100644 --- a/packages/slate-editor/src/modules/editor/plugins/withElementsEqualityCheck.ts +++ b/packages/slate-editor/src/modules/editor/plugins/ElementsEqualityCheckPlugin.ts @@ -10,32 +10,21 @@ import { VideoNode, } from '@prezly/slate-types'; import { isEqual } from '@technically/lodash'; -import type { SlateEditor } from '@udecode/plate-common'; -import type { Element } from 'slate'; +import type { Element } from '@udecode/plate'; +import { createPlatePlugin } from '@udecode/plate/react'; import { EmbedNode } from '#extensions/embed'; import { PlaceholderNode } from '#extensions/placeholders'; -export interface ElementsEqualityCheckEditor { - /** - * Compare two elements. - * - * This is useful to implement smarter comparison rules to, - * for example, ignore data-independent properties like `uuid`. - * - * `children` arrays can be omitted from the comparison, - * as the outer code will compare them anyway. - */ - isElementEqual(node: Element, another: Element): boolean | undefined; -} - -export function withElementsEqualityCheck( - editor: T, -): T & ElementsEqualityCheckEditor { - return Object.assign(editor, { - isElementEqual, - }); -} +export const ElementsEqualityCheckPlugin = createPlatePlugin({ + key: 'withElementsEqualityCheck', +}).overrideEditor(() => { + return { + api: { + isElementEqual, + }, + }; +}); function isElementEqual(node: Element, another: Element): boolean | undefined { if (isAttachmentNode(node) && isAttachmentNode(another)) { diff --git a/packages/slate-editor/src/modules/editor/plugins/index.ts b/packages/slate-editor/src/modules/editor/plugins/index.ts index c0a182984..262a87357 100644 --- a/packages/slate-editor/src/modules/editor/plugins/index.ts +++ b/packages/slate-editor/src/modules/editor/plugins/index.ts @@ -1,7 +1,4 @@ export { DefaultTextBlockPlugin } from './DefaultTextBlockPlugin'; -export { withDeserializeHtml } from './withDeserializeHtml'; -export { - type ElementsEqualityCheckEditor, - withElementsEqualityCheck, -} from './withElementsEqualityCheck'; +export { ElementsEqualityCheckPlugin } from './ElementsEqualityCheckPlugin'; export { RichBlocksPlugin } from './RichBlocksPlugin'; +export { withDeserializeHtml } from './withDeserializeHtml'; From 94a3fd8fc4aec75bb8baf42fff246a00bc8f467e Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 19:26:08 +0100 Subject: [PATCH 6/7] [DEV-19130] Fix `slate-types` --- packages/slate-types/src/nodes/ElementNode.ts | 2 +- packages/slate-types/src/nodes/TableNode.ts | 9 ++++----- packages/slate-types/src/nodes/TextNode.ts | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/slate-types/src/nodes/ElementNode.ts b/packages/slate-types/src/nodes/ElementNode.ts index ebf19076f..288387ee0 100644 --- a/packages/slate-types/src/nodes/ElementNode.ts +++ b/packages/slate-types/src/nodes/ElementNode.ts @@ -1,4 +1,4 @@ -import type { TElement } from '@udecode/plate-common'; +import type { TElement } from '@udecode/plate'; import { isObject } from './validation'; diff --git a/packages/slate-types/src/nodes/TableNode.ts b/packages/slate-types/src/nodes/TableNode.ts index cecd7cbc0..3c92e98ed 100644 --- a/packages/slate-types/src/nodes/TableNode.ts +++ b/packages/slate-types/src/nodes/TableNode.ts @@ -1,5 +1,4 @@ -import type { TNode } from '@udecode/plate-common'; -import type { Node } from 'slate'; +import type { TNode } from '@udecode/plate'; import { type ElementNode, isElementNode } from './ElementNode'; @@ -27,14 +26,14 @@ export interface TableCellNode extends ElementNode { colspan?: number; } -export function isTableNode(value: Node | TNode): value is TableNode { +export function isTableNode(value: TNode): value is TableNode { return isElementNode(value, TABLE_NODE_TYPE); } -export function isTableCellNode(value: Node | TNode): value is TableCellNode { +export function isTableCellNode(value: TNode): value is TableCellNode { return isElementNode(value, TABLE_CELL_NODE_TYPE); } -export function isTableRowNode(value: Node | TNode): value is TableRowNode { +export function isTableRowNode(value: TNode): value is TableRowNode { return isElementNode(value, TABLE_ROW_NODE_TYPE); } diff --git a/packages/slate-types/src/nodes/TextNode.ts b/packages/slate-types/src/nodes/TextNode.ts index 3c84b60b5..a504e0165 100644 --- a/packages/slate-types/src/nodes/TextNode.ts +++ b/packages/slate-types/src/nodes/TextNode.ts @@ -1,11 +1,10 @@ -import type { TText } from '@udecode/plate-common'; -import type { Node } from 'slate'; +import type { TText, TNode } from '@udecode/plate'; import type { Stylable } from './interfaces'; import { isObject } from './validation'; export interface TextNode extends TText, Stylable {} -export function isTextNode(node: Node): node is TextNode { +export function isTextNode(node: TNode): node is TextNode { return isObject(node) && 'text' in node; } From 2a625480dd2b1a020375a81908d471a50967a128 Mon Sep 17 00:00:00 2001 From: Ivan Voskoboinyk Date: Wed, 15 Jan 2025 22:11:41 +0100 Subject: [PATCH 7/7] [DEV-19130] Drop `plate-common` dependency from the root package All references are now replaced with `/plate` --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 62a7e2364..a12986d21 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", "@udecode/plate": "^42.1.2", - "@udecode/plate-common": "^42.0.0", "react": "^18.3.0", "react-dom": "^18.3.0" },