mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-10 13:43:38 +08:00
Lexical: Started on table actions
Started building table cell form/actions
This commit is contained in:
@ -11,6 +11,7 @@ import {EditorUiContext} from "./ui/framework/core";
|
|||||||
import {listen as listenToCommonEvents} from "./common-events";
|
import {listen as listenToCommonEvents} from "./common-events";
|
||||||
import {handleDropEvents} from "./drop-handling";
|
import {handleDropEvents} from "./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";
|
||||||
|
|
||||||
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 = {
|
||||||
@ -48,6 +49,7 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
|
|||||||
registerRichText(editor),
|
registerRichText(editor),
|
||||||
registerHistory(editor, createEmptyHistoryState(), 300),
|
registerHistory(editor, createEmptyHistoryState(), 300),
|
||||||
registerTableResizer(editor, editWrap),
|
registerTableResizer(editor, editWrap),
|
||||||
|
registerTableSelectionHandler(editor),
|
||||||
registerTaskListHandler(editor, editArea),
|
registerTaskListHandler(editor, editArea),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ export function $createCustomTableNode(): CustomTableNode {
|
|||||||
return new CustomTableNode();
|
return new CustomTableNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function $isCustomTableNode(node: LexicalNode | null | undefined): boolean {
|
export function $isCustomTableNode(node: LexicalNode | null | undefined): node is CustomTableNode {
|
||||||
return node instanceof CustomTableNode;
|
return node instanceof CustomTableNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
## In progress
|
## In progress
|
||||||
|
|
||||||
- Table features
|
- Table features
|
||||||
- Continued table dropdown menu
|
- Continued table dropdown menu
|
||||||
|
- Connect up cell properties form
|
||||||
|
- Merge cell action
|
||||||
|
|
||||||
## Main Todo
|
## Main Todo
|
||||||
|
|
||||||
@ -21,6 +23,10 @@
|
|||||||
- 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)
|
||||||
|
|
||||||
|
## Secondary Todo
|
||||||
|
|
||||||
|
- Color picker support in table form color fields
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
|
||||||
- Image resizing currently bugged, maybe change to ghost resizer in decorator instead of updating core node.
|
- Image resizing currently bugged, maybe change to ghost resizer in decorator instead of updating core node.
|
||||||
|
@ -18,8 +18,8 @@ import {
|
|||||||
$deleteTableColumn__EXPERIMENTAL,
|
$deleteTableColumn__EXPERIMENTAL,
|
||||||
$deleteTableRow__EXPERIMENTAL,
|
$deleteTableRow__EXPERIMENTAL,
|
||||||
$insertTableColumn__EXPERIMENTAL,
|
$insertTableColumn__EXPERIMENTAL,
|
||||||
$insertTableRow__EXPERIMENTAL,
|
$insertTableRow__EXPERIMENTAL, $isTableCellNode,
|
||||||
$isTableNode,
|
$isTableNode, $isTableSelection, $unmergeCell, TableCellNode,
|
||||||
} from "@lexical/table";
|
} from "@lexical/table";
|
||||||
|
|
||||||
|
|
||||||
@ -128,4 +128,62 @@ export const deleteColumn: EditorButtonDefinition = {
|
|||||||
isActive() {
|
isActive() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cellProperties: EditorButtonDefinition = {
|
||||||
|
label: 'Cell properties',
|
||||||
|
action(context: EditorUiContext) {
|
||||||
|
context.editor.getEditorState().read(() => {
|
||||||
|
const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
|
||||||
|
if ($isTableCellNode(cell)) {
|
||||||
|
|
||||||
|
const modalForm = context.manager.createModal('cell_properties');
|
||||||
|
modalForm.show({});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isActive() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
isDisabled(selection) {
|
||||||
|
return !$selectionContainsNodeType(selection, $isTableCellNode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mergeCells: EditorButtonDefinition = {
|
||||||
|
label: 'Merge cells',
|
||||||
|
action(context: EditorUiContext) {
|
||||||
|
context.editor.update(() => {
|
||||||
|
// Todo - Needs to be done manually
|
||||||
|
// Playground reference:
|
||||||
|
// https://github.com/facebook/lexical/blob/f373759a7849f473d34960a6bf4e34b2a011e762/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx#L299
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isActive() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
isDisabled(selection) {
|
||||||
|
return !$isTableSelection(selection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const splitCell: EditorButtonDefinition = {
|
||||||
|
label: 'Split cell',
|
||||||
|
action(context: EditorUiContext) {
|
||||||
|
context.editor.update(() => {
|
||||||
|
$unmergeCell();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isActive() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
isDisabled(selection) {
|
||||||
|
const cell = $getNodeFromSelection(selection, $isTableCellNode) as TableCellNode|null;
|
||||||
|
if (cell) {
|
||||||
|
const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;
|
||||||
|
return !merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
18
resources/js/wysiwyg/ui/defaults/forms/controls.ts
Normal file
18
resources/js/wysiwyg/ui/defaults/forms/controls.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {EditorFormDefinition} from "../../framework/forms";
|
||||||
|
import {EditorUiContext} from "../../framework/core";
|
||||||
|
import {setEditorContentFromHtml} from "../../../actions";
|
||||||
|
|
||||||
|
export const source: EditorFormDefinition = {
|
||||||
|
submitText: 'Save',
|
||||||
|
async action(formData, context: EditorUiContext) {
|
||||||
|
setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: 'Source',
|
||||||
|
name: 'source',
|
||||||
|
type: 'textarea',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -1,13 +1,49 @@
|
|||||||
import {EditorFormDefinition, EditorFormTabs, EditorSelectFormFieldDefinition} from "../framework/forms";
|
import {EditorFormDefinition, EditorFormTabs, EditorSelectFormFieldDefinition} from "../../framework/forms";
|
||||||
import {EditorUiContext} from "../framework/core";
|
import {EditorUiContext} from "../../framework/core";
|
||||||
|
import {$createTextNode, $getSelection} from "lexical";
|
||||||
|
import {$createImageNode} from "../../../nodes/image";
|
||||||
import {$createLinkNode} from "@lexical/link";
|
import {$createLinkNode} from "@lexical/link";
|
||||||
import {$createTextNode, $getSelection, LexicalNode} from "lexical";
|
import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../../nodes/media";
|
||||||
import {$createImageNode} from "../../nodes/image";
|
import {$getNodeFromSelection} from "../../../helpers";
|
||||||
import {setEditorContentFromHtml} from "../../actions";
|
|
||||||
import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../nodes/media";
|
|
||||||
import {$getNodeFromSelection} from "../../helpers";
|
|
||||||
import {$insertNodeToNearestRoot} from "@lexical/utils";
|
import {$insertNodeToNearestRoot} from "@lexical/utils";
|
||||||
|
|
||||||
|
export const image: EditorFormDefinition = {
|
||||||
|
submitText: 'Apply',
|
||||||
|
async action(formData, context: EditorUiContext) {
|
||||||
|
context.editor.update(() => {
|
||||||
|
const selection = $getSelection();
|
||||||
|
const imageNode = $createImageNode(formData.get('src')?.toString() || '', {
|
||||||
|
alt: formData.get('alt')?.toString() || '',
|
||||||
|
height: Number(formData.get('height')?.toString() || '0'),
|
||||||
|
width: Number(formData.get('width')?.toString() || '0'),
|
||||||
|
});
|
||||||
|
selection?.insertNodes([imageNode]);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: 'Source',
|
||||||
|
name: 'src',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Alternative description',
|
||||||
|
name: 'alt',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Width',
|
||||||
|
name: 'width',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Height',
|
||||||
|
name: 'height',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
export const link: EditorFormDefinition = {
|
export const link: EditorFormDefinition = {
|
||||||
submitText: 'Apply',
|
submitText: 'Apply',
|
||||||
@ -54,44 +90,6 @@ export const link: EditorFormDefinition = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const image: EditorFormDefinition = {
|
|
||||||
submitText: 'Apply',
|
|
||||||
async action(formData, context: EditorUiContext) {
|
|
||||||
context.editor.update(() => {
|
|
||||||
const selection = $getSelection();
|
|
||||||
const imageNode = $createImageNode(formData.get('src')?.toString() || '', {
|
|
||||||
alt: formData.get('alt')?.toString() || '',
|
|
||||||
height: Number(formData.get('height')?.toString() || '0'),
|
|
||||||
width: Number(formData.get('width')?.toString() || '0'),
|
|
||||||
});
|
|
||||||
selection?.insertNodes([imageNode]);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: 'Source',
|
|
||||||
name: 'src',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Alternative description',
|
|
||||||
name: 'alt',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Width',
|
|
||||||
name: 'width',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Height',
|
|
||||||
name: 'height',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const media: EditorFormDefinition = {
|
export const media: EditorFormDefinition = {
|
||||||
submitText: 'Save',
|
submitText: 'Save',
|
||||||
async action(formData, context: EditorUiContext) {
|
async action(formData, context: EditorUiContext) {
|
||||||
@ -169,19 +167,4 @@ export const media: EditorFormDefinition = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
|
||||||
|
|
||||||
export const source: EditorFormDefinition = {
|
|
||||||
submitText: 'Save',
|
|
||||||
async action(formData, context: EditorUiContext) {
|
|
||||||
setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: 'Source',
|
|
||||||
name: 'source',
|
|
||||||
type: 'textarea',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
112
resources/js/wysiwyg/ui/defaults/forms/tables.ts
Normal file
112
resources/js/wysiwyg/ui/defaults/forms/tables.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import {
|
||||||
|
EditorFormDefinition,
|
||||||
|
EditorFormFieldDefinition,
|
||||||
|
EditorFormTabs,
|
||||||
|
EditorSelectFormFieldDefinition
|
||||||
|
} from "../../framework/forms";
|
||||||
|
import {EditorUiContext} from "../../framework/core";
|
||||||
|
import {setEditorContentFromHtml} from "../../../actions";
|
||||||
|
|
||||||
|
export const cellProperties: EditorFormDefinition = {
|
||||||
|
submitText: 'Save',
|
||||||
|
async action(formData, context: EditorUiContext) {
|
||||||
|
setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
build() {
|
||||||
|
const generalFields: EditorFormFieldDefinition[] = [
|
||||||
|
{
|
||||||
|
label: 'Width',
|
||||||
|
name: 'width',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Height',
|
||||||
|
name: 'height',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cell type',
|
||||||
|
name: 'type',
|
||||||
|
type: 'select',
|
||||||
|
valuesByLabel: {
|
||||||
|
'Cell': 'cell',
|
||||||
|
'Header cell': 'header',
|
||||||
|
}
|
||||||
|
} as EditorSelectFormFieldDefinition,
|
||||||
|
{
|
||||||
|
label: 'Horizontal align',
|
||||||
|
name: 'h_align',
|
||||||
|
type: 'select',
|
||||||
|
valuesByLabel: {
|
||||||
|
'None': '',
|
||||||
|
'Left': 'left',
|
||||||
|
'Center': 'center',
|
||||||
|
'Right': 'right',
|
||||||
|
}
|
||||||
|
} as EditorSelectFormFieldDefinition,
|
||||||
|
{
|
||||||
|
label: 'Vertical align',
|
||||||
|
name: 'v_align',
|
||||||
|
type: 'select',
|
||||||
|
valuesByLabel: {
|
||||||
|
'None': '',
|
||||||
|
'Top': 'top',
|
||||||
|
'Middle': 'middle',
|
||||||
|
'Bottom': 'bottom',
|
||||||
|
}
|
||||||
|
} as EditorSelectFormFieldDefinition,
|
||||||
|
];
|
||||||
|
|
||||||
|
const advancedFields: EditorFormFieldDefinition[] = [
|
||||||
|
{
|
||||||
|
label: 'Border width',
|
||||||
|
name: 'border_width',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Border style',
|
||||||
|
name: 'border_style',
|
||||||
|
type: 'select',
|
||||||
|
valuesByLabel: {
|
||||||
|
'Select...': '',
|
||||||
|
"Solid": 'solid',
|
||||||
|
"Dotted": 'dotted',
|
||||||
|
"Dashed": 'dashed',
|
||||||
|
"Double": 'double',
|
||||||
|
"Groove": 'groove',
|
||||||
|
"Ridge": 'ridge',
|
||||||
|
"Inset": 'inset',
|
||||||
|
"Outset": 'outset',
|
||||||
|
"None": 'none',
|
||||||
|
"Hidden": 'hidden',
|
||||||
|
}
|
||||||
|
} as EditorSelectFormFieldDefinition,
|
||||||
|
{
|
||||||
|
label: 'Border color',
|
||||||
|
name: 'border_color',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Background color',
|
||||||
|
name: 'background_color',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return new EditorFormTabs([
|
||||||
|
{
|
||||||
|
label: 'General',
|
||||||
|
contents: generalFields,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Advanced',
|
||||||
|
contents: advancedFields,
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
27
resources/js/wysiwyg/ui/defaults/modals.ts
Normal file
27
resources/js/wysiwyg/ui/defaults/modals.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import {EditorFormModalDefinition} from "../framework/modals";
|
||||||
|
import {image, link, media} from "./forms/objects";
|
||||||
|
import {source} from "./forms/controls";
|
||||||
|
import {cellProperties} from "./forms/tables";
|
||||||
|
|
||||||
|
export const modals: Record<string, EditorFormModalDefinition> = {
|
||||||
|
link: {
|
||||||
|
title: 'Insert/Edit link',
|
||||||
|
form: link,
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
title: 'Insert/Edit Image',
|
||||||
|
form: image,
|
||||||
|
},
|
||||||
|
media: {
|
||||||
|
title: 'Insert/Edit Media',
|
||||||
|
form: media,
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
title: 'Source code',
|
||||||
|
form: source,
|
||||||
|
},
|
||||||
|
cell_properties: {
|
||||||
|
title: 'Cell Properties',
|
||||||
|
form: cellProperties,
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,80 @@
|
|||||||
|
import {$getNodeByKey, LexicalEditor} from "lexical";
|
||||||
|
import {NodeKey} from "lexical/LexicalNode";
|
||||||
|
import {
|
||||||
|
$isTableNode,
|
||||||
|
applyTableHandlers,
|
||||||
|
HTMLTableElementWithWithTableSelectionState,
|
||||||
|
TableNode,
|
||||||
|
TableObserver
|
||||||
|
} from "@lexical/table";
|
||||||
|
import {$isCustomTableNode, CustomTableNode} from "../../../nodes/custom-table";
|
||||||
|
|
||||||
|
// File adapted from logic in:
|
||||||
|
// https://github.com/facebook/lexical/blob/f373759a7849f473d34960a6bf4e34b2a011e762/packages/lexical-react/src/LexicalTablePlugin.ts#L49
|
||||||
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
// License: MIT
|
||||||
|
|
||||||
|
class TableSelectionHandler {
|
||||||
|
|
||||||
|
protected editor: LexicalEditor
|
||||||
|
protected tableSelections = new Map<NodeKey, TableObserver>();
|
||||||
|
protected unregisterMutationListener = () => {};
|
||||||
|
|
||||||
|
constructor(editor: LexicalEditor) {
|
||||||
|
this.editor = editor;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected init() {
|
||||||
|
this.unregisterMutationListener = this.editor.registerMutationListener(CustomTableNode, (mutations) => {
|
||||||
|
for (const [nodeKey, mutation] of mutations) {
|
||||||
|
if (mutation === 'created') {
|
||||||
|
this.editor.getEditorState().read(() => {
|
||||||
|
const tableNode = $getNodeByKey<CustomTableNode>(nodeKey);
|
||||||
|
if ($isCustomTableNode(tableNode)) {
|
||||||
|
this.initializeTableNode(tableNode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (mutation === 'destroyed') {
|
||||||
|
const tableSelection = this.tableSelections.get(nodeKey);
|
||||||
|
|
||||||
|
if (tableSelection !== undefined) {
|
||||||
|
tableSelection.removeListeners();
|
||||||
|
this.tableSelections.delete(nodeKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected initializeTableNode(tableNode: TableNode) {
|
||||||
|
const nodeKey = tableNode.getKey();
|
||||||
|
const tableElement = this.editor.getElementByKey(
|
||||||
|
nodeKey,
|
||||||
|
) as HTMLTableElementWithWithTableSelectionState;
|
||||||
|
if (tableElement && !this.tableSelections.has(nodeKey)) {
|
||||||
|
const tableSelection = applyTableHandlers(
|
||||||
|
tableNode,
|
||||||
|
tableElement,
|
||||||
|
this.editor,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
this.tableSelections.set(nodeKey, tableSelection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
this.unregisterMutationListener();
|
||||||
|
for (const [, tableSelection] of this.tableSelections) {
|
||||||
|
tableSelection.removeListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerTableSelectionHandler(editor: LexicalEditor): (() => void) {
|
||||||
|
const resizer = new TableSelectionHandler(editor);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizer.teardown();
|
||||||
|
};
|
||||||
|
}
|
@ -6,11 +6,11 @@ import {
|
|||||||
getMainEditorFullToolbar, getTableToolbarContent
|
getMainEditorFullToolbar, getTableToolbarContent
|
||||||
} from "./toolbars";
|
} from "./toolbars";
|
||||||
import {EditorUIManager} from "./framework/manager";
|
import {EditorUIManager} from "./framework/manager";
|
||||||
import {image as imageFormDefinition, link as linkFormDefinition, media as mediaFormDefinition, source as sourceFormDefinition} from "./defaults/form-definitions";
|
|
||||||
import {ImageDecorator} from "./decorators/image";
|
import {ImageDecorator} from "./decorators/image";
|
||||||
import {EditorUiContext} from "./framework/core";
|
import {EditorUiContext} from "./framework/core";
|
||||||
import {CodeBlockDecorator} from "./decorators/code-block";
|
import {CodeBlockDecorator} from "./decorators/code-block";
|
||||||
import {DiagramDecorator} from "./decorators/diagram";
|
import {DiagramDecorator} from "./decorators/diagram";
|
||||||
|
import {modals} from "./defaults/modals";
|
||||||
|
|
||||||
export function buildEditorUI(container: HTMLElement, element: HTMLElement, scrollContainer: HTMLElement, editor: LexicalEditor, options: Record<string, any>): EditorUiContext {
|
export function buildEditorUI(container: HTMLElement, element: HTMLElement, scrollContainer: HTMLElement, editor: LexicalEditor, options: Record<string, any>): EditorUiContext {
|
||||||
const manager = new EditorUIManager();
|
const manager = new EditorUIManager();
|
||||||
@ -30,22 +30,9 @@ export function buildEditorUI(container: HTMLElement, element: HTMLElement, scro
|
|||||||
manager.setToolbar(getMainEditorFullToolbar());
|
manager.setToolbar(getMainEditorFullToolbar());
|
||||||
|
|
||||||
// Register modals
|
// Register modals
|
||||||
manager.registerModal('link', {
|
for (const key of Object.keys(modals)) {
|
||||||
title: 'Insert/Edit link',
|
manager.registerModal(key, modals[key]);
|
||||||
form: linkFormDefinition,
|
}
|
||||||
});
|
|
||||||
manager.registerModal('image', {
|
|
||||||
title: 'Insert/Edit Image',
|
|
||||||
form: imageFormDefinition
|
|
||||||
});
|
|
||||||
manager.registerModal('media', {
|
|
||||||
title: 'Insert/Edit Media',
|
|
||||||
form: mediaFormDefinition,
|
|
||||||
});
|
|
||||||
manager.registerModal('source', {
|
|
||||||
title: 'Source code',
|
|
||||||
form: sourceFormDefinition,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register context toolbars
|
// Register context toolbars
|
||||||
manager.registerContextToolbar('image', {
|
manager.registerContextToolbar('image', {
|
||||||
|
@ -9,12 +9,13 @@ import {EditorTableCreator} from "./framework/blocks/table-creator";
|
|||||||
import {EditorColorButton} from "./framework/blocks/color-button";
|
import {EditorColorButton} from "./framework/blocks/color-button";
|
||||||
import {EditorOverflowContainer} from "./framework/blocks/overflow-container";
|
import {EditorOverflowContainer} from "./framework/blocks/overflow-container";
|
||||||
import {
|
import {
|
||||||
|
cellProperties,
|
||||||
deleteColumn,
|
deleteColumn,
|
||||||
deleteRow,
|
deleteRow,
|
||||||
deleteTable, deleteTableMenuAction, insertColumnAfter,
|
deleteTable, deleteTableMenuAction, insertColumnAfter,
|
||||||
insertColumnBefore,
|
insertColumnBefore,
|
||||||
insertRowAbove,
|
insertRowAbove,
|
||||||
insertRowBelow,
|
insertRowBelow, mergeCells, splitCell,
|
||||||
table
|
table
|
||||||
} from "./defaults/buttons/tables";
|
} from "./defaults/buttons/tables";
|
||||||
import {fullscreen, redo, source, undo} from "./defaults/buttons/controls";
|
import {fullscreen, redo, source, undo} from "./defaults/buttons/controls";
|
||||||
@ -118,6 +119,11 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
|||||||
new EditorDropdownButton({button: {...table, format: 'long'}, showOnHover: true}, [
|
new EditorDropdownButton({button: {...table, format: 'long'}, showOnHover: true}, [
|
||||||
new EditorTableCreator(),
|
new EditorTableCreator(),
|
||||||
]),
|
]),
|
||||||
|
new EditorDropdownButton({button: {label: 'Cell'}}, [
|
||||||
|
new EditorButton(cellProperties),
|
||||||
|
new EditorButton(mergeCells),
|
||||||
|
new EditorButton(splitCell),
|
||||||
|
]),
|
||||||
new EditorButton(deleteTableMenuAction),
|
new EditorButton(deleteTableMenuAction),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user