@exmg/exm-markdown-editor 1.1.36 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/actions.d.ts +6 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/actions.js +227 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-base.d.ts +89 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-base.js +334 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar-base.d.ts +12 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar-base.js +52 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar.d.ts +9 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar.js +12 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor.d.ts +76 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor.js +83 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/icons.d.ts +3 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/icons.js +5 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/index.d.ts +6 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/index.js +6 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-codemirror-css.d.ts +1 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-codemirror-css.js +491 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-css.d.ts +1 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-css.js +210 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-toolbar-css.d.ts +1 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-toolbar-css.js +22 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/types.d.ts +13 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/utils/configurations.d.ts +4 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/utils/configurations.js +14 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/validator/exm-markdown-editor-validator.d.ts +23 -0
- package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/validator/exm-markdown-editor-validator.js +35 -0
- package/dist/actions.js +5 -3
- package/dist/exm-markdown-editor-base.js +11 -8
- package/dist/exm-markdown-editor-toolbar-base.js +6 -3
- package/dist/exm-markdown-editor-toolbar.js +6 -4
- package/dist/exm-markdown-editor.js +7 -5
- package/dist/icons.js +5 -2
- package/dist/index.js +3 -4
- package/dist/styles/exm-markdown-codemirror-css.js +5 -2
- package/dist/styles/exm-markdown-editor-css.js +5 -2
- package/dist/styles/exm-markdown-editor-toolbar-css.js +5 -2
- package/dist/utils/configurations.js +5 -3
- package/dist/validator/exm-markdown-editor-validator.js +6 -3
- package/package.json +2 -2
- /package/{dist → .rollup.cache/root/repo/packages/exm-markdown-editor/dist}/types.js +0 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
export const toolbarActions = [
|
|
2
|
+
{
|
|
3
|
+
name: 'undo',
|
|
4
|
+
icon: 'undo',
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
name: 'redo',
|
|
8
|
+
icon: 'redo',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'header_one',
|
|
12
|
+
icon: 'format_h1',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'header_two',
|
|
16
|
+
icon: 'format_h2',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'header_three',
|
|
20
|
+
icon: 'format_h3',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'unordered_list',
|
|
24
|
+
icon: 'format_list_bulleted',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'ordered_list',
|
|
28
|
+
icon: 'format_list_numbered',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'bold',
|
|
32
|
+
icon: 'format_bold',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'italic',
|
|
36
|
+
icon: 'format_italic',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'strikethrough',
|
|
40
|
+
icon: 'format_strikethrough',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'quote',
|
|
44
|
+
icon: 'format_quote',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'code',
|
|
48
|
+
icon: 'data_object',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'link',
|
|
52
|
+
icon: 'insert_link',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'image',
|
|
56
|
+
icon: 'insert_photo',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'hr',
|
|
60
|
+
icon: 'horizontal_rule',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'table',
|
|
64
|
+
icon: 'table_chart',
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
export const markdownActions = {
|
|
68
|
+
undo: (editor) => {
|
|
69
|
+
editor.getDoc().undo();
|
|
70
|
+
editor.focus();
|
|
71
|
+
},
|
|
72
|
+
redo: (editor) => {
|
|
73
|
+
editor.getDoc().redo();
|
|
74
|
+
editor.focus();
|
|
75
|
+
},
|
|
76
|
+
header_one: (editor) => header(editor, '#'),
|
|
77
|
+
header_two: (editor) => header(editor, '##'),
|
|
78
|
+
header_three: (editor) => header(editor, '###'),
|
|
79
|
+
bold: (editor) => emphasis(editor, ['**', '__']),
|
|
80
|
+
italic: (editor) => emphasis(editor, ['*', '_']),
|
|
81
|
+
strikethrough: (editor) => emphasis(editor, ['~~']),
|
|
82
|
+
quote: (editor) => emphasis(editor, ['`']),
|
|
83
|
+
link: (editor) => insertLink(editor),
|
|
84
|
+
image: (editor, url) => insertImage(editor, url),
|
|
85
|
+
code: (editor) => insertCode(editor),
|
|
86
|
+
hr: (editor) => insertHr(editor),
|
|
87
|
+
table: (editor) => insertTable(editor),
|
|
88
|
+
ordered_list: (editor) => insertList(editor, '#'),
|
|
89
|
+
unordered_list: (editor) => insertList(editor, '*'),
|
|
90
|
+
};
|
|
91
|
+
const header = (editor, symbol) => {
|
|
92
|
+
const selection = editor.getDoc().getSelection().trim();
|
|
93
|
+
let text = selection;
|
|
94
|
+
const regex = new RegExp(`(?<sa>[#]{1,3})(?<text>.*)`, 'g');
|
|
95
|
+
text = processText(text, regex, symbol);
|
|
96
|
+
if (text === selection) {
|
|
97
|
+
text = `${symbol} ${text.length > 0 ? text : 'header'}`;
|
|
98
|
+
editor.getDoc().replaceSelection(text);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
editor.getDoc().replaceSelection(text);
|
|
102
|
+
text.startsWith(symbol) &&
|
|
103
|
+
editor.getDoc().setCursor({
|
|
104
|
+
line: editor.getDoc().getCursor().line + 1,
|
|
105
|
+
ch: editor.getDoc().getCursor().ch,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const emphasis = (editor, symbols) => {
|
|
110
|
+
const selection = editor.getDoc().getSelection();
|
|
111
|
+
let text = selection;
|
|
112
|
+
symbols.forEach((symbol) => {
|
|
113
|
+
const regex = new RegExp(`(?<sa>[\\${symbol.slice(0, 1)}]{${symbol.length}})(?<text>.*?)(?<sb>[\\${symbol.slice(0, 1)}]{1,${symbol.length}})`, 'g');
|
|
114
|
+
text = processText(text, regex, symbol);
|
|
115
|
+
});
|
|
116
|
+
if (text === selection) {
|
|
117
|
+
text = `${symbols[0]}${text.length > 0 ? text : symbols[0] === '`' ? 'quote' : 'emphasis'}${symbols[0]}`;
|
|
118
|
+
}
|
|
119
|
+
editor.getDoc().replaceSelection(text);
|
|
120
|
+
};
|
|
121
|
+
const insertLink = (editor) => {
|
|
122
|
+
const selection = editor.getSelection();
|
|
123
|
+
let text = selection;
|
|
124
|
+
if (text) {
|
|
125
|
+
text = `[${text}]()`;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
text = `[Markdown Live Preview](Your link here)`;
|
|
129
|
+
}
|
|
130
|
+
editor.getDoc().replaceSelection(text);
|
|
131
|
+
const cursor = editor.getDoc().getCursor();
|
|
132
|
+
if (text.split('')[text.length - 2] === 'e') {
|
|
133
|
+
editor.setSelection({
|
|
134
|
+
line: cursor.line,
|
|
135
|
+
ch: cursor.ch - 15,
|
|
136
|
+
}, { ...cursor, ch: cursor.ch - 1 });
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
editor.setCursor({ ...cursor, ch: cursor.ch - 1 });
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const insertImage = (editor, url) => {
|
|
143
|
+
const selection = editor.getSelection();
|
|
144
|
+
let text = selection;
|
|
145
|
+
if (text) {
|
|
146
|
+
text = ``;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
text = ``;
|
|
150
|
+
}
|
|
151
|
+
editor.getDoc().replaceSelection(text);
|
|
152
|
+
const cursor = editor.getDoc().getCursor();
|
|
153
|
+
if (text.startsWith('![A')) {
|
|
154
|
+
editor.setSelection({
|
|
155
|
+
line: cursor.line,
|
|
156
|
+
ch: cursor.ch - 4 - text.length,
|
|
157
|
+
}, {
|
|
158
|
+
line: cursor.line,
|
|
159
|
+
ch: cursor.ch - 18 - text.length,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
editor.setSelection({
|
|
164
|
+
line: cursor.line,
|
|
165
|
+
ch: cursor.ch - 25,
|
|
166
|
+
}, {
|
|
167
|
+
line: cursor.line,
|
|
168
|
+
ch: cursor.ch - 2,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const insertCode = (editor) => {
|
|
173
|
+
const selection = editor.getSelection();
|
|
174
|
+
let text = selection;
|
|
175
|
+
if (text.trim().startsWith('```')) {
|
|
176
|
+
const textArray = text.split('```');
|
|
177
|
+
textArray.pop();
|
|
178
|
+
textArray.reverse().pop();
|
|
179
|
+
text = textArray.reverse().join('');
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
text = `\`\`\`${text}\n\`\`\``;
|
|
183
|
+
}
|
|
184
|
+
editor.replaceSelection(text);
|
|
185
|
+
};
|
|
186
|
+
const insertHr = (editor) => {
|
|
187
|
+
const selection = editor.getSelection();
|
|
188
|
+
editor.replaceSelection(`${selection}\n___\n`);
|
|
189
|
+
};
|
|
190
|
+
const insertTable = (editor) => {
|
|
191
|
+
const selection = editor.getSelection();
|
|
192
|
+
editor.replaceSelection(`${selection}
|
|
193
|
+
| Left columns | Center columns | Right columns |
|
|
194
|
+
| ------------- |:-------------: |--------------:|
|
|
195
|
+
| left foo | right foo | right foo |
|
|
196
|
+
| left bar | right bar | right foo |
|
|
197
|
+
| left baz | right baz | right foo |
|
|
198
|
+
\n`);
|
|
199
|
+
};
|
|
200
|
+
const insertList = (editor, symbol) => {
|
|
201
|
+
const selection = editor.getSelection();
|
|
202
|
+
let text = '';
|
|
203
|
+
for (let i = 0; i < 3; i++) {
|
|
204
|
+
const bullet = `${symbol === '*' ? symbol : `${i + 1}.`}`;
|
|
205
|
+
const item = i === 0 && selection.length > 0 ? selection : `Item ${i + 1}`;
|
|
206
|
+
text += `${bullet} ${item}\n`;
|
|
207
|
+
}
|
|
208
|
+
editor.replaceSelection(`${text}\n`);
|
|
209
|
+
editor.setSelection({
|
|
210
|
+
ch: symbol === '*' ? 2 : 3,
|
|
211
|
+
line: editor.getCursor().line - 4,
|
|
212
|
+
}, {
|
|
213
|
+
ch: selection.length > 0 ? (selection.length + symbol === '*' ? 2 : 3) : 8,
|
|
214
|
+
line: editor.getCursor().line - 4,
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
const processText = (text, regex, symbol) => {
|
|
218
|
+
const matchList = regex.exec(text);
|
|
219
|
+
if (matchList) {
|
|
220
|
+
text = text
|
|
221
|
+
.split(regex)
|
|
222
|
+
.filter((v) => v !== symbol)
|
|
223
|
+
.join('');
|
|
224
|
+
}
|
|
225
|
+
return text.trim();
|
|
226
|
+
};
|
|
227
|
+
//# sourceMappingURL=actions.js.map
|
package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-base.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { PropertyValueMap } from 'lit';
|
|
2
|
+
import { Editor, EditorConfiguration } from 'codemirror';
|
|
3
|
+
import { ExmgElement } from '@exmg/lit-base';
|
|
4
|
+
import { MarkdownActions, ToolbarIcons, ToolbarItem } from './types.js';
|
|
5
|
+
import { TokenizerAndRendererExtension } from 'marked';
|
|
6
|
+
import { getFormValue } from '@material/web/labs/behaviors/form-associated.js';
|
|
7
|
+
import { MardownEditorValidator } from './validator/exm-markdown-editor-validator.js';
|
|
8
|
+
import { createValidator, getValidityAnchor } from '@material/web/labs/behaviors/constraint-validation.js';
|
|
9
|
+
import './exm-markdown-editor-toolbar.js';
|
|
10
|
+
declare const MarkdownBaseClass: import("@material/web/labs/behaviors/mixin.js").MixinReturn<import("@material/web/labs/behaviors/mixin.js").MixinReturn<(abstract new (...args: any[]) => import("@material/web/labs/behaviors/element-internals.js").WithElementInternals) & typeof ExmgElement & import("@material/web/labs/behaviors/form-associated.js").FormAssociatedConstructor, import("@material/web/labs/behaviors/form-associated.js").FormAssociated>, import("@material/web/labs/behaviors/constraint-validation.js").ConstraintValidation>;
|
|
11
|
+
/**
|
|
12
|
+
* Markdown editor element.
|
|
13
|
+
* An out of the box customizable Markdown Editor for Exmachina
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* <exm-markdown-editor markdown="# Header 1"></exm-markdown-editor>
|
|
17
|
+
* ```
|
|
18
|
+
* ### Styling
|
|
19
|
+
*
|
|
20
|
+
* Custom property | Description | Default
|
|
21
|
+
* ----------------|-------------|----------
|
|
22
|
+
* `--exm-markdown-editor-code-color` | Editor's text color | --md-sys-color-on-surface
|
|
23
|
+
* `--exm-markdown-editor-code-cursor-color` | Editor's cursor color | --md-sys-color-on-surface
|
|
24
|
+
* `--exm-markdown-editor-code-header-color` | H1 color in editor | #4a8fc0;
|
|
25
|
+
* `--exm-markdown-editor-code-inline-code-color` | Inline code color | #ea881f
|
|
26
|
+
* `--exm-markdown-editor-code-list-color` | Lists color | rgb(25, 165, 28)
|
|
27
|
+
* `--exm-markdown-editor-selected-code-color` | Selected text color | rgb(140, 140, 140)
|
|
28
|
+
* `--exm-markdown-editor-border-color` | Editor's border color | --md-sys-color-primary
|
|
29
|
+
* `--exm-markdown-editor-background-color` | Toolbar and default preview background | --md-sys-color-surface-container-high
|
|
30
|
+
* `--exm-markdown-editor-code-background-color` | Editor's background color when focused | --md-sys-color-surface-container-high
|
|
31
|
+
*
|
|
32
|
+
* # Events:
|
|
33
|
+
* - change - where detail is current markdown value
|
|
34
|
+
* - insert-image - if the Editor is set to upload, it will trigger this event when the insert-image is clicked
|
|
35
|
+
*
|
|
36
|
+
* @customElement
|
|
37
|
+
* @element exm-markdown-editor
|
|
38
|
+
* @memberof Exmg
|
|
39
|
+
* @extends ExmgElement
|
|
40
|
+
* @summary Markdown editor element
|
|
41
|
+
*/
|
|
42
|
+
export declare class MarkdownEditorElementBase extends MarkdownBaseClass {
|
|
43
|
+
value: string;
|
|
44
|
+
html?: string;
|
|
45
|
+
label: string;
|
|
46
|
+
upload: boolean;
|
|
47
|
+
toolbarActions?: ToolbarItem[];
|
|
48
|
+
toolbarIcons?: ToolbarIcons;
|
|
49
|
+
markedExtension?: TokenizerAndRendererExtension[];
|
|
50
|
+
required: boolean;
|
|
51
|
+
disabled: boolean;
|
|
52
|
+
supportingText: string;
|
|
53
|
+
splitView: boolean;
|
|
54
|
+
fullScreen: boolean;
|
|
55
|
+
editorElement?: HTMLDivElement;
|
|
56
|
+
editorContainerElement?: HTMLDivElement;
|
|
57
|
+
previewElement?: Element | null;
|
|
58
|
+
isFullScreen?: boolean;
|
|
59
|
+
preview: boolean;
|
|
60
|
+
editorConfiguration: EditorConfiguration;
|
|
61
|
+
editorActions: MarkdownActions;
|
|
62
|
+
codeMirrorEditor?: Editor;
|
|
63
|
+
internalTextarea?: HTMLTextAreaElement;
|
|
64
|
+
blurHandlerBinding: any;
|
|
65
|
+
heightStyleMap?: any;
|
|
66
|
+
reset(): void;
|
|
67
|
+
protected updated(changedProps: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
|
|
68
|
+
[getFormValue](): string;
|
|
69
|
+
[createValidator](): MardownEditorValidator;
|
|
70
|
+
[getValidityAnchor](): HTMLTextAreaElement;
|
|
71
|
+
formResetCallback(): void;
|
|
72
|
+
formStateRestoreCallback(state: string): void;
|
|
73
|
+
focus(): void;
|
|
74
|
+
protected firstUpdated(): void;
|
|
75
|
+
protected disconectedCallback(): void;
|
|
76
|
+
protected getPreviewElement(): Element | null;
|
|
77
|
+
private handleEditorScroll;
|
|
78
|
+
private toggleFullscreen;
|
|
79
|
+
private handleExitFullScreen;
|
|
80
|
+
codeMirrorSetup(): void;
|
|
81
|
+
handleFocus(): void;
|
|
82
|
+
handleBlur(): void;
|
|
83
|
+
handleAction(e: CustomEvent): void;
|
|
84
|
+
handleInsertImage(url: string): void;
|
|
85
|
+
updateValue(newValue?: string): void;
|
|
86
|
+
private handleContainerClick;
|
|
87
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
88
|
+
}
|
|
89
|
+
export {};
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { html, nothing } from 'lit';
|
|
3
|
+
import { query, property, state } from 'lit/decorators.js';
|
|
4
|
+
import { defaultConfiguration } from './utils/configurations.js';
|
|
5
|
+
import { ExmgElement, observer } from '@exmg/lit-base';
|
|
6
|
+
import { markdownActions, toolbarActions } from './actions.js';
|
|
7
|
+
import { marked } from 'marked';
|
|
8
|
+
import { mixinElementInternals } from '@material/web/labs/behaviors/element-internals.js';
|
|
9
|
+
import { getFormValue, mixinFormAssociated } from '@material/web/labs/behaviors/form-associated.js';
|
|
10
|
+
import { toolbarIcons } from './icons.js';
|
|
11
|
+
import { MardownEditorValidator } from './validator/exm-markdown-editor-validator.js';
|
|
12
|
+
import { createValidator, getValidityAnchor, mixinConstraintValidation, } from '@material/web/labs/behaviors/constraint-validation.js';
|
|
13
|
+
import './exm-markdown-editor-toolbar.js';
|
|
14
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
15
|
+
const MarkdownBaseClass = mixinConstraintValidation(mixinFormAssociated(mixinElementInternals(ExmgElement)));
|
|
16
|
+
/**
|
|
17
|
+
* Markdown editor element.
|
|
18
|
+
* An out of the box customizable Markdown Editor for Exmachina
|
|
19
|
+
*
|
|
20
|
+
* ```
|
|
21
|
+
* <exm-markdown-editor markdown="# Header 1"></exm-markdown-editor>
|
|
22
|
+
* ```
|
|
23
|
+
* ### Styling
|
|
24
|
+
*
|
|
25
|
+
* Custom property | Description | Default
|
|
26
|
+
* ----------------|-------------|----------
|
|
27
|
+
* `--exm-markdown-editor-code-color` | Editor's text color | --md-sys-color-on-surface
|
|
28
|
+
* `--exm-markdown-editor-code-cursor-color` | Editor's cursor color | --md-sys-color-on-surface
|
|
29
|
+
* `--exm-markdown-editor-code-header-color` | H1 color in editor | #4a8fc0;
|
|
30
|
+
* `--exm-markdown-editor-code-inline-code-color` | Inline code color | #ea881f
|
|
31
|
+
* `--exm-markdown-editor-code-list-color` | Lists color | rgb(25, 165, 28)
|
|
32
|
+
* `--exm-markdown-editor-selected-code-color` | Selected text color | rgb(140, 140, 140)
|
|
33
|
+
* `--exm-markdown-editor-border-color` | Editor's border color | --md-sys-color-primary
|
|
34
|
+
* `--exm-markdown-editor-background-color` | Toolbar and default preview background | --md-sys-color-surface-container-high
|
|
35
|
+
* `--exm-markdown-editor-code-background-color` | Editor's background color when focused | --md-sys-color-surface-container-high
|
|
36
|
+
*
|
|
37
|
+
* # Events:
|
|
38
|
+
* - change - where detail is current markdown value
|
|
39
|
+
* - insert-image - if the Editor is set to upload, it will trigger this event when the insert-image is clicked
|
|
40
|
+
*
|
|
41
|
+
* @customElement
|
|
42
|
+
* @element exm-markdown-editor
|
|
43
|
+
* @memberof Exmg
|
|
44
|
+
* @extends ExmgElement
|
|
45
|
+
* @summary Markdown editor element
|
|
46
|
+
*/
|
|
47
|
+
export class MarkdownEditorElementBase extends MarkdownBaseClass {
|
|
48
|
+
constructor() {
|
|
49
|
+
super(...arguments);
|
|
50
|
+
this.value = '';
|
|
51
|
+
this.label = '';
|
|
52
|
+
this.upload = false;
|
|
53
|
+
this.toolbarActions = toolbarActions;
|
|
54
|
+
this.toolbarIcons = toolbarIcons;
|
|
55
|
+
this.required = false;
|
|
56
|
+
this.disabled = false;
|
|
57
|
+
this.supportingText = '';
|
|
58
|
+
this.splitView = false;
|
|
59
|
+
this.fullScreen = false;
|
|
60
|
+
this.isFullScreen = false;
|
|
61
|
+
this.preview = true;
|
|
62
|
+
this.editorConfiguration = defaultConfiguration;
|
|
63
|
+
this.editorActions = markdownActions;
|
|
64
|
+
}
|
|
65
|
+
reset() {
|
|
66
|
+
var _a;
|
|
67
|
+
this.value = (_a = this.getAttribute('value')) !== null && _a !== void 0 ? _a : '';
|
|
68
|
+
}
|
|
69
|
+
updated(changedProps) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
if (changedProps.has('value') && ((_a = this.codeMirrorEditor) === null || _a === void 0 ? void 0 : _a.getValue()) !== this.value) {
|
|
72
|
+
(_b = this.codeMirrorEditor) === null || _b === void 0 ? void 0 : _b.setValue(this.value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
[getFormValue]() {
|
|
76
|
+
return this.value;
|
|
77
|
+
}
|
|
78
|
+
[createValidator]() {
|
|
79
|
+
return new MardownEditorValidator(() => this);
|
|
80
|
+
}
|
|
81
|
+
[getValidityAnchor]() {
|
|
82
|
+
return this.internalTextarea;
|
|
83
|
+
}
|
|
84
|
+
formResetCallback() {
|
|
85
|
+
this.reset();
|
|
86
|
+
}
|
|
87
|
+
formStateRestoreCallback(state) {
|
|
88
|
+
this.value = state;
|
|
89
|
+
}
|
|
90
|
+
focus() {
|
|
91
|
+
var _a;
|
|
92
|
+
(_a = this.codeMirrorEditor) === null || _a === void 0 ? void 0 : _a.focus();
|
|
93
|
+
}
|
|
94
|
+
firstUpdated() {
|
|
95
|
+
var _a;
|
|
96
|
+
if (!this.disabled) {
|
|
97
|
+
this.codeMirrorSetup();
|
|
98
|
+
}
|
|
99
|
+
this.previewElement = this.getPreviewElement();
|
|
100
|
+
/* Height */
|
|
101
|
+
if (this.previewElement.hasAttribute('slot')) {
|
|
102
|
+
(_a = this.shadowRoot.querySelector('#preview')) === null || _a === void 0 ? void 0 : _a.remove();
|
|
103
|
+
}
|
|
104
|
+
/** Blur global handling */
|
|
105
|
+
this.blurHandlerBinding = this.handleBlur.bind(this);
|
|
106
|
+
this.addEventListener('blur', this.handleBlur);
|
|
107
|
+
if (this.value) {
|
|
108
|
+
this.updateValue(this.value);
|
|
109
|
+
this.codeMirrorEditor.refresh();
|
|
110
|
+
}
|
|
111
|
+
if (this.label && this.required) {
|
|
112
|
+
this.setAttribute('aria-required', 'true');
|
|
113
|
+
this.label += ' *';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
disconectedCallback() {
|
|
117
|
+
this.removeEventListener('blur', this.handleBlur);
|
|
118
|
+
}
|
|
119
|
+
getPreviewElement() {
|
|
120
|
+
return this.shadowRoot.querySelector('#preview');
|
|
121
|
+
}
|
|
122
|
+
// CodeMirror types is not handling the scroll event type correct
|
|
123
|
+
handleEditorScroll(event) {
|
|
124
|
+
const previewContainer = this.renderRoot.querySelector('.preview');
|
|
125
|
+
const previewArea = this.renderRoot.querySelector('.preview-content');
|
|
126
|
+
if (!previewArea || !previewContainer || (!this.splitView && !this.isFullScreen)) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// DOMRectList of CodeMirrors scroll area
|
|
130
|
+
const scroller = event.display.scroller.getClientRects()[0];
|
|
131
|
+
// DOMRectList of CodeMirrors editor/content area
|
|
132
|
+
const sizer = event.display.sizer.getClientRects()[0];
|
|
133
|
+
// DOMRectList of previewArea
|
|
134
|
+
const preview = previewArea.getClientRects()[0];
|
|
135
|
+
// Get the total distance scroller in the editor
|
|
136
|
+
const scrolledDistance = scroller.y - sizer.y;
|
|
137
|
+
// Get the maximal scroll distance for the editor
|
|
138
|
+
const maxEditorScrollDistance = sizer.height - scroller.height;
|
|
139
|
+
// Get the maximal scroll distance for the preview
|
|
140
|
+
const maxPreviewScrollDistance = preview.height - scroller.height;
|
|
141
|
+
// Calculate the scroll progress bases on the above values
|
|
142
|
+
const scrollProgress = Math.min(scrolledDistance / maxEditorScrollDistance, 1);
|
|
143
|
+
previewContainer.scrollTo({
|
|
144
|
+
top: maxPreviewScrollDistance * scrollProgress,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
toggleFullscreen() {
|
|
148
|
+
if (!this.editorContainerElement) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this.isFullScreen = !this.isFullScreen;
|
|
152
|
+
if (!document.fullscreenElement) {
|
|
153
|
+
this.editorContainerElement.requestFullscreen();
|
|
154
|
+
document.addEventListener('fullscreenchange', this.handleExitFullScreen.bind(this));
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
document.exitFullscreen();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
handleExitFullScreen() {
|
|
161
|
+
if (!document.fullscreenElement) {
|
|
162
|
+
this.isFullScreen = false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
codeMirrorSetup() {
|
|
166
|
+
if (!this.editorElement) {
|
|
167
|
+
console.log('Error');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (this.markedExtension) {
|
|
171
|
+
marked.use({ extensions: this.markedExtension });
|
|
172
|
+
}
|
|
173
|
+
// eslint-disable-next-line
|
|
174
|
+
this.codeMirrorEditor = window.CodeMirror(this.editorElement, {
|
|
175
|
+
...this.editorConfiguration,
|
|
176
|
+
value: this.value || '',
|
|
177
|
+
});
|
|
178
|
+
this.codeMirrorEditor.on('focus', (_) => {
|
|
179
|
+
this.handleFocus();
|
|
180
|
+
});
|
|
181
|
+
this.codeMirrorEditor.on('change', (editor) => {
|
|
182
|
+
this.updateValue(editor.getValue());
|
|
183
|
+
});
|
|
184
|
+
this.codeMirrorEditor.on('scroll', this.handleEditorScroll.bind(this));
|
|
185
|
+
this.internalTextarea = this.codeMirrorEditor.getInputField();
|
|
186
|
+
}
|
|
187
|
+
handleFocus() {
|
|
188
|
+
this.codeMirrorEditor.refresh();
|
|
189
|
+
}
|
|
190
|
+
handleBlur() {
|
|
191
|
+
this.previewElement.innerHTML = `
|
|
192
|
+
<main class="preview-content">
|
|
193
|
+
${this.html}
|
|
194
|
+
</main>
|
|
195
|
+
`;
|
|
196
|
+
this.preview = true;
|
|
197
|
+
}
|
|
198
|
+
handleAction(e) {
|
|
199
|
+
var _a;
|
|
200
|
+
const actionName = e.detail;
|
|
201
|
+
if (!this.editorActions[actionName]) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
this.editorActions[actionName](this.codeMirrorEditor);
|
|
205
|
+
this.preview = false;
|
|
206
|
+
(_a = this.codeMirrorEditor) === null || _a === void 0 ? void 0 : _a.focus();
|
|
207
|
+
}
|
|
208
|
+
handleInsertImage(url) {
|
|
209
|
+
this.editorActions['image'](this.codeMirrorEditor, url);
|
|
210
|
+
}
|
|
211
|
+
updateValue(newValue) {
|
|
212
|
+
this.html = marked.parse(newValue !== null && newValue !== void 0 ? newValue : '');
|
|
213
|
+
if (this.previewElement) {
|
|
214
|
+
this.previewElement.innerHTML = `
|
|
215
|
+
<main class="preview-content">
|
|
216
|
+
${this.html}
|
|
217
|
+
</main>
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
if (newValue === this.value) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
this.value = newValue || '';
|
|
224
|
+
this.fire('change', this.value);
|
|
225
|
+
}
|
|
226
|
+
handleContainerClick() {
|
|
227
|
+
if (!this.disabled) {
|
|
228
|
+
this.preview = false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
render() {
|
|
232
|
+
const containerClasses = {
|
|
233
|
+
'has-label': !!this.label,
|
|
234
|
+
'preview-mode': this.preview,
|
|
235
|
+
'split-view': (this.splitView || !!this.isFullScreen) && !this.disabled,
|
|
236
|
+
'full-screen': this.fullScreen,
|
|
237
|
+
};
|
|
238
|
+
const labelClasses = { 'not-empty': !!this.value, 'preview-mode': this.preview };
|
|
239
|
+
return html `
|
|
240
|
+
<div
|
|
241
|
+
id="markdownEditorContainer"
|
|
242
|
+
class="container ${classMap(containerClasses)}"
|
|
243
|
+
@click=${this.handleContainerClick}
|
|
244
|
+
>
|
|
245
|
+
<div class="background"></div>
|
|
246
|
+
<div class="state-layer"></div>
|
|
247
|
+
${this.label
|
|
248
|
+
? html `<label class="${classMap(labelClasses)}" for="markdownEditorContainer">${this.label}</label>`
|
|
249
|
+
: nothing}
|
|
250
|
+
<exm-markdown-editor-toolbar
|
|
251
|
+
?upload=${this.upload}
|
|
252
|
+
@action=${this.handleAction}
|
|
253
|
+
.actions=${this.toolbarActions || []}
|
|
254
|
+
.icons=${this.toolbarIcons || []}
|
|
255
|
+
></exm-markdown-editor-toolbar>
|
|
256
|
+
<section class="label-bar">
|
|
257
|
+
<span>Editor</span>
|
|
258
|
+
<span>Preview</span>
|
|
259
|
+
</section>
|
|
260
|
+
<div class="editor" id="editor"></div>
|
|
261
|
+
<div id="preview" class="preview"></div>
|
|
262
|
+
${this.fullScreen
|
|
263
|
+
? html `
|
|
264
|
+
<section class="full-screen-button">
|
|
265
|
+
<md-icon-button @click=${this.toggleFullscreen} title="Toggle for a full screen editor mode"
|
|
266
|
+
><md-icon>${this.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}</md-icon></md-icon-button
|
|
267
|
+
>
|
|
268
|
+
</section>
|
|
269
|
+
`
|
|
270
|
+
: nothing}
|
|
271
|
+
<slot name="preview"></slot>
|
|
272
|
+
${this.supportingText ? html `<div class="supporting-text">${this.supportingText}</div>` : nothing}
|
|
273
|
+
</div>
|
|
274
|
+
`;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
__decorate([
|
|
278
|
+
property({ type: String })
|
|
279
|
+
], MarkdownEditorElementBase.prototype, "value", void 0);
|
|
280
|
+
__decorate([
|
|
281
|
+
property()
|
|
282
|
+
], MarkdownEditorElementBase.prototype, "html", void 0);
|
|
283
|
+
__decorate([
|
|
284
|
+
property({ type: String })
|
|
285
|
+
], MarkdownEditorElementBase.prototype, "label", void 0);
|
|
286
|
+
__decorate([
|
|
287
|
+
property({ type: Boolean })
|
|
288
|
+
], MarkdownEditorElementBase.prototype, "upload", void 0);
|
|
289
|
+
__decorate([
|
|
290
|
+
property({ type: Array })
|
|
291
|
+
], MarkdownEditorElementBase.prototype, "toolbarActions", void 0);
|
|
292
|
+
__decorate([
|
|
293
|
+
property({ type: Object })
|
|
294
|
+
], MarkdownEditorElementBase.prototype, "toolbarIcons", void 0);
|
|
295
|
+
__decorate([
|
|
296
|
+
property({ type: Array })
|
|
297
|
+
], MarkdownEditorElementBase.prototype, "markedExtension", void 0);
|
|
298
|
+
__decorate([
|
|
299
|
+
property({ type: Boolean, reflect: true })
|
|
300
|
+
], MarkdownEditorElementBase.prototype, "required", void 0);
|
|
301
|
+
__decorate([
|
|
302
|
+
property({ type: Boolean, reflect: true })
|
|
303
|
+
], MarkdownEditorElementBase.prototype, "disabled", void 0);
|
|
304
|
+
__decorate([
|
|
305
|
+
property({ type: String, attribute: 'supporting-text' })
|
|
306
|
+
], MarkdownEditorElementBase.prototype, "supportingText", void 0);
|
|
307
|
+
__decorate([
|
|
308
|
+
property({ type: Boolean, attribute: 'split-view' })
|
|
309
|
+
], MarkdownEditorElementBase.prototype, "splitView", void 0);
|
|
310
|
+
__decorate([
|
|
311
|
+
property({ type: Boolean, attribute: 'full-screen' })
|
|
312
|
+
], MarkdownEditorElementBase.prototype, "fullScreen", void 0);
|
|
313
|
+
__decorate([
|
|
314
|
+
query('#editor')
|
|
315
|
+
], MarkdownEditorElementBase.prototype, "editorElement", void 0);
|
|
316
|
+
__decorate([
|
|
317
|
+
query('#markdownEditorContainer')
|
|
318
|
+
], MarkdownEditorElementBase.prototype, "editorContainerElement", void 0);
|
|
319
|
+
__decorate([
|
|
320
|
+
state()
|
|
321
|
+
], MarkdownEditorElementBase.prototype, "previewElement", void 0);
|
|
322
|
+
__decorate([
|
|
323
|
+
state()
|
|
324
|
+
], MarkdownEditorElementBase.prototype, "isFullScreen", void 0);
|
|
325
|
+
__decorate([
|
|
326
|
+
state(),
|
|
327
|
+
observer(function (preview) {
|
|
328
|
+
var _a;
|
|
329
|
+
if (preview === false) {
|
|
330
|
+
(_a = this.codeMirrorEditor) === null || _a === void 0 ? void 0 : _a.focus();
|
|
331
|
+
}
|
|
332
|
+
})
|
|
333
|
+
], MarkdownEditorElementBase.prototype, "preview", void 0);
|
|
334
|
+
//# sourceMappingURL=exm-markdown-editor-base.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToolbarIcons, ToolbarItem } from './types.js';
|
|
2
|
+
import { ExmgElement } from '@exmg/lit-base/index.js';
|
|
3
|
+
import '@material/web/iconbutton/icon-button.js';
|
|
4
|
+
import '@material/web/icon/icon.js';
|
|
5
|
+
export declare class MarkdownEditorToolbarBase extends ExmgElement {
|
|
6
|
+
upload: boolean;
|
|
7
|
+
actions: ToolbarItem[];
|
|
8
|
+
icons: ToolbarIcons;
|
|
9
|
+
renderActionButtons(): import("lit-html").TemplateResult<1>[];
|
|
10
|
+
action(action: string): void;
|
|
11
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
12
|
+
}
|