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) | - Alignments: Handle inline block content (image, video) | ||||||
| - Image paste upload | - Image paste upload | ||||||
| - Keyboard shortcuts support | - 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) | - 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) | - Media resize support (like images) | ||||||
| - Table caption text support | - Table caption text support | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ import { | ||||||
|     $insertNewBlockNodeAtSelection, |     $insertNewBlockNodeAtSelection, | ||||||
|     $selectionContainsNodeType |     $selectionContainsNodeType | ||||||
| } from "../../../utils/selection"; | } from "../../../utils/selection"; | ||||||
| import {$isDiagramNode, $openDrawingEditorForNode} from "../../../utils/diagrams"; | import {$isDiagramNode, $openDrawingEditorForNode, showDiagramManagerForInsert} from "../../../utils/diagrams"; | ||||||
| import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images"; | import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images"; | ||||||
| import {$showImageForm} from "../forms/objects"; | 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 = { | export const media: EditorButtonDefinition = { | ||||||
|     label: 'Insert/edit Media', |     label: 'Insert/edit Media', | ||||||
|     icon: mediaIcon, |     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 { | import { | ||||||
|     codeBlock, |     codeBlock, | ||||||
|     details, |     details, | ||||||
|     diagram, |     diagram, diagramManager, | ||||||
|     editCodeBlock, |     editCodeBlock, | ||||||
|     horizontalRule, |     horizontalRule, | ||||||
|     image, |     image, | ||||||
|     link, media, |     link, media, | ||||||
|     unlink |     unlink | ||||||
| } from "./defaults/buttons/objects"; | } from "./defaults/buttons/objects"; | ||||||
| import {$isTableNode} from "@lexical/table"; |  | ||||||
| import {$selectionContainsNodeType} from "../utils/selection"; |  | ||||||
| import {el} from "../utils/dom"; | import {el} from "../utils/dom"; | ||||||
|  | import {EditorButtonWithMenu} from "./framework/blocks/button-with-menu"; | ||||||
| 
 | 
 | ||||||
| export function getMainEditorFullToolbar(): EditorContainerUiElement { | export function getMainEditorFullToolbar(): EditorContainerUiElement { | ||||||
|     return new EditorSimpleClassContainer('editor-toolbar-main', [ |     return new EditorSimpleClassContainer('editor-toolbar-main', [ | ||||||
|  | @ -166,7 +165,10 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement { | ||||||
|             new EditorButton(image), |             new EditorButton(image), | ||||||
|             new EditorButton(horizontalRule), |             new EditorButton(horizontalRule), | ||||||
|             new EditorButton(codeBlock), |             new EditorButton(codeBlock), | ||||||
|             new EditorButton(diagram), |             new EditorButtonWithMenu( | ||||||
|  |                 new EditorButton(diagram), | ||||||
|  |                 [new EditorButton(diagramManager)], | ||||||
|  |             ), | ||||||
|             new EditorButton(media), |             new EditorButton(media), | ||||||
|             new EditorButton(details), |             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 {HttpError} from "../../services/http"; | ||||||
| import {EditorUiContext} from "../ui/framework/core"; | import {EditorUiContext} from "../ui/framework/core"; | ||||||
| import * as DrawIO from "../../services/drawio"; | 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 { | export function $isDiagramNode(node: LexicalNode | null | undefined): node is DiagramNode { | ||||||
|     return node instanceof DiagramNode; |     return node instanceof DiagramNode; | ||||||
|  | @ -68,3 +71,25 @@ export function $openDrawingEditorForNode(context: EditorUiContext, node: Diagra | ||||||
|         return updateDrawingNodeFromData(context, node, pngData, isNew); |         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 {$createImageNode} from "../nodes/image"; | ||||||
| import {$createLinkNode, LinkNode} from "@lexical/link"; | import {$createLinkNode, LinkNode} from "@lexical/link"; | ||||||
| 
 | 
 | ||||||
| type EditorImageData = { | export type EditorImageData = { | ||||||
|  |     id: string; | ||||||
|     url: string; |     url: string; | ||||||
|     thumbs?: {display: string}; |     thumbs?: {display: string}; | ||||||
|     name: string; |     name: string; | ||||||
|  |  | ||||||
|  | @ -82,6 +82,31 @@ body.editor-is-fullscreen { | ||||||
|   fill: currentColor; |   fill: currentColor; | ||||||
|   display: block; |   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 | // Containers | ||||||
| .editor-dropdown-menu-container { | .editor-dropdown-menu-container { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue