mirror of https://github.com/artf/grapesjs.git
15 changed files with 700 additions and 126 deletions
@ -1,83 +1,264 @@ |
|||||
import { isString } from 'underscore'; |
import { isFunction, isString } from 'underscore'; |
||||
import Editor from '../editor'; |
import { ItemManagerModule, ModuleConfig } from '../abstract/Module'; |
||||
import { getGlobal } from '../utils/mixins'; |
import BlocksEvents from '../block_manager/types'; |
||||
|
import { ComponentsEvents } from '../dom_components/types'; |
||||
|
import DeviceEvents from '../device_manager/types'; |
||||
|
import EditorModel from '../editor/model/Editor'; |
||||
|
import { KeymapsEvents } from '../keymaps/types'; |
||||
|
import { StyleManagerEvents } from '../style_manager/types'; |
||||
|
import PluginModel, { createPluginAdded } from './model/Plugin'; |
||||
|
import Plugins from './model/Plugins'; |
||||
|
import { |
||||
|
Plugin, |
||||
|
PluginAdded, |
||||
|
PluginCleanup, |
||||
|
PluginCleanupHandler, |
||||
|
PluginDescriptor, |
||||
|
PluginInput, |
||||
|
PluginOptions, |
||||
|
PluginWithMeta, |
||||
|
PluginsEvents, |
||||
|
} from './types'; |
||||
|
import { |
||||
|
addLegacyPlugin, |
||||
|
getLegacyPlugin, |
||||
|
getLegacyPlugins, |
||||
|
getPluginId, |
||||
|
getPlugin, |
||||
|
isPluginDescriptor, |
||||
|
isPluginFunction, |
||||
|
logPluginWarn, |
||||
|
legacyGlobalPlugins, |
||||
|
unwrapPluginMeta, |
||||
|
usePlugin, |
||||
|
} from './utils'; |
||||
|
|
||||
type PluginOptions = Record<string, any>; |
export type { |
||||
|
Plugin, |
||||
|
PluginAdded, |
||||
|
PluginCleanup, |
||||
|
PluginCleanupHandler, |
||||
|
PluginDescriptor, |
||||
|
PluginInput, |
||||
|
PluginOptions, |
||||
|
PluginWithMeta, |
||||
|
}; |
||||
|
export { addLegacyPlugin, getLegacyPlugin, getLegacyPlugins, getPlugin, legacyGlobalPlugins, logPluginWarn, usePlugin }; |
||||
|
|
||||
export type Plugin<T extends PluginOptions = {}> = (editor: Editor, config: T) => void; |
type PluginTarget = string | Plugin<any> | PluginModel; |
||||
|
|
||||
const getPluginById = (pluginId: string, plugins: PluginManager) => { |
export default class PluginManager extends ItemManagerModule<ModuleConfig, Plugins> { |
||||
let result = plugins.get(pluginId); |
events = PluginsEvents; |
||||
|
storageKey = ''; |
||||
|
|
||||
// Try to search in global context
|
constructor(em: EditorModel) { |
||||
if (!result) { |
super(em, 'PluginManager', new Plugins(), PluginsEvents, {}); |
||||
const wplg = (getGlobal() as any)[pluginId]; |
|
||||
result = wplg?.default || wplg; |
|
||||
} |
} |
||||
|
|
||||
return result; |
get editor() { |
||||
}; |
return this.em.getEditor(); |
||||
|
} |
||||
|
|
||||
export const getPlugin = (plugin: string | Plugin<any>, plugins: PluginManager) => { |
private getConfigPluginOptions(id: string, sourcePlugin: string | Plugin<any>) { |
||||
return isString(plugin) |
const pluginsOpts = this.editor.getConfig().pluginsOpts || {}; |
||||
? getPluginById(plugin, plugins) |
const inlineKey = isFunction(sourcePlugin) ? sourcePlugin.toString() : ''; |
||||
: (plugin as unknown as { default: Plugin<any> })?.default || plugin; |
return pluginsOpts[id] || (inlineKey ? pluginsOpts[inlineKey] || {} : {}); |
||||
}; |
} |
||||
|
|
||||
export const logPluginWarn = (editor: Editor, plugin: string) => { |
private generatePluginId() { |
||||
editor.getModel().logWarning(`Plugin ${plugin} not found`, { |
return `gjs-plugin:${this._createId(8)}`; |
||||
context: 'plugins', |
} |
||||
plugin, |
|
||||
}); |
private resolvePluginId(input: string | Plugin<any>, plugin: Plugin<any>, explicitId?: string) { |
||||
}; |
return explicitId || (isString(input) ? input : '') || getPluginId(plugin) || this.generatePluginId(); |
||||
|
} |
||||
|
|
||||
|
private resolvePluginTarget(target: PluginTarget) { |
||||
|
if (target instanceof PluginModel) return target; |
||||
|
|
||||
|
if (isString(target)) return this.get(target); |
||||
|
|
||||
export default class PluginManager { |
const { plugin } = unwrapPluginMeta(target); |
||||
plugins: Record<string, Plugin> = {}; |
if (!isPluginFunction(plugin)) return; |
||||
|
|
||||
/** |
return this.getAll().find((item) => item.get('plugin') === plugin); |
||||
* Add new plugin. Plugins could not be overwritten |
} |
||||
* @param {string} id Plugin ID |
|
||||
* @param {Function} plugin Function which contains all plugin logic |
private normalizePlugin(input: PluginInput, options: PluginOptions = {}) { |
||||
* @return {Function} The plugin function |
const descriptor = isPluginDescriptor(input) ? input : undefined; |
||||
* @deprecated Don't use named plugins, create plugins as simple functions. More about [Plugins](https://grapesjs.com/docs/modules/Plugins.html)
|
const sourcePlugin = (descriptor ? descriptor.plugin : input) as string | Plugin<any>; |
||||
* @example |
const explicitId = descriptor?.id || ''; |
||||
* PluginManager.add('some-plugin', function(editor) { |
const unwrapped = unwrapPluginMeta(sourcePlugin); |
||||
* editor.Commands.add('new-command', { |
const resolvedPlugin = getPlugin(unwrapped.plugin); |
||||
* run: function(editor, senderBtn){ |
let normalized; |
||||
* console.log('Executed new-command'); |
|
||||
* } |
if (!resolvedPlugin || !isPluginFunction(resolvedPlugin)) { |
||||
* }) |
const pluginId = isString(unwrapped.plugin) ? unwrapped.plugin : getPluginId(unwrapped.plugin) || explicitId; |
||||
* }); |
if (explicitId) { |
||||
*/ |
throw new Error(`Plugin ${explicitId} not found`); |
||||
add<T extends PluginOptions>(id: string, plugin: Plugin<T>) { |
} |
||||
const plg = this.get(id); |
logPluginWarn(this.editor, pluginId || 'unknown'); |
||||
|
} else { |
||||
if (plg) { |
const id = explicitId || this.resolvePluginId(sourcePlugin, resolvedPlugin); |
||||
return plg; |
normalized = { |
||||
|
id, |
||||
|
plugin: resolvedPlugin, |
||||
|
options: { |
||||
|
...this.getConfigPluginOptions(id, sourcePlugin), |
||||
|
...unwrapped.options, |
||||
|
...options, |
||||
|
}, |
||||
|
}; |
||||
} |
} |
||||
|
|
||||
// @ts-ignore
|
return normalized; |
||||
this.plugins[id] = plugin; |
} |
||||
|
|
||||
|
private createAddedTracker() { |
||||
|
const added = createPluginAdded(); |
||||
|
const cleanup: PluginCleanup[] = []; |
||||
|
const { editor } = this; |
||||
|
const listeners: Array<[string, (...args: any[]) => void]> = []; |
||||
|
const listen = (event: string, callback: (...args: any[]) => void) => { |
||||
|
editor.on(event, callback); |
||||
|
listeners.push([event, callback]); |
||||
|
}; |
||||
|
|
||||
|
listen(BlocksEvents.add, (block: any) => { |
||||
|
const id = block.get?.('id'); |
||||
|
if (!id || added.blocks.includes(id)) return; |
||||
|
added.blocks.push(id); |
||||
|
cleanup.push(() => editor.Blocks.remove(id)); |
||||
|
}); |
||||
|
|
||||
|
listen(KeymapsEvents.add, (keymap: any) => { |
||||
|
const id = keymap.id; |
||||
|
if (!id || added.keymaps.includes(id)) return; |
||||
|
added.keymaps.push(id); |
||||
|
cleanup.push(() => editor.Keymaps.remove(id)); |
||||
|
}); |
||||
|
|
||||
|
listen(ComponentsEvents.typeAdd, (type: any) => { |
||||
|
const id = type?.id; |
||||
|
if (!id || added.componentTypes.includes(id)) return; |
||||
|
added.componentTypes.push(id); |
||||
|
cleanup.push(() => editor.Components.removeType(id)); |
||||
|
}); |
||||
|
|
||||
|
listen(DeviceEvents.add, (device: any) => { |
||||
|
const id = device?.id || device?.get?.('id'); |
||||
|
if (!id || added.devices.includes(id)) return; |
||||
|
added.devices.push(id); |
||||
|
cleanup.push(() => editor.Devices.remove(id)); |
||||
|
}); |
||||
|
|
||||
|
listen(StyleManagerEvents.sectorAdd, (sector: any) => { |
||||
|
const id = sector?.id || sector?.get?.('id'); |
||||
|
if (!id || added.styleSectors.includes(id)) return; |
||||
|
added.styleSectors.push(id); |
||||
|
cleanup.push(() => editor.StyleManager.removeSector(id)); |
||||
|
}); |
||||
|
|
||||
|
listen(StyleManagerEvents.propertyAdd, (property: any) => { |
||||
|
const sectorId = property?.collection?.sector?.get?.('id'); |
||||
|
const id = property?.get?.('property') || property?.get?.('id'); |
||||
|
const alreadyAdded = added.styleProperties.some((item) => item.sectorId === sectorId && item.id === id); |
||||
|
if (!sectorId || !id || alreadyAdded) return; |
||||
|
added.styleProperties.push({ sectorId, id }); |
||||
|
cleanup.push(() => editor.StyleManager.removeProperty(sectorId, id)); |
||||
|
}); |
||||
|
|
||||
|
return { |
||||
|
added, |
||||
|
stop: () => listeners.forEach(([event, callback]) => editor.off(event, callback)), |
||||
|
cleanup: () => { |
||||
|
cleanup |
||||
|
.slice() |
||||
|
.reverse() |
||||
|
.forEach((cb) => cb()); |
||||
|
}, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
add(input: PluginInput, options: PluginOptions = {}) { |
||||
|
const normalized = this.normalizePlugin(input, options); |
||||
|
if (!normalized) return; |
||||
|
|
||||
|
const existing = this.get(normalized.id); |
||||
|
if (existing) return existing; |
||||
|
|
||||
|
const tracking = this.createAddedTracker(); |
||||
|
let result: unknown; |
||||
|
|
||||
|
try { |
||||
|
result = normalized.plugin(this.editor, normalized.options); |
||||
|
} catch (error) { |
||||
|
tracking.stop(); |
||||
|
tracking.cleanup(); |
||||
|
throw error; |
||||
|
} |
||||
|
|
||||
|
tracking.stop(); |
||||
|
|
||||
|
const plugin = new PluginModel({ |
||||
|
id: normalized.id, |
||||
|
plugin: normalized.plugin, |
||||
|
options: normalized.options, |
||||
|
added: tracking.added, |
||||
|
cleanup: () => {}, |
||||
|
}); |
||||
|
|
||||
|
let cleaned = false; |
||||
|
const builtInCleanup = () => { |
||||
|
if (cleaned) return; |
||||
|
cleaned = true; |
||||
|
tracking.cleanup(); |
||||
|
}; |
||||
|
|
||||
|
const cleanup = () => { |
||||
|
if (cleaned) return; |
||||
|
const customCleanup = isFunction(result) ? result : null; |
||||
|
|
||||
|
if (customCleanup) { |
||||
|
customCleanup({ |
||||
|
cleanup: builtInCleanup, |
||||
|
editor: this.editor, |
||||
|
plugin, |
||||
|
}); |
||||
|
} else { |
||||
|
builtInCleanup(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
plugin.set('cleanup', cleanup); |
||||
|
this.all.add(plugin); |
||||
return plugin; |
return plugin; |
||||
} |
} |
||||
|
|
||||
/** |
get(id: string): PluginModel | undefined { |
||||
* Returns plugin by ID |
return this.all.get(id); |
||||
* @param {string} id Plugin ID |
|
||||
* @return {Function|undefined} Plugin |
|
||||
* @example |
|
||||
* var plugin = PluginManager.get('some-plugin'); |
|
||||
* plugin(editor); |
|
||||
*/ |
|
||||
get<T extends PluginOptions>(id: string): Plugin<T> | undefined { |
|
||||
return this.plugins[id]; |
|
||||
} |
} |
||||
|
|
||||
/** |
|
||||
* Returns object with all plugins |
|
||||
*/ |
|
||||
getAll() { |
getAll() { |
||||
return this.plugins; |
return [...this.all.models] as PluginModel[]; |
||||
|
} |
||||
|
|
||||
|
remove(target: PluginTarget, opts: Record<string, any> = {}) { |
||||
|
const plugin = this.resolvePluginTarget(target); |
||||
|
if (!plugin) return; |
||||
|
|
||||
|
const { em, events } = this; |
||||
|
const rm = () => { |
||||
|
plugin.get('cleanup')?.(); |
||||
|
this.all.remove(plugin, opts); |
||||
|
return plugin; |
||||
|
}; |
||||
|
|
||||
|
!opts.silent && em.trigger(events.removeBefore, plugin, rm, opts); |
||||
|
return !opts.abort ? rm() : undefined; |
||||
|
} |
||||
|
|
||||
|
destroy() { |
||||
|
this.__destroy(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,35 @@ |
|||||
|
import { Model } from '../../common'; |
||||
|
import { Plugin as PluginFn, PluginAdded, PluginCleanup } from '../types'; |
||||
|
|
||||
|
export const createPluginAdded = (): PluginAdded => ({ |
||||
|
blocks: [], |
||||
|
commands: [], |
||||
|
keymaps: [], |
||||
|
componentTypes: [], |
||||
|
devices: [], |
||||
|
traitTypes: [], |
||||
|
styleTypes: [], |
||||
|
assetTypes: [], |
||||
|
styleSectors: [], |
||||
|
styleProperties: [], |
||||
|
}); |
||||
|
|
||||
|
export interface PluginProperties { |
||||
|
id: string; |
||||
|
plugin: PluginFn<any>; |
||||
|
options: Record<string, any>; |
||||
|
added: PluginAdded; |
||||
|
cleanup: PluginCleanup; |
||||
|
} |
||||
|
|
||||
|
export default class Plugin extends Model<PluginProperties> { |
||||
|
defaults(): PluginProperties { |
||||
|
return { |
||||
|
id: '', |
||||
|
plugin: (() => {}) as PluginFn<any>, |
||||
|
options: {}, |
||||
|
added: createPluginAdded(), |
||||
|
cleanup: () => {}, |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
import { Collection } from '../../common'; |
||||
|
import Plugin from './Plugin'; |
||||
|
|
||||
|
export default class Plugins extends Collection<Plugin> {} |
||||
|
|
||||
|
Plugins.prototype.model = Plugin; |
||||
@ -0,0 +1,101 @@ |
|||||
|
import type Editor from '../editor'; |
||||
|
import { |
||||
|
EventCallbackAdd, |
||||
|
EventCallbackAll, |
||||
|
EventCallbackRemove, |
||||
|
EventCallbackRemoveBefore, |
||||
|
EventCallbackUpdate, |
||||
|
} from '../common'; |
||||
|
import PluginModel from './model/Plugin'; |
||||
|
|
||||
|
export type PluginOptions = Record<string, any>; |
||||
|
|
||||
|
export interface PluginAdded { |
||||
|
blocks: string[]; |
||||
|
commands: string[]; |
||||
|
keymaps: string[]; |
||||
|
componentTypes: string[]; |
||||
|
devices: string[]; |
||||
|
traitTypes: string[]; |
||||
|
styleTypes: string[]; |
||||
|
assetTypes: string[]; |
||||
|
styleSectors: string[]; |
||||
|
styleProperties: Array<{ sectorId: string; id: string }>; |
||||
|
} |
||||
|
|
||||
|
export type PluginCleanup = () => void; |
||||
|
|
||||
|
export type PluginCleanupHandler = (ctx: { cleanup: PluginCleanup; plugin: PluginModel }) => void; |
||||
|
|
||||
|
export type PluginResult = void | PluginCleanupHandler | object | null | undefined; |
||||
|
|
||||
|
export interface Plugin<T extends PluginOptions = {}> { |
||||
|
(editor: Editor, config: T): PluginResult; |
||||
|
__gjsPluginId?: string; |
||||
|
} |
||||
|
|
||||
|
export interface PluginDescriptor { |
||||
|
id: string; |
||||
|
plugin: Plugin<any>; |
||||
|
} |
||||
|
|
||||
|
export interface PluginWithMeta<T extends PluginOptions = {}> extends Plugin<T> { |
||||
|
__gjsPluginMeta?: { |
||||
|
plugin: string | Plugin<any>; |
||||
|
options?: T; |
||||
|
id?: string; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export type PluginInput = string | Plugin<any> | PluginDescriptor; |
||||
|
|
||||
|
export type PluginEvent = `${PluginsEvents}`; |
||||
|
|
||||
|
/**{START_EVENTS}*/ |
||||
|
export enum PluginsEvents { |
||||
|
/** |
||||
|
* @event `plugin:add` Plugin installed in the editor. |
||||
|
* @example |
||||
|
* editor.on('plugin:add', (plugin) => { ... }); |
||||
|
*/ |
||||
|
add = 'plugin:add', |
||||
|
|
||||
|
/** |
||||
|
* @event `plugin:remove` Plugin removed from the editor. |
||||
|
* @example |
||||
|
* editor.on('plugin:remove', (plugin) => { ... }); |
||||
|
*/ |
||||
|
remove = 'plugin:remove', |
||||
|
|
||||
|
/** |
||||
|
* @event `plugin:remove:before` Triggered before plugin removal. |
||||
|
* @example |
||||
|
* editor.on('plugin:remove:before', (plugin, remove, opts) => { ... }); |
||||
|
*/ |
||||
|
removeBefore = 'plugin:remove:before', |
||||
|
|
||||
|
/** |
||||
|
* @event `plugin:update` Plugin updated. |
||||
|
* @example |
||||
|
* editor.on('plugin:update', (plugin, changes) => { ... }); |
||||
|
*/ |
||||
|
update = 'plugin:update', |
||||
|
|
||||
|
/** |
||||
|
* @event `plugin` Catch-all event for plugin changes. |
||||
|
* @example |
||||
|
* editor.on('plugin', ({ event, model, ... }) => { ... }); |
||||
|
*/ |
||||
|
all = 'plugin', |
||||
|
} |
||||
|
/**{END_EVENTS}*/ |
||||
|
|
||||
|
export interface PluginsEventCallback { |
||||
|
[PluginsEvents.add]: EventCallbackAdd<PluginModel>; |
||||
|
[PluginsEvents.remove]: EventCallbackRemove<PluginModel>; |
||||
|
[PluginsEvents.removeBefore]: EventCallbackRemoveBefore<PluginModel>; |
||||
|
[PluginsEvents.update]: EventCallbackUpdate<PluginModel>; |
||||
|
[PluginsEvents.all]: EventCallbackAll<PluginEvent, PluginModel>; |
||||
|
} |
||||
|
|
||||
|
export default PluginsEvents; |
||||
@ -0,0 +1,118 @@ |
|||||
|
import { isFunction, isString } from 'underscore'; |
||||
|
import type Editor from '../editor'; |
||||
|
import EditorModel from '../editor/model/Editor'; |
||||
|
import { getGlobal } from '../utils/mixins'; |
||||
|
import type { Plugin, PluginDescriptor, PluginOptions, PluginWithMeta } from './types'; |
||||
|
|
||||
|
const LEGACY_PLUGIN_ERROR = |
||||
|
'grapesjs.plugins.add(...) is deprecated. Pass plugins directly via init({ plugins: [...] }) or use usePlugin(...).'; |
||||
|
|
||||
|
const legacyPlugins = new Map<string, Plugin<any>>(); |
||||
|
|
||||
|
export const isPluginFunction = (value: unknown): value is Plugin<any> => isFunction(value); |
||||
|
|
||||
|
export const isPluginDescriptor = (value: unknown): value is PluginDescriptor => |
||||
|
!!value && typeof value === 'object' && !isFunction(value) && 'plugin' in value; |
||||
|
|
||||
|
export const unwrapPluginMeta = ( |
||||
|
plugin: string | Plugin<any>, |
||||
|
): { plugin: string | Plugin<any>; options: PluginOptions; id?: string } => { |
||||
|
let current = plugin; |
||||
|
const options: PluginOptions = {}; |
||||
|
let id: string | undefined; |
||||
|
|
||||
|
while (isPluginFunction(current) && (current as PluginWithMeta<any>).__gjsPluginMeta) { |
||||
|
const meta = (current as PluginWithMeta<any>).__gjsPluginMeta!; |
||||
|
current = meta.plugin; |
||||
|
Object.assign(options, meta.options || {}); |
||||
|
id = id || meta.id; |
||||
|
} |
||||
|
|
||||
|
return { plugin: current, options, id }; |
||||
|
}; |
||||
|
|
||||
|
export const getLegacyPlugin = (pluginId: string) => legacyPlugins.get(pluginId); |
||||
|
|
||||
|
export const getLegacyPlugins = () => legacyPlugins; |
||||
|
|
||||
|
export const clearLegacyPlugins = () => legacyPlugins.clear(); |
||||
|
|
||||
|
export const addLegacyPlugin = <T extends PluginOptions>(id: string, plugin: Plugin<T>) => { |
||||
|
console.error(LEGACY_PLUGIN_ERROR); |
||||
|
legacyPlugins.set(id, plugin as Plugin<any>); |
||||
|
return plugin; |
||||
|
}; |
||||
|
|
||||
|
export const legacyGlobalPlugins = { |
||||
|
add: addLegacyPlugin, |
||||
|
get: getLegacyPlugin, |
||||
|
getAll: getLegacyPlugins, |
||||
|
clear: clearLegacyPlugins, |
||||
|
}; |
||||
|
|
||||
|
export const findLegacyPluginId = (plugin: Plugin<any>) => { |
||||
|
let result = ''; |
||||
|
legacyPlugins.forEach((storedPlugin, id) => { |
||||
|
if (!result && storedPlugin === plugin) { |
||||
|
result = id; |
||||
|
} |
||||
|
}); |
||||
|
return result || undefined; |
||||
|
}; |
||||
|
|
||||
|
export const findGlobalPluginId = (plugin: Plugin<any>) => { |
||||
|
const globalPlugins = getGlobal() as Record<string, any>; |
||||
|
|
||||
|
return Object.keys(globalPlugins).find((id) => { |
||||
|
const globalPlugin = globalPlugins[id]; |
||||
|
return globalPlugin === plugin || globalPlugin?.default === plugin; |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
export const getPluginId = (plugin: Plugin<any>) => |
||||
|
plugin.__gjsPluginId || findLegacyPluginId(plugin) || findGlobalPluginId(plugin); |
||||
|
|
||||
|
export const getPluginById = (pluginId: string) => { |
||||
|
const legacy = getLegacyPlugin(pluginId); |
||||
|
|
||||
|
if (legacy) { |
||||
|
return legacy; |
||||
|
} |
||||
|
|
||||
|
const globalPlugin = (getGlobal() as any)[pluginId]; |
||||
|
return globalPlugin?.default || globalPlugin; |
||||
|
}; |
||||
|
|
||||
|
export const getPlugin = (plugin: string | Plugin<any>) => { |
||||
|
const { plugin: unwrapped } = unwrapPluginMeta(plugin); |
||||
|
return isString(unwrapped) |
||||
|
? getPluginById(unwrapped) |
||||
|
: (unwrapped as unknown as { default?: Plugin<any> })?.default || unwrapped; |
||||
|
}; |
||||
|
|
||||
|
export const logPluginWarn = (editor: { getModel(): EditorModel }, plugin: string) => { |
||||
|
editor.getModel().logWarning(`Plugin ${plugin} not found`, { |
||||
|
context: 'plugins', |
||||
|
plugin, |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
export const usePlugin = <P extends Plugin<any> | string>(plugin: P, opts?: P extends Plugin<infer C> ? C : {}) => { |
||||
|
const wrapped = ((editor: Editor) => { |
||||
|
const pluginResult = getPlugin(plugin); |
||||
|
|
||||
|
if (pluginResult) { |
||||
|
pluginResult(editor, opts || {}); |
||||
|
} else { |
||||
|
logPluginWarn(editor as { getModel(): EditorModel }, plugin as string); |
||||
|
} |
||||
|
}) as PluginWithMeta<any>; |
||||
|
|
||||
|
wrapped.__gjsPluginMeta = { |
||||
|
plugin, |
||||
|
options: (opts || {}) as Record<string, any>, |
||||
|
id: typeof plugin === 'string' ? plugin : plugin.__gjsPluginId, |
||||
|
}; |
||||
|
|
||||
|
return wrapped; |
||||
|
}; |
||||
Loading…
Reference in new issue