1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2024-10-30 07:32:39 +01:00

Lexical: Split helpers to utils, refactored files

This commit is contained in:
Dan Brown 2024-08-03 18:14:01 +01:00
parent e94ad78ea7
commit efec752985
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
39 changed files with 152 additions and 136 deletions

View File

@ -4,14 +4,14 @@ import {registerRichText} from '@lexical/rich-text';
import {mergeRegister} from '@lexical/utils'; import {mergeRegister} from '@lexical/utils';
import {getNodesForPageEditor, registerCommonNodeMutationListeners} from './nodes'; import {getNodesForPageEditor, registerCommonNodeMutationListeners} from './nodes';
import {buildEditorUI} from "./ui"; import {buildEditorUI} from "./ui";
import {getEditorContentAsHtml, setEditorContentFromHtml} from "./actions"; import {getEditorContentAsHtml, setEditorContentFromHtml} from "./utils/actions";
import {registerTableResizer} from "./ui/framework/helpers/table-resizer"; import {registerTableResizer} from "./ui/framework/helpers/table-resizer";
import {el} from "./helpers";
import {EditorUiContext} from "./ui/framework/core"; import {EditorUiContext} from "./ui/framework/core";
import {listen as listenToCommonEvents} from "./common-events"; import {listen as listenToCommonEvents} from "./services/common-events";
import {handleDropEvents} from "./drop-handling"; import {handleDropEvents} from "./services/drop-handling";
import {registerTaskListHandler} from "./ui/framework/helpers/task-list-handler"; import {registerTaskListHandler} from "./ui/framework/helpers/task-list-handler";
import {registerTableSelectionHandler} from "./ui/framework/helpers/table-selection-handler"; import {registerTableSelectionHandler} from "./ui/framework/helpers/table-selection-handler";
import {el} from "./utils/dom";
export function createPageEditorInstance(container: HTMLElement, htmlContent: string, options: Record<string, any> = {}): SimpleWysiwygEditorInterface { export function createPageEditorInstance(container: HTMLElement, htmlContent: string, options: Record<string, any> = {}): SimpleWysiwygEditorInterface {
const config: CreateEditorArgs = { const config: CreateEditorArgs = {

View File

@ -8,9 +8,9 @@ import {
Spread Spread
} from "lexical"; } from "lexical";
import type {EditorConfig} from "lexical/LexicalEditor"; import type {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../helpers";
import {EditorDecoratorAdapter} from "../ui/framework/decorator"; import {EditorDecoratorAdapter} from "../ui/framework/decorator";
import {CodeEditor} from "../../components"; import {CodeEditor} from "../../components";
import {el} from "../utils/dom";
export type SerializedCodeBlockNode = Spread<{ export type SerializedCodeBlockNode = Spread<{
language: string; language: string;

View File

@ -1,7 +1,8 @@
import {$isListNode, ListItemNode, SerializedListItemNode} from "@lexical/list"; import {$isListNode, ListItemNode, SerializedListItemNode} from "@lexical/list";
import {EditorConfig} from "lexical/LexicalEditor"; import {EditorConfig} from "lexical/LexicalEditor";
import {DOMExportOutput, LexicalEditor, LexicalNode} from "lexical"; import {DOMExportOutput, LexicalEditor, LexicalNode} from "lexical";
import {el} from "../helpers";
import {el} from "../utils/dom";
function updateListItemChecked( function updateListItemChecked(
dom: HTMLElement, dom: HTMLElement,

View File

@ -1,7 +1,8 @@
import {SerializedTableNode, TableNode, TableRowNode} from "@lexical/table"; import {SerializedTableNode, TableNode, TableRowNode} from "@lexical/table";
import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalEditor, LexicalNode, Spread} from "lexical"; import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalEditor, LexicalNode, Spread} from "lexical";
import {EditorConfig} from "lexical/LexicalEditor"; import {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../helpers";
import {el} from "../utils/dom";
export type SerializedCustomTableNode = Spread<{ export type SerializedCustomTableNode = Spread<{
id: string; id: string;

View File

@ -7,7 +7,8 @@ import {
SerializedElementNode, SerializedElementNode,
} from 'lexical'; } from 'lexical';
import type {EditorConfig} from "lexical/LexicalEditor"; import type {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../helpers";
import {el} from "../utils/dom";
export class DetailsNode extends ElementNode { export class DetailsNode extends ElementNode {

View File

@ -8,11 +8,11 @@ import {
Spread Spread
} from "lexical"; } from "lexical";
import type {EditorConfig} from "lexical/LexicalEditor"; import type {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../helpers";
import {EditorDecoratorAdapter} from "../ui/framework/decorator"; import {EditorDecoratorAdapter} from "../ui/framework/decorator";
import * as DrawIO from '../../services/drawio'; import * as DrawIO from '../../services/drawio';
import {EditorUiContext} from "../ui/framework/core"; import {EditorUiContext} from "../ui/framework/core";
import {HttpError} from "../../services/http"; import {HttpError} from "../../services/http";
import {el} from "../utils/dom";
export type SerializedDiagramNode = Spread<{ export type SerializedDiagramNode = Spread<{
id: string; id: string;

View File

@ -8,8 +8,8 @@ import {
Spread Spread
} from "lexical"; } from "lexical";
import type {EditorConfig} from "lexical/LexicalEditor"; import type {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../helpers";
import {EditorDecoratorAdapter} from "../ui/framework/decorator"; import {EditorDecoratorAdapter} from "../ui/framework/decorator";
import {el} from "../utils/dom";
export interface ImageNodeOptions { export interface ImageNodeOptions {
alt?: string; alt?: string;

View File

@ -7,7 +7,8 @@ import {
SerializedElementNode, Spread SerializedElementNode, Spread
} from 'lexical'; } from 'lexical';
import type {EditorConfig} from "lexical/LexicalEditor"; import type {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../helpers";
import {el} from "../utils/dom";
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio'; export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
export type MediaNodeSource = { export type MediaNodeSource = {

View File

@ -5,7 +5,7 @@ import {
insertHtmlIntoEditor, insertHtmlIntoEditor,
prependHtmlToEditor, prependHtmlToEditor,
setEditorContentFromHtml setEditorContentFromHtml
} from "./actions"; } from "../utils/actions";
type EditorEventContent = { type EditorEventContent = {
html: string; html: string;

View File

@ -3,12 +3,8 @@ import {
LexicalEditor, LexicalEditor,
LexicalNode LexicalNode
} from "lexical"; } from "lexical";
import { import {$insertNewBlockNodesAtSelection, $selectSingleNode} from "../utils/selection";
$getNearestBlockNodeForCoords, import {$getNearestBlockNodeForCoords, $htmlToBlockNodes} from "../utils/nodes";
$htmlToBlockNodes,
$insertNewBlockNodesAtSelection,
$selectSingleNode
} from "./helpers";
function $getNodeFromMouseEvent(event: MouseEvent, editor: LexicalEditor): LexicalNode|null { function $getNodeFromMouseEvent(event: MouseEvent, editor: LexicalEditor): LexicalNode|null {
const x = event.clientX; const x = event.clientX;

View File

@ -1,8 +1,8 @@
import {EditorDecorator} from "../framework/decorator"; import {EditorDecorator} from "../framework/decorator";
import {EditorUiContext} from "../framework/core"; import {EditorUiContext} from "../framework/core";
import {$openCodeEditorForNode, CodeBlockNode} from "../../nodes/code-block"; import {$openCodeEditorForNode, CodeBlockNode} from "../../nodes/code-block";
import {$selectionContainsNode, $selectSingleNode} from "../../helpers";
import {BaseSelection} from "lexical"; import {BaseSelection} from "lexical";
import {$selectionContainsNode, $selectSingleNode} from "../../utils/selection";
export class CodeBlockDecorator extends EditorDecorator { export class CodeBlockDecorator extends EditorDecorator {

View File

@ -1,8 +1,8 @@
import {EditorDecorator} from "../framework/decorator"; import {EditorDecorator} from "../framework/decorator";
import {EditorUiContext} from "../framework/core"; import {EditorUiContext} from "../framework/core";
import {$selectionContainsNode, $selectSingleNode} from "../../helpers";
import {BaseSelection} from "lexical"; import {BaseSelection} from "lexical";
import {$openDrawingEditorForNode, DiagramNode} from "../../nodes/diagram"; import {$openDrawingEditorForNode, DiagramNode} from "../../nodes/diagram";
import {$selectionContainsNode, $selectSingleNode} from "../../utils/selection";
export class DiagramDecorator extends EditorDecorator { export class DiagramDecorator extends EditorDecorator {

View File

@ -1,9 +1,10 @@
import {EditorDecorator} from "../framework/decorator"; import {EditorDecorator} from "../framework/decorator";
import {el, $selectSingleNode} from "../../helpers";
import {$createNodeSelection, $setSelection} from "lexical"; import {$createNodeSelection, $setSelection} from "lexical";
import {EditorUiContext} from "../framework/core"; import {EditorUiContext} from "../framework/core";
import {ImageNode} from "../../nodes/image"; import {ImageNode} from "../../nodes/image";
import {MouseDragTracker, MouseDragTrackerDistance} from "../framework/helpers/mouse-drag-tracker"; import {MouseDragTracker, MouseDragTrackerDistance} from "../framework/helpers/mouse-drag-tracker";
import {$selectSingleNode} from "../../utils/selection";
import {el} from "../../utils/dom";
export class ImageDecorator extends EditorDecorator { export class ImageDecorator extends EditorDecorator {

View File

@ -1,11 +1,11 @@
import {$getSelection, BaseSelection, ElementFormatType} from "lexical"; import {$getSelection, BaseSelection, ElementFormatType} from "lexical";
import {$getBlockElementNodesInSelection, $selectionContainsElementFormat} from "../../../helpers";
import {EditorButtonDefinition} from "../../framework/buttons"; import {EditorButtonDefinition} from "../../framework/buttons";
import alignLeftIcon from "@icons/editor/align-left.svg"; import alignLeftIcon from "@icons/editor/align-left.svg";
import {EditorUiContext} from "../../framework/core"; import {EditorUiContext} from "../../framework/core";
import alignCenterIcon from "@icons/editor/align-center.svg"; import alignCenterIcon from "@icons/editor/align-center.svg";
import alignRightIcon from "@icons/editor/align-right.svg"; import alignRightIcon from "@icons/editor/align-right.svg";
import alignJustifyIcon from "@icons/editor/align-justify.svg"; import alignJustifyIcon from "@icons/editor/align-justify.svg";
import {$getBlockElementNodesInSelection, $selectionContainsElementFormat} from "../../../utils/selection";
function setAlignmentForSection(alignment: ElementFormatType): void { function setAlignmentForSection(alignment: ElementFormatType): void {

View File

@ -1,7 +1,6 @@
import {$createCalloutNode, $isCalloutNodeOfCategory, CalloutCategory} from "../../../nodes/callout"; import {$createCalloutNode, $isCalloutNodeOfCategory, CalloutCategory} from "../../../nodes/callout";
import {EditorButtonDefinition} from "../../framework/buttons"; import {EditorButtonDefinition} from "../../framework/buttons";
import {EditorUiContext} from "../../framework/core"; import {EditorUiContext} from "../../framework/core";
import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../helpers";
import {$createParagraphNode, $isParagraphNode, BaseSelection, LexicalNode} from "lexical"; import {$createParagraphNode, $isParagraphNode, BaseSelection, LexicalNode} from "lexical";
import { import {
$createHeadingNode, $createHeadingNode,
@ -11,6 +10,7 @@ import {
HeadingNode, HeadingNode,
HeadingTagType HeadingTagType
} from "@lexical/rich-text"; } from "@lexical/rich-text";
import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../utils/selection";
function buildCalloutButton(category: CalloutCategory, name: string): EditorButtonDefinition { function buildCalloutButton(category: CalloutCategory, name: string): EditorButtonDefinition {
return { return {

View File

@ -11,7 +11,7 @@ import {
} from "lexical"; } from "lexical";
import redoIcon from "@icons/editor/redo.svg"; import redoIcon from "@icons/editor/redo.svg";
import sourceIcon from "@icons/editor/source-view.svg"; import sourceIcon from "@icons/editor/source-view.svg";
import {getEditorContentAsHtml} from "../../../actions"; import {getEditorContentAsHtml} from "../../../utils/actions";
import fullscreenIcon from "@icons/editor/fullscreen.svg"; import fullscreenIcon from "@icons/editor/fullscreen.svg";
export const undo: EditorButtonDefinition = { export const undo: EditorButtonDefinition = {

View File

@ -1,7 +1,6 @@
import {$getSelection, $isTextNode, BaseSelection, FORMAT_TEXT_COMMAND, TextFormatType} from "lexical"; import {$getSelection, $isTextNode, BaseSelection, FORMAT_TEXT_COMMAND, TextFormatType} from "lexical";
import {EditorBasicButtonDefinition, EditorButtonDefinition} from "../../framework/buttons"; import {EditorBasicButtonDefinition, EditorButtonDefinition} from "../../framework/buttons";
import {EditorUiContext} from "../../framework/core"; import {EditorUiContext} from "../../framework/core";
import {$selectionContainsTextFormat} from "../../../helpers";
import boldIcon from "@icons/editor/bold.svg"; import boldIcon from "@icons/editor/bold.svg";
import italicIcon from "@icons/editor/italic.svg"; import italicIcon from "@icons/editor/italic.svg";
import underlinedIcon from "@icons/editor/underlined.svg"; import underlinedIcon from "@icons/editor/underlined.svg";
@ -12,6 +11,7 @@ import superscriptIcon from "@icons/editor/superscript.svg";
import subscriptIcon from "@icons/editor/subscript.svg"; import subscriptIcon from "@icons/editor/subscript.svg";
import codeIcon from "@icons/editor/code.svg"; import codeIcon from "@icons/editor/code.svg";
import formatClearIcon from "@icons/editor/format-clear.svg"; import formatClearIcon from "@icons/editor/format-clear.svg";
import {$selectionContainsTextFormat} from "../../../utils/selection";
function buildFormatButton(label: string, format: TextFormatType, icon: string): EditorButtonDefinition { function buildFormatButton(label: string, format: TextFormatType, icon: string): EditorButtonDefinition {
return { return {

View File

@ -2,10 +2,10 @@ import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/
import {EditorButtonDefinition} from "../../framework/buttons"; import {EditorButtonDefinition} from "../../framework/buttons";
import {EditorUiContext} from "../../framework/core"; import {EditorUiContext} from "../../framework/core";
import {$getSelection, BaseSelection, LexicalNode} from "lexical"; import {$getSelection, BaseSelection, LexicalNode} from "lexical";
import {$selectionContainsNodeType} from "../../../helpers";
import listBulletIcon from "@icons/editor/list-bullet.svg"; import listBulletIcon from "@icons/editor/list-bullet.svg";
import listNumberedIcon from "@icons/editor/list-numbered.svg"; import listNumberedIcon from "@icons/editor/list-numbered.svg";
import listCheckIcon from "@icons/editor/list-check.svg"; import listCheckIcon from "@icons/editor/list-check.svg";
import {$selectionContainsNodeType} from "../../../utils/selection";
function buildListButton(label: string, type: ListType, icon: string): EditorButtonDefinition { function buildListButton(label: string, type: ListType, icon: string): EditorButtonDefinition {

View File

@ -10,7 +10,6 @@ import {
BaseSelection, BaseSelection,
ElementNode ElementNode
} from "lexical"; } from "lexical";
import {$getNodeFromSelection, $insertNewBlockNodeAtSelection, $selectionContainsNodeType} from "../../../helpers";
import {$isLinkNode, LinkNode} from "@lexical/link"; import {$isLinkNode, LinkNode} from "@lexical/link";
import unlinkIcon from "@icons/editor/unlink.svg"; import unlinkIcon from "@icons/editor/unlink.svg";
import imageIcon from "@icons/editor/image.svg"; import imageIcon from "@icons/editor/image.svg";
@ -26,6 +25,11 @@ import detailsIcon from "@icons/editor/details.svg";
import mediaIcon from "@icons/editor/media.svg"; import mediaIcon from "@icons/editor/media.svg";
import {$createDetailsNode, $isDetailsNode} from "../../../nodes/details"; import {$createDetailsNode, $isDetailsNode} from "../../../nodes/details";
import {$isMediaNode, MediaNode} from "../../../nodes/media"; import {$isMediaNode, MediaNode} from "../../../nodes/media";
import {
$getNodeFromSelection,
$insertNewBlockNodeAtSelection,
$selectionContainsNodeType
} from "../../../utils/selection";
export const link: EditorButtonDefinition = { export const link: EditorButtonDefinition = {
label: 'Insert/edit link', label: 'Insert/edit link',

View File

@ -8,10 +8,6 @@ import insertColumnBeforeIcon from "@icons/editor/table-insert-column-before.svg
import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg"; import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg";
import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg"; import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg";
import {EditorUiContext} from "../../framework/core"; import {EditorUiContext} from "../../framework/core";
import {
$getNodeFromSelection, $getParentOfType,
$selectionContainsNodeType
} from "../../../helpers";
import {$getSelection, BaseSelection} from "lexical"; import {$getSelection, BaseSelection} from "lexical";
import {$isCustomTableNode} from "../../../nodes/custom-table"; import {$isCustomTableNode} from "../../../nodes/custom-table";
import { import {
@ -22,6 +18,8 @@ import {
$insertTableRow__EXPERIMENTAL, $isTableCellNode, $insertTableRow__EXPERIMENTAL, $isTableCellNode,
$isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode, TableNode, $isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode, TableNode,
} from "@lexical/table"; } from "@lexical/table";
import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
import {$getParentOfType} from "../../../utils/nodes";
const neverActive = (): boolean => false; const neverActive = (): boolean => false;
const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isTableCellNode); const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isTableCellNode);

View File

@ -1,6 +1,6 @@
import {EditorFormDefinition} from "../../framework/forms"; import {EditorFormDefinition} from "../../framework/forms";
import {EditorUiContext} from "../../framework/core"; import {EditorUiContext} from "../../framework/core";
import {setEditorContentFromHtml} from "../../../actions"; import {setEditorContentFromHtml} from "../../../utils/actions";
export const source: EditorFormDefinition = { export const source: EditorFormDefinition = {
submitText: 'Save', submitText: 'Save',

View File

@ -4,8 +4,8 @@ import {$createTextNode, $getSelection} from "lexical";
import {$createImageNode} from "../../../nodes/image"; import {$createImageNode} from "../../../nodes/image";
import {$createLinkNode} from "@lexical/link"; import {$createLinkNode} from "@lexical/link";
import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../../nodes/media"; import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../../nodes/media";
import {$getNodeFromSelection} from "../../../helpers";
import {$insertNodeToNearestRoot} from "@lexical/utils"; import {$insertNodeToNearestRoot} from "@lexical/utils";
import {$getNodeFromSelection} from "../../../utils/selection";
export const image: EditorFormDefinition = { export const image: EditorFormDefinition = {
submitText: 'Apply', submitText: 'Apply',

View File

@ -1,7 +1,7 @@
import {el} from "../../../helpers";
import {EditorUiElement} from "../core"; import {EditorUiElement} from "../core";
import {$getSelection} from "lexical"; import {$getSelection} from "lexical";
import {$patchStyleText} from "@lexical/selection"; import {$patchStyleText} from "@lexical/selection";
import {el} from "../../../utils/dom";
const colorChoices = [ const colorChoices = [
'#000000', '#000000',

View File

@ -1,7 +1,7 @@
import {el} from "../../../helpers";
import {handleDropdown} from "../helpers/dropdowns"; import {handleDropdown} from "../helpers/dropdowns";
import {EditorContainerUiElement, EditorUiElement} from "../core"; import {EditorContainerUiElement, EditorUiElement} from "../core";
import {EditorBasicButtonDefinition, EditorButton} from "../buttons"; import {EditorBasicButtonDefinition, EditorButton} from "../buttons";
import {el} from "../../../utils/dom";
export type EditorDropdownButtonOptions = { export type EditorDropdownButtonOptions = {
showOnHover?: boolean; showOnHover?: boolean;

View File

@ -1,7 +1,7 @@
import {el} from "../../../helpers";
import {EditorUiStateUpdate, EditorContainerUiElement} from "../core"; import {EditorUiStateUpdate, EditorContainerUiElement} from "../core";
import {EditorButton} from "../buttons"; import {EditorButton} from "../buttons";
import {handleDropdown} from "../helpers/dropdowns"; import {handleDropdown} from "../helpers/dropdowns";
import {el} from "../../../utils/dom";
export class EditorFormatMenu extends EditorContainerUiElement { export class EditorFormatMenu extends EditorContainerUiElement {
buildDOM(): HTMLElement { buildDOM(): HTMLElement {

View File

@ -1,5 +1,5 @@
import {el} from "../../../helpers";
import {EditorButton, EditorButtonDefinition} from "../buttons"; import {EditorButton, EditorButtonDefinition} from "../buttons";
import {el} from "../../../utils/dom";
export class FormatPreviewButton extends EditorButton { export class FormatPreviewButton extends EditorButton {
protected previewSampleElement: HTMLElement; protected previewSampleElement: HTMLElement;

View File

@ -1,7 +1,7 @@
import {EditorContainerUiElement, EditorUiElement} from "../core"; import {EditorContainerUiElement, EditorUiElement} from "../core";
import {el} from "../../../helpers";
import {EditorDropdownButton} from "./dropdown-button"; import {EditorDropdownButton} from "./dropdown-button";
import moreHorizontal from "@icons/editor/more-horizontal.svg" import moreHorizontal from "@icons/editor/more-horizontal.svg"
import {el} from "../../../utils/dom";
export class EditorOverflowContainer extends EditorContainerUiElement { export class EditorOverflowContainer extends EditorContainerUiElement {

View File

@ -1,7 +1,8 @@
import {el, $insertNewBlockNodeAtSelection} from "../../../helpers";
import {EditorUiElement} from "../core"; import {EditorUiElement} from "../core";
import {$createTableNodeWithDimensions} from "@lexical/table"; import {$createTableNodeWithDimensions} from "@lexical/table";
import {CustomTableNode} from "../../../nodes/custom-table"; import {CustomTableNode} from "../../../nodes/custom-table";
import {$insertNewBlockNodeAtSelection} from "../../../utils/selection";
import {el} from "../../../utils/dom";
export class EditorTableCreator extends EditorUiElement { export class EditorTableCreator extends EditorUiElement {

View File

@ -1,6 +1,7 @@
import {BaseSelection} from "lexical"; import {BaseSelection} from "lexical";
import {EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core"; import {EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core";
import {el} from "../../helpers";
import {el} from "../../utils/dom";
export interface EditorBasicButtonDefinition { export interface EditorBasicButtonDefinition {
label: string; label: string;

View File

@ -1,6 +1,7 @@
import {BaseSelection, LexicalEditor} from "lexical"; import {BaseSelection, LexicalEditor} from "lexical";
import {EditorUIManager} from "./manager"; import {EditorUIManager} from "./manager";
import {el} from "../../helpers";
import {el} from "../../utils/dom";
export type EditorUiStateUpdate = { export type EditorUiStateUpdate = {
editor: LexicalEditor; editor: LexicalEditor;

View File

@ -5,8 +5,8 @@ import {
EditorUiBuilderDefinition, EditorUiBuilderDefinition,
isUiBuilderDefinition isUiBuilderDefinition
} from "./core"; } from "./core";
import {el} from "../../helpers";
import {uniqueId} from "../../../services/util"; import {uniqueId} from "../../../services/util";
import {el} from "../../utils/dom";
export interface EditorFormFieldDefinition { export interface EditorFormFieldDefinition {
label: string; label: string;

View File

@ -1,8 +1,8 @@
import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical"; import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical";
import {el} from "../../../helpers";
import {MouseDragTracker, MouseDragTrackerDistance} from "./mouse-drag-tracker"; import {MouseDragTracker, MouseDragTrackerDistance} from "./mouse-drag-tracker";
import {$getTableColumnWidth, $setTableColumnWidth, CustomTableNode} from "../../../nodes/custom-table"; import {$getTableColumnWidth, $setTableColumnWidth, CustomTableNode} from "../../../nodes/custom-table";
import {TableRowNode} from "@lexical/table"; import {TableRowNode} from "@lexical/table";
import {el} from "../../../utils/dom";
type MarkerDomRecord = {x: HTMLElement, y: HTMLElement}; type MarkerDomRecord = {x: HTMLElement, y: HTMLElement};

View File

@ -1,7 +1,7 @@
import {EditorForm, EditorFormDefinition} from "./forms"; import {EditorForm, EditorFormDefinition} from "./forms";
import {el} from "../../helpers";
import {EditorContainerUiElement} from "./core"; import {EditorContainerUiElement} from "./core";
import closeIcon from "@icons/close.svg"; import closeIcon from "@icons/close.svg";
import {el} from "../../utils/dom";
export interface EditorModalDefinition { export interface EditorModalDefinition {
title: string; title: string;

View File

@ -1,5 +1,6 @@
import {EditorContainerUiElement, EditorUiElement} from "./core"; import {EditorContainerUiElement, EditorUiElement} from "./core";
import {el} from "../../helpers";
import {el} from "../../utils/dom";
export type EditorContextToolbarDefinition = { export type EditorContextToolbarDefinition = {
selector: string; selector: string;

View File

@ -1,6 +1,5 @@
import {EditorButton} from "./framework/buttons"; import {EditorButton} from "./framework/buttons";
import {EditorContainerUiElement, EditorSimpleClassContainer, EditorUiElement} from "./framework/core"; import {EditorContainerUiElement, EditorSimpleClassContainer, EditorUiElement} from "./framework/core";
import {$selectionContainsNodeType, el} from "../helpers";
import {EditorFormatMenu} from "./framework/blocks/format-menu"; import {EditorFormatMenu} from "./framework/blocks/format-menu";
import {FormatPreviewButton} from "./framework/blocks/format-preview-button"; import {FormatPreviewButton} from "./framework/blocks/format-preview-button";
import {EditorDropdownButton} from "./framework/blocks/dropdown-button"; import {EditorDropdownButton} from "./framework/blocks/dropdown-button";
@ -65,6 +64,8 @@ import {
unlink unlink
} from "./defaults/buttons/objects"; } from "./defaults/buttons/objects";
import {$isTableNode} from "@lexical/table"; import {$isTableNode} from "@lexical/table";
import {$selectionContainsNodeType} from "../utils/selection";
import {el} from "../utils/dom";
export function getMainEditorFullToolbar(): EditorContainerUiElement { export function getMainEditorFullToolbar(): EditorContainerUiElement {
return new EditorSimpleClassContainer('editor-toolbar-main', [ return new EditorSimpleClassContainer('editor-toolbar-main', [

View File

@ -1,8 +1,6 @@
import {$getRoot, $getSelection, LexicalEditor} from "lexical"; import {$getRoot, $getSelection, LexicalEditor} from "lexical";
import {$generateHtmlFromNodes} from "@lexical/html"; import {$generateHtmlFromNodes} from "@lexical/html";
import {$htmlToBlockNodes} from "./helpers"; import {$htmlToBlockNodes} from "./nodes";
export function setEditorContentFromHtml(editor: LexicalEditor, html: string) { export function setEditorContentFromHtml(editor: LexicalEditor, html: string) {
editor.update(() => { editor.update(() => {

View File

@ -0,0 +1,24 @@
export function el(tag: string, attrs: Record<string, string | null> = {}, children: (string | HTMLElement)[] = []): HTMLElement {
const el = document.createElement(tag);
const attrKeys = Object.keys(attrs);
for (const attr of attrKeys) {
if (attrs[attr] !== null) {
el.setAttribute(attr, attrs[attr] as string);
}
}
for (const child of children) {
if (typeof child === 'string') {
el.append(document.createTextNode(child));
} else {
el.append(child);
}
}
return el;
}
export function htmlToDom(html: string): Document {
const parser = new DOMParser();
return parser.parseFromString(html, 'text/html');
}

View File

@ -0,0 +1,53 @@
import {$getRoot, $isTextNode, LexicalEditor, LexicalNode} from "lexical";
import {LexicalNodeMatcher} from "../nodes";
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
import {$generateNodesFromDOM} from "@lexical/html";
import {htmlToDom} from "./dom";
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
return nodes.map(node => {
if ($isTextNode(node)) {
const paragraph = $createCustomParagraphNode();
paragraph.append(node);
return paragraph;
}
return node;
});
}
export function $htmlToBlockNodes(editor: LexicalEditor, html: string): LexicalNode[] {
const dom = htmlToDom(html);
const nodes = $generateNodesFromDOM(editor, dom);
return wrapTextNodes(nodes);
}
export function $getParentOfType(node: LexicalNode, matcher: LexicalNodeMatcher): LexicalNode | null {
for (const parent of node.getParents()) {
if (matcher(parent)) {
return parent;
}
}
return null;
}
/**
* Get the nearest root/block level node for the given position.
*/
export function $getNearestBlockNodeForCoords(editor: LexicalEditor, x: number, y: number): LexicalNode | null {
// TODO - Take into account x for floated blocks?
const rootNodes = $getRoot().getChildren();
for (const node of rootNodes) {
const nodeDom = editor.getElementByKey(node.__key);
if (!nodeDom) {
continue;
}
const bounds = nodeDom.getBoundingClientRect();
if (y <= bounds.bottom) {
return node;
}
}
return null;
}

View File

@ -1,64 +1,28 @@
import { import {
$createNodeSelection, $createNodeSelection,
$createParagraphNode, $getRoot, $createParagraphNode,
$getSelection, $isElementNode, $getRoot,
$isTextNode, $setSelection, $getSelection,
BaseSelection, ElementFormatType, ElementNode, LexicalEditor, $isElementNode,
LexicalNode, TextFormatType $isTextNode,
$setSelection,
BaseSelection,
ElementFormatType,
ElementNode,
LexicalNode,
TextFormatType
} from "lexical"; } from "lexical";
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "./nodes";
import {$findMatchingParent, $getNearestBlockElementAncestorOrThrow} from "@lexical/utils"; import {$findMatchingParent, $getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "../nodes";
import {$setBlocksType} from "@lexical/selection"; import {$setBlocksType} from "@lexical/selection";
import {$createCustomParagraphNode} from "./nodes/custom-paragraph";
import {$generateNodesFromDOM} from "@lexical/html";
export function el(tag: string, attrs: Record<string, string|null> = {}, children: (string|HTMLElement)[] = []): HTMLElement { import {$getParentOfType} from "./nodes";
const el = document.createElement(tag);
const attrKeys = Object.keys(attrs);
for (const attr of attrKeys) {
if (attrs[attr] !== null) {
el.setAttribute(attr, attrs[attr] as string);
}
}
for (const child of children) { export function $selectionContainsNodeType(selection: BaseSelection | null, matcher: LexicalNodeMatcher): boolean {
if (typeof child === 'string') {
el.append(document.createTextNode(child));
} else {
el.append(child);
}
}
return el;
}
function htmlToDom(html: string): Document {
const parser = new DOMParser();
return parser.parseFromString(html, 'text/html');
}
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
return nodes.map(node => {
if ($isTextNode(node)) {
const paragraph = $createCustomParagraphNode();
paragraph.append(node);
return paragraph;
}
return node;
});
}
export function $htmlToBlockNodes(editor: LexicalEditor, html: string): LexicalNode[] {
const dom = htmlToDom(html);
const nodes = $generateNodesFromDOM(editor, dom);
return wrapTextNodes(nodes);
}
export function $selectionContainsNodeType(selection: BaseSelection|null, matcher: LexicalNodeMatcher): boolean {
return $getNodeFromSelection(selection, matcher) !== null; return $getNodeFromSelection(selection, matcher) !== null;
} }
export function $getNodeFromSelection(selection: BaseSelection|null, matcher: LexicalNodeMatcher): LexicalNode|null { export function $getNodeFromSelection(selection: BaseSelection | null, matcher: LexicalNodeMatcher): LexicalNode | null {
if (!selection) { if (!selection) {
return null; return null;
} }
@ -77,17 +41,7 @@ export function $getNodeFromSelection(selection: BaseSelection|null, matcher: Le
return null; return null;
} }
export function $getParentOfType(node: LexicalNode, matcher: LexicalNodeMatcher): LexicalNode|null { export function $selectionContainsTextFormat(selection: BaseSelection | null, format: TextFormatType): boolean {
for (const parent of node.getParents()) {
if (matcher(parent)) {
return parent;
}
}
return null;
}
export function $selectionContainsTextFormat(selection: BaseSelection|null, format: TextFormatType): boolean {
if (!selection) { if (!selection) {
return false; return false;
} }
@ -140,7 +94,7 @@ export function $selectSingleNode(node: LexicalNode) {
$setSelection(nodeSelection); $setSelection(nodeSelection);
} }
export function $selectionContainsNode(selection: BaseSelection|null, node: LexicalNode): boolean { export function $selectionContainsNode(selection: BaseSelection | null, node: LexicalNode): boolean {
if (!selection) { if (!selection) {
return false; return false;
} }
@ -155,7 +109,7 @@ export function $selectionContainsNode(selection: BaseSelection|null, node: Lexi
return false; return false;
} }
export function $selectionContainsElementFormat(selection: BaseSelection|null, format: ElementFormatType): boolean { export function $selectionContainsElementFormat(selection: BaseSelection | null, format: ElementFormatType): boolean {
const nodes = $getBlockElementNodesInSelection(selection); const nodes = $getBlockElementNodesInSelection(selection);
for (const node of nodes) { for (const node of nodes) {
if (node.getFormatType() === format) { if (node.getFormatType() === format) {
@ -166,7 +120,7 @@ export function $selectionContainsElementFormat(selection: BaseSelection|null, f
return false; return false;
} }
export function $getBlockElementNodesInSelection(selection: BaseSelection|null): ElementNode[] { export function $getBlockElementNodesInSelection(selection: BaseSelection | null): ElementNode[] {
if (!selection) { if (!selection) {
return []; return [];
} }
@ -175,7 +129,7 @@ export function $getBlockElementNodesInSelection(selection: BaseSelection|null):
for (const node of selection.getNodes()) { for (const node of selection.getNodes()) {
const blockElement = $findMatchingParent(node, (node) => { const blockElement = $findMatchingParent(node, (node) => {
return $isElementNode(node) && !node.isInline(); return $isElementNode(node) && !node.isInline();
}) as ElementNode|null; }) as ElementNode | null;
if (blockElement) { if (blockElement) {
blockNodes.set(blockElement.getKey(), blockElement); blockNodes.set(blockElement.getKey(), blockElement);
@ -184,24 +138,3 @@ export function $getBlockElementNodesInSelection(selection: BaseSelection|null):
return Array.from(blockNodes.values()); return Array.from(blockNodes.values());
} }
/**
* Get the nearest root/block level node for the given position.
*/
export function $getNearestBlockNodeForCoords(editor: LexicalEditor, x: number, y: number): LexicalNode|null {
// TODO - Take into account x for floated blocks?
const rootNodes = $getRoot().getChildren();
for (const node of rootNodes) {
const nodeDom = editor.getElementByKey(node.__key);
if (!nodeDom) {
continue;
}
const bounds = nodeDom.getBoundingClientRect();
if (y <= bounds.bottom) {
return node;
}
}
return null;
}