Skip to content

Commit

Permalink
perf: added menu config ts type (#246)
Browse files Browse the repository at this point in the history
* perf: add more menu config type

* perf: add more ts type

* perf: add more menu config ts type

* Create spicy-foxes-add.md
  • Loading branch information
cycleccc authored Oct 12, 2024
1 parent 1809d35 commit eea16b2
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 46 deletions.
7 changes: 7 additions & 0 deletions .changeset/spicy-foxes-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@wangeditor-next/basic-modules": patch
"@wangeditor-next/core": patch
"@wangeditor-next/editor": patch
---

perf: added menu config ts type
2 changes: 1 addition & 1 deletion packages/basic-modules/src/modules/image/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,5 @@ export async function updateImageNode(
const imageNode = DomEditor.getSelectedNodeByType(editor, 'image')
const { onUpdatedImage } = editor.getMenuConfig('editImage')

if (onUpdatedImage) { onUpdatedImage(imageNode) }
if (onUpdatedImage) { onUpdatedImage(imageNode as ImageElement) }
}
2 changes: 1 addition & 1 deletion packages/basic-modules/src/modules/link/menu/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function genLinkMenuConfig() {
* @param text link text
* @param url link url
*/
checkLink(text: string, url: string): boolean | string | undefined {
checkLink(_text: string, _url: string): boolean | string | undefined {
// 1. 返回 true ,说明检查通过
// 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
* @author wangfupeng
*/

import forEach from 'lodash.foreach'
import cloneDeep from 'lodash.clonedeep'
import forEach from 'lodash.foreach'

import { IEditorConfig, IMenuConfig, IToolbarConfig } from './interface'
import { GLOBAL_MENU_CONF } from './register'

Expand All @@ -13,10 +14,11 @@ import { GLOBAL_MENU_CONF } from './register'
*/
export function genEditorConfig(userConfig: Partial<IEditorConfig> = {}): IEditorConfig {
const defaultMenuConf = cloneDeep(GLOBAL_MENU_CONF)
const newMenuConf: IMenuConfig = {}
const newMenuConf: Partial<IMenuConfig> = {}

// 单独处理 menuConf
const { MENU_CONF: userMenuConf = {} } = userConfig

forEach(defaultMenuConf, (menuConf, menuKey) => {
// 生成新的 menu config
newMenuConf[menuKey] = {
Expand Down
157 changes: 152 additions & 5 deletions packages/core/src/config/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
* @author wangfupeng
*/

import { Range, NodeEntry, Node } from 'slate'
import { ImageElement } from 'packages/basic-modules/src/modules/image/custom-types'
import { VideoElement } from 'packages/video-module/src/module/custom-types'
import { Node, NodeEntry, Range } from 'slate'

import { IDomEditor } from '../editor/interface'
import { IMenuGroup } from '../menus/interface'
import { IUploadConfig } from '../upload'

interface IHoverbarConf {
// key 即 element type
Expand All @@ -18,18 +22,161 @@ interface IHoverbarConf {
export type AlertType = 'success' | 'info' | 'warning' | 'error'

export interface ISingleMenuConfig {
[key: string]: any
[key: string]: any;
iconSvg?: string;
}

interface IColorConfig {
colors: string[];
}

interface IFontSizeItem {
name: string;
value: string;
}

interface IFontSizeConfig {
fontSizeList: (string | IFontSizeItem)[];
}

interface IFontFamilyItem {
name: string;
value: string;
}

interface IFontFamilyConfig {
fontFamilyList: (string | IFontFamilyItem)[];
}

interface ILineHeightConfig {
lineHeightList: string[];
}

interface IImageMenuBaseConfig {
checkImage?: (src: string, alt: string, url: string) => boolean | undefined | string;
parseImageSrc?: (src: string) => string;
}

interface IInsertImageConfig extends IImageMenuBaseConfig {
onInsertedImage?: (imageNode: ImageElement | null) => void;
}

interface IEditImageConfig extends IImageMenuBaseConfig {
onUpdatedImage?: (imageNode: ImageElement | null) => void;
}
interface IEmotionConfig {
emotions: string[];
}

interface IInsertTableConfig {
minWidth: number;
tableHeader: {
selected: boolean;
};
tableFullWidth: {
selected: boolean;
}
}

interface ILinkConfig {
checkLink: (text:string, url:string)=> string | boolean | undefined
parseLinkUrl: (url: string) => string
}

interface IInsertVideoConfig {
onInsertedVideo: (videoNode: VideoElement) => NodeEntry | Range;
checkVideo: (src:string, poster:string)=> string | boolean | undefined
parseVideoSrc: (url: string) => string
}

interface IUploadVideoConfig extends IUploadConfig {
// 视频专属配置
}

interface IUploadImageConfig extends IUploadConfig {
base64LimitSize?: number;
}

interface ICodeLangConfig {
codeLangs: { text: string; value: string }[];
}

export interface IMenuConfig {
[key: string]: ISingleMenuConfig
bold: ISingleMenuConfig;
underline: ISingleMenuConfig;
italic: ISingleMenuConfig;
through: ISingleMenuConfig;
code: ISingleMenuConfig;
sub: ISingleMenuConfig;
sup: ISingleMenuConfig;
clearStyle: ISingleMenuConfig;
color: IColorConfig;
bgColor: IColorConfig;
fontSize: IFontSizeConfig;
fontFamily: IFontFamilyConfig;
indent: ISingleMenuConfig;
delIndent: ISingleMenuConfig;
justifyLeft: ISingleMenuConfig;
justifyRight: ISingleMenuConfig;
justifyCenter: ISingleMenuConfig;
justifyJustify: ISingleMenuConfig;
lineHeight: ILineHeightConfig;
insertImage: IInsertImageConfig;
deleteImage: ISingleMenuConfig;
editImage: IEditImageConfig;
viewImageLink: ISingleMenuConfig;
imageWidth30: ISingleMenuConfig;
imageWidth50: ISingleMenuConfig;
imageWidth100: ISingleMenuConfig;
editorImageSizeMenu: ISingleMenuConfig;
divider: ISingleMenuConfig;
emotion: IEmotionConfig;
insertLink: ILinkConfig;
editLink: ILinkConfig;
unLink: ISingleMenuConfig;
viewLink: ISingleMenuConfig;
codeBlock: ISingleMenuConfig;
blockquote: ISingleMenuConfig;
headerSelect: ISingleMenuConfig;
header1: ISingleMenuConfig;
header2: ISingleMenuConfig;
header3: ISingleMenuConfig;
header4: ISingleMenuConfig;
header5: ISingleMenuConfig;
header6: ISingleMenuConfig;
todo: ISingleMenuConfig;
formatPainter: ISingleMenuConfig;
redo: ISingleMenuConfig;
undo: ISingleMenuConfig;
fullScreen: ISingleMenuConfig;
enter: ISingleMenuConfig;
bulletedList: ISingleMenuConfig;
numberedList: ISingleMenuConfig;
insertTable: ISingleMenuConfig;
deleteTable: ISingleMenuConfig;
insertTableRow: IInsertTableConfig;
deleteTableRow: ISingleMenuConfig;
insertTableCol: ISingleMenuConfig;
deleteTableCol: ISingleMenuConfig;
tableHeader: ISingleMenuConfig;
tableFullWidth: ISingleMenuConfig;
mergeTableCell: ISingleMenuConfig;
splitTableCell: ISingleMenuConfig;
setTableProperty: ISingleMenuConfig;
setTableCellProperty: ISingleMenuConfig;
insertVideo: IInsertVideoConfig;
uploadVideo: IUploadVideoConfig;
editVideoSize: ISingleMenuConfig;
editVideoSrc: ISingleMenuConfig;
uploadImage: IUploadImageConfig;
codeSelectLang: ICodeLangConfig;
}

/**
* editor config
*/
export interface IEditorConfig {
//【注意】如增加 onXxx 回调函数时,要同步到 vue2/vue3 组件
// 【注意】如增加 onXxx 回调函数时,要同步到 vue2/vue3 组件
customAlert: (info: string, type: AlertType) => void

onCreated?: (editor: IDomEditor) => void
Expand All @@ -54,7 +201,7 @@ export interface IEditorConfig {
maxLength?: number

// 各个 menu 的配置汇总,可以通过 key 获取单个 menu 的配置
MENU_CONF?: IMenuConfig
MENU_CONF?: Partial<IMenuConfig>

// 悬浮菜单栏 menu
hoverbarKeys?: IHoverbarConf
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/config/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
import { IMenuConfig, ISingleMenuConfig } from '../config/interface'

// 全局的菜单配置
export const GLOBAL_MENU_CONF: IMenuConfig = {}
export const GLOBAL_MENU_CONF: Partial<IMenuConfig> = {}

/**
* 注册全局菜单配置
* @param key menu key
* @param config config
*/
export function registerGlobalMenuConf(key: string, config?: ISingleMenuConfig) {
if (config == null) return
if (config == null) { return }
GLOBAL_MENU_CONF[key] = config
}
13 changes: 10 additions & 3 deletions packages/core/src/editor/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@
* @author wangfupeng
*/

import { Editor, Location, Node, Ancestor, Element } from 'slate'
import ee from 'event-emitter'
import { IEditorConfig, AlertType, ISingleMenuConfig } from '../config/interface'
import {
Ancestor, Editor, Element, Location, Node,
} from 'slate'

import {
AlertType, IEditorConfig, IMenuConfig, ISingleMenuConfig,
} from '../config/interface'
import { IPositionStyle } from '../menus/interface'
import { DOMElement } from '../utils/dom'

export type ElementWithId = Element & { id: string }

export type getMenuConfigReturnType<K> = K extends keyof IMenuConfig ? IMenuConfig[K] : ISingleMenuConfig

/**
* 扩展 slate Editor 接口
*/
Expand All @@ -21,7 +28,7 @@ export interface IDomEditor extends Editor {

// config
getConfig: () => IEditorConfig
getMenuConfig: (menuKey: string) => ISingleMenuConfig
getMenuConfig: <K extends string>(menuKey: K) => getMenuConfigReturnType<K>
getAllMenuKeys: () => string[]
alert: (info: string, type: AlertType) => void

Expand Down
20 changes: 13 additions & 7 deletions packages/core/src/editor/plugins/with-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
*/

import { Editor } from 'slate'
import { IDomEditor } from '../..'
import { EDITOR_TO_CONFIG } from '../../utils/weak-maps'
import { IEditorConfig, AlertType, ISingleMenuConfig } from '../../config/interface'

import { getMenuConfigReturnType, IDomEditor } from '../..'
import { AlertType, IEditorConfig } from '../../config/interface'
import { MENU_ITEM_FACTORIES } from '../../menus/register'
import { EDITOR_TO_CONFIG } from '../../utils/weak-maps'

export const withConfig = <T extends Editor>(editor: T) => {
const e = editor as T & IDomEditor

e.getAllMenuKeys = (): string[] => {
const arr: string[] = []
for (let key in MENU_ITEM_FACTORIES) {

// eslint-disable-next-line guard-for-in
for (const key in MENU_ITEM_FACTORIES) {
arr.push(key)
}
return arr
Expand All @@ -23,20 +26,23 @@ export const withConfig = <T extends Editor>(editor: T) => {
// 获取 editor 配置信息
e.getConfig = (): IEditorConfig => {
const config = EDITOR_TO_CONFIG.get(e)
if (config == null) throw new Error('Can not get editor config')

if (config == null) { throw new Error('Can not get editor config') }
return config
}

// 获取 menu config
e.getMenuConfig = (menuKey: string): ISingleMenuConfig => {
e.getMenuConfig = <K extends string>(menuKey: string): getMenuConfigReturnType<K> => {
const { MENU_CONF = {} } = e.getConfig()

return MENU_CONF[menuKey] || {}
}

// alert
e.alert = (info: string, type: AlertType = 'info') => {
const { customAlert } = e.getConfig()
if (customAlert) customAlert(info, type)

if (customAlert) { customAlert(info, type) }
}

return e
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/menus/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*/

import { Node } from 'slate'

import { ISingleMenuConfig } from '../config/interface'
import { IDomEditor } from '../editor/interface'
import { DOMElement } from '../utils/dom'

Expand Down Expand Up @@ -72,5 +74,5 @@ export type MenuFactoryType = () => IButtonMenu | ISelectMenu | IDropPanelMenu |
export interface IRegisterMenuConf {
key: string
factory: MenuFactoryType
config?: { [key: string]: any }
config?: ISingleMenuConfig
}
5 changes: 3 additions & 2 deletions packages/core/src/menus/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
* @author wangfupeng
*/

import { MenuFactoryType, IRegisterMenuConf } from './interface'
import { ISingleMenuConfig } from '../config/interface'
import { registerGlobalMenuConf } from '../config/register'
import { IRegisterMenuConf, MenuFactoryType } from './interface'

// menu item 的工厂函数 - 集合
export const MENU_ITEM_FACTORIES: {
Expand All @@ -18,7 +19,7 @@ export const MENU_ITEM_FACTORIES: {
*/
export function registerMenu(
registerMenuConf: IRegisterMenuConf,
customConfig?: { [key: string]: any }
customConfig?: ISingleMenuConfig,
) {
const { key, factory, config } = registerMenuConf

Expand Down
Loading

0 comments on commit eea16b2

Please sign in to comment.