Lexical: Added button icon system
With a bunch of default icons
|
@ -32,6 +32,13 @@ esbuild.build({
|
||||||
format: 'esm',
|
format: 'esm',
|
||||||
minify: isProd,
|
minify: isProd,
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
|
loader: {
|
||||||
|
'.svg': 'text',
|
||||||
|
},
|
||||||
|
absWorkingDir: path.join(__dirname, '../..'),
|
||||||
|
alias: {
|
||||||
|
'@icons': './resources/icons',
|
||||||
|
},
|
||||||
banner: {
|
banner: {
|
||||||
js: '// See the "/licenses" URI for full package license details',
|
js: '// See the "/licenses" URI for full package license details',
|
||||||
css: '/* See the "/licenses" URI for full package license details */',
|
css: '/* See the "/licenses" URI for full package license details */',
|
||||||
|
|
1
resources/icons/editor/align-center.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm160-160v-80h400v80H280ZM120-440v-80h720v80H120Zm160-160v-80h400v80H280ZM120-760v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 203 B |
1
resources/icons/editor/align-justify.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 195 B |
1
resources/icons/editor/align-left.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 195 B |
1
resources/icons/editor/align-right.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-760v-80h720v80H120Zm240 160v-80h480v80H360ZM120-440v-80h720v80H120Zm240 160v-80h480v80H360ZM120-120v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 203 B |
1
resources/icons/editor/bold.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M272-200v-560h221q65 0 120 40t55 111q0 51-23 78.5T602-491q25 11 55.5 41t30.5 90q0 89-65 124.5T501-200H272Zm121-112h104q48 0 58.5-24.5T566-372q0-11-10.5-35.5T494-432H393v120Zm0-228h93q33 0 48-17t15-38q0-24-17-39t-44-15h-95v109Z"/></svg>
|
After Width: | Height: | Size: 309 B |
1
resources/icons/editor/code-block.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>
|
After Width: | Height: | Size: 336 B |
1
resources/icons/editor/code.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>
|
After Width: | Height: | Size: 186 B |
1
resources/icons/editor/details.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-480H200v480Zm80-280v-80h400v80H280Zm0 160v-80h240v80H280Z"/></svg>
|
After Width: | Height: | Size: 270 B |
1
resources/icons/editor/format-clear.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m528-546-93-93-121-121h486v120H568l-40 94ZM792-56 460-388l-80 188H249l119-280L56-792l56-56 736 736-56 56Z"/></svg>
|
After Width: | Height: | Size: 188 B |
1
resources/icons/editor/help.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
After Width: | Height: | Size: 653 B |
1
resources/icons/editor/horizontal-rule.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M160-440v-80h640v80H160Z"/></svg>
|
After Width: | Height: | Size: 107 B |
1
resources/icons/editor/image.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h360v80H200v560h560v-360h80v360q0 33-23.5 56.5T760-120H200Zm480-480v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM240-280h480L570-480 450-320l-90-120-120 160Zm-40-480v560-560Z"/></svg>
|
After Width: | Height: | Size: 315 B |
1
resources/icons/editor/indent-decrease.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm160 440L120-480l160-160v320Z"/></svg>
|
After Width: | Height: | Size: 228 B |
1
resources/icons/editor/indent-increase.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm0 440v-320l160 160-160 160Z"/></svg>
|
After Width: | Height: | Size: 227 B |
1
resources/icons/editor/italic.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-200v-100h160l120-360H320v-100h400v100H580L460-300h140v100H200Z"/></svg>
|
After Width: | Height: | Size: 150 B |
1
resources/icons/editor/link.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M680-160v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm560-40h-80q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480Z"/></svg>
|
After Width: | Height: | Size: 345 B |
1
resources/icons/editor/list-bullet.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm0-240q-33 0-56.5-23.5T120-720q0-33 23.5-56.5T200-800q33 0 56.5 23.5T280-720q0 33-23.5 56.5T200-640Z"/></svg>
|
After Width: | Height: | Size: 453 B |
1
resources/icons/editor/list-check.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="M222-200 80-342l56-56 85 85 170-170 56 57-225 226Zm0-320L80-662l56-56 85 85 170-170 56 57-225 226Zm298 240v-80h360v80H520Zm0-320v-80h360v80H520Z"/></svg>
|
After Width: | Height: | Size: 242 B |
1
resources/icons/editor/list-numbered.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="M120-80v-60h100v-30h-60v-60h60v-30H120v-60h120q17 0 28.5 11.5T280-280v40q0 17-11.5 28.5T240-200q17 0 28.5 11.5T280-160v40q0 17-11.5 28.5T240-80H120Zm0-280v-110q0-17 11.5-28.5T160-510h60v-30H120v-60h120q17 0 28.5 11.5T280-560v70q0 17-11.5 28.5T240-450h-60v30h100v60H120Zm60-280v-180h-60v-60h120v240h-60Zm180 440v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360Z"/></svg>
|
After Width: | Height: | Size: 468 B |
1
resources/icons/editor/redo.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" ><path d="M396-200q-97 0-166.5-63T160-420q0-94 69.5-157T396-640h252L544-744l56-56 200 200-200 200-56-56 104-104H396q-63 0-109.5 40T240-420q0 60 46.5 100T396-280h284v80H396Z"/></svg>
|
After Width: | Height: | Size: 246 B |
1
resources/icons/editor/source-view.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m384-336 56-58-86-86 86-86-56-58-144 144 144 144Zm192 0 144-144-144-144-56 58 86 86-86 86 56 58ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h168q13-36 43.5-58t68.5-22q38 0 68.5 22t43.5 58h168q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm280-590q13 0 21.5-8.5T510-820q0-13-8.5-21.5T480-850q-13 0-21.5 8.5T450-820q0 13 8.5 21.5T480-790ZM200-200v-560 560Z"/></svg>
|
After Width: | Height: | Size: 484 B |
1
resources/icons/editor/strikethrough.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M80-400v-80h800v80H80Zm340-160v-120H200v-120h560v120H540v120H420Zm0 400v-160h120v160H420Z"/></svg>
|
After Width: | Height: | Size: 172 B |
1
resources/icons/editor/subscript.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M760-160v-80q0-17 11.5-28.5T800-280h80v-40H760v-40h120q17 0 28.5 11.5T920-320v40q0 17-11.5 28.5T880-240h-80v40h120v40H760Zm-525-80 185-291-172-269h106l124 200h4l123-200h107L539-531l186 291H618L482-457h-4L342-240H235Z"/></svg>
|
After Width: | Height: | Size: 299 B |
1
resources/icons/editor/superscript.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M760-600v-80q0-17 11.5-28.5T800-720h80v-40H760v-40h120q17 0 28.5 11.5T920-760v40q0 17-11.5 28.5T880-680h-80v40h120v40H760ZM235-160l185-291-172-269h106l124 200h4l123-200h107L539-451l186 291H618L482-377h-4L342-160H235Z"/></svg>
|
After Width: | Height: | Size: 299 B |
1
resources/icons/editor/underlined.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120v-80h560v80H200Zm280-160q-101 0-157-63t-56-167v-330h103v336q0 56 28 91t82 35q54 0 82-35t28-91v-336h103v330q0 104-56 167t-157 63Z"/></svg>
|
After Width: | Height: | Size: 219 B |
1
resources/icons/editor/undo.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"/></svg>
|
After Width: | Height: | Size: 244 B |
4
resources/js/global.d.ts
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
declare module '*.svg' {
|
||||||
|
const content: string;
|
||||||
|
export default content;
|
||||||
|
}
|
|
@ -9,11 +9,13 @@ import {LexicalElementNodeCreator, LexicalNodeMatcher} from "./nodes";
|
||||||
import {$getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
|
import {$getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
|
||||||
import {$setBlocksType} from "@lexical/selection";
|
import {$setBlocksType} from "@lexical/selection";
|
||||||
|
|
||||||
export function el(tag: string, attrs: Record<string, string> = {}, children: (string|HTMLElement)[] = []): HTMLElement {
|
export function el(tag: string, attrs: Record<string, string|null> = {}, children: (string|HTMLElement)[] = []): HTMLElement {
|
||||||
const el = document.createElement(tag);
|
const el = document.createElement(tag);
|
||||||
const attrKeys = Object.keys(attrs);
|
const attrKeys = Object.keys(attrs);
|
||||||
for (const attr of attrKeys) {
|
for (const attr of attrKeys) {
|
||||||
el.setAttribute(attr, attrs[attr]);
|
if (attrs[attr] !== null) {
|
||||||
|
el.setAttribute(attr, attrs[attr] as string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
|
|
|
@ -29,9 +29,27 @@ import {$isImageNode, ImageNode} from "../../nodes/image";
|
||||||
import {$createDetailsNode, $isDetailsNode} from "../../nodes/details";
|
import {$createDetailsNode, $isDetailsNode} from "../../nodes/details";
|
||||||
import {getEditorContentAsHtml} from "../../actions";
|
import {getEditorContentAsHtml} from "../../actions";
|
||||||
import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/list";
|
import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/list";
|
||||||
|
import undoIcon from "@icons/editor/undo.svg"
|
||||||
|
import redoIcon from "@icons/editor/redo.svg"
|
||||||
|
import boldIcon from "@icons/editor/bold.svg"
|
||||||
|
import italicIcon from "@icons/editor/italic.svg"
|
||||||
|
import underlinedIcon from "@icons/editor/underlined.svg"
|
||||||
|
import strikethroughIcon from "@icons/editor/strikethrough.svg"
|
||||||
|
import superscriptIcon from "@icons/editor/superscript.svg"
|
||||||
|
import subscriptIcon from "@icons/editor/subscript.svg"
|
||||||
|
import codeIcon from "@icons/editor/code.svg"
|
||||||
|
import formatClearIcon from "@icons/editor/format-clear.svg"
|
||||||
|
import listBulletIcon from "@icons/editor/list-bullet.svg"
|
||||||
|
import listNumberedIcon from "@icons/editor/list-numbered.svg"
|
||||||
|
import listCheckIcon from "@icons/editor/list-check.svg"
|
||||||
|
import linkIcon from "@icons/editor/link.svg"
|
||||||
|
import imageIcon from "@icons/editor/image.svg"
|
||||||
|
import detailsIcon from "@icons/editor/details.svg"
|
||||||
|
import sourceIcon from "@icons/editor/source-view.svg"
|
||||||
|
|
||||||
export const undo: EditorButtonDefinition = {
|
export const undo: EditorButtonDefinition = {
|
||||||
label: 'Undo',
|
label: 'Undo',
|
||||||
|
icon: undoIcon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.dispatchCommand(UNDO_COMMAND, undefined);
|
context.editor.dispatchCommand(UNDO_COMMAND, undefined);
|
||||||
},
|
},
|
||||||
|
@ -42,6 +60,7 @@ export const undo: EditorButtonDefinition = {
|
||||||
|
|
||||||
export const redo: EditorButtonDefinition = {
|
export const redo: EditorButtonDefinition = {
|
||||||
label: 'Redo',
|
label: 'Redo',
|
||||||
|
icon: redoIcon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.dispatchCommand(REDO_COMMAND, undefined);
|
context.editor.dispatchCommand(REDO_COMMAND, undefined);
|
||||||
},
|
},
|
||||||
|
@ -116,9 +135,10 @@ export const paragraph: EditorButtonDefinition = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildFormatButton(label: string, format: TextFormatType): EditorButtonDefinition {
|
function buildFormatButton(label: string, format: TextFormatType, icon: string): EditorButtonDefinition {
|
||||||
return {
|
return {
|
||||||
label: label,
|
label: label,
|
||||||
|
icon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
context.editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
||||||
},
|
},
|
||||||
|
@ -128,18 +148,19 @@ function buildFormatButton(label: string, format: TextFormatType): EditorButtonD
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const bold: EditorButtonDefinition = buildFormatButton('Bold', 'bold');
|
export const bold: EditorButtonDefinition = buildFormatButton('Bold', 'bold', boldIcon);
|
||||||
export const italic: EditorButtonDefinition = buildFormatButton('Italic', 'italic');
|
export const italic: EditorButtonDefinition = buildFormatButton('Italic', 'italic', italicIcon);
|
||||||
export const underline: EditorButtonDefinition = buildFormatButton('Underline', 'underline');
|
export const underline: EditorButtonDefinition = buildFormatButton('Underline', 'underline', underlinedIcon);
|
||||||
export const textColor: EditorBasicButtonDefinition = {label: 'Text color'};
|
export const textColor: EditorBasicButtonDefinition = {label: 'Text color'};
|
||||||
export const highlightColor: EditorBasicButtonDefinition = {label: 'Highlight color'};
|
export const highlightColor: EditorBasicButtonDefinition = {label: 'Highlight color'};
|
||||||
|
|
||||||
export const strikethrough: EditorButtonDefinition = buildFormatButton('Strikethrough', 'strikethrough');
|
export const strikethrough: EditorButtonDefinition = buildFormatButton('Strikethrough', 'strikethrough', strikethroughIcon);
|
||||||
export const superscript: EditorButtonDefinition = buildFormatButton('Superscript', 'superscript');
|
export const superscript: EditorButtonDefinition = buildFormatButton('Superscript', 'superscript', superscriptIcon);
|
||||||
export const subscript: EditorButtonDefinition = buildFormatButton('Subscript', 'subscript');
|
export const subscript: EditorButtonDefinition = buildFormatButton('Subscript', 'subscript', subscriptIcon);
|
||||||
export const code: EditorButtonDefinition = buildFormatButton('Inline Code', 'code');
|
export const code: EditorButtonDefinition = buildFormatButton('Inline Code', 'code', codeIcon);
|
||||||
export const clearFormating: EditorButtonDefinition = {
|
export const clearFormating: EditorButtonDefinition = {
|
||||||
label: 'Clear formatting',
|
label: 'Clear formatting',
|
||||||
|
icon: formatClearIcon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.update(() => {
|
context.editor.update(() => {
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
|
@ -155,9 +176,10 @@ export const clearFormating: EditorButtonDefinition = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function buildListButton(label: string, type: ListType): EditorButtonDefinition {
|
function buildListButton(label: string, type: ListType, icon: string): EditorButtonDefinition {
|
||||||
return {
|
return {
|
||||||
label,
|
label,
|
||||||
|
icon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.getEditorState().read(() => {
|
context.editor.getEditorState().read(() => {
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
|
@ -176,13 +198,14 @@ function buildListButton(label: string, type: ListType): EditorButtonDefinition
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const bulletList: EditorButtonDefinition = buildListButton('Bullet list', 'bullet');
|
export const bulletList: EditorButtonDefinition = buildListButton('Bullet list', 'bullet', listBulletIcon);
|
||||||
export const numberList: EditorButtonDefinition = buildListButton('Numbered list', 'number');
|
export const numberList: EditorButtonDefinition = buildListButton('Numbered list', 'number', listNumberedIcon);
|
||||||
export const taskList: EditorButtonDefinition = buildListButton('Task list', 'check');
|
export const taskList: EditorButtonDefinition = buildListButton('Task list', 'check', listCheckIcon);
|
||||||
|
|
||||||
|
|
||||||
export const link: EditorButtonDefinition = {
|
export const link: EditorButtonDefinition = {
|
||||||
label: 'Insert/edit link',
|
label: 'Insert/edit link',
|
||||||
|
icon: linkIcon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
const linkModal = context.manager.createModal('link');
|
const linkModal = context.manager.createModal('link');
|
||||||
context.editor.getEditorState().read(() => {
|
context.editor.getEditorState().read(() => {
|
||||||
|
@ -215,6 +238,7 @@ export const link: EditorButtonDefinition = {
|
||||||
|
|
||||||
export const image: EditorButtonDefinition = {
|
export const image: EditorButtonDefinition = {
|
||||||
label: 'Insert/Edit Image',
|
label: 'Insert/Edit Image',
|
||||||
|
icon: imageIcon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
const imageModal = context.manager.createModal('image');
|
const imageModal = context.manager.createModal('image');
|
||||||
const selection = context.lastSelection;
|
const selection = context.lastSelection;
|
||||||
|
@ -247,6 +271,7 @@ export const image: EditorButtonDefinition = {
|
||||||
|
|
||||||
export const details: EditorButtonDefinition = {
|
export const details: EditorButtonDefinition = {
|
||||||
label: 'Insert collapsible block',
|
label: 'Insert collapsible block',
|
||||||
|
icon: detailsIcon,
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.update(() => {
|
context.editor.update(() => {
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
|
@ -274,6 +299,7 @@ export const details: EditorButtonDefinition = {
|
||||||
|
|
||||||
export const source: EditorButtonDefinition = {
|
export const source: EditorButtonDefinition = {
|
||||||
label: 'Source code',
|
label: 'Source code',
|
||||||
|
icon: sourceIcon,
|
||||||
async action(context: EditorUiContext) {
|
async action(context: EditorUiContext) {
|
||||||
const modal = context.manager.createModal('source');
|
const modal = context.manager.createModal('source');
|
||||||
const source = await getEditorContentAsHtml(context.editor);
|
const source = await getEditorContentAsHtml(context.editor);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {el} from "../../helpers";
|
||||||
|
|
||||||
export interface EditorBasicButtonDefinition {
|
export interface EditorBasicButtonDefinition {
|
||||||
label: string;
|
label: string;
|
||||||
|
icon?: string|undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditorButtonDefinition extends EditorBasicButtonDefinition {
|
export interface EditorButtonDefinition extends EditorBasicButtonDefinition {
|
||||||
|
@ -21,10 +22,19 @@ export class EditorButton extends EditorUiElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected buildDOM(): HTMLButtonElement {
|
protected buildDOM(): HTMLButtonElement {
|
||||||
|
|
||||||
|
const label = this.getLabel();
|
||||||
|
let child: string|HTMLElement = label;
|
||||||
|
if (this.definition.icon) {
|
||||||
|
child = el('span', {class: 'editor-button-icon'});
|
||||||
|
child.innerHTML = this.definition.icon;
|
||||||
|
}
|
||||||
|
|
||||||
const button = el('button', {
|
const button = el('button', {
|
||||||
type: 'button',
|
type: 'button',
|
||||||
class: 'editor-button',
|
class: 'editor-button',
|
||||||
}, [this.getLabel()]) as HTMLButtonElement;
|
title: this.definition.icon ? label : null,
|
||||||
|
}, [child]) as HTMLButtonElement;
|
||||||
|
|
||||||
button.addEventListener('click', this.onClick.bind(this));
|
button.addEventListener('click', this.onClick.bind(this));
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {FormatPreviewButton} from "./framework/blocks/format-preview-button";
|
||||||
import {EditorDropdownButton} from "./framework/blocks/dropdown-button";
|
import {EditorDropdownButton} from "./framework/blocks/dropdown-button";
|
||||||
import {EditorColorPicker} from "./framework/blocks/color-picker";
|
import {EditorColorPicker} from "./framework/blocks/color-picker";
|
||||||
|
|
||||||
|
console.log(undo);
|
||||||
|
|
||||||
export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
||||||
return new EditorSimpleClassContainer('editor-toolbar-main', [
|
return new EditorSimpleClassContainer('editor-toolbar-main', [
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.editor-button-icon svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
fill: #000;
|
||||||
|
}
|
||||||
|
|
||||||
// Containers
|
// Containers
|
||||||
.editor-dropdown-menu-container {
|
.editor-dropdown-menu-container {
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
"paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
|
"@icons/*": ["./resources/icons/*"]
|
||||||
|
},
|
||||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||||
|
|