UNPKG

@kedao/editor

Version:

Rich Text Editor Based On Draft.js

137 lines 7.67 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import '@draft-js-plugins/mention/lib/plugin.css'; import React from 'react'; import createMentionPlugin, { defaultSuggestionsFilter } from '@draft-js-plugins/mention'; /** * 基于 @draft-js-plugins/mention 的 mention 扩展 * 除了 includeEditors 和 excludeEditors 外 * 其他属性将会传递给 @draft-js-plugins/mention * 参考 https://www.draft-js-plugins.com/plugin/mention */ export default (options = {}) => { const { includeEditors, excludeEditors } = options, mentionPluginOptions = __rest(options, ["includeEditors", "excludeEditors"]); const mentionPlugin = createMentionPlugin(mentionPluginOptions); // MentionSuggestions 是一个 React Component 用来定制 mention 的数据 const { MentionSuggestions } = mentionPlugin, draftEditorPlugin = __rest(mentionPlugin /** * draft-js-plugin 为每个 plugin 的很多地方都注入了 get 和 set * 在 @kedao/editor 里面 由于 在 useExtension 里面并拿不到 editor 的实例 * 只能在 prop-interception 的时候 有机会拿到 因此先用一个 对象引用起来 再传递 */ , ["MentionSuggestions"]); /** * draft-js-plugin 为每个 plugin 的很多地方都注入了 get 和 set * 在 @kedao/editor 里面 由于 在 useExtension 里面并拿不到 editor 的实例 * 只能在 prop-interception 的时候 有机会拿到 因此先用一个 对象引用起来 再传递 */ const getAndSetState = { getEditorState: () => { throw new Error("can't use get state"); }, setEditorState: (state) => { throw new Error(`can't use set state ${state}`); } }; return [ [ { type: 'prop-interception', interceptor: (editorProps, editor) => { // hack // 没有地方可以有 init 的时机,属性拦截器这里会把编辑器的实例传过来 // 所以在这里初始化插件 getAndSetState.getEditorState = editor.getValue.bind(editor); getAndSetState.setEditorState = editor.setValue.bind(editor); if (draftEditorPlugin.initialize) { // 这里 mention 插件 只用了 get/setEditor State 所以其他可以不传 draftEditorPlugin.initialize(getAndSetState); } // mention 的 plugin 需要 hack editor 的 onChange // 如果有更好的办法请告知 const hackOnChange = editor.onChange; if (hackOnChange) { editor.onChange = (editorState, callback) => { hackOnChange.call(editor, editorState, callback); if (draftEditorPlugin.onChange) { draftEditorPlugin.onChange(editorState, getAndSetState); } }; } // 应该是 draft-js 和 draft-js-mention-plugin 之间的磨合除了问题 // mention 需要处理 以下几个键盘事件 但是 draft-js 对这几个事件有特殊处理 // 仅仅调用了 props 传递进去的 而不会通过 keyBindingFn 调用 // 所以这里额外处理,并通过 prop-interception 传递给 draftProps // bug 可在 https://stackblitz.com/edit/draft-js-mention?file=index.tsx 使用 DraftEditor 复现 const passSomeKeyEventToKeyBindingFn = (props) => { const handleName = [ 'onUpArrow', 'onRightArrow', 'onDownArrow', 'onLeftArrow', 'onEscape', 'onTab' ]; return handleName.reduce((acc, name) => { const hackHandle = props[name]; const handler = (event) => { if (typeof hackHandle === 'function') { hackHandle(event); } draftEditorPlugin.keyBindingFn(event, getAndSetState); }; return Object.assign(Object.assign({}, acc), { [name]: handler }); }, {}); }; return Object.assign(Object.assign({}, editorProps), { draftProps: Object.assign(Object.assign(Object.assign({}, editorProps.draftProps), draftEditorPlugin.getAccessibilityProps()), passSomeKeyEventToKeyBindingFn(editorProps.draftProps || {})), keyBindingFn: (event) => { // 先处理前面插件的 keyBindingFn // 暂时没有发现 mention 必须优先处理的必要性 const originHandler = editorProps.keyBindingFn; let ret = null; if (typeof originHandler === 'function') { ret = originHandler(event); } return ret != null ? ret : draftEditorPlugin.keyBindingFn(event, getAndSetState); }, handleReturn: (event, editorState, editor) => { const originHandler = editorProps.handleReturn; // 这里 mention 要优于其他的插件处理 回车 事件 // 因为在 mention 弹出 suggestion 时 有「确认选择」的功能 if (draftEditorPlugin.handleReturn(event, editorState, getAndSetState) === 'handled') { return 'handled'; } return originHandler ? originHandler(event, editorState, editor) : 'not-handled'; } }); } }, ...(draftEditorPlugin.decorators || []).map((decorate) => { return { type: 'decorator', includeEditors, excludeEditors, decorator: Object.assign(Object.assign({}, decorate), { component: (props) => { // 这里需要注入 getAndSet 是因为平时 draft-js-plugin 里面 对所有的非自定义类型的装饰器进行了注入 // 所以这里也要模仿 // see draft-js-plugins/packages/editor/src/Editor/resolveDecorators.ts return React.createElement(decorate.component, Object.assign(Object.assign({}, props), getAndSetState)); } }) }; }) ], MentionSuggestions ]; }; export { defaultSuggestionsFilter }; //# sourceMappingURL=index.js.map