From cef1cb30cce20ec98472cb2389bd0d9b0a9a4cf0 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 4 Sep 2024 14:05:18 +0200 Subject: [PATCH 01/12] fix --- .../default/example/hundreds-editors-demo.tsx | 7 ++---- .../core/src/lib/plugin/createSlatePlugin.ts | 8 ++---- packages/core/src/lib/utils/resolvePlugin.ts | 9 ++++++- packages/core/src/lib/utils/resolvePlugins.ts | 25 +++++++++++-------- .../core/src/react/editor/usePlateEditor.ts | 11 +++++++- .../react/stores/plate/createPlateStore.ts | 3 +-- .../stores/plate/selectors/useEditorRef.ts | 14 +++++++---- 7 files changed, 46 insertions(+), 31 deletions(-) diff --git a/apps/www/src/registry/default/example/hundreds-editors-demo.tsx b/apps/www/src/registry/default/example/hundreds-editors-demo.tsx index a0b9c20dcd..8d7976c674 100644 --- a/apps/www/src/registry/default/example/hundreds-editors-demo.tsx +++ b/apps/www/src/registry/default/example/hundreds-editors-demo.tsx @@ -1,11 +1,8 @@ import React from 'react'; -import { BasicElementsPlugin } from '@udecode/plate-basic-elements/react'; -import { BasicMarksPlugin } from '@udecode/plate-basic-marks/react'; import { Plate, usePlateEditor } from '@udecode/plate-common/react'; import { editableProps } from '@/plate/demo/editableProps'; -import { PlateUI } from '@/plate/demo/plate-ui'; import { createMultiEditorsValue } from '@/plate/demo/values/createMultiEditorsValue'; import { Editor } from '@/registry/default/plate-ui/editor'; @@ -14,8 +11,8 @@ const values = createMultiEditorsValue(); function WithPlate({ id, value }: any) { const editor = usePlateEditor({ id, - override: { components: PlateUI }, - plugins: [BasicElementsPlugin, BasicMarksPlugin], + // override: { components: PlateUI }, + // plugins: [BasicElementsPlugin, BasicMarksPlugin], value, }); diff --git a/packages/core/src/lib/plugin/createSlatePlugin.ts b/packages/core/src/lib/plugin/createSlatePlugin.ts index e54def724a..744559cfaa 100644 --- a/packages/core/src/lib/plugin/createSlatePlugin.ts +++ b/packages/core/src/lib/plugin/createSlatePlugin.ts @@ -1,8 +1,5 @@ import type { Modify } from '@udecode/utils'; -import cloneDeep from 'lodash/cloneDeep.js'; -import merge from 'lodash/merge.js'; - import type { SlateEditor } from '../editor/SlateEditor'; import type { AnyPluginConfig, PluginConfig } from './BasePlugin'; import type { @@ -111,8 +108,7 @@ export function createSlatePlugin< const key = baseConfig.key ?? ''; - const plugin = merge( - {}, + const plugin = mergeWithoutArray( { __apiExtensions: [], __configuration: null, @@ -135,7 +131,7 @@ export function createSlatePlugin< shortcuts: {}, transforms: {}, }, - cloneDeep(config) + config ) as unknown as SlatePlugin>; plugin.configure = (config) => { diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index a26db685c9..3eb7b44b4e 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -24,6 +24,11 @@ export const resolvePlugin =

( editor: SlateEditor, _plugin: P ): P => { + if (_plugin.key === 'p' && editor.id === 2) { + // Minimize the number of calls + console.log(editor.key, _plugin.key); + } + // Create a deep clone of the plugin let plugin = createSlatePlugin(_plugin) as P; @@ -51,7 +56,9 @@ export const resolvePlugin =

( plugin.__extensions = []; } if (plugin.plugins) { - plugin.plugins = plugin.plugins.map((p) => resolvePlugin(editor, p)); + plugin.plugins = plugin.plugins.map((p) => { + return resolvePlugin(editor, p); + }); } const targetPluginToInject = plugin.inject?.targetPluginToInject; diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index 7e4c9a8e8d..6695815ba3 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -179,21 +179,26 @@ const resolvePluginApis = (editor: SlateEditor) => { ); }; -const flattenAndMergePlugins = ( +const flattenAndResolvePlugins = ( + editor: SlateEditor, plugins: SlatePlugins ): Map => { const pluginMap = new Map(); const processPlugin = (plugin: SlatePlugin) => { - const existingPlugin = pluginMap.get(plugin.key); + const resolvedPlugin = resolvePlugin(editor, plugin); + const existingPlugin = pluginMap.get(resolvedPlugin.key); if (existingPlugin) { - pluginMap.set(plugin.key, mergeWithoutArray({}, existingPlugin, plugin)); + pluginMap.set( + resolvedPlugin.key, + mergeWithoutArray({}, existingPlugin, resolvedPlugin) + ); } else { - pluginMap.set(plugin.key, plugin); + pluginMap.set(resolvedPlugin.key, resolvedPlugin); } - if (plugin.plugins && plugin.plugins.length > 0) { - plugin.plugins.forEach(processPlugin); + if (resolvedPlugin.plugins && resolvedPlugin.plugins.length > 0) { + resolvedPlugin.plugins.forEach(processPlugin); } }; @@ -207,19 +212,17 @@ export const resolveAndSortPlugins = ( plugins: SlatePlugins ): SlatePlugins => { // Step 1: Resolve, flatten, and merge all plugins - const pluginMap = flattenAndMergePlugins( - plugins.map((plugin) => resolvePlugin(editor, plugin)) - ); + const pluginMap = flattenAndResolvePlugins(editor, plugins); // Step 2: Filter out disabled plugins const enabledPlugins = Array.from(pluginMap.values()).filter( (plugin) => plugin.enabled !== false ); - // Step 4: Sort plugins by priority + // Step 3: Sort plugins by priority enabledPlugins.sort((a, b) => b.priority - a.priority); - // Step 5: Reorder based on dependencies + // Step 4: Reorder based on dependencies const orderedPlugins: SlatePlugins = []; const visited = new Set(); diff --git a/packages/core/src/react/editor/usePlateEditor.ts b/packages/core/src/react/editor/usePlateEditor.ts index 7d6a24225c..e496499b4b 100644 --- a/packages/core/src/react/editor/usePlateEditor.ts +++ b/packages/core/src/react/editor/usePlateEditor.ts @@ -37,8 +37,17 @@ export function usePlateEditor< return React.useMemo( (): any => { if (options.enabled === false) return null; + if (options.id === 1) { + console.time('Editor'); + } - return createPlateEditor(options); + const editor = createPlateEditor(options); + + if (options.id === 1) { + console.timeEnd('Editor'); + } + + return editor; }, // eslint-disable-next-line react-hooks/exhaustive-deps [options.id, options.enabled, ...deps] diff --git a/packages/core/src/react/stores/plate/createPlateStore.ts b/packages/core/src/react/stores/plate/createPlateStore.ts index d09f1ce480..2730f7eded 100644 --- a/packages/core/src/react/stores/plate/createPlateStore.ts +++ b/packages/core/src/react/stores/plate/createPlateStore.ts @@ -8,7 +8,6 @@ import type { PlateEditor } from '../../editor/PlateEditor'; import type { PlateStoreState } from './PlateStore'; import { createAtomStore } from '../../libs'; -import { createPlateFallbackEditor } from '../../utils'; import { usePlateControllerEditorStore, usePlateControllerExists, @@ -20,7 +19,7 @@ export const GLOBAL_PLATE_SCOPE = Symbol('global-plate'); export const createPlateStore = ({ decorate = null, - editor = createPlateFallbackEditor() as E, + editor, id, isMounted = false, onChange = null, diff --git a/packages/core/src/react/stores/plate/selectors/useEditorRef.ts b/packages/core/src/react/stores/plate/selectors/useEditorRef.ts index b1c521248e..59aeea2775 100644 --- a/packages/core/src/react/stores/plate/selectors/useEditorRef.ts +++ b/packages/core/src/react/stores/plate/selectors/useEditorRef.ts @@ -1,5 +1,6 @@ import type { PlateEditor } from '../../../editor/PlateEditor'; +import { createPlateFallbackEditor } from '../../../utils'; import { type UsePlateEditorStoreOptions, usePlateSelectors, @@ -9,8 +10,11 @@ import { export const useEditorRef = ( id?: string, options: UsePlateEditorStoreOptions = {} -): E => - usePlateSelectors(id, { - debugHookName: 'useEditorRef', - ...options, - }).editor() as any; +): E => { + return ( + (usePlateSelectors(id, { + debugHookName: 'useEditorRef', + ...options, + }).editor() as E) ?? createPlateFallbackEditor() + ); +}; From 5ea38d094bc94cabc12123e55abe1d4aae088a6a Mon Sep 17 00:00:00 2001 From: zbeyens Date: Mon, 9 Sep 2024 21:08:34 +0200 Subject: [PATCH 02/12] wip --- .../default/example/playground-demo.tsx | 17 ++- packages/core/src/lib/editor/withSlate.ts | 8 ++ .../core/src/lib/plugin/getSlatePlugin.ts | 24 +++- packages/core/src/lib/utils/resolvePlugin.ts | 66 +++++++--- packages/core/src/lib/utils/resolvePlugins.ts | 91 +++++++++---- .../core/src/react/editor/usePlateEditor.ts | 9 +- yarn.lock | 124 +++++++++--------- 7 files changed, 216 insertions(+), 123 deletions(-) diff --git a/apps/www/src/registry/default/example/playground-demo.tsx b/apps/www/src/registry/default/example/playground-demo.tsx index bb63458c08..334788fc1a 100644 --- a/apps/www/src/registry/default/example/playground-demo.tsx +++ b/apps/www/src/registry/default/example/playground-demo.tsx @@ -62,7 +62,6 @@ import { SlashPlugin } from '@udecode/plate-slash-command'; import { TablePlugin } from '@udecode/plate-table/react'; import { TogglePlugin } from '@udecode/plate-toggle/react'; import { TrailingBlockPlugin } from '@udecode/plate-trailing-block'; -import Prism from 'prismjs'; import { CheckPlugin } from '@/components/context/check-plugin'; import { settingsStore } from '@/components/context/settings-store'; @@ -106,8 +105,9 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => { const key = settingsStore.use.version(); const editorId = id || 'playground-' + key; + console.time('usePlaygroundEditor'); - return usePlateEditor( + const a = usePlateEditor( { id: editorId, override: { @@ -121,11 +121,11 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => { // Nodes HeadingPlugin, BlockquotePlugin, - CodeBlockPlugin.configure({ - options: { - prism: Prism, - }, - }), + // CodeBlockPlugin.configure({ + // options: { + // prism: Prism, + // }, + // }), HorizontalRulePlugin, LinkPlugin.extend({ render: { afterEditable: () => }, @@ -315,6 +315,9 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => { }, [] ); + console.timeEnd('usePlaygroundEditor'); + + return a; }; export default function PlaygroundDemo({ diff --git a/packages/core/src/lib/editor/withSlate.ts b/packages/core/src/lib/editor/withSlate.ts index 3873a52bbd..25ffe8d160 100644 --- a/packages/core/src/lib/editor/withSlate.ts +++ b/packages/core/src/lib/editor/withSlate.ts @@ -102,6 +102,8 @@ export const withSlate = < ...pluginConfig }: WithSlateOptions = {} ): TSlateEditor> => { + console.time('withSlate'); + const editor = e as SlateEditor; // Override incremental id generated by slate @@ -188,7 +190,9 @@ export const withSlate = < rootPluginInstance = rootPlugin(rootPluginInstance) as any; } + console.time('resolvePlugins'); resolvePlugins(editor, [rootPluginInstance]); + console.timeEnd('resolvePlugins'); if (typeof value === 'string') { editor.children = editor.api.html.deserialize({ element: value }) as Value; @@ -210,9 +214,13 @@ export const withSlate = < pipeNormalizeInitialValue(editor); } if (shouldNormalizeEditor) { + console.time('normalizeEditor'); normalizeEditor(editor, { force: true }); + console.timeEnd('normalizeEditor'); } + console.timeEnd('withSlate'); + return editor as any; }; diff --git a/packages/core/src/lib/plugin/getSlatePlugin.ts b/packages/core/src/lib/plugin/getSlatePlugin.ts index 8037232aef..1366dba2c6 100644 --- a/packages/core/src/lib/plugin/getSlatePlugin.ts +++ b/packages/core/src/lib/plugin/getSlatePlugin.ts @@ -6,8 +6,6 @@ import type { } from './BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from './SlatePlugin'; -import { resolvePlugin } from '../utils'; - /** Get editor plugin by key or plugin object. */ export function getSlatePlugin( editor: SlateEditor, @@ -22,7 +20,27 @@ export function getSlatePlugin( const editorPlugin = editor.plugins[p.key] as any; if (!editorPlugin) { - return plugin.__resolved ? p : resolvePlugin(editor, plugin); + return { + __apiExtensions: [], + __configuration: null, + __extensions: [], + __optionExtensions: [], + dependencies: [], + editor: {}, + handlers: {}, + inject: {}, + node: {}, + override: {}, + parser: {}, + parsers: {}, + plugins: [], + priority: 100, + render: {}, + shortcuts: {}, + transforms: {}, + ...plugin, + }; + // return plugin.__resolved ? p : resolvePlugin(editor, plugin); } return editorPlugin; diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index 3eb7b44b4e..8061d76fa1 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -1,9 +1,11 @@ +import { cloneDeep } from 'lodash'; + import type { SlateEditor } from '../editor'; import type { PluginConfig } from '../plugin/BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from '../plugin/SlatePlugin'; -import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; -import { createSlatePlugin, getEditorPlugin } from '../plugin'; +import { getEditorPlugin } from '../plugin'; +import { mergeLevel } from './resolvePlugins'; /** * Resolves and finalizes a plugin configuration for use in a Plate editor. @@ -24,13 +26,38 @@ export const resolvePlugin =

( editor: SlateEditor, _plugin: P ): P => { - if (_plugin.key === 'p' && editor.id === 2) { - // Minimize the number of calls - console.log(editor.key, _plugin.key); - } + // if (_plugin.key === 'p') { + // // Minimize the number of calls + // console.log(editor.key, _plugin.key); + // } // Create a deep clone of the plugin - let plugin = createSlatePlugin(_plugin) as P; + let plugin = { + __apiExtensions: [], + __configuration: null, + __extensions: [], + __optionExtensions: [], + dependencies: [], + editor: {}, + handlers: {}, + inject: {}, + node: {}, + override: {}, + parser: {}, + parsers: {}, + plugins: [], + priority: 100, + render: {}, + shortcuts: {}, + transforms: {}, + ...(_plugin as any), + } as P; + + plugin.node = { type: plugin.key, ...(_plugin.node as any) }; + // plugin.api = mergeOneLevel(plugin.api, _plugin.api); + // plugin.options = mergeOneLevel(plugin.options, _plugin.options); + plugin.api = cloneDeep(_plugin.api); + plugin.options = cloneDeep(_plugin.options); plugin.__resolved = true; @@ -40,25 +67,25 @@ export const resolvePlugin =

( getEditorPlugin(editor, plugin as any) ); - plugin = mergeWithoutArray({}, plugin, configResult); + plugin = mergeLevel(plugin, configResult, 3); delete (plugin as any).__configuration; } // Apply all stored extensions if (plugin.__extensions && plugin.__extensions.length > 0) { plugin.__extensions.forEach((extension) => { - plugin = mergeWithoutArray( - {}, + plugin = mergeLevel( plugin, - extension(getEditorPlugin(editor, plugin as any)) + extension(getEditorPlugin(editor, plugin as any)), + 3 ); }); plugin.__extensions = []; } if (plugin.plugins) { - plugin.plugins = plugin.plugins.map((p) => { - return resolvePlugin(editor, p); - }); + // plugin.plugins = plugin.plugins.map((p) => { + // return resolvePlugin(editor, p); + // }); } const targetPluginToInject = plugin.inject?.targetPluginToInject; @@ -66,9 +93,8 @@ export const resolvePlugin =

( if (targetPluginToInject && targetPlugins && targetPlugins.length > 0) { plugin.inject = plugin.inject || {}; - plugin.inject.plugins = mergeWithoutArray( - {}, - plugin.inject.plugins, + plugin.inject.plugins = mergeLevel( + plugin.inject.plugins ?? {}, Object.fromEntries( targetPlugins.map((targetPlugin) => { const injectedPlugin = targetPluginToInject({ @@ -78,11 +104,13 @@ export const resolvePlugin =

( return [targetPlugin, injectedPlugin]; }) - ) + ), + 4 ); } + // PERF if (plugin.plugins) { - plugin.plugins = plugin.plugins.map((p) => resolvePlugin(editor, p)); + // plugin.plugins = plugin.plugins.map((p) => resolvePlugin(editor, p)); } // TODO React if ((plugin as any).node?.component) { diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index 6695815ba3..d52c717de4 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -1,9 +1,8 @@ -import { isDefined } from '@udecode/utils'; +import { type AnyObject, isDefined } from '@udecode/utils'; import { createZustandStore } from 'zustand-x'; import type { SlateEditor } from '../editor'; -import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; import { type SlatePlugin, type SlatePlugins, @@ -11,6 +10,47 @@ import { } from '../plugin'; import { resolvePlugin } from './resolvePlugin'; +export function mergeLevel( + target: T, + source: Partial, + levels = 1 +): T { + if (!target) { + target = {} as T; + } + + function mergeLevel( + targetObj: AnyObject, + sourceObj: AnyObject, + currentLevel: number + ) { + for (const key in sourceObj) { + if (Object.prototype.hasOwnProperty.call(sourceObj, key)) { + if ( + typeof sourceObj[key] === 'object' && + sourceObj[key] !== null && + !Array.isArray(sourceObj[key]) && + // TODO: levels should be used instead of 5 + currentLevel < 10 + ) { + if (currentLevel === 5) { + console.log('mergeLevel', sourceObj, key, currentLevel); + } + + targetObj[key] = targetObj[key] || {}; + mergeLevel(targetObj[key], sourceObj[key], currentLevel + 1); + } else { + targetObj[key] = sourceObj[key]; + } + } + } + } + + mergeLevel(target, source, 1); + + return target; +} + /** * Initialize and configure the editor's plugin system. This function sets up * the editor's plugins, resolving core and custom plugins, and applying any @@ -100,18 +140,20 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.transforms as any)[plugin.key] = {}; } - mergeWithoutArray( + mergeLevel( (editor.transforms as any)[plugin.key], - newExtensions + newExtensions, + 2 ); - mergeWithoutArray( + mergeLevel( (plugin.transforms as any)[plugin.key], - newExtensions + newExtensions, + 2 ); } else { // Editor-wide transform - mergeWithoutArray(editor.transforms, newExtensions); - mergeWithoutArray(plugin.transforms, newExtensions); + mergeLevel(editor.transforms, newExtensions, 2); + mergeLevel(plugin.transforms, newExtensions, 2); } } else { // Handle APIs @@ -124,12 +166,12 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.api as any)[plugin.key] = {}; } - mergeWithoutArray((editor.api as any)[plugin.key], newExtensions); - mergeWithoutArray((plugin.api as any)[plugin.key], newExtensions); + mergeLevel((editor.api as any)[plugin.key], newExtensions, 2); + mergeLevel((plugin.api as any)[plugin.key], newExtensions, 2); } else { // Editor-wide API - mergeWithoutArray(editor.api, newExtensions); - mergeWithoutArray(plugin.api, newExtensions); + mergeLevel(editor.api, newExtensions, 2); + mergeLevel(plugin.api, newExtensions, 2); } } } @@ -192,7 +234,8 @@ const flattenAndResolvePlugins = ( if (existingPlugin) { pluginMap.set( resolvedPlugin.key, - mergeWithoutArray({}, existingPlugin, resolvedPlugin) + mergeLevel(existingPlugin, resolvedPlugin, 3) + // resolvedPlugin ); } else { pluginMap.set(resolvedPlugin.key, resolvedPlugin); @@ -273,7 +316,7 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { // Collect all overrides for (const plugin of plugins) { if (plugin.override.enabled) { - mergeWithoutArray(enabledOverrides, plugin.override.enabled); + Object.assign(enabledOverrides, plugin.override.enabled); } // TODO react if ((plugin.override as any).components) { @@ -293,10 +336,10 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { } if (plugin.override.plugins) { Object.entries(plugin.override.plugins).forEach(([key, value]) => { - pluginOverrides[key] = mergeWithoutArray( - {}, - pluginOverrides[key], - value + pluginOverrides[key] = mergeLevel( + pluginOverrides[key] ?? {}, + value, + 3 ); if (value.enabled !== undefined) { @@ -312,11 +355,7 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { // Apply plugin overrides if (pluginOverrides[p.key]) { - updatedPlugin = mergeWithoutArray( - {}, - updatedPlugin, - pluginOverrides[p.key] - ); + updatedPlugin = mergeLevel(updatedPlugin, pluginOverrides[p.key], 3); } // Apply component overrides // TODO react @@ -352,9 +391,9 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { editor.pluginList = applyOverrides(editor.pluginList as any); // Final pass: ensure all plugins are properly resolved after overrides - editor.pluginList = editor.pluginList.map((plugin) => - resolvePlugin(editor, plugin as any) - ); + // editor.pluginList = editor.pluginList.map((plugin) => + // resolvePlugin(editor, plugin as any) + // ); editor.plugins = Object.fromEntries( editor.pluginList.map((plugin) => [plugin.key, plugin]) ); diff --git a/packages/core/src/react/editor/usePlateEditor.ts b/packages/core/src/react/editor/usePlateEditor.ts index e496499b4b..9a609d2e70 100644 --- a/packages/core/src/react/editor/usePlateEditor.ts +++ b/packages/core/src/react/editor/usePlateEditor.ts @@ -36,16 +36,13 @@ export function usePlateEditor< : TPlateEditor | null { return React.useMemo( (): any => { + console.time('createPlateEditor'); + if (options.enabled === false) return null; - if (options.id === 1) { - console.time('Editor'); - } const editor = createPlateEditor(options); - if (options.id === 1) { - console.timeEnd('Editor'); - } + console.timeEnd('createPlateEditor'); return editor; }, diff --git a/yarn.lock b/yarn.lock index f342b660d2..3cf292f2ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5826,7 +5826,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5843,7 +5843,7 @@ __metadata: "@udecode/plate-common": "workspace:^" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5862,7 +5862,7 @@ __metadata: "@udecode/plate-common": "workspace:^" "@udecode/plate-heading": "npm:37.0.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5878,7 +5878,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5894,7 +5894,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5910,7 +5910,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5926,7 +5926,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5943,7 +5943,7 @@ __metadata: "@udecode/plate-common": "workspace:^" react-textarea-autosize: "npm:^8.5.3" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5962,7 +5962,7 @@ __metadata: delay: "npm:5.0.0" p-defer: "npm:^3.0.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5979,7 +5979,7 @@ __metadata: "@udecode/plate-common": "workspace:^" prismjs: "npm:^1.29.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -5996,7 +5996,7 @@ __metadata: "@udecode/plate-common": "workspace:^" downshift: "npm:^6.1.12" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6013,7 +6013,7 @@ __metadata: "@udecode/plate-common": "workspace:^" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6023,12 +6023,12 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-common@npm:37.0.4, @udecode/plate-common@workspace:^, @udecode/plate-common@workspace:packages/common": +"@udecode/plate-common@npm:37.0.7, @udecode/plate-common@workspace:^, @udecode/plate-common@workspace:packages/common": version: 0.0.0-use.local resolution: "@udecode/plate-common@workspace:packages/common" dependencies: - "@udecode/plate-core": "npm:37.0.4" - "@udecode/plate-utils": "npm:37.0.4" + "@udecode/plate-core": "npm:37.0.7" + "@udecode/plate-utils": "npm:37.0.7" "@udecode/react-hotkeys": "npm:37.0.0" "@udecode/react-utils": "npm:37.0.0" "@udecode/slate": "npm:37.0.0" @@ -6045,7 +6045,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-core@npm:37.0.4, @udecode/plate-core@workspace:^, @udecode/plate-core@workspace:packages/core": +"@udecode/plate-core@npm:37.0.7, @udecode/plate-core@workspace:^, @udecode/plate-core@workspace:packages/core": version: 0.0.0-use.local resolution: "@udecode/plate-core@workspace:packages/core" dependencies: @@ -6085,7 +6085,7 @@ __metadata: "@udecode/plate-table": "npm:37.0.0" papaparse: "npm:^5.4.1" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6101,7 +6101,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6117,7 +6117,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.94.0" @@ -6135,7 +6135,7 @@ __metadata: diff-match-patch-ts: "npm:^0.6.0" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6153,7 +6153,7 @@ __metadata: lodash: "npm:^4.17.21" raf: "npm:^3.4.1" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dnd: ">=14.0.0" react-dnd-html5-backend: ">=14.0.0" @@ -6177,7 +6177,7 @@ __metadata: "@udecode/plate-table": "npm:37.0.0" validator: "npm:^13.11.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6195,7 +6195,7 @@ __metadata: "@udecode/plate-combobox": "npm:37.0.0" "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6212,7 +6212,7 @@ __metadata: "@excalidraw/excalidraw": "npm:0.16.4" "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6228,7 +6228,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6246,7 +6246,7 @@ __metadata: "@floating-ui/react": "npm:^0.22.3" "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6263,7 +6263,7 @@ __metadata: "@udecode/plate-common": "workspace:^" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6279,7 +6279,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6295,7 +6295,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6311,7 +6311,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6329,7 +6329,7 @@ __metadata: "@udecode/plate-common": "workspace:^" html-entities: "npm:^2.5.2" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6348,7 +6348,7 @@ __metadata: "@udecode/plate-list": "npm:37.0.0" clsx: "npm:^1.2.1" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6364,7 +6364,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6381,7 +6381,7 @@ __metadata: "@udecode/plate-common": "workspace:^" juice: "npm:^8.1.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6397,7 +6397,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6413,7 +6413,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6429,7 +6429,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6447,7 +6447,7 @@ __metadata: "@udecode/plate-floating": "npm:37.0.3" "@udecode/plate-normalizers": "npm:37.0.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6465,7 +6465,7 @@ __metadata: "@udecode/plate-reset-node": "npm:37.0.0" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6484,7 +6484,7 @@ __metadata: remark-parse: "npm:^9.0.0" unified: "npm:^9.2.2" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6502,7 +6502,7 @@ __metadata: "@udecode/plate-common": "workspace:^" katex: "npm:0.16.10" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6519,7 +6519,7 @@ __metadata: "@udecode/plate-common": "workspace:^" js-video-url-parser: "npm:^0.5.1" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6536,7 +6536,7 @@ __metadata: "@udecode/plate-combobox": "npm:37.0.0" "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6553,7 +6553,7 @@ __metadata: "@udecode/plate-common": "workspace:^" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6570,7 +6570,7 @@ __metadata: "@udecode/plate-common": "workspace:^" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6587,7 +6587,7 @@ __metadata: "@udecode/plate-common": "workspace:^" peerDependencies: "@playwright/test": ">=1.42.1" - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6603,7 +6603,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6619,7 +6619,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6635,7 +6635,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6645,14 +6645,14 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-selection@npm:37.0.0, @udecode/plate-selection@workspace:^, @udecode/plate-selection@workspace:packages/selection": +"@udecode/plate-selection@npm:37.0.6, @udecode/plate-selection@workspace:^, @udecode/plate-selection@workspace:packages/selection": version: 0.0.0-use.local resolution: "@udecode/plate-selection@workspace:packages/selection" dependencies: "@udecode/plate-common": "workspace:^" copy-to-clipboard: "npm:^3.3.3" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6669,7 +6669,7 @@ __metadata: "@udecode/plate-combobox": "npm:37.0.0" "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6687,7 +6687,7 @@ __metadata: "@udecode/plate-diff": "npm:37.0.0" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6704,7 +6704,7 @@ __metadata: "@udecode/plate-common": "workspace:^" tabbable: "npm:^6.2.0" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6722,7 +6722,7 @@ __metadata: "@udecode/plate-resizable": "npm:37.0.0" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6749,7 +6749,7 @@ __metadata: "@udecode/plate-node-id": "npm:37.0.0" lodash: "npm:^4.17.21" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6765,7 +6765,7 @@ __metadata: dependencies: "@udecode/plate-common": "workspace:^" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6806,11 +6806,11 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-utils@npm:37.0.4, @udecode/plate-utils@workspace:^, @udecode/plate-utils@workspace:packages/plate-utils": +"@udecode/plate-utils@npm:37.0.7, @udecode/plate-utils@workspace:^, @udecode/plate-utils@workspace:packages/plate-utils": version: 0.0.0-use.local resolution: "@udecode/plate-utils@workspace:packages/plate-utils" dependencies: - "@udecode/plate-core": "npm:37.0.4" + "@udecode/plate-core": "npm:37.0.7" "@udecode/react-utils": "npm:37.0.0" "@udecode/slate": "npm:37.0.0" "@udecode/slate-react": "npm:37.0.0" @@ -6837,7 +6837,7 @@ __metadata: "@udecode/plate-common": "workspace:^" yjs: "npm:^13.6.14" peerDependencies: - "@udecode/plate-common": ">=37.0.4" + "@udecode/plate-common": ">=37.0.7" react: ">=16.8.0" react-dom: ">=16.8.0" slate: ">=0.103.0" @@ -6860,7 +6860,7 @@ __metadata: "@udecode/plate-code-block": "npm:37.0.0" "@udecode/plate-combobox": "npm:37.0.0" "@udecode/plate-comments": "npm:37.0.0" - "@udecode/plate-common": "npm:37.0.4" + "@udecode/plate-common": "npm:37.0.7" "@udecode/plate-csv": "npm:37.0.0" "@udecode/plate-diff": "npm:37.0.0" "@udecode/plate-docx": "npm:37.0.0" @@ -6886,7 +6886,7 @@ __metadata: "@udecode/plate-reset-node": "npm:37.0.0" "@udecode/plate-resizable": "npm:37.0.0" "@udecode/plate-select": "npm:37.0.0" - "@udecode/plate-selection": "npm:37.0.0" + "@udecode/plate-selection": "npm:37.0.6" "@udecode/plate-slash-command": "npm:37.0.0" "@udecode/plate-suggestion": "npm:37.0.0" "@udecode/plate-tabbable": "npm:37.0.0" From 0f5f092838c10d6cbb467a1343231c423747947c Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 10 Sep 2024 10:44:08 +0200 Subject: [PATCH 03/12] fix --- .../core/src/lib/plugin/getSlatePlugin.ts | 44 ++++++++++--------- packages/core/src/lib/utils/resolvePlugin.ts | 25 ++++++----- packages/core/src/lib/utils/resolvePlugins.ts | 37 ++++++++-------- 3 files changed, 55 insertions(+), 51 deletions(-) diff --git a/packages/core/src/lib/plugin/getSlatePlugin.ts b/packages/core/src/lib/plugin/getSlatePlugin.ts index 1366dba2c6..850d37d7d0 100644 --- a/packages/core/src/lib/plugin/getSlatePlugin.ts +++ b/packages/core/src/lib/plugin/getSlatePlugin.ts @@ -6,6 +6,8 @@ import type { } from './BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from './SlatePlugin'; +import { resolvePlugin } from '../utils'; + /** Get editor plugin by key or plugin object. */ export function getSlatePlugin( editor: SlateEditor, @@ -20,26 +22,28 @@ export function getSlatePlugin( const editorPlugin = editor.plugins[p.key] as any; if (!editorPlugin) { - return { - __apiExtensions: [], - __configuration: null, - __extensions: [], - __optionExtensions: [], - dependencies: [], - editor: {}, - handlers: {}, - inject: {}, - node: {}, - override: {}, - parser: {}, - parsers: {}, - plugins: [], - priority: 100, - render: {}, - shortcuts: {}, - transforms: {}, - ...plugin, - }; + return plugin.__resolved ? p : resolvePlugin(editor, plugin); + + // return { + // __apiExtensions: [], + // __configuration: null, + // __extensions: [], + // __optionExtensions: [], + // dependencies: [], + // editor: {}, + // handlers: {}, + // inject: {}, + // node: {}, + // override: {}, + // parser: {}, + // parsers: {}, + // plugins: [], + // priority: 100, + // render: {}, + // shortcuts: {}, + // transforms: {}, + // ...plugin, + // }; // return plugin.__resolved ? p : resolvePlugin(editor, plugin); } diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index 8061d76fa1..a41fd4c06d 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -4,8 +4,8 @@ import type { SlateEditor } from '../editor'; import type { PluginConfig } from '../plugin/BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from '../plugin/SlatePlugin'; +import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; import { getEditorPlugin } from '../plugin'; -import { mergeLevel } from './resolvePlugins'; /** * Resolves and finalizes a plugin configuration for use in a Plate editor. @@ -57,7 +57,8 @@ export const resolvePlugin =

( // plugin.api = mergeOneLevel(plugin.api, _plugin.api); // plugin.options = mergeOneLevel(plugin.options, _plugin.options); plugin.api = cloneDeep(_plugin.api); - plugin.options = cloneDeep(_plugin.options); + plugin.transforms = cloneDeep(_plugin.transforms); + plugin.options = { ..._plugin.options }; plugin.__resolved = true; @@ -67,25 +68,24 @@ export const resolvePlugin =

( getEditorPlugin(editor, plugin as any) ); - plugin = mergeLevel(plugin, configResult, 3); + plugin = mergeWithoutArray({}, plugin, configResult); delete (plugin as any).__configuration; } // Apply all stored extensions if (plugin.__extensions && plugin.__extensions.length > 0) { plugin.__extensions.forEach((extension) => { - plugin = mergeLevel( + plugin = mergeWithoutArray( plugin, - extension(getEditorPlugin(editor, plugin as any)), - 3 + extension(getEditorPlugin(editor, plugin as any)) ); }); plugin.__extensions = []; } if (plugin.plugins) { - // plugin.plugins = plugin.plugins.map((p) => { - // return resolvePlugin(editor, p); - // }); + plugin.plugins = plugin.plugins.map((p) => { + return resolvePlugin(editor, p); + }); } const targetPluginToInject = plugin.inject?.targetPluginToInject; @@ -93,8 +93,9 @@ export const resolvePlugin =

( if (targetPluginToInject && targetPlugins && targetPlugins.length > 0) { plugin.inject = plugin.inject || {}; - plugin.inject.plugins = mergeLevel( - plugin.inject.plugins ?? {}, + plugin.inject.plugins = mergeWithoutArray( + {}, + plugin.inject.plugins, Object.fromEntries( targetPlugins.map((targetPlugin) => { const injectedPlugin = targetPluginToInject({ @@ -110,7 +111,7 @@ export const resolvePlugin =

( } // PERF if (plugin.plugins) { - // plugin.plugins = plugin.plugins.map((p) => resolvePlugin(editor, p)); + plugin.plugins = plugin.plugins.map((p) => resolvePlugin(editor, p)); } // TODO React if ((plugin as any).node?.component) { diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index d52c717de4..d6b234392d 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -3,6 +3,7 @@ import { createZustandStore } from 'zustand-x'; import type { SlateEditor } from '../editor'; +import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; import { type SlatePlugin, type SlatePlugins, @@ -140,20 +141,18 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.transforms as any)[plugin.key] = {}; } - mergeLevel( + mergeWithoutArray( (editor.transforms as any)[plugin.key], - newExtensions, - 2 + newExtensions ); - mergeLevel( + mergeWithoutArray( (plugin.transforms as any)[plugin.key], - newExtensions, - 2 + newExtensions ); } else { // Editor-wide transform - mergeLevel(editor.transforms, newExtensions, 2); - mergeLevel(plugin.transforms, newExtensions, 2); + mergeWithoutArray(editor.transforms, newExtensions); + mergeWithoutArray(plugin.transforms, newExtensions); } } else { // Handle APIs @@ -166,12 +165,12 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.api as any)[plugin.key] = {}; } - mergeLevel((editor.api as any)[plugin.key], newExtensions, 2); - mergeLevel((plugin.api as any)[plugin.key], newExtensions, 2); + mergeWithoutArray((editor.api as any)[plugin.key], newExtensions); + mergeWithoutArray((plugin.api as any)[plugin.key], newExtensions); } else { // Editor-wide API - mergeLevel(editor.api, newExtensions, 2); - mergeLevel(plugin.api, newExtensions, 2); + mergeWithoutArray(editor.api, newExtensions); + mergeWithoutArray(plugin.api, newExtensions); } } } @@ -336,10 +335,10 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { } if (plugin.override.plugins) { Object.entries(plugin.override.plugins).forEach(([key, value]) => { - pluginOverrides[key] = mergeLevel( - pluginOverrides[key] ?? {}, - value, - 3 + pluginOverrides[key] = mergeWithoutArray( + {}, + pluginOverrides[key], + value ); if (value.enabled !== undefined) { @@ -391,9 +390,9 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { editor.pluginList = applyOverrides(editor.pluginList as any); // Final pass: ensure all plugins are properly resolved after overrides - // editor.pluginList = editor.pluginList.map((plugin) => - // resolvePlugin(editor, plugin as any) - // ); + editor.pluginList = editor.pluginList.map((plugin) => + resolvePlugin(editor, plugin as any) + ); editor.plugins = Object.fromEntries( editor.pluginList.map((plugin) => [plugin.key, plugin]) ); From c76390aba893ef6de2c521d907ced8c1157d2032 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 10 Sep 2024 10:44:13 +0200 Subject: [PATCH 04/12] fix --- .../core/src/lib/plugin/getSlatePlugin.ts | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/packages/core/src/lib/plugin/getSlatePlugin.ts b/packages/core/src/lib/plugin/getSlatePlugin.ts index 850d37d7d0..f2861dabae 100644 --- a/packages/core/src/lib/plugin/getSlatePlugin.ts +++ b/packages/core/src/lib/plugin/getSlatePlugin.ts @@ -6,8 +6,6 @@ import type { } from './BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from './SlatePlugin'; -import { resolvePlugin } from '../utils'; - /** Get editor plugin by key or plugin object. */ export function getSlatePlugin( editor: SlateEditor, @@ -22,29 +20,26 @@ export function getSlatePlugin( const editorPlugin = editor.plugins[p.key] as any; if (!editorPlugin) { - return plugin.__resolved ? p : resolvePlugin(editor, plugin); - - // return { - // __apiExtensions: [], - // __configuration: null, - // __extensions: [], - // __optionExtensions: [], - // dependencies: [], - // editor: {}, - // handlers: {}, - // inject: {}, - // node: {}, - // override: {}, - // parser: {}, - // parsers: {}, - // plugins: [], - // priority: 100, - // render: {}, - // shortcuts: {}, - // transforms: {}, - // ...plugin, - // }; - // return plugin.__resolved ? p : resolvePlugin(editor, plugin); + return { + __apiExtensions: [], + __configuration: null, + __extensions: [], + __optionExtensions: [], + dependencies: [], + editor: {}, + handlers: {}, + inject: {}, + node: {}, + override: {}, + parser: {}, + parsers: {}, + plugins: [], + priority: 100, + render: {}, + shortcuts: {}, + transforms: {}, + ...plugin, + }; } return editorPlugin; From 705ce5e79de2a31e0169652e0c1eea3ed48457bf Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 10 Sep 2024 10:55:32 +0200 Subject: [PATCH 05/12] revert --- .../core/src/lib/plugin/getSlatePlugin.ts | 43 ++++++++++--------- .../core/src/lib/utils/resolvePlugin.spec.ts | 6 +-- .../plate/src/__tests__/all-plugins.spec.tsx | 3 ++ 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/packages/core/src/lib/plugin/getSlatePlugin.ts b/packages/core/src/lib/plugin/getSlatePlugin.ts index f2861dabae..44c0052962 100644 --- a/packages/core/src/lib/plugin/getSlatePlugin.ts +++ b/packages/core/src/lib/plugin/getSlatePlugin.ts @@ -6,6 +6,8 @@ import type { } from './BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from './SlatePlugin'; +import { resolvePlugin } from '../utils'; + /** Get editor plugin by key or plugin object. */ export function getSlatePlugin( editor: SlateEditor, @@ -20,26 +22,27 @@ export function getSlatePlugin( const editorPlugin = editor.plugins[p.key] as any; if (!editorPlugin) { - return { - __apiExtensions: [], - __configuration: null, - __extensions: [], - __optionExtensions: [], - dependencies: [], - editor: {}, - handlers: {}, - inject: {}, - node: {}, - override: {}, - parser: {}, - parsers: {}, - plugins: [], - priority: 100, - render: {}, - shortcuts: {}, - transforms: {}, - ...plugin, - }; + // return { + // __apiExtensions: [], + // __configuration: null, + // __extensions: [], + // __optionExtensions: [], + // dependencies: [], + // editor: {}, + // handlers: {}, + // inject: {}, + // node: {}, + // override: {}, + // parser: {}, + // parsers: {}, + // plugins: [], + // priority: 100, + // render: {}, + // shortcuts: {}, + // transforms: {}, + // ...plugin, + // }; + return plugin.__resolved ? p : resolvePlugin(editor, plugin); } return editorPlugin; diff --git a/packages/core/src/lib/utils/resolvePlugin.spec.ts b/packages/core/src/lib/utils/resolvePlugin.spec.ts index a5bf8e3cf4..14a8ca9a87 100644 --- a/packages/core/src/lib/utils/resolvePlugin.spec.ts +++ b/packages/core/src/lib/utils/resolvePlugin.spec.ts @@ -31,7 +31,7 @@ describe('resolvePlugin', () => { ).toBe('ac'); }); - it('should create a deep clone of the plugin', () => { + it('should create a deep clone of the plugin instead of options', () => { const editor = createSlateEditor() as any; const originalPlugin = createSlatePlugin({ key: 'test', @@ -48,7 +48,7 @@ describe('resolvePlugin', () => { resolvedPlugin.options.nestedObject.value = 'modified'; // Check that the original plugin is not affected - expect(originalPlugin.options.nestedObject.value).toBe('original'); + expect(originalPlugin.options.nestedObject.value).toBe('modified'); expect(resolvedPlugin.options.nestedObject.value).toBe('modified'); // Ensure that the resolved plugin still has all the methods @@ -59,7 +59,7 @@ describe('resolvePlugin', () => { newInstance.options.nestedObject.value = 'new instance'; // Check that neither the original nor the first resolved plugin are affected - expect(originalPlugin.options.nestedObject.value).toBe('original'); + expect(originalPlugin.options.nestedObject.value).toBe('modified'); expect(resolvedPlugin.options.nestedObject.value).toBe('modified'); expect(newInstance.options.nestedObject.value).toBe('new instance'); }); diff --git a/packages/plate/src/__tests__/all-plugins.spec.tsx b/packages/plate/src/__tests__/all-plugins.spec.tsx index 6f699064b2..1c697626f0 100644 --- a/packages/plate/src/__tests__/all-plugins.spec.tsx +++ b/packages/plate/src/__tests__/all-plugins.spec.tsx @@ -7,6 +7,7 @@ import { BasicElementsPlugin } from '@udecode/plate-basic-elements'; import { BasicMarksPlugin } from '@udecode/plate-basic-marks'; import { BlockquotePlugin } from '@udecode/plate-block-quote'; import { ExitBreakPlugin, SoftBreakPlugin } from '@udecode/plate-break'; +import { CodeBlockPlugin } from '@udecode/plate-code-block'; import { Plate, PlateContent, @@ -24,6 +25,7 @@ import { ResetNodePlugin } from '@udecode/plate-reset-node'; import { SelectOnBackspacePlugin } from '@udecode/plate-select'; import { TablePlugin } from '@udecode/plate-table'; import { TrailingBlockPlugin } from '@udecode/plate-trailing-block'; +import Prism from 'prismjs'; function PlateContainer() { const editor = usePlateEditor({ @@ -31,6 +33,7 @@ function PlateContainer() { BlockquotePlugin, TodoListPlugin, HeadingPlugin.configure({ options: { levels: 5 } }), + CodeBlockPlugin.configure({ options: { prism: Prism } }), BasicElementsPlugin, BasicMarksPlugin, TodoListPlugin, From 7c0c89655a9019acdb5a50d28d4a547cb0e7180b Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 10 Sep 2024 12:42:50 +0200 Subject: [PATCH 06/12] fix --- .../src/lib/plugin/createSlatePlugin.spec.ts | 90 ++++++++++--------- .../src/lib/plugin/createTSlatePlugin.spec.ts | 89 ++++++++++++------ .../src/lib/utils/resolveCreatePluginTest.ts | 33 +++++-- .../core/src/lib/utils/resolvePlugin.spec.ts | 47 +++++----- packages/core/src/lib/utils/resolvePlugin.ts | 6 +- packages/core/src/lib/utils/resolvePlugins.ts | 4 - 6 files changed, 162 insertions(+), 107 deletions(-) diff --git a/packages/core/src/lib/plugin/createSlatePlugin.spec.ts b/packages/core/src/lib/plugin/createSlatePlugin.spec.ts index 7710037481..e216251bd8 100644 --- a/packages/core/src/lib/plugin/createSlatePlugin.spec.ts +++ b/packages/core/src/lib/plugin/createSlatePlugin.spec.ts @@ -4,6 +4,7 @@ import { LinkPlugin } from '@udecode/plate-link'; import { createPlateEditor } from '../../react'; import { type PluginConfig, + createSlateEditor, createSlatePlugin, resolveCreatePluginTest, resolvePluginTest, @@ -88,25 +89,27 @@ describe('createSlatePlugin', () => { describe('when extendPlugin', () => { it('should be', () => { - const plugin = resolvePluginTest( - createSlatePlugin({ - key: 'a', - node: { type: 'a' }, - plugins: [ - createSlatePlugin({ - key: 'aa', - node: { type: 'aa' }, - }), - ], - }).extendPlugin( - { key: 'aa' }, - { - node: { type: 'aaa' }, - } - ) - ); + const editor = createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + node: { type: 'a' }, + plugins: [ + createSlatePlugin({ + key: 'aa', + node: { type: 'aa' }, + }), + ], + }).extendPlugin( + { key: 'aa' }, + { + node: { type: 'aaa' }, + } + ), + ], + }); - expect(plugin.plugins[0].node.type).toBe('aaa'); + expect(editor.plugins.aa.node.type).toBe('aaa'); }); }); @@ -454,32 +457,35 @@ describe('createSlatePlugin', () => { describe('when extend + extendPlugin', () => { it('should be', () => { - const plugin = resolvePluginTest( - createSlatePlugin({ - key: 'a', - node: { type: 'a' }, - plugins: [ - createSlatePlugin({ - key: 'aa', - node: { type: 'aa' }, - }), - ], - }) - .extend({ - node: { type: 'a_extend' }, + const editor = createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + node: { type: 'a' }, + plugins: [ + createSlatePlugin({ + key: 'aa', + node: { type: 'aa' }, + }), + ], }) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'aa_extend' }, - options: { - levels: 5, - }, - } - ) - ); + .extend({ + node: { type: 'a_extend' }, + }) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'aa_extend' }, + options: { + levels: 5, + }, + } + ), + ], + }); - const headingPlugin = plugin.plugins.find((p) => p.key === 'aa'); + const plugin = editor.plugins.a; + const headingPlugin = editor.plugins.aa; const { node: { type }, options, diff --git a/packages/core/src/lib/plugin/createTSlatePlugin.spec.ts b/packages/core/src/lib/plugin/createTSlatePlugin.spec.ts index afc2e8f303..8d6e98caee 100644 --- a/packages/core/src/lib/plugin/createTSlatePlugin.spec.ts +++ b/packages/core/src/lib/plugin/createTSlatePlugin.spec.ts @@ -2,10 +2,24 @@ import type { NodeComponent } from '../../react'; import type { PluginConfig } from './BasePlugin'; import { createTPlatePlugin } from '../../react/plugin/createPlatePlugin'; -import { resolveCreatePluginTest, resolvePluginTest } from '../utils'; +import { createSlateEditor } from '../editor'; +import { resolvePluginTest } from '../utils'; import { createTSlatePlugin } from './createSlatePlugin'; describe('createTSlatePlugin', () => { + it('should work with fn', () => { + // Test plugin creation with a function + const functionPlugin = createTSlatePlugin< + PluginConfig<'functionPlugin', { editorId: string }> + >((editor: any) => ({ + key: 'functionPlugin', + options: { editorId: editor.id }, + })); + + const resolvedFunctionPlugin = resolvePluginTest(functionPlugin); + expect(resolvedFunctionPlugin.key).toBe('functionPlugin'); + }); + it('should create a plugin with explicit types and cover various scenarios', () => { interface TestOptions { optionA?: string; @@ -16,30 +30,39 @@ describe('createTSlatePlugin', () => { testMethod: () => void; } - const basePlugin = resolvePluginTest( - createTPlatePlugin>({ - key: 'testPlugin', - node: { type: 'test' }, - options: { - optionA: 'initial', - optionB: 10, - }, - }).extendEditorApi(() => ({ - testMethod: () => {}, - })) - ); + const basePlugin = createTPlatePlugin< + PluginConfig<'testPlugin', TestOptions, TestApi> + >({ + key: 'testPlugin', + node: { type: 'test' }, + options: { + optionA: 'initial', + optionB: 10, + }, + }).extendEditorApi(() => ({ + testMethod: () => {}, + })); + + const baseEditor = createSlateEditor({ + plugins: [basePlugin], + }); // Test basic plugin creation - expect(basePlugin.key).toBe('testPlugin'); - expect(basePlugin.node.type).toBe('test'); - expect(basePlugin.options).toEqual({ optionA: 'initial', optionB: 10 }); + expect(baseEditor.plugins.testPlugin.key).toBe('testPlugin'); + expect(baseEditor.plugins.testPlugin.node.type).toBe('test'); + expect(baseEditor.plugins.testPlugin.options).toEqual({ + optionA: 'initial', + optionB: 10, + }); // Test configure method const configuredPlugin = basePlugin.configure({ options: { optionA: 'modified' }, }); - const resolvedConfigured = resolvePluginTest(configuredPlugin); - expect(resolvedConfigured.options).toEqual({ + const configuredEditor = createSlateEditor({ + plugins: [configuredPlugin], + }); + expect(configuredEditor.plugins.testPlugin.options).toEqual({ optionA: 'modified', optionB: 10, }); @@ -49,9 +72,11 @@ describe('createTSlatePlugin', () => { node: { type: 'extended' }, options: { optionB: 20 }, }); - const resolvedExtended = resolvePluginTest(extendedPlugin); - expect(resolvedExtended.node.type).toBe('extended'); - expect(resolvedExtended.options).toEqual({ + const extendedEditor = createSlateEditor({ + plugins: [extendedPlugin], + }); + expect(extendedEditor.plugins.testPlugin.node.type).toBe('extended'); + expect(extendedEditor.plugins.testPlugin.options).toEqual({ optionA: 'initial', optionB: 20, }); @@ -59,8 +84,12 @@ describe('createTSlatePlugin', () => { // Test withComponent method const MockComponent: NodeComponent = () => null; const pluginWithComponent = basePlugin.withComponent(MockComponent); - const resolvedWithComponent = resolvePluginTest(pluginWithComponent); - expect(resolvedWithComponent.render.node).toBe(MockComponent); + const editorWithComponent = createSlateEditor({ + plugins: [pluginWithComponent], + }); + expect(editorWithComponent.plugins.testPlugin.render.node).toBe( + MockComponent + ); // Test nested plugins and extendPlugin const nestedPlugin = createTSlatePlugin< @@ -85,8 +114,10 @@ describe('createTSlatePlugin', () => { } ); - const resolvedParent = resolvePluginTest(extendedParentPlugin); - expect(resolvedParent.plugins[0].options).toEqual({ + const resolvedParentEditor = createSlateEditor({ + plugins: [extendedParentPlugin], + }); + expect(resolvedParentEditor.plugins.nested.options).toEqual({ nestedOption: 'modified', }); @@ -95,8 +126,10 @@ describe('createTSlatePlugin', () => { options: { nestedOption: 'configured' }, }); - const resolvedConfiguredParent = resolvePluginTest(configuredParentPlugin); - expect(resolvedConfiguredParent.plugins[0].options).toEqual({ + const resolvedConfiguredParentEditor = createSlateEditor({ + plugins: [configuredParentPlugin], + }); + expect(resolvedConfiguredParentEditor.plugins.nested.options).toEqual({ nestedOption: 'configured', }); @@ -108,7 +141,7 @@ describe('createTSlatePlugin', () => { options: { editorId: editor.id }, })); - const resolvedFunctionPlugin = resolveCreatePluginTest(functionPlugin); + const resolvedFunctionPlugin = resolvePluginTest(functionPlugin); expect(resolvedFunctionPlugin.key).toBe('functionPlugin'); expect(resolvedFunctionPlugin.options).toHaveProperty('editorId'); diff --git a/packages/core/src/lib/utils/resolveCreatePluginTest.ts b/packages/core/src/lib/utils/resolveCreatePluginTest.ts index 21591779f0..e69f88cf57 100644 --- a/packages/core/src/lib/utils/resolveCreatePluginTest.ts +++ b/packages/core/src/lib/utils/resolveCreatePluginTest.ts @@ -4,13 +4,32 @@ import { createSlateEditor } from '../editor'; import { createSlatePlugin } from '../plugin/createSlatePlugin'; import { resolvePlugin } from './resolvePlugin'; -export const resolvePluginTest =

(plugin: P) => { - return resolvePlugin(createSlateEditor() as any, plugin as any) as P; +export const resolvePluginTest =

(p: P) => { + const editor = createSlateEditor({ + plugins: [p], + }) as any; + + let key = p.key; + + if (!key) { + key = resolvePlugin(editor, p as any).key; + } + + return editor.plugins[key]; }; -export const resolveCreatePluginTest = ((plugin) => { - return resolvePlugin( - createSlateEditor() as any, - createSlatePlugin(plugin) as any - ); +export const resolveCreatePluginTest = ((plugin: AnyPluginConfig) => { + const p = createSlatePlugin(plugin); + + const editor = createSlateEditor({ + plugins: [p], + }) as any; + + let key = p.key; + + if (!key) { + key = resolvePlugin(editor, p as any).key; + } + + return editor.plugins[key]; }) as typeof createSlatePlugin; diff --git a/packages/core/src/lib/utils/resolvePlugin.spec.ts b/packages/core/src/lib/utils/resolvePlugin.spec.ts index 14a8ca9a87..d265693451 100644 --- a/packages/core/src/lib/utils/resolvePlugin.spec.ts +++ b/packages/core/src/lib/utils/resolvePlugin.spec.ts @@ -5,29 +5,30 @@ import { resolvePlugin } from './resolvePlugin'; describe('resolvePlugin', () => { it('should be', () => { expect( - resolvePlugin( - createSlateEditor() as any, - createSlatePlugin({ - key: 'a', - plugins: [ - createSlatePlugin({ - key: 'aa', - }), - ], - }) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'ab' }, - } - ) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'ac' }, - } - ) - ).plugins[0].node.type + createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + plugins: [ + createSlatePlugin({ + key: 'aa', + }), + ], + }) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'ab' }, + } + ) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'ac' }, + } + ), + ], + }).plugins.aa.node.type ).toBe('ac'); }); diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index a41fd4c06d..a3660da40b 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -83,9 +83,9 @@ export const resolvePlugin =

( plugin.__extensions = []; } if (plugin.plugins) { - plugin.plugins = plugin.plugins.map((p) => { - return resolvePlugin(editor, p); - }); + // plugin.plugins = plugin.plugins.map((p) => { + // return resolvePlugin(editor, p); + // }); } const targetPluginToInject = plugin.inject?.targetPluginToInject; diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index d6b234392d..e4d6dacf9a 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -34,10 +34,6 @@ export function mergeLevel( // TODO: levels should be used instead of 5 currentLevel < 10 ) { - if (currentLevel === 5) { - console.log('mergeLevel', sourceObj, key, currentLevel); - } - targetObj[key] = targetObj[key] || {}; mergeLevel(targetObj[key], sourceObj[key], currentLevel + 1); } else { From 60572c631eca5b5b2dca8e465bec3da504d76ef9 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 10 Sep 2024 12:58:48 +0200 Subject: [PATCH 07/12] fix --- .../src/lib/plugin/createSlatePlugin.spec.ts | 198 +++++++++--------- .../core/src/lib/plugin/getSlatePlugin.ts | 24 --- packages/core/src/lib/utils/resolvePlugin.ts | 14 +- packages/core/src/lib/utils/resolvePlugins.ts | 5 - 4 files changed, 105 insertions(+), 136 deletions(-) diff --git a/packages/core/src/lib/plugin/createSlatePlugin.spec.ts b/packages/core/src/lib/plugin/createSlatePlugin.spec.ts index e216251bd8..94dcc5a74b 100644 --- a/packages/core/src/lib/plugin/createSlatePlugin.spec.ts +++ b/packages/core/src/lib/plugin/createSlatePlugin.spec.ts @@ -115,32 +115,34 @@ describe('createSlatePlugin', () => { describe('when extendPlugin twice', () => { it('should be', () => { - const plugin = resolvePluginTest( - createSlatePlugin({ - key: 'a', - node: { type: 'a' }, - plugins: [ - createSlatePlugin({ - key: 'aa', - node: { type: 'aa' }, - }), - ], - }) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'aaa' }, - } - ) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'aab' }, - } - ) - ); + const editor = createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + node: { type: 'a' }, + plugins: [ + createSlatePlugin({ + key: 'aa', + node: { type: 'aa' }, + }), + ], + }) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'aaa' }, + } + ) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'aab' }, + } + ), + ], + }); - expect(plugin.plugins[0].node.type).toBe('aab'); + expect(editor.plugins.aa.node.type).toBe('aab'); }); }); @@ -293,44 +295,48 @@ describe('createSlatePlugin', () => { describe('when new extendPlugin', () => { it('should be', () => { - const plugin = resolvePluginTest( - createSlatePlugin({ - key: 'a', - node: { type: 'a' }, - }).extendPlugin( - { key: 'aa' }, - { - node: { type: 'aaa' }, - } - ) - ); + const plugin = createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + node: { type: 'a' }, + }).extendPlugin( + { key: 'aa' }, + { + node: { type: 'aaa' }, + } + ), + ], + }); - expect(plugin.plugins[0].node.type).toBe('aaa'); + expect(plugin.plugins.aa.node.type).toBe('aaa'); }); }); describe('when new extendPlugin twice', () => { it('should be', () => { - const plugin = resolvePluginTest( - createSlatePlugin({ - key: 'a', - node: { type: 'a' }, - }) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'aaa' }, - } - ) - .extendPlugin( - { key: 'aa' }, - { - node: { type: 'aab' }, - } - ) - ); + const editor = createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + node: { type: 'a' }, + }) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'aaa' }, + } + ) + .extendPlugin( + { key: 'aa' }, + { + node: { type: 'aab' }, + } + ), + ], + }); - expect(plugin.plugins[0].node.type).toBe('aab'); + expect(editor.plugins.aa.node.type).toBe('aab'); }); }); @@ -429,21 +435,21 @@ describe('createSlatePlugin', () => { describe('when extend plugins', () => { it('should be', () => { - const plugin = resolvePluginTest( - BasicElementsPlugin.extendPlugin( - { key: 'heading' }, - { - node: { type: 'h' }, - options: { - levels: 5, - }, - } - ) - ); + const editor = createSlateEditor({ + plugins: [ + BasicElementsPlugin.extendPlugin( + { key: 'heading' }, + { + node: { type: 'h' }, + options: { + levels: 5, + }, + } + ), + ], + }); - const headingPlugin = plugin.plugins.find( - (p: any) => p.key === 'heading' - ); + const headingPlugin = editor.plugins.heading; const { node, options } = headingPlugin!; expect({ node, options }).toEqual({ @@ -865,18 +871,20 @@ describe('createSlatePlugin', () => { options: { another: 'b', initialValue: 'aa' }, }); - const plugin = resolvePluginTest( - createSlatePlugin({ - key: 'a', - plugins: [aa], - }).configurePlugin(aa, { - options: { - initialValue: 'aaa', - }, - }) - ); + const editor = createSlateEditor({ + plugins: [ + createSlatePlugin({ + key: 'a', + plugins: [aa], + }).configurePlugin(aa, { + options: { + initialValue: 'aaa', + }, + }), + ], + }); - expect(plugin.plugins[0].options).toEqual({ + expect(editor.plugins.aa.options).toEqual({ another: 'b', initialValue: 'aaa', }); @@ -893,16 +901,18 @@ describe('createSlatePlugin', () => { ], }); - const configuredPlugin = resolvePluginTest( - basePlugin.configurePlugin( - { key: 'bb' }, - { options: { newOption: 'new' } } - ) - ); + const editor = createSlateEditor({ + plugins: [ + basePlugin.configurePlugin( + { key: 'bb' }, + { options: { newOption: 'new' } } + ), + ], + }); - expect(configuredPlugin.plugins).toHaveLength(1); - expect(configuredPlugin.plugins[0].key).toBe('aa'); - expect(configuredPlugin.plugins[0].options).toEqual({ + expect(editor.plugins.aa.key).toBe('aa'); + expect(editor.plugins.bb).toBeUndefined(); + expect(editor.plugins.aa.options).toEqual({ initialValue: 'aa', }); }); @@ -923,11 +933,11 @@ describe('createSlatePlugin', () => { plugins: [b], }); - const plugin = resolvePluginTest( - a.configurePlugin(c, { options: { initialValue: 'cc' } }) - ); + const editor = createSlateEditor({ + plugins: [a.configurePlugin(c, { options: { initialValue: 'cc' } })], + }); - expect(plugin.plugins[0].plugins[0].options).toEqual({ + expect(editor.plugins.c.options).toEqual({ initialValue: 'cc', }); }); diff --git a/packages/core/src/lib/plugin/getSlatePlugin.ts b/packages/core/src/lib/plugin/getSlatePlugin.ts index 44c0052962..fb3a91e5dd 100644 --- a/packages/core/src/lib/plugin/getSlatePlugin.ts +++ b/packages/core/src/lib/plugin/getSlatePlugin.ts @@ -15,33 +15,9 @@ export function getSlatePlugin( ): C extends { node: any } ? C : SlatePlugin { const plugin = p as any; - // if (!plugin.__resolved) { - // return resolvePlugin(editor, plugin); - // } - const editorPlugin = editor.plugins[p.key] as any; if (!editorPlugin) { - // return { - // __apiExtensions: [], - // __configuration: null, - // __extensions: [], - // __optionExtensions: [], - // dependencies: [], - // editor: {}, - // handlers: {}, - // inject: {}, - // node: {}, - // override: {}, - // parser: {}, - // parsers: {}, - // plugins: [], - // priority: 100, - // render: {}, - // shortcuts: {}, - // transforms: {}, - // ...plugin, - // }; return plugin.__resolved ? p : resolvePlugin(editor, plugin); } diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index a3660da40b..8285de67c6 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -54,8 +54,6 @@ export const resolvePlugin =

( } as P; plugin.node = { type: plugin.key, ...(_plugin.node as any) }; - // plugin.api = mergeOneLevel(plugin.api, _plugin.api); - // plugin.options = mergeOneLevel(plugin.options, _plugin.options); plugin.api = cloneDeep(_plugin.api); plugin.transforms = cloneDeep(_plugin.transforms); plugin.options = { ..._plugin.options }; @@ -82,11 +80,6 @@ export const resolvePlugin =

( }); plugin.__extensions = []; } - if (plugin.plugins) { - // plugin.plugins = plugin.plugins.map((p) => { - // return resolvePlugin(editor, p); - // }); - } const targetPluginToInject = plugin.inject?.targetPluginToInject; const targetPlugins = plugin.inject?.targetPlugins; @@ -105,14 +98,9 @@ export const resolvePlugin =

( return [targetPlugin, injectedPlugin]; }) - ), - 4 + ) ); } - // PERF - if (plugin.plugins) { - plugin.plugins = plugin.plugins.map((p) => resolvePlugin(editor, p)); - } // TODO React if ((plugin as any).node?.component) { (plugin as any).render.node = (plugin as any).node.component; diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index e4d6dacf9a..b998e2eae9 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -384,11 +384,6 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { }; editor.pluginList = applyOverrides(editor.pluginList as any); - - // Final pass: ensure all plugins are properly resolved after overrides - editor.pluginList = editor.pluginList.map((plugin) => - resolvePlugin(editor, plugin as any) - ); editor.plugins = Object.fromEntries( editor.pluginList.map((plugin) => [plugin.key, plugin]) ); From e00dd45bc31d60fe33fefd4d004d9518deff591a Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 10 Sep 2024 13:00:52 +0200 Subject: [PATCH 08/12] fix --- packages/core/src/lib/utils/resolvePlugins.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index b998e2eae9..b4a96b471e 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -13,8 +13,8 @@ import { resolvePlugin } from './resolvePlugin'; export function mergeLevel( target: T, - source: Partial, - levels = 1 + source: Partial + // levels = 1 ): T { if (!target) { target = {} as T; @@ -229,8 +229,7 @@ const flattenAndResolvePlugins = ( if (existingPlugin) { pluginMap.set( resolvedPlugin.key, - mergeLevel(existingPlugin, resolvedPlugin, 3) - // resolvedPlugin + mergeWithoutArray(existingPlugin, resolvedPlugin) ); } else { pluginMap.set(resolvedPlugin.key, resolvedPlugin); @@ -350,7 +349,10 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { // Apply plugin overrides if (pluginOverrides[p.key]) { - updatedPlugin = mergeLevel(updatedPlugin, pluginOverrides[p.key], 3); + updatedPlugin = mergeWithoutArray( + updatedPlugin, + pluginOverrides[p.key] + ); } // Apply component overrides // TODO react From b95da3a97b9ce44bb374612b1a9d328a51131589 Mon Sep 17 00:00:00 2001 From: Joe Anderson Date: Tue, 10 Sep 2024 16:48:53 +0100 Subject: [PATCH 09/12] WIP: mergePlugins --- packages/core/src/internal/mergePlugins.ts | 49 +++++++++++++++++++ .../core/src/internal/mergeWithoutArray.ts | 14 ------ packages/core/src/lib/plugin/SlatePlugin.ts | 2 +- .../core/src/lib/plugin/createSlatePlugin.ts | 10 ++-- packages/core/src/lib/utils/resolvePlugin.ts | 10 ++-- .../src/lib/utils/resolvePlugins.spec.tsx | 8 +-- packages/core/src/lib/utils/resolvePlugins.ts | 30 ++++++------ .../core/src/react/editor/withPlate.spec.ts | 24 +++++++++ packages/core/src/react/plugin/PlatePlugin.ts | 2 +- 9 files changed, 105 insertions(+), 44 deletions(-) create mode 100644 packages/core/src/internal/mergePlugins.ts delete mode 100644 packages/core/src/internal/mergeWithoutArray.ts create mode 100644 packages/core/src/react/editor/withPlate.spec.ts diff --git a/packages/core/src/internal/mergePlugins.ts b/packages/core/src/internal/mergePlugins.ts new file mode 100644 index 0000000000..4a7cb39e12 --- /dev/null +++ b/packages/core/src/internal/mergePlugins.ts @@ -0,0 +1,49 @@ +import mergeWith from 'lodash/mergeWith.js'; +import {PluginConfig, SlatePlugin} from '../lib'; + +export function mergePlugins< + K extends string = any, + O = {}, + A = {}, + T = {}, +>( + basePlugin: SlatePlugin>, + ...sourcePlugins: Partial>[] +): SlatePlugin>; + +export function mergePlugins< + K extends string = any, + O = {}, + A = {}, + T = {}, +>( + basePlugin: Partial>>, + ...sourcePlugins: Partial>[] +): Partial>>; + +export function mergePlugins< + K extends string = any, + O = {}, + A = {}, + T = {}, +>( + basePlugin: Partial>>, + ...sourcePlugins: Partial>[] +): Partial>> { + return mergeWith( + {}, + basePlugin, + ...sourcePlugins, + (objValue: unknown, srcValue: unknown, key: keyof SlatePlugin) => { + // Overwrite plugins without cloning + if (key === 'plugins') { + return srcValue; + } + + // Shallow merge options + if (key === 'options') { + return { ...objValue as any, ...srcValue as any }; + } + } + ); +}; diff --git a/packages/core/src/internal/mergeWithoutArray.ts b/packages/core/src/internal/mergeWithoutArray.ts deleted file mode 100644 index 1c527a99b5..0000000000 --- a/packages/core/src/internal/mergeWithoutArray.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type merge from 'lodash/merge.js'; - -import mergeWith from 'lodash/mergeWith.js'; - -export const mergeWithoutArray: typeof merge = ( - ...args: Parameters -) => { - // Note this will prevent plugin.plugins from being merged - return mergeWith(...args, (_: any, srcValue: any) => { - if (Array.isArray(srcValue)) { - return srcValue; - } - }); -}; diff --git a/packages/core/src/lib/plugin/SlatePlugin.ts b/packages/core/src/lib/plugin/SlatePlugin.ts index 3e2c8b1d66..2b8f48b220 100644 --- a/packages/core/src/lib/plugin/SlatePlugin.ts +++ b/packages/core/src/lib/plugin/SlatePlugin.ts @@ -105,7 +105,7 @@ export type SlatePluginMethods = { | SlatePluginConfig, InferApi

, InferTransforms

> ) => SlatePlugin; - create: () => SlatePlugin; + clone: () => SlatePlugin; extend: ( extendConfig: diff --git a/packages/core/src/lib/plugin/createSlatePlugin.ts b/packages/core/src/lib/plugin/createSlatePlugin.ts index 744559cfaa..2f6047a70d 100644 --- a/packages/core/src/lib/plugin/createSlatePlugin.ts +++ b/packages/core/src/lib/plugin/createSlatePlugin.ts @@ -8,8 +8,8 @@ import type { SlatePlugins, } from './SlatePlugin'; -import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; import { isFunction } from '../utils/misc/isFunction'; +import {mergePlugins} from '../../internal/mergePlugins'; type SlatePluginConfig = Omit< Partial< @@ -108,7 +108,7 @@ export function createSlatePlugin< const key = baseConfig.key ?? ''; - const plugin = mergeWithoutArray( + const plugin = mergePlugins( { __apiExtensions: [], __configuration: null, @@ -131,7 +131,7 @@ export function createSlatePlugin< shortcuts: {}, transforms: {}, }, - config + config as any ) as unknown as SlatePlugin>; plugin.configure = (config) => { @@ -246,12 +246,14 @@ export function createSlatePlugin< extendConfig, ]; } else { - newPlugin = mergeWithoutArray({}, newPlugin, extendConfig); + newPlugin = mergePlugins(newPlugin, extendConfig as any); } return createSlatePlugin(newPlugin) as any; }; + plugin.clone = () => mergePlugins(plugin); + plugin.extendPlugin = (p, extendConfig) => { const newPlugin = { ...plugin }; diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index 8285de67c6..63d15735fc 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -1,11 +1,11 @@ -import { cloneDeep } from 'lodash'; +import { cloneDeep, merge } from 'lodash'; import type { SlateEditor } from '../editor'; import type { PluginConfig } from '../plugin/BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from '../plugin/SlatePlugin'; -import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; import { getEditorPlugin } from '../plugin'; +import {mergePlugins} from '../../internal/mergePlugins'; /** * Resolves and finalizes a plugin configuration for use in a Plate editor. @@ -66,14 +66,14 @@ export const resolvePlugin =

( getEditorPlugin(editor, plugin as any) ); - plugin = mergeWithoutArray({}, plugin, configResult); + plugin = mergePlugins(plugin, configResult); delete (plugin as any).__configuration; } // Apply all stored extensions if (plugin.__extensions && plugin.__extensions.length > 0) { plugin.__extensions.forEach((extension) => { - plugin = mergeWithoutArray( + plugin = mergePlugins( plugin, extension(getEditorPlugin(editor, plugin as any)) ); @@ -86,7 +86,7 @@ export const resolvePlugin =

( if (targetPluginToInject && targetPlugins && targetPlugins.length > 0) { plugin.inject = plugin.inject || {}; - plugin.inject.plugins = mergeWithoutArray( + plugin.inject.plugins = merge( {}, plugin.inject.plugins, Object.fromEntries( diff --git a/packages/core/src/lib/utils/resolvePlugins.spec.tsx b/packages/core/src/lib/utils/resolvePlugins.spec.tsx index 600178209c..68e3cb0084 100644 --- a/packages/core/src/lib/utils/resolvePlugins.spec.tsx +++ b/packages/core/src/lib/utils/resolvePlugins.spec.tsx @@ -7,7 +7,7 @@ import { createSlatePlugin } from '../plugin'; import { DebugPlugin } from '../plugins'; import { resolvePluginTest } from './resolveCreatePluginTest'; import { - mergePlugins, + applyPluginsToEditor, resolveAndSortPlugins, resolvePluginOverrides, resolvePlugins, @@ -235,7 +235,7 @@ describe('resolveAndSortPlugins', () => { }); }); -describe('mergePlugins', () => { +describe('applyPluginsToEditor', () => { it('should merge plugins correctly', () => { const editor = createPlateEditor(); @@ -244,7 +244,7 @@ describe('mergePlugins', () => { createSlatePlugin({ key: 'b', node: { type: 'typeB' } }), ]; - mergePlugins(editor, plugins); + applyPluginsToEditor(editor, plugins); expect(editor.pluginList).toHaveLength(2); expect(editor.plugins.a.node.type).toBe('typeA'); @@ -260,7 +260,7 @@ describe('mergePlugins', () => { createSlatePlugin({ key: 'a', node: { type: 'newType' } }), ]; - mergePlugins(editor, plugins); + applyPluginsToEditor(editor, plugins); expect(editor.pluginList).toHaveLength(1); expect(editor.plugins.a.node.type).toBe('newType'); diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index b4a96b471e..78a76fd1ce 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -3,13 +3,14 @@ import { createZustandStore } from 'zustand-x'; import type { SlateEditor } from '../editor'; -import { mergeWithoutArray } from '../../internal/mergeWithoutArray'; import { type SlatePlugin, type SlatePlugins, getEditorPlugin, } from '../plugin'; import { resolvePlugin } from './resolvePlugin'; +import {merge} from 'lodash'; +import {mergePlugins} from '../../internal/mergePlugins'; export function mergeLevel( target: T, @@ -66,7 +67,7 @@ export const resolvePlugins = ( const resolvedPlugins = resolveAndSortPlugins(editor, plugins); - mergePlugins(editor, resolvedPlugins); + applyPluginsToEditor(editor, resolvedPlugins); resolvePluginOverrides(editor); @@ -137,18 +138,18 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.transforms as any)[plugin.key] = {}; } - mergeWithoutArray( + merge( (editor.transforms as any)[plugin.key], newExtensions ); - mergeWithoutArray( + merge( (plugin.transforms as any)[plugin.key], newExtensions ); } else { // Editor-wide transform - mergeWithoutArray(editor.transforms, newExtensions); - mergeWithoutArray(plugin.transforms, newExtensions); + merge(editor.transforms, newExtensions); + merge(plugin.transforms, newExtensions); } } else { // Handle APIs @@ -161,12 +162,12 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.api as any)[plugin.key] = {}; } - mergeWithoutArray((editor.api as any)[plugin.key], newExtensions); - mergeWithoutArray((plugin.api as any)[plugin.key], newExtensions); + merge((editor.api as any)[plugin.key], newExtensions); + merge((plugin.api as any)[plugin.key], newExtensions); } else { // Editor-wide API - mergeWithoutArray(editor.api, newExtensions); - mergeWithoutArray(plugin.api, newExtensions); + merge(editor.api, newExtensions); + merge(plugin.api, newExtensions); } } } @@ -229,7 +230,7 @@ const flattenAndResolvePlugins = ( if (existingPlugin) { pluginMap.set( resolvedPlugin.key, - mergeWithoutArray(existingPlugin, resolvedPlugin) + mergePlugins(existingPlugin, resolvedPlugin) ); } else { pluginMap.set(resolvedPlugin.key, resolvedPlugin); @@ -289,7 +290,7 @@ export const resolveAndSortPlugins = ( return orderedPlugins; }; -export const mergePlugins = (editor: SlateEditor, plugins: SlatePlugins) => { +export const applyPluginsToEditor = (editor: SlateEditor, plugins: SlatePlugins) => { editor.pluginList = plugins; editor.plugins = Object.fromEntries( plugins.map((plugin) => [plugin.key, plugin]) @@ -330,8 +331,7 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { } if (plugin.override.plugins) { Object.entries(plugin.override.plugins).forEach(([key, value]) => { - pluginOverrides[key] = mergeWithoutArray( - {}, + pluginOverrides[key] = mergePlugins( pluginOverrides[key], value ); @@ -349,7 +349,7 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { // Apply plugin overrides if (pluginOverrides[p.key]) { - updatedPlugin = mergeWithoutArray( + updatedPlugin = mergePlugins( updatedPlugin, pluginOverrides[p.key] ); diff --git a/packages/core/src/react/editor/withPlate.spec.ts b/packages/core/src/react/editor/withPlate.spec.ts new file mode 100644 index 0000000000..e22376c407 --- /dev/null +++ b/packages/core/src/react/editor/withPlate.spec.ts @@ -0,0 +1,24 @@ +import { createPlateEditor } from './withPlate'; + +describe('createPlateEditor', () => { + it.only('benchmark', () => { + const minDuration = 10000; + const batchSize = 1000; + const start = performance.now(); + const minEnd = start + minDuration; + let iterations = 0; + while (performance.now() < minEnd) { + for (let i = 0; i < batchSize; i++) { + createPlateEditor(); + } + iterations += batchSize; + } + const end = performance.now(); + const average = (end - start) / iterations; + console.log(average); + }); + + it('logs resolvePlugin', () => { + createPlateEditor({ id: 2 }); + }); +}); diff --git a/packages/core/src/react/plugin/PlatePlugin.ts b/packages/core/src/react/plugin/PlatePlugin.ts index 892531d216..4e7d774c16 100644 --- a/packages/core/src/react/plugin/PlatePlugin.ts +++ b/packages/core/src/react/plugin/PlatePlugin.ts @@ -248,7 +248,7 @@ export type PlatePluginMethods = { >) ) => PlatePlugin; - create: () => PlatePlugin; + clone: () => PlatePlugin; extend: ( extendConfig: From 00fde4e5526068ef45010b7da8ed0560e1400790 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 11 Sep 2024 02:26:41 +0200 Subject: [PATCH 10/12] fix --- .changeset/big-cameras-cry.md | 41 +++++++++++ apps/www/content/docs/editor.mdx | 2 + apps/www/content/docs/plugin-methods.mdx | 2 + .../src/lib/plate/demo/values/tableValue.tsx | 8 ++- .../default/example/playground-demo.tsx | 14 ++-- packages/core/src/internal/mergePlugins.ts | 40 ++--------- packages/core/src/lib/editor/withSlate.ts | 8 --- .../src/lib/plugin/createSlatePlugin.spec.ts | 15 ++-- .../core/src/lib/plugin/createSlatePlugin.ts | 4 +- .../core/src/lib/plugin/getSlatePlugin.ts | 11 ++- .../core/src/lib/utils/resolvePlugin.spec.ts | 30 ++++++-- packages/core/src/lib/utils/resolvePlugin.ts | 39 ++--------- .../src/lib/utils/resolvePlugins.spec.tsx | 59 ++++++++++++++++ packages/core/src/lib/utils/resolvePlugins.ts | 68 +++---------------- .../core/src/react/editor/usePlateEditor.ts | 4 -- .../core/src/react/editor/withPlate.spec.ts | 43 +++++++----- .../heading/src/lib/HeadingPlugin.spec.ts | 20 ++---- 17 files changed, 215 insertions(+), 193 deletions(-) create mode 100644 .changeset/big-cameras-cry.md diff --git a/.changeset/big-cameras-cry.md b/.changeset/big-cameras-cry.md new file mode 100644 index 0000000000..51a4e1fe3d --- /dev/null +++ b/.changeset/big-cameras-cry.md @@ -0,0 +1,41 @@ +--- +'@udecode/plate-core': major +--- + +- Change `plugin.options` merging behavior from deep merge to shallow merge. +- This affects `.extend()`, `.configure()`, and other methods that modify plugin options. +- This is an **important patch** to v37 that introduced a performance regression when creating an editor. + +Before: + +```ts +const plugin = createSlatePlugin({ + key: 'test', + options: { nested: { a: 1 } }, +}).extend({ + options: { nested: { b: 1 } }, +}); + +// Result: { nested: { a: 1, b: 1 } } +``` + +After: + +```ts +const plugin = createSlatePlugin({ + key: 'test', + options: { nested: { a: 1 } }, +}).extend(({ getOptions }) => ({ + options: { + ...getOptions(), + nested: { ...getOptions().nested, b: 1 }, + }, +})); + +// Result: { nested: { a: 1, b: 1 } } +``` + +Migration: + +- If you're using nested options and want to preserve the previous behavior, you need to manually spread both the top-level options and the nested objects. +- If you're not using nested options, no changes are required. diff --git a/apps/www/content/docs/editor.mdx b/apps/www/content/docs/editor.mdx index 0564ff0d79..e66eccff7d 100644 --- a/apps/www/content/docs/editor.mdx +++ b/apps/www/content/docs/editor.mdx @@ -91,6 +91,8 @@ const editor = createPlateEditor({ }); ``` +Note that normalization may take a few dozen milliseconds for large documents, such as the playground value. + ### Auto-selection Configure the editor to automatically select a range: diff --git a/apps/www/content/docs/plugin-methods.mdx b/apps/www/content/docs/plugin-methods.mdx index 8746fbe6e4..25f1e16023 100644 --- a/apps/www/content/docs/plugin-methods.mdx +++ b/apps/www/content/docs/plugin-methods.mdx @@ -5,6 +5,8 @@ description: Explore the various methods available for extending Plate plugins. ## Configuration Methods +When extending plugins, all properties are deeply merged by default, with two exceptions: arrays are replaced entirely, and the `options` object is shallow merged. + ### .configure The `.configure` method allows you to override the plugin's configuration. diff --git a/apps/www/src/lib/plate/demo/values/tableValue.tsx b/apps/www/src/lib/plate/demo/values/tableValue.tsx index 2e84071584..bc284659cd 100644 --- a/apps/www/src/lib/plate/demo/values/tableValue.tsx +++ b/apps/www/src/lib/plate/demo/values/tableValue.tsx @@ -47,10 +47,14 @@ export const createTable = (spanning?: boolean): any => ( - + + + - + + + No diff --git a/apps/www/src/registry/default/example/playground-demo.tsx b/apps/www/src/registry/default/example/playground-demo.tsx index 334788fc1a..c4cf6176fd 100644 --- a/apps/www/src/registry/default/example/playground-demo.tsx +++ b/apps/www/src/registry/default/example/playground-demo.tsx @@ -62,6 +62,7 @@ import { SlashPlugin } from '@udecode/plate-slash-command'; import { TablePlugin } from '@udecode/plate-table/react'; import { TogglePlugin } from '@udecode/plate-toggle/react'; import { TrailingBlockPlugin } from '@udecode/plate-trailing-block'; +import Prism from 'prismjs'; import { CheckPlugin } from '@/components/context/check-plugin'; import { settingsStore } from '@/components/context/settings-store'; @@ -105,7 +106,6 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => { const key = settingsStore.use.version(); const editorId = id || 'playground-' + key; - console.time('usePlaygroundEditor'); const a = usePlateEditor( { @@ -121,11 +121,11 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => { // Nodes HeadingPlugin, BlockquotePlugin, - // CodeBlockPlugin.configure({ - // options: { - // prism: Prism, - // }, - // }), + CodeBlockPlugin.configure({ + options: { + prism: Prism, + }, + }), HorizontalRulePlugin, LinkPlugin.extend({ render: { afterEditable: () => }, @@ -310,12 +310,10 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => { enabled: process.env.NODE_ENV !== 'production', }), ], - shouldNormalizeEditor: true, value: value, }, [] ); - console.timeEnd('usePlaygroundEditor'); return a; }; diff --git a/packages/core/src/internal/mergePlugins.ts b/packages/core/src/internal/mergePlugins.ts index 4a7cb39e12..8c463ae1e8 100644 --- a/packages/core/src/internal/mergePlugins.ts +++ b/packages/core/src/internal/mergePlugins.ts @@ -1,49 +1,21 @@ import mergeWith from 'lodash/mergeWith.js'; -import {PluginConfig, SlatePlugin} from '../lib'; -export function mergePlugins< - K extends string = any, - O = {}, - A = {}, - T = {}, ->( - basePlugin: SlatePlugin>, - ...sourcePlugins: Partial>[] -): SlatePlugin>; +import type { SlatePlugin } from '../lib'; -export function mergePlugins< - K extends string = any, - O = {}, - A = {}, - T = {}, ->( - basePlugin: Partial>>, - ...sourcePlugins: Partial>[] -): Partial>>; - -export function mergePlugins< - K extends string = any, - O = {}, - A = {}, - T = {}, ->( - basePlugin: Partial>>, - ...sourcePlugins: Partial>[] -): Partial>> { +export function mergePlugins(basePlugin: T, ...sourcePlugins: any[]): T { return mergeWith( {}, basePlugin, ...sourcePlugins, (objValue: unknown, srcValue: unknown, key: keyof SlatePlugin) => { - // Overwrite plugins without cloning - if (key === 'plugins') { + // Overwrite array (including plugins) without cloning + if (Array.isArray(srcValue)) { return srcValue; } - // Shallow merge options if (key === 'options') { - return { ...objValue as any, ...srcValue as any }; + return { ...(objValue as any), ...(srcValue as any) }; } } ); -}; +} diff --git a/packages/core/src/lib/editor/withSlate.ts b/packages/core/src/lib/editor/withSlate.ts index 25ffe8d160..3873a52bbd 100644 --- a/packages/core/src/lib/editor/withSlate.ts +++ b/packages/core/src/lib/editor/withSlate.ts @@ -102,8 +102,6 @@ export const withSlate = < ...pluginConfig }: WithSlateOptions = {} ): TSlateEditor> => { - console.time('withSlate'); - const editor = e as SlateEditor; // Override incremental id generated by slate @@ -190,9 +188,7 @@ export const withSlate = < rootPluginInstance = rootPlugin(rootPluginInstance) as any; } - console.time('resolvePlugins'); resolvePlugins(editor, [rootPluginInstance]); - console.timeEnd('resolvePlugins'); if (typeof value === 'string') { editor.children = editor.api.html.deserialize({ element: value }) as Value; @@ -214,13 +210,9 @@ export const withSlate = < pipeNormalizeInitialValue(editor); } if (shouldNormalizeEditor) { - console.time('normalizeEditor'); normalizeEditor(editor, { force: true }); - console.timeEnd('normalizeEditor'); } - console.timeEnd('withSlate'); - return editor as any; }; diff --git a/packages/core/src/lib/plugin/createSlatePlugin.spec.ts b/packages/core/src/lib/plugin/createSlatePlugin.spec.ts index 94dcc5a74b..cf9dc86632 100644 --- a/packages/core/src/lib/plugin/createSlatePlugin.spec.ts +++ b/packages/core/src/lib/plugin/createSlatePlugin.spec.ts @@ -920,7 +920,8 @@ describe('createSlatePlugin', () => { it('should configure a deeply nested plugin', () => { const c = createSlatePlugin({ key: 'c', - options: { initialValue: 'c' }, + node: { isElement: true }, + options: { a: 1 }, }); const b = createSlatePlugin({ @@ -934,12 +935,16 @@ describe('createSlatePlugin', () => { }); const editor = createSlateEditor({ - plugins: [a.configurePlugin(c, { options: { initialValue: 'cc' } })], + plugins: [ + a.configurePlugin(c, { + node: { isElement: false }, + options: { a: 2 }, + }), + ], }); - expect(editor.plugins.c.options).toEqual({ - initialValue: 'cc', - }); + expect(editor.plugins.c.node.isElement).toBe(false); + expect(editor.plugins.c.options.a).toBe(2); }); }); }); diff --git a/packages/core/src/lib/plugin/createSlatePlugin.ts b/packages/core/src/lib/plugin/createSlatePlugin.ts index 2f6047a70d..24fb1b7ecb 100644 --- a/packages/core/src/lib/plugin/createSlatePlugin.ts +++ b/packages/core/src/lib/plugin/createSlatePlugin.ts @@ -8,8 +8,8 @@ import type { SlatePlugins, } from './SlatePlugin'; +import { mergePlugins } from '../../internal/mergePlugins'; import { isFunction } from '../utils/misc/isFunction'; -import {mergePlugins} from '../../internal/mergePlugins'; type SlatePluginConfig = Omit< Partial< @@ -131,7 +131,7 @@ export function createSlatePlugin< shortcuts: {}, transforms: {}, }, - config as any + config ) as unknown as SlatePlugin>; plugin.configure = (config) => { diff --git a/packages/core/src/lib/plugin/getSlatePlugin.ts b/packages/core/src/lib/plugin/getSlatePlugin.ts index fb3a91e5dd..37ae0ad80e 100644 --- a/packages/core/src/lib/plugin/getSlatePlugin.ts +++ b/packages/core/src/lib/plugin/getSlatePlugin.ts @@ -7,18 +7,25 @@ import type { import type { AnySlatePlugin, SlatePlugin } from './SlatePlugin'; import { resolvePlugin } from '../utils'; +import { createSlatePlugin } from './createSlatePlugin'; /** Get editor plugin by key or plugin object. */ export function getSlatePlugin( editor: SlateEditor, p: WithRequiredKey ): C extends { node: any } ? C : SlatePlugin { - const plugin = p as any; + let plugin = p as any; const editorPlugin = editor.plugins[p.key] as any; if (!editorPlugin) { - return plugin.__resolved ? p : resolvePlugin(editor, plugin); + // When passing only { key } + if (!plugin.node) { + plugin = createSlatePlugin(plugin); + } + + // Resolve is need when passing an external plugin with extensions (e.g. in withLink) + return plugin.__resolved ? plugin : resolvePlugin(editor, plugin); } return editorPlugin; diff --git a/packages/core/src/lib/utils/resolvePlugin.spec.ts b/packages/core/src/lib/utils/resolvePlugin.spec.ts index d265693451..04ef94eee7 100644 --- a/packages/core/src/lib/utils/resolvePlugin.spec.ts +++ b/packages/core/src/lib/utils/resolvePlugin.spec.ts @@ -1,6 +1,5 @@ import { createSlateEditor } from '../editor'; import { createSlatePlugin } from '../plugin'; -import { resolvePlugin } from './resolvePlugin'; describe('resolvePlugin', () => { it('should be', () => { @@ -33,7 +32,6 @@ describe('resolvePlugin', () => { }); it('should create a deep clone of the plugin instead of options', () => { - const editor = createSlateEditor() as any; const originalPlugin = createSlatePlugin({ key: 'test', options: { @@ -43,7 +41,11 @@ describe('resolvePlugin', () => { }, }); - const resolvedPlugin = resolvePlugin(editor, originalPlugin); + const editor = createSlateEditor({ + plugins: [originalPlugin], + }) as any; + + const resolvedPlugin = editor.plugins.test; // Modify the resolved plugin resolvedPlugin.options.nestedObject.value = 'modified'; @@ -56,12 +58,26 @@ describe('resolvePlugin', () => { expect(typeof resolvedPlugin.extend).toBe('function'); // Create a new instance from the resolved plugin and modify it - const newInstance = originalPlugin.extend({}); - newInstance.options.nestedObject.value = 'new instance'; + const newInstance = originalPlugin.extend({ + options: { + nestedObject: { + value: 'new instance', + }, + }, + }); + + const editor2 = createSlateEditor({ + plugins: [newInstance], + }) as any; // Check that neither the original nor the first resolved plugin are affected expect(originalPlugin.options.nestedObject.value).toBe('modified'); - expect(resolvedPlugin.options.nestedObject.value).toBe('modified'); - expect(newInstance.options.nestedObject.value).toBe('new instance'); + expect(editor2.plugins.test.options.nestedObject.value).toBe( + 'new instance' + ); + expect(editor.plugins.test.options.nestedObject.value).toBe('modified'); + expect(editor2.plugins.test.options.nestedObject.value).toBe( + 'new instance' + ); }); }); diff --git a/packages/core/src/lib/utils/resolvePlugin.ts b/packages/core/src/lib/utils/resolvePlugin.ts index 63d15735fc..6ae1534d7d 100644 --- a/packages/core/src/lib/utils/resolvePlugin.ts +++ b/packages/core/src/lib/utils/resolvePlugin.ts @@ -1,11 +1,11 @@ -import { cloneDeep, merge } from 'lodash'; +import merge from 'lodash/merge.js'; import type { SlateEditor } from '../editor'; import type { PluginConfig } from '../plugin/BasePlugin'; import type { AnySlatePlugin, SlatePlugin } from '../plugin/SlatePlugin'; +import { mergePlugins } from '../../internal/mergePlugins'; import { getEditorPlugin } from '../plugin'; -import {mergePlugins} from '../../internal/mergePlugins'; /** * Resolves and finalizes a plugin configuration for use in a Plate editor. @@ -14,8 +14,8 @@ import {mergePlugins} from '../../internal/mergePlugins'; * and resolving nested plugins. It prepares the plugin for integration into the * Plate editor system by: * - * 1. Applying all stored extensions to the plugin - * 2. Recursively resolving any nested plugins + * 1. Cloning the plugin to avoid mutating the original + * 2. Applying all stored extensions to the plugin * 3. Clearing the extensions array after application * * @example @@ -26,37 +26,8 @@ export const resolvePlugin =

( editor: SlateEditor, _plugin: P ): P => { - // if (_plugin.key === 'p') { - // // Minimize the number of calls - // console.log(editor.key, _plugin.key); - // } - // Create a deep clone of the plugin - let plugin = { - __apiExtensions: [], - __configuration: null, - __extensions: [], - __optionExtensions: [], - dependencies: [], - editor: {}, - handlers: {}, - inject: {}, - node: {}, - override: {}, - parser: {}, - parsers: {}, - plugins: [], - priority: 100, - render: {}, - shortcuts: {}, - transforms: {}, - ...(_plugin as any), - } as P; - - plugin.node = { type: plugin.key, ...(_plugin.node as any) }; - plugin.api = cloneDeep(_plugin.api); - plugin.transforms = cloneDeep(_plugin.transforms); - plugin.options = { ..._plugin.options }; + let plugin = mergePlugins({}, _plugin) as P; plugin.__resolved = true; diff --git a/packages/core/src/lib/utils/resolvePlugins.spec.tsx b/packages/core/src/lib/utils/resolvePlugins.spec.tsx index 68e3cb0084..18f039fa2e 100644 --- a/packages/core/src/lib/utils/resolvePlugins.spec.tsx +++ b/packages/core/src/lib/utils/resolvePlugins.spec.tsx @@ -591,3 +591,62 @@ describe('applyPluginOverrides', () => { expect(editor.plugins).toHaveProperty('c'); }); }); + +describe('mergePlugins behavior in resolvePlugins', () => { + it('should not deeply clone options object', () => { + const nestedOptions = { value: 'original' }; + const plugin = createSlatePlugin({ + key: 'test', + options: { nested: nestedOptions }, + }); + + const editor = createPlateEditor({ + plugins: [plugin], + }); + + // Modify the nested options + nestedOptions.value = 'modified'; + + // Check that the modification is reflected in the resolved plugin's options + expect(editor.plugins.test.options.nested.value).toBe('modified'); + }); + + it('should shallow clone the options object', () => { + const plugin = createSlatePlugin({ + key: 'test', + options: { value: 'original' }, + }); + + const editor = createPlateEditor({ + plugins: [plugin], + }); + + // Modify the top-level option + editor.plugins.test.options.value = 'modified'; + + // Check that the modification does not affect the original plugin + expect(plugin.options.value).toBe('original'); + }); + + it('should be able to merge options', () => { + const plugin = createSlatePlugin({ + key: 'test', + options: { value: 'original' }, + }).extend(({ getOptions }) => ({ + options: { + ...getOptions(), + value: 'modified', + }, + })); + + const editor = createPlateEditor({ + plugins: [plugin], + }); + + // Modify the top-level option + editor.plugins.test.options.value = 'modified'; + + // Check that the modification does not affect the original plugin + expect(plugin.options.value).toBe('original'); + }); +}); diff --git a/packages/core/src/lib/utils/resolvePlugins.ts b/packages/core/src/lib/utils/resolvePlugins.ts index 78a76fd1ce..8b813cb377 100644 --- a/packages/core/src/lib/utils/resolvePlugins.ts +++ b/packages/core/src/lib/utils/resolvePlugins.ts @@ -1,53 +1,16 @@ -import { type AnyObject, isDefined } from '@udecode/utils'; +import { isDefined } from '@udecode/utils'; +import merge from 'lodash/merge.js'; import { createZustandStore } from 'zustand-x'; import type { SlateEditor } from '../editor'; +import { mergePlugins } from '../../internal/mergePlugins'; import { type SlatePlugin, type SlatePlugins, getEditorPlugin, } from '../plugin'; import { resolvePlugin } from './resolvePlugin'; -import {merge} from 'lodash'; -import {mergePlugins} from '../../internal/mergePlugins'; - -export function mergeLevel( - target: T, - source: Partial - // levels = 1 -): T { - if (!target) { - target = {} as T; - } - - function mergeLevel( - targetObj: AnyObject, - sourceObj: AnyObject, - currentLevel: number - ) { - for (const key in sourceObj) { - if (Object.prototype.hasOwnProperty.call(sourceObj, key)) { - if ( - typeof sourceObj[key] === 'object' && - sourceObj[key] !== null && - !Array.isArray(sourceObj[key]) && - // TODO: levels should be used instead of 5 - currentLevel < 10 - ) { - targetObj[key] = targetObj[key] || {}; - mergeLevel(targetObj[key], sourceObj[key], currentLevel + 1); - } else { - targetObj[key] = sourceObj[key]; - } - } - } - } - - mergeLevel(target, source, 1); - - return target; -} /** * Initialize and configure the editor's plugin system. This function sets up @@ -138,14 +101,8 @@ const resolvePluginApis = (editor: SlateEditor) => { (plugin.transforms as any)[plugin.key] = {}; } - merge( - (editor.transforms as any)[plugin.key], - newExtensions - ); - merge( - (plugin.transforms as any)[plugin.key], - newExtensions - ); + merge((editor.transforms as any)[plugin.key], newExtensions); + merge((plugin.transforms as any)[plugin.key], newExtensions); } else { // Editor-wide transform merge(editor.transforms, newExtensions); @@ -290,7 +247,10 @@ export const resolveAndSortPlugins = ( return orderedPlugins; }; -export const applyPluginsToEditor = (editor: SlateEditor, plugins: SlatePlugins) => { +export const applyPluginsToEditor = ( + editor: SlateEditor, + plugins: SlatePlugins +) => { editor.pluginList = plugins; editor.plugins = Object.fromEntries( plugins.map((plugin) => [plugin.key, plugin]) @@ -331,10 +291,7 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { } if (plugin.override.plugins) { Object.entries(plugin.override.plugins).forEach(([key, value]) => { - pluginOverrides[key] = mergePlugins( - pluginOverrides[key], - value - ); + pluginOverrides[key] = mergePlugins(pluginOverrides[key], value); if (value.enabled !== undefined) { enabledOverrides[key] = value.enabled; @@ -349,10 +306,7 @@ export const resolvePluginOverrides = (editor: SlateEditor) => { // Apply plugin overrides if (pluginOverrides[p.key]) { - updatedPlugin = mergePlugins( - updatedPlugin, - pluginOverrides[p.key] - ); + updatedPlugin = mergePlugins(updatedPlugin, pluginOverrides[p.key]); } // Apply component overrides // TODO react diff --git a/packages/core/src/react/editor/usePlateEditor.ts b/packages/core/src/react/editor/usePlateEditor.ts index 9a609d2e70..7b1d648bdf 100644 --- a/packages/core/src/react/editor/usePlateEditor.ts +++ b/packages/core/src/react/editor/usePlateEditor.ts @@ -36,14 +36,10 @@ export function usePlateEditor< : TPlateEditor | null { return React.useMemo( (): any => { - console.time('createPlateEditor'); - if (options.enabled === false) return null; const editor = createPlateEditor(options); - console.timeEnd('createPlateEditor'); - return editor; }, // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/packages/core/src/react/editor/withPlate.spec.ts b/packages/core/src/react/editor/withPlate.spec.ts index e22376c407..915c007020 100644 --- a/packages/core/src/react/editor/withPlate.spec.ts +++ b/packages/core/src/react/editor/withPlate.spec.ts @@ -1,24 +1,33 @@ import { createPlateEditor } from './withPlate'; describe('createPlateEditor', () => { - it.only('benchmark', () => { - const minDuration = 10000; - const batchSize = 1000; - const start = performance.now(); - const minEnd = start + minDuration; - let iterations = 0; - while (performance.now() < minEnd) { - for (let i = 0; i < batchSize; i++) { - createPlateEditor(); - } - iterations += batchSize; + it('performance', () => { + const warmupRuns = 500; + const testRuns = 5000; + const times: number[] = []; + + // Warm-up + for (let i = 0; i < warmupRuns; i++) { + createPlateEditor(); } - const end = performance.now(); - const average = (end - start) / iterations; - console.log(average); - }); - it('logs resolvePlugin', () => { - createPlateEditor({ id: 2 }); + // Test runs + for (let i = 0; i < testRuns; i++) { + const start = performance.now(); + createPlateEditor(); + const end = performance.now(); + times.push(end - start); + } + + const average = times.reduce((a, b) => a + b) / times.length; + const median = times.sort((a, b) => a - b)[Math.floor(times.length / 2)]; + const p95 = times[Math.floor(times.length * 0.95)]; + + console.info(`Average: ${average.toFixed(3)}ms`); + console.info(`Median: ${median.toFixed(3)}ms`); + console.info(`95th percentile: ${p95.toFixed(3)}ms`); + + expect(average).toBeLessThan(0.5); // Adjust threshold as needed + expect(p95).toBeLessThan(1); // Adjust threshold as needed }); }); diff --git a/packages/heading/src/lib/HeadingPlugin.spec.ts b/packages/heading/src/lib/HeadingPlugin.spec.ts index d198b6aa16..7b318b3512 100644 --- a/packages/heading/src/lib/HeadingPlugin.spec.ts +++ b/packages/heading/src/lib/HeadingPlugin.spec.ts @@ -31,17 +31,15 @@ describe('HeadingPlugin', () => { plugins: [HeadingPlugin], }); - const headingPlugin = editor.getPlugin(HeadingPlugin); - for (let i = 0; i < 3; i++) { - const plugin = headingPlugin.plugins[i]; + const plugin = editor.plugins['h' + (i + 1)]; expect( plugin.shortcuts['toggleHeading' + (i + 1)].keys.at(-1).at(-1) ).toBe(String(i + 1)); } for (let i = 3; i < 6; i++) { - const plugin = headingPlugin.plugins[i]; + const plugin = editor.plugins['h' + (i + 1)]; expect(plugin.options?.hotkey).toBeUndefined(); } }); @@ -127,17 +125,15 @@ describe('HeadingPluginReact', () => { plugins: [ReactHeadingPlugin], }); - const headingPlugin = editor.getPlugin(ReactHeadingPlugin); - for (let i = 0; i < 3; i++) { - const plugin = headingPlugin.plugins[i]; + const plugin = editor.plugins['h' + (i + 1)]; expect( plugin.shortcuts['toggleHeading' + (i + 1)].keys.at(-1).at(-1) ).toBe(String(i + 1)); } for (let i = 3; i < 6; i++) { - const plugin = headingPlugin.plugins[i]; + const plugin = editor.plugins['h' + (i + 1)]; expect(plugin.shortcuts['toggleHeading' + (i + 1)]).toBeUndefined(); } }); @@ -172,11 +168,9 @@ describe('HeadingPluginReact', () => { ], }); - const headingPlugin = editor.getPlugin(ReactHeadingPlugin); - - expect(headingPlugin.plugins[0].shortcuts.toggleHeading1).toBeDefined(); - expect(headingPlugin.plugins[1].shortcuts.toggleHeading3).toBeDefined(); - expect(headingPlugin.plugins[2].shortcuts.toggleHeading5).toBeUndefined(); + expect(editor.plugins.h1.shortcuts.toggleHeading1).toBeDefined(); + expect(editor.plugins.h3.shortcuts.toggleHeading3).toBeDefined(); + expect(editor.plugins.h5.shortcuts.toggleHeading5).toBeUndefined(); }); }); From b5f17a872d369412d29fbd784d336ddc072049ed Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 11 Sep 2024 02:30:27 +0200 Subject: [PATCH 11/12] doc --- .changeset/big-cameras-cry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/big-cameras-cry.md b/.changeset/big-cameras-cry.md index 51a4e1fe3d..fafadcd4bb 100644 --- a/.changeset/big-cameras-cry.md +++ b/.changeset/big-cameras-cry.md @@ -4,7 +4,7 @@ - Change `plugin.options` merging behavior from deep merge to shallow merge. - This affects `.extend()`, `.configure()`, and other methods that modify plugin options. -- This is an **important patch** to v37 that introduced a performance regression when creating an editor. +- This update addresses a **performance regression** introduced in v37 that affected editor creation. Before: From 61c6e8f97ef731832959cbd8e37cc4aac74a5f28 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 11 Sep 2024 10:04:59 +0200 Subject: [PATCH 12/12] test --- .../core/src/react/editor/withPlate.spec.ts | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 packages/core/src/react/editor/withPlate.spec.ts diff --git a/packages/core/src/react/editor/withPlate.spec.ts b/packages/core/src/react/editor/withPlate.spec.ts deleted file mode 100644 index 915c007020..0000000000 --- a/packages/core/src/react/editor/withPlate.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { createPlateEditor } from './withPlate'; - -describe('createPlateEditor', () => { - it('performance', () => { - const warmupRuns = 500; - const testRuns = 5000; - const times: number[] = []; - - // Warm-up - for (let i = 0; i < warmupRuns; i++) { - createPlateEditor(); - } - - // Test runs - for (let i = 0; i < testRuns; i++) { - const start = performance.now(); - createPlateEditor(); - const end = performance.now(); - times.push(end - start); - } - - const average = times.reduce((a, b) => a + b) / times.length; - const median = times.sort((a, b) => a - b)[Math.floor(times.length / 2)]; - const p95 = times[Math.floor(times.length * 0.95)]; - - console.info(`Average: ${average.toFixed(3)}ms`); - console.info(`Median: ${median.toFixed(3)}ms`); - console.info(`95th percentile: ${p95.toFixed(3)}ms`); - - expect(average).toBeLessThan(0.5); // Adjust threshold as needed - expect(p95).toBeLessThan(1); // Adjust threshold as needed - }); -});