@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.
Files changed (39) hide show
  1. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/actions.d.ts +6 -0
  2. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/actions.js +227 -0
  3. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-base.d.ts +89 -0
  4. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-base.js +334 -0
  5. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar-base.d.ts +12 -0
  6. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar-base.js +52 -0
  7. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar.d.ts +9 -0
  8. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor-toolbar.js +12 -0
  9. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor.d.ts +76 -0
  10. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/exm-markdown-editor.js +83 -0
  11. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/icons.d.ts +3 -0
  12. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/icons.js +5 -0
  13. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/index.d.ts +6 -0
  14. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/index.js +6 -0
  15. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-codemirror-css.d.ts +1 -0
  16. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-codemirror-css.js +491 -0
  17. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-css.d.ts +1 -0
  18. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-css.js +210 -0
  19. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-toolbar-css.d.ts +1 -0
  20. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/styles/exm-markdown-editor-toolbar-css.js +22 -0
  21. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/types.d.ts +13 -0
  22. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/utils/configurations.d.ts +4 -0
  23. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/utils/configurations.js +14 -0
  24. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/validator/exm-markdown-editor-validator.d.ts +23 -0
  25. package/.rollup.cache/root/repo/packages/exm-markdown-editor/dist/validator/exm-markdown-editor-validator.js +35 -0
  26. package/dist/actions.js +5 -3
  27. package/dist/exm-markdown-editor-base.js +11 -8
  28. package/dist/exm-markdown-editor-toolbar-base.js +6 -3
  29. package/dist/exm-markdown-editor-toolbar.js +6 -4
  30. package/dist/exm-markdown-editor.js +7 -5
  31. package/dist/icons.js +5 -2
  32. package/dist/index.js +3 -4
  33. package/dist/styles/exm-markdown-codemirror-css.js +5 -2
  34. package/dist/styles/exm-markdown-editor-css.js +5 -2
  35. package/dist/styles/exm-markdown-editor-toolbar-css.js +5 -2
  36. package/dist/utils/configurations.js +5 -3
  37. package/dist/validator/exm-markdown-editor-validator.js +6 -3
  38. package/package.json +2 -2
  39. /package/{dist → .rollup.cache/root/repo/packages/exm-markdown-editor/dist}/types.js +0 -0
@@ -0,0 +1,6 @@
1
+ import { MarkdownActions } from './types.js';
2
+ export declare const toolbarActions: {
3
+ name: string;
4
+ icon: string;
5
+ }[];
6
+ export declare const markdownActions: MarkdownActions;
@@ -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 = `![Alternative ${text}](${url ? url : 'Your link here'} "${text}")`;
147
+ }
148
+ else {
149
+ text = `![This is an alt text.](${url ? url : 'http://placekitten.com/g/200/300'} "This is a sample image.")`;
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
@@ -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
+ }