Lexical: Further fixes

- Improved node resizer positioning to be more accurate
- Fixed drop handling not running within editor margin space
- Made media dom update smarter to reduce reloads
- Fixed media alignment, broken due to added wrapper
This commit is contained in:
Dan Brown 2024-09-09 12:28:01 +01:00
parent 16518a4f89
commit fd07aa0f05
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
7 changed files with 68 additions and 12 deletions

View File

@ -13,7 +13,7 @@ import {registerTaskListHandler} from "./ui/framework/helpers/task-list-handler"
import {registerTableSelectionHandler} from "./ui/framework/helpers/table-selection-handler";
import {el} from "./utils/dom";
import {registerShortcuts} from "./services/shortcuts";
import {registerNodeResizer} from "./ui/framework/helpers/image-resizer";
import {registerNodeResizer} from "./ui/framework/helpers/node-resizer";
export function createPageEditorInstance(container: HTMLElement, htmlContent: string, options: Record<string, any> = {}): SimpleWysiwygEditorInterface {
const config: CreateEditorArgs = {

View File

@ -4,18 +4,17 @@ import {
ElementNode,
LexicalEditor,
LexicalNode,
SerializedElementNode, Spread
Spread
} from 'lexical';
import type {EditorConfig} from "lexical/LexicalEditor";
import {el, sizeToPixels} from "../utils/dom";
import {el, setOrRemoveAttribute, sizeToPixels} from "../utils/dom";
import {
CommonBlockAlignment,
SerializedCommonBlockNode,
setCommonBlockPropsFromElement,
updateElementWithCommonBlockProps
} from "./_common";
import {elem} from "../../services/dom";
import {$selectSingleNode} from "../utils/selection";
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
@ -218,8 +217,37 @@ export class MediaNode extends ElementNode {
return wrap;
}
updateDOM(prevNode: unknown, dom: HTMLElement) {
return true;
updateDOM(prevNode: MediaNode, dom: HTMLElement): boolean {
if (prevNode.__tag !== this.__tag) {
return true;
}
if (JSON.stringify(prevNode.__sources) !== JSON.stringify(this.__sources)) {
return true;
}
if (JSON.stringify(prevNode.__attributes) !== JSON.stringify(this.__attributes)) {
return true;
}
const mediaEl = dom.firstElementChild as HTMLElement;
if (prevNode.__id !== this.__id) {
setOrRemoveAttribute(mediaEl, 'id', this.__id);
}
if (prevNode.__alignment !== this.__alignment) {
if (prevNode.__alignment) {
dom.classList.remove(`align-${prevNode.__alignment}`);
mediaEl.classList.remove(`align-${prevNode.__alignment}`);
}
if (this.__alignment) {
dom.classList.add(`align-${this.__alignment}`);
mediaEl.classList.add(`align-${this.__alignment}`);
}
}
return false;
}
static importDOM(): DOMConversionMap|null {

View File

@ -103,6 +103,7 @@ function createDropListener(context: EditorUiContext): (event: DragEvent) => boo
if (templateId) {
insertTemplateToEditor(editor, templateId, event);
event.preventDefault();
event.stopPropagation();
return true;
}
@ -114,6 +115,7 @@ function createDropListener(context: EditorUiContext): (event: DragEvent) => boo
$insertNodesAtEvent(newNodes, event, editor);
});
event.preventDefault();
event.stopPropagation();
return true;
}
@ -121,6 +123,7 @@ function createDropListener(context: EditorUiContext): (event: DragEvent) => boo
const handled = handleMediaInsert(event.dataTransfer, context);
if (handled) {
event.preventDefault();
event.stopPropagation();
return true;
}
}
@ -150,9 +153,11 @@ export function registerDropPasteHandling(context: EditorUiContext): () => void
const unregisterDrop = context.editor.registerCommand(DROP_COMMAND, dropListener, COMMAND_PRIORITY_HIGH);
const unregisterPaste = context.editor.registerCommand(PASTE_COMMAND, pasteListener, COMMAND_PRIORITY_HIGH);
context.scrollDOM.addEventListener('drop', dropListener);
return () => {
unregisterDrop();
unregisterPaste();
context.scrollDOM.removeEventListener('drop', dropListener);
};
}

View File

@ -16,4 +16,4 @@
## Bugs
- Template drag/drop not handled when outside core editor area (ignored in margin area).
//

View File

@ -73,11 +73,15 @@ class NodeResizer {
return;
}
const nodeDOMBounds = nodeDOM.getBoundingClientRect();
this.dom.style.left = nodeDOM.offsetLeft + 'px';
this.dom.style.top = nodeDOM.offsetTop + 'px';
this.dom.style.width = nodeDOMBounds.width + 'px';
this.dom.style.height = nodeDOMBounds.height + 'px';
const scrollAreaRect = this.scrollContainer.getBoundingClientRect();
const nodeRect = nodeDOM.getBoundingClientRect();
const top = nodeRect.top - (scrollAreaRect.top - this.scrollContainer.scrollTop);
const left = nodeRect.left - scrollAreaRect.left;
this.dom.style.top = `${top}px`;
this.dom.style.left = `${left}px`;
this.dom.style.width = nodeRect.width + 'px';
this.dom.style.height = nodeRect.height + 'px';
}
protected updateDOMSize(width: number, height: number): void {

View File

@ -70,4 +70,12 @@ export function extractStyleMapFromElement(element: HTMLElement): StyleMap {
}
return map;
}
export function setOrRemoveAttribute(element: HTMLElement, name: string, value: string|null|undefined) {
if (value) {
element.setAttribute(name, value);
} else {
element.removeAttribute(name);
}
}

View File

@ -374,10 +374,21 @@ body.editor-is-fullscreen {
}
.editor-media-wrap {
display: inline-block;
cursor: not-allowed;
iframe {
pointer-events: none;
}
&.align-left {
float: left;
}
&.align-right {
float: right;
}
&.align-center {
display: block;
margin-inline: auto;
}
}
/**