--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m770-302-60-62q40-11 65-42.5t25-73.5q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 57-29.5 105T770-302ZM634-440l-80-80h86v80h-6ZM792-56 56-792l56-56 736 736-56 56ZM440-280H280q-83 0-141.5-58.5T80-480q0-69 42-123t108-71l74 74h-24q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h65l79 80H320Z"/></svg>
\ No newline at end of file
import {EditorBasicButtonDefinition, EditorButton, EditorButtonDefinition} from "../framework/buttons";
import {
$createNodeSelection,
- $createParagraphNode, $getRoot, $getSelection,
+ $createParagraphNode, $createTextNode, $getRoot, $getSelection,
$isParagraphNode, $isTextNode, $setSelection,
BaseSelection, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, ElementNode, FORMAT_TEXT_COMMAND,
LexicalNode,
import listNumberedIcon from "@icons/editor/list-numbered.svg"
import listCheckIcon from "@icons/editor/list-check.svg"
import linkIcon from "@icons/editor/link.svg"
+import unlinkIcon from "@icons/editor/unlink.svg"
import tableIcon from "@icons/editor/table.svg"
import imageIcon from "@icons/editor/image.svg"
import horizontalRuleIcon from "@icons/editor/horizontal-rule.svg"
import detailsIcon from "@icons/editor/details.svg"
import sourceIcon from "@icons/editor/source-view.svg"
-import {$createHorizontalRuleNode, $isHorizontalRuleNode, HorizontalRuleNode} from "../../nodes/horizontal-rule";
+import {$createHorizontalRuleNode, $isHorizontalRuleNode} from "../../nodes/horizontal-rule";
export const undo: EditorButtonDefinition = {
label: 'Undo',
}
};
+export const unlink: EditorButtonDefinition = {
+ label: 'Remove link',
+ icon: unlinkIcon,
+ action(context: EditorUiContext) {
+ context.editor.update(() => {
+ const selection = context.lastSelection;
+ const selectedLink = getNodeFromSelection(selection, $isLinkNode) as LinkNode|null;
+ const selectionPoints = selection?.getStartEndPoints();
+
+ if (selectedLink) {
+ const newNode = $createTextNode(selectedLink.getTextContent());
+ selectedLink.replace(newNode);
+ if (selectionPoints?.length === 2) {
+ newNode.select(selectionPoints[0].offset, selectionPoints[1].offset);
+ } else {
+ newNode.select();
+ }
+ }
+ });
+ },
+ isActive(selection: BaseSelection|null): boolean {
+ return false;
+ }
+};
+
export const table: EditorBasicButtonDefinition = {
label: 'Table',
icon: tableIcon,
for (const toolbar of this.activeContextToolbars) {
toolbar.updateState(update);
}
+ // console.log('selection update', update.selection);
}
protected updateContextToolbars(update: EditorUiStateUpdate): void {
}
attachTo(target: HTMLElement) {
- // Todo - attach to target position
- console.log('attaching context toolbar to', target);
+ const targetBounds = target.getBoundingClientRect();
+ const dom = this.getDOMElement();
+ const domBounds = dom.getBoundingClientRect();
+
+ const targetMid = targetBounds.left + (targetBounds.width / 2);
+ const targetLeft = targetMid - (domBounds.width / 2);
+ dom.style.top = (targetBounds.bottom + 6) + 'px';
+ dom.style.left = targetLeft + 'px';
}
insert(children: EditorUiElement[]) {
import {LexicalEditor} from "lexical";
-import {getImageToolbarContent, getMainEditorFullToolbar} from "./toolbars";
+import {getImageToolbarContent, getLinkToolbarContent, getMainEditorFullToolbar} from "./toolbars";
import {EditorUIManager} from "./framework/manager";
import {image as imageFormDefinition, link as linkFormDefinition, source as sourceFormDefinition} from "./defaults/form-definitions";
import {ImageDecorator} from "./decorators/image";
return originalTarget.closest('a') || originalTarget;
}
});
+ manager.registerContextToolbar('link', {
+ selector: 'a',
+ content: getLinkToolbarContent(),
+ });
// Register image decorator listener
manager.registerDecoratorType('image', ImageDecorator);
infoCallout, italic, link, numberList, paragraph,
redo, source, strikethrough, subscript,
successCallout, superscript, table, taskList, textColor, underline,
- undo,
+ undo, unlink,
warningCallout
} from "./defaults/button-definitions";
import {EditorContainerUiElement, EditorSimpleClassContainer, EditorUiContext, EditorUiElement} from "./framework/core";
export function getImageToolbarContent(): EditorUiElement[] {
return [new EditorButton(image)];
+}
+
+export function getLinkToolbarContent(): EditorUiElement[] {
+ return [
+ new EditorButton(link),
+ new EditorButton(unlink),
+ ];
}
\ No newline at end of file
display: flex;
}
+.editor-context-toolbar {
+ position: fixed;
+ background-color: #FFF;
+ border: 1px solid #DDD;
+ padding: .2rem;
+ border-radius: 4px;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12);
+ &:before {
+ content: '';
+ z-index: -1;
+ display: block;
+ width: 8px;
+ height: 8px;
+ position: absolute;
+ background-color: #FFF;
+ border-top: 1px solid #DDD;
+ border-left: 1px solid #DDD;
+ transform: rotate(45deg);
+ left: 50%;
+ margin-left: -4px;
+ top: -5px;
+ }
+}
+
// Modals
.editor-modal-wrapper {
position: fixed;