@@ -49,8 +49,12 @@ export interface ExtensionOptions {
4949 editor: Editor ;
5050 }) => ToolboxItem | ToolboxItem [];
5151
52- // 拖拽扩展
53- getDraggable? : ({ editor }: { editor: Editor }) => DraggableItem | boolean ;
52+ // 拖拽菜单扩展
53+ getDraggableMenuItems? : ({
54+ editor,
55+ }: {
56+ editor: Editor ;
57+ }) => DragButtonType | DragButtonType [];
5458}
5559```
5660
@@ -367,111 +371,128 @@ addOptions() {
367371}
368372```
369373
370- #### 5. 拖拽功能扩展
374+ #### 5. 拖拽菜单扩展
375+
376+ 拖拽菜单扩展主要用于拖拽的菜单功能扩展,例如转换为、复制、剪切、删除等操作。
371377
372- 拖拽功能的扩展,可用于支持当前块元素的拖拽功能。
378+ ![ 拖拽功能扩展 ] ( /img/developer-guide/plugin/extension-points/ui/default-editor-extension-drag-menu.png )
373379
374- ![ 拖拽功能扩展] ( /img/developer-guide/plugin/extension-points/ui/default-editor-extension-drag.png )
380+ 在 [ https://github.com/halo-dev/halo/pull/7861 ] ( https://github.com/halo-dev/halo/pull/7861 ) 中,我们重构了对编辑器拖拽区域的扩展,并且支持了对拖拽菜单的扩展。如果需要对拖拽菜单进行扩展,只需要在具体的 Tiptap Extension 中的 ` addOptions ` 中定义 ` getDraggableMenuItems ` 函数即可,如:
381+
382+ ``` ts
383+ {
384+ addOptions () {
385+ return {
386+ ... this .parent ?.(),
387+ getDraggableMenuItems({ editor }: { editor: Editor }) {
388+ return []
389+ },
390+ };
391+ },
392+ }
393+ ```
375394
376- 在 [ https://github.com/halo-sigs/richtext-editor/pull/48 ] ( https://github.com/halo-sigs/richtext-editor/pull/48 ) 中,我们实现了对所有元素的拖拽功能,如果需要让当前扩展支持拖拽,只需要在具体的 Tiptap Extension 中的 ` addOptions ` 中定义 ` getDraggable ` 函数,并让其返回 true 即可 。如:
395+ 并且,拖拽菜单最多支持两级菜单嵌套, 如果想扩展已有的一级菜单,为其二级菜单增加内容,则只需将二级菜单的 ` parentKey ` 设置为一级菜单的 ` key ` 。如:
377396
378397``` ts
379398{
380399 addOptions () {
381400 return {
382401 ... this .parent ?.(),
383- getDraggable() {
384- return true ;
402+ getDraggableMenuItems({ editor }: { editor: Editor }) {
403+ return {
404+ parentKey: CONVERT_TO_KEY ,
405+ children: {
406+ items: [
407+ {
408+ priority: 10 ,
409+ icon: markRaw (MdiFormatParagraph ),
410+ title: i18n .global .t (" editor.common.heading.paragraph" ),
411+ action : ({ editor }: { editor: Editor }) =>
412+ editor .chain ().focus ().setParagraph ().run (),
413+ },
414+ ],
415+ },
416+ }
385417 },
386418 };
387419 },
388420}
389421```
390422
391- 其中 ` getDraggable ` 即为为当前扩展增加可拖拽的功能。其返回类型为 :
423+ 下面为 ` getDraggableMenuItems ` 的返回类型 :
392424
393425``` ts
394- // 拖拽扩展
395- getDraggable ?: ({ editor }: { editor: Editor }) => DraggableItem | boolean ;
396426
397- export interface DraggableItem {
398- getRenderContainer? : ({ // 拖拽按钮计算偏移位置的基准 DOM
399- dom,
400- view,
427+ // 拖拽菜单扩展
428+ getDraggableMenuItems ?: ({
429+ editor ,
430+ }: {
431+ editor: Editor ;
432+ }) => DragButtonType | DragButtonType [];
433+
434+ // 拖拽菜单项目属性
435+ export interface DragButtonItemProps {
436+ priority? : number ; // 优先级,数字越小优先级越大,越靠前
437+ title? : string | (() => string ); // 标题
438+ icon? : Component ; // 图标
439+ key? : string ; // 唯一标识,如果同级菜单项设置了同样的 key,则会被合并为一个菜单项。
440+ action? : ({ // 点击菜单后的操作,如果返回 Component,则会将其包含在子菜单中。
441+ // 可以通过调用 close 方法可以在操作完成后关闭拖拽菜单,或者当返回为 true 或 undefined 时,会自动关闭拖拽菜单,如果返回 false,则不会关闭拖拽菜单。
442+ editor,
443+ node,
444+ pos,
445+ close,
446+ }: {
447+ editor: Editor ;
448+ node: PMNode | null ;
449+ pos: number ;
450+ close: () => void ;
451+ }) => Component | boolean | void | Promise <Component | boolean | void >;
452+ iconStyle? : string ; // 图标自定义样式
453+ class? : string ; // 自定义样式
454+ visible? : ({ // 是否显示当前菜单项,默认为 true
455+ editor,
456+ node,
457+ pos,
458+ }: {
459+ editor: Editor ;
460+ node: PMNode | null ;
461+ pos: number ;
462+ }) => boolean ;
463+ isActive? : ({ // 当前菜单项是否处于活动状态,默认为 false
464+ editor,
465+ node,
466+ pos,
401467 }: {
402- dom: HTMLElement ;
403- view: EditorView ;
404- }) => DragSelectionNode ;
405- handleDrop? : ({ // 完成拖拽功能之后的处理。返回 true 则会阻止拖拽的发生
406- view,
407- event,
408- slice,
409- insertPos,
468+ editor: Editor ;
469+ node: PMNode | null ;
470+ pos: number ;
471+ }) => boolean ;
472+ disabled? : ({ // 是否禁用当前菜单项,默认为 false
473+ editor,
410474 node,
411- selection ,
475+ pos ,
412476 }: {
413- view: EditorView ;
414- event: DragEvent ;
415- slice: Slice ;
416- insertPos: number ;
417- node: Node ;
418- selection: Selection ;
419- }) => boolean | void ;
420- allowPropagationDownward? : boolean ; // 是否允许拖拽事件向内部传播,
477+ editor: Editor ;
478+ node: PMNode | null ;
479+ pos: number ;
480+ }) => boolean ;
481+ keyboard? : string ; // 快捷键,遵循 https://tiptap.dev/docs/editor/core-concepts/keyboard-shortcuts
482+ component? : Component ; // 自定义组件,如果提供了该属性,则不会显示默认的菜单项,而是会显示自定义组件,并且将所有 props 传递给自定义组件。
483+ [key : string ]: any ; // 其他自定义属性,将会传递给自定义组件。
421484}
422485
423- export interface DragSelectionNode {
424- $pos? : ResolvedPos ;
425- node? : Node ;
426- el: HTMLElement ;
427- nodeOffset? : number ;
428- dragDomOffset? : {
429- x: number ;
430- y: number ;
486+ // 一级菜单项
487+ export interface DragButtonType extends DragButtonItemProps {
488+ parentKey? : string ; // 父级菜单项的唯一标识,如果提供了该属性,则视为扩展目标菜单项的二级菜单。
489+ children? : { // 子菜单项,如果提供了该属性,则视为扩展目标菜单项的二级菜单。
490+ component? : Component ; // 自定义组件,如果提供了该属性,则不会显示默认的子菜单项,而是会显示自定义组件,并且将所有 props 传递给自定义组件。
491+ items? : DragButtonItemProps []; // 子菜单项列表,如果提供了该属性,则视为扩展目标菜单项的二级菜单。
431492 };
432493}
433494```
434495
435- > 拖拽会从父 Node 节点开始触发,直到找到一个实现 ` getDraggable ` 的扩展,如果没有找到,则不会触发拖拽事件。父 Node 可以通过 ` allowPropagationDownward ` 来控制是否允许拖拽事件向内部传播。如果 ` allowPropagationDownward ` 设置为 true,则会继续向内部寻找实现 ` getDraggable ` 的扩展,如果没有找到,则触发父 Node 的 ` getDraggable ` 实现,否则继续进行传播。
436-
437- 如下为 [ ` Iframe ` ] ( https://github.com/halo-dev/halo/blob/main/console/packages/editor/src/extensions/iframe/index.ts ) 扩展中对于 ` getDraggable ` 拖拽功能的扩展示例:
438-
439- ``` ts
440- addOptions () {
441- return {
442- ... this .parent ?.(),
443- getDraggable() {
444- return {
445- getRenderContainer({ dom , view }) {
446- let container = dom ;
447- while (
448- container .parentElement &&
449- container .parentElement .tagName !== " P"
450- ) {
451- container = container .parentElement ;
452- }
453- if (container ) {
454- container = container .firstElementChild
455- ?.firstElementChild as HTMLElement ;
456- }
457- let node;
458- if (container .firstElementChild ) {
459- const pos = view .posAtDOM (container .firstElementChild , 0 );
460- const $pos = view .state .doc .resolve (pos );
461- node = $pos .node ();
462- }
463-
464- return {
465- node: node ,
466- el: container as HTMLElement ,
467- };
468- },
469- };
470- },
471- }
472- }
473- ```
474-
475496## 实现案例
476497
477498- [ https://github.com/halo-sigs/plugin-hybrid-edit-block ] ( https://github.com/halo-sigs/plugin-hybrid-edit-block )
0 commit comments