Lexical: Integrated diagram manager, added menu split button
This commit is contained in:
		
							parent
							
								
									ad6b26ba97
								
							
						
					
					
						commit
						0039f893cc
					
				|  | @ -0,0 +1 @@ | |||
| <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m2 6.9159 10 10.168 10-10.168z" stroke-width="2.0168"/></svg> | ||||
| After Width: | Height: | Size: 131 B | 
|  | @ -10,7 +10,6 @@ | |||
| - Alignments: Handle inline block content (image, video) | ||||
| - Image paste upload | ||||
| - Keyboard shortcuts support | ||||
| - Drawing gallery integration | ||||
| - Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts) | ||||
| - Media resize support (like images) | ||||
| - Table caption text support | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ import { | |||
|     $insertNewBlockNodeAtSelection, | ||||
|     $selectionContainsNodeType | ||||
| } from "../../../utils/selection"; | ||||
| import {$isDiagramNode, $openDrawingEditorForNode} from "../../../utils/diagrams"; | ||||
| import {$isDiagramNode, $openDrawingEditorForNode, showDiagramManagerForInsert} from "../../../utils/diagrams"; | ||||
| import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images"; | ||||
| import {$showImageForm} from "../forms/objects"; | ||||
| 
 | ||||
|  | @ -184,6 +184,16 @@ export const diagram: EditorButtonDefinition = { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| export const diagramManager: EditorButtonDefinition = { | ||||
|     label: 'Drawing manager', | ||||
|     action(context: EditorUiContext) { | ||||
|         showDiagramManagerForInsert(context); | ||||
|     }, | ||||
|     isActive(): boolean { | ||||
|         return false; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| export const media: EditorButtonDefinition = { | ||||
|     label: 'Insert/edit Media', | ||||
|     icon: mediaIcon, | ||||
|  |  | |||
|  | @ -0,0 +1,31 @@ | |||
| import {EditorContainerUiElement, EditorUiElement} from "../core"; | ||||
| import {el} from "../../../utils/dom"; | ||||
| import {EditorButton} from "../buttons"; | ||||
| import {EditorDropdownButton} from "./dropdown-button"; | ||||
| import caretDownIcon from "@icons/caret-down-large.svg"; | ||||
| 
 | ||||
| export class EditorButtonWithMenu extends EditorContainerUiElement { | ||||
|     protected button: EditorButton; | ||||
|     protected dropdownButton: EditorDropdownButton; | ||||
| 
 | ||||
|     constructor(button: EditorButton, menuItems: EditorUiElement[]) { | ||||
|         super([button]); | ||||
| 
 | ||||
|         this.button = button; | ||||
|         this.dropdownButton = new EditorDropdownButton({ | ||||
|             button: {label: 'Menu', icon: caretDownIcon}, | ||||
|             showOnHover: false, | ||||
|             direction: 'vertical', | ||||
|         }, menuItems); | ||||
|         this.addChildren(this.dropdownButton); | ||||
|     } | ||||
| 
 | ||||
|     buildDOM(): HTMLElement { | ||||
|         return el('div', { | ||||
|             class: 'editor-button-with-menu-container', | ||||
|         }, [ | ||||
|             this.button.getDOMElement(), | ||||
|             this.dropdownButton.getDOMElement() | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
|  | @ -56,16 +56,15 @@ import {bulletList, numberList, taskList} from "./defaults/buttons/lists"; | |||
| import { | ||||
|     codeBlock, | ||||
|     details, | ||||
|     diagram, | ||||
|     diagram, diagramManager, | ||||
|     editCodeBlock, | ||||
|     horizontalRule, | ||||
|     image, | ||||
|     link, media, | ||||
|     unlink | ||||
| } from "./defaults/buttons/objects"; | ||||
| import {$isTableNode} from "@lexical/table"; | ||||
| import {$selectionContainsNodeType} from "../utils/selection"; | ||||
| import {el} from "../utils/dom"; | ||||
| import {EditorButtonWithMenu} from "./framework/blocks/button-with-menu"; | ||||
| 
 | ||||
| export function getMainEditorFullToolbar(): EditorContainerUiElement { | ||||
|     return new EditorSimpleClassContainer('editor-toolbar-main', [ | ||||
|  | @ -166,7 +165,10 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement { | |||
|             new EditorButton(image), | ||||
|             new EditorButton(horizontalRule), | ||||
|             new EditorButton(codeBlock), | ||||
|             new EditorButtonWithMenu( | ||||
|                 new EditorButton(diagram), | ||||
|                 [new EditorButton(diagramManager)], | ||||
|             ), | ||||
|             new EditorButton(media), | ||||
|             new EditorButton(details), | ||||
|         ]), | ||||
|  |  | |||
|  | @ -1,8 +1,11 @@ | |||
| import {LexicalEditor, LexicalNode} from "lexical"; | ||||
| import {$getSelection, $insertNodes, LexicalEditor, LexicalNode} from "lexical"; | ||||
| import {HttpError} from "../../services/http"; | ||||
| import {EditorUiContext} from "../ui/framework/core"; | ||||
| import * as DrawIO from "../../services/drawio"; | ||||
| import {DiagramNode} from "../nodes/diagram"; | ||||
| import {$createDiagramNode, DiagramNode} from "../nodes/diagram"; | ||||
| import {ImageManager} from "../../components"; | ||||
| import {EditorImageData} from "./images"; | ||||
| import {$getNodeFromSelection} from "./selection"; | ||||
| 
 | ||||
| export function $isDiagramNode(node: LexicalNode | null | undefined): node is DiagramNode { | ||||
|     return node instanceof DiagramNode; | ||||
|  | @ -68,3 +71,25 @@ export function $openDrawingEditorForNode(context: EditorUiContext, node: Diagra | |||
|         return updateDrawingNodeFromData(context, node, pngData, isNew); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export function showDiagramManager(callback: (image: EditorImageData) => any) { | ||||
|     const imageManager: ImageManager = window.$components.first('image-manager') as ImageManager; | ||||
|     imageManager.show((image: EditorImageData) => { | ||||
|         callback(image); | ||||
|     }, 'drawio'); | ||||
| } | ||||
| 
 | ||||
| export function showDiagramManagerForInsert(context: EditorUiContext) { | ||||
|     const selection = context.lastSelection; | ||||
|     showDiagramManager((image: EditorImageData) => { | ||||
|         context.editor.update(() => { | ||||
|             const diagramNode = $createDiagramNode(image.id, image.url); | ||||
|             const selectedDiagram = $getNodeFromSelection(selection, $isDiagramNode); | ||||
|             if ($isDiagramNode(selectedDiagram)) { | ||||
|                 selectedDiagram.replace(diagramNode); | ||||
|             } else { | ||||
|                 $insertNodes([diagramNode]); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | @ -2,7 +2,8 @@ import {ImageManager} from "../../components"; | |||
| import {$createImageNode} from "../nodes/image"; | ||||
| import {$createLinkNode, LinkNode} from "@lexical/link"; | ||||
| 
 | ||||
| type EditorImageData = { | ||||
| export type EditorImageData = { | ||||
|     id: string; | ||||
|     url: string; | ||||
|     thumbs?: {display: string}; | ||||
|     name: string; | ||||
|  |  | |||
|  | @ -82,6 +82,31 @@ body.editor-is-fullscreen { | |||
|   fill: currentColor; | ||||
|   display: block; | ||||
| } | ||||
| .editor-button-with-menu-container { | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
|   gap: 0; | ||||
|   align-items: stretch; | ||||
|   border-radius: 4px; | ||||
|   .editor-dropdown-menu-container { | ||||
|     display: flex; | ||||
|   } | ||||
|   .editor-dropdown-menu-container > .editor-dropdown-menu { | ||||
|     top: 100%; | ||||
|   } | ||||
|   .editor-dropdown-menu-container > .editor-button { | ||||
|     padding-inline: 4px; | ||||
|     margin-inline-start: -3px; | ||||
|     svg { | ||||
|       width: 12px; | ||||
|       height: 12px; | ||||
|     } | ||||
|   } | ||||
|   &:hover { | ||||
|     outline: 1px solid #DDD; | ||||
|     outline-offset: -3px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Containers | ||||
| .editor-dropdown-menu-container { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue