@dile/editor 2.1.39 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/editor",
3
- "version": "2.1.39",
3
+ "version": "2.3.0",
4
4
  "description": "Webcomponent to create a user editor interface, configured on various ways",
5
5
  "keywords": [
6
6
  "markdown",
@@ -29,8 +29,8 @@
29
29
  "url": "https://github.com/Polydile/dile-components/issues"
30
30
  },
31
31
  "dependencies": {
32
- "@dile/icons": "^2.0.12",
33
- "@dile/ui": "^2.1.39",
32
+ "@dile/icons": "^2.1.0",
33
+ "@dile/ui": "^2.3.0",
34
34
  "lit": "^2.7.0 || ^3.0.0",
35
35
  "prosemirror-commands": "^1.5.0",
36
36
  "prosemirror-example-setup": "^1.2.1",
@@ -41,5 +41,5 @@
41
41
  "prosemirror-state": "^1.4.2",
42
42
  "prosemirror-view": "^1.30.1"
43
43
  },
44
- "gitHead": "072d0ecf23ade48c6f33d3dc37b29a209114f08b"
44
+ "gitHead": "b36ca91ece255381a48008c90b7e4f54c6e6c046"
45
45
  }
package/src/DileEditor.js CHANGED
@@ -4,6 +4,7 @@ import './dile-editor-markdown.js';
4
4
  import '@dile/ui/components/pages/pages.js';
5
5
  import '@dile/ui/components/tabs/tabs.js';
6
6
  import { messageStyles } from '@dile/ui/components/input/index.js';
7
+ import { defaultToolbarConfig } from './defaultToolbarConfig.js';
7
8
 
8
9
  export class DileEditor extends DileEmmitChange(LitElement) {
9
10
  static styles = [
@@ -107,6 +108,10 @@ export class DileEditor extends DileEmmitChange(LitElement) {
107
108
  opacity: 0.5;
108
109
  }
109
110
 
111
+ .ProseMirror img {
112
+ max-width: 100%;
113
+ }
114
+
110
115
  dile-tabs {
111
116
  margin-bottom: 0.3rem;
112
117
  }
@@ -152,15 +157,27 @@ export class DileEditor extends DileEmmitChange(LitElement) {
152
157
 
153
158
  /** Hide errors on input */
154
159
  hideErrorOnInput: { type: Boolean },
160
+
161
+ /** Disable toolbar items, string with items separated by tubes like "italic|h4" */
162
+ disableToolbarItems: { type: String },
163
+
164
+ addicionalCommands: { type: Object },
165
+
166
+ /** Menu config */
167
+ _menuConfig: { type: Object },
155
168
  };
156
169
  }
157
170
 
158
171
  constructor() {
159
172
  super();
173
+ this.initialized = false;
160
174
  this.value = this.innerHTML;
161
175
  this.label = '';
162
176
  this.viewSelected = 'design';
163
177
  this.message = '';
178
+ this.disableToolbarItems = '';
179
+ this._menuConfig = {...defaultToolbarConfig};
180
+ this.addicionalCommands = {}
164
181
  }
165
182
 
166
183
  updated(changedProperties) {
@@ -170,10 +187,20 @@ export class DileEditor extends DileEmmitChange(LitElement) {
170
187
  }
171
188
 
172
189
  firstUpdated() {
190
+ this.setupMenuConfig();
173
191
  this.editor = this.shadowRoot.getElementById('editor');
174
192
  this.textarea = this.shadowRoot.getElementById('eltextarea');
175
193
  }
176
194
 
195
+ setupMenuConfig() {
196
+ const disabledItems = this.disableToolbarItems.split('|');
197
+ disabledItems.forEach(item => {
198
+ if (this._menuConfig.hasOwnProperty(item)) {
199
+ this._menuConfig[item] = false;
200
+ }
201
+ });
202
+ }
203
+
177
204
  render() {
178
205
  return html`
179
206
  <div class="column-reverse">
@@ -209,6 +236,9 @@ export class DileEditor extends DileEmmitChange(LitElement) {
209
236
  <dile-editor-markdown
210
237
  id="editor"
211
238
  @dile-editor-change=${this.updateValue}
239
+ ._menuConfig=${this._menuConfig}
240
+ @dile-editor-markdown-initialized=${this.setInitialized}
241
+ .addicionalCommands=${this.addicionalCommands}
212
242
  ></dile-editor-markdown>
213
243
  </section>
214
244
  </dile-pages>
@@ -231,8 +261,12 @@ export class DileEditor extends DileEmmitChange(LitElement) {
231
261
  }
232
262
 
233
263
  updateEditorContent(value) {
234
- this.editor.updateEditorContent(value);
235
- this.textarea.value = value;
264
+ if(this.initialized) {
265
+ this.editor.updateEditorContent(value);
266
+ this.textarea.value = value;
267
+ } else {
268
+ setTimeout(() => this.updateEditorContent(value), 100);
269
+ }
236
270
  }
237
271
 
238
272
  get isValueExternalyUpdated() {
@@ -257,4 +291,8 @@ export class DileEditor extends DileEmmitChange(LitElement) {
257
291
  this.message = '';
258
292
  }
259
293
  }
294
+
295
+ setInitialized() {
296
+ this.initialized = true;
297
+ }
260
298
  }
@@ -0,0 +1,19 @@
1
+ export const defaultToolbarConfig = {
2
+ bold: true,
3
+ italic: true,
4
+ code_mark: true,
5
+ link: true,
6
+ removeLink: true,
7
+ image: true,
8
+ unordered_list: true,
9
+ ordered_list: true,
10
+ lift: true,
11
+ paragraph: true,
12
+ h1: true,
13
+ h2: true,
14
+ h3: true,
15
+ h4: true,
16
+ code: true,
17
+ undo: true,
18
+ redo: true
19
+ };
@@ -30,9 +30,9 @@ export class DileEditorImageDialog extends LitElement {
30
30
  <div slot="content">
31
31
  <section class="grid">
32
32
  <div>URL:</div>
33
- <div><input type="text" id="src" value="https://placekitten.com/540/360"></div>
33
+ <div><input type="text" id="src"></div>
34
34
  <div>Alt:</div>
35
- <div><input type="text" id="alt" value="Un gatito"></div>
35
+ <div><input type="text" id="alt"></div>
36
36
  </section>
37
37
  <dile-button @click=${this.accept}>Accept</dile-button> <dile-button @click=${this.close}>Cancel</dile-button>
38
38
  </div>
@@ -69,6 +69,8 @@ export class DileEditorImageDialog extends LitElement {
69
69
  alt: this.altInput.value,
70
70
  }
71
71
  }));
72
+ this.srcInput.value = '';
73
+ this.altInput.value = '';
72
74
  }
73
75
  }
74
76
  customElements.define('dile-editor-image-dialog', DileEditorImageDialog);
@@ -45,6 +45,15 @@ export class DileEditorLinkDialog extends LitElement {
45
45
  get menu() {
46
46
  return this.shadowRoot.querySelector('dile-menu-overlay');
47
47
  }
48
+
49
+ get urlInput() {
50
+ return this.shadowRoot.getElementById('url');
51
+ }
52
+
53
+ get titleInput() {
54
+ return this.shadowRoot.getElementById('title');
55
+ }
56
+
48
57
  open() {
49
58
  this.menu.open();
50
59
  }
@@ -57,10 +66,12 @@ export class DileEditorLinkDialog extends LitElement {
57
66
  bubbles: true,
58
67
  composed: true,
59
68
  detail: {
60
- url: this.shadowRoot.getElementById('url').value,
61
- title: this.shadowRoot.getElementById('title').value,
69
+ url: this.urlInput.value,
70
+ title: this.titleInput.value,
62
71
  }
63
72
  }));
73
+ this.urlInput.value = '';
74
+ this.titleInput.value = '';
64
75
  }
65
76
  }
66
77
  customElements.define('dile-editor-link-dialog', DileEditorLinkDialog);
@@ -23,8 +23,22 @@ export class DileEditorMarkdown extends LitElement {
23
23
  `
24
24
  ];
25
25
 
26
+ static get properties() {
27
+ return {
28
+ _menuConfig: { type: Object },
29
+ addicionalCommands: { type: Object },
30
+ };
31
+ }
26
32
  constructor() {
27
33
  super();
34
+ this._menuConfig = {}
35
+ }
36
+
37
+ createRenderRoot() {
38
+ return this;
39
+ }
40
+
41
+ firstUpdated() {
28
42
  const editorElement = this;
29
43
  const dispatchChange = this.dispatchChange.bind(this);
30
44
  const state = this.createState('');
@@ -37,14 +51,13 @@ export class DileEditorMarkdown extends LitElement {
37
51
  }
38
52
  })
39
53
  this.view = view;
40
- }
41
-
42
- createRenderRoot() {
43
- return this;
54
+ this.dispatchEvent(new CustomEvent('dile-editor-markdown-initialized'));
44
55
  }
45
56
 
46
57
  get editorMarkdown() {
47
- return defaultMarkdownSerializer.serialize(this.view.state.doc);
58
+ if(this.view) {
59
+ return defaultMarkdownSerializer.serialize(this.view.state.doc);
60
+ }
48
61
  }
49
62
 
50
63
  createState(content) {
@@ -54,7 +67,7 @@ export class DileEditorMarkdown extends LitElement {
54
67
  history(),
55
68
  keymap(buildKeymap(schema)),
56
69
  keymap(baseKeymap),
57
- menuPlugin(),
70
+ menuPlugin(this._menuConfig, this.addicionalCommands),
58
71
  ]
59
72
  })
60
73
  }
@@ -37,8 +37,7 @@ export class DileEditorToolbarItem extends LitElement {
37
37
  .icon=${this.item.icon}
38
38
  @click=${this.doCommand}
39
39
  ></dile-icon>
40
- <dile-editor-link-dialog id="linkDialog"></dile-editor-link-dialog>
41
- <dile-editor-image-dialog id="imageDialog"></dile-editor-image-dialog>
40
+ ${this.item.dialogTemplate ? this.item.dialogTemplate : ''}
42
41
  `;
43
42
  }
44
43
 
@@ -2,7 +2,7 @@ import { LitElement, html, css } from 'lit';
2
2
  import { notesIcon } from '@dile/icons'
3
3
  import './dile-editor-toolbar-item.js';
4
4
  import '@dile/ui/components/select/select.js';
5
- import { toolbarItems, undoItems, blockItems } from './prosemirror/menu-items.js';
5
+ import { getToolbarItems, getUndoItems, getBlockItems } from './prosemirror/menu-items.js';
6
6
  import { linkCommand } from './prosemirror/markdown-commands.js';
7
7
  import { schema } from "prosemirror-markdown";
8
8
 
@@ -48,32 +48,38 @@ export class DileEditorToolbar extends LitElement {
48
48
  toolbarItems: { type: Array },
49
49
  blockItems: { type: Array },
50
50
  undoItems: { type: Array },
51
+ menuConfig: { type: Object },
52
+ addicionalCommands: { type: Object },
51
53
  };
52
54
  }
53
55
 
54
56
  constructor() {
55
57
  super();
56
- this.toolbarItems = toolbarItems;
57
-
58
- this.undoItems = undoItems
59
-
60
- this.blockItems = blockItems
58
+ this.addicionalCommands = {}
61
59
  }
62
60
 
63
61
  firstUpdated() {
64
-
65
62
  this.blockselect = this.shadowRoot.getElementById('blockselect');
63
+ this.toolbarItems = getToolbarItems(this.menuConfig, this.addicionalCommands.toolbarItems || []);
64
+ this.undoItems = getUndoItems(this.menuConfig, this.addicionalCommands.undoItems || []);
65
+ this.blockItems = getBlockItems(this.menuConfig, this.addicionalCommands.blockItems || []);
66
66
  }
67
67
 
68
68
  render() {
69
69
  return html`
70
- ${this.showItems(this.toolbarItems, 'marks')}
71
- ${this.paragraphTypes}
72
- ${this.showItems(this.undoItems, 'blocks')}
70
+ ${this.menuConfig
71
+ ? html`
72
+ ${this.showItems(this.toolbarItems, 'marks')}
73
+ ${this.paragraphTypes}
74
+ ${this.showItems(this.undoItems, 'blocks')}
75
+ `
76
+ : ''
77
+ }
73
78
  `;
74
79
  }
75
80
 
76
81
  showItems(items, cssClass) {
82
+ if(!items) return '';
77
83
  return html`
78
84
  <div class="${cssClass}">
79
85
  ${items.map(item => html`
@@ -97,21 +103,26 @@ export class DileEditorToolbar extends LitElement {
97
103
 
98
104
  get paragraphTypes() {
99
105
  return html`
100
- <div class="blocks">
101
- <dile-icon .icon=${notesIcon}></dile-icon>
102
- <dile-select
103
- id="blockselect"
104
- name="blockselect"
105
- @element-changed=${this.blockElementChanged}
106
- quietOnStart
107
- >
108
- <select slot="select">
109
- ${this.blockItems.map(item => html`
110
- <option value="${item.commandName}">${item.commandName}</option>
111
- `)}
112
- </select>
113
- </dile-select>
114
- </div>
106
+ ${this.blockItems
107
+ ? html `
108
+ <div class="blocks">
109
+ <dile-icon .icon=${notesIcon}></dile-icon>
110
+ <dile-select
111
+ id="blockselect"
112
+ name="blockselect"
113
+ @element-changed=${this.blockElementChanged}
114
+ quietOnStart
115
+ >
116
+ <select slot="select">
117
+ ${this.blockItems.map(item => html`
118
+ <option value="${item.commandName}">${item.commandName}</option>
119
+ `)}
120
+ </select>
121
+ </dile-select>
122
+ </div>
123
+ `
124
+ : ''
125
+ }
115
126
  `
116
127
  }
117
128
 
@@ -1,3 +1,4 @@
1
+ import { html } from "lit";
1
2
  import { undo, redo } from "prosemirror-history";
2
3
  import {
3
4
  formatBoldIcon,
@@ -26,7 +27,7 @@ import {
26
27
  } from './markdown-commands.js';
27
28
  import { ToolbarItem, ToolbarLink, ToolbarRemoveLink, ToolbarImage } from "./toolbar-item.js";
28
29
 
29
- export const toolbarItems = [
30
+ export const getToolbarItems = (config, additionalItems) => [
30
31
  new ToolbarItem({
31
32
  command: boldCommand,
32
33
  commandName: 'bold',
@@ -46,6 +47,7 @@ export const toolbarItems = [
46
47
  command: linkCommand,
47
48
  commandName: 'link',
48
49
  icon: insertLinkIcon,
50
+ dialogTemplate: html`<dile-editor-link-dialog id="linkDialog"></dile-editor-link-dialog> `,
49
51
  }),
50
52
  new ToolbarRemoveLink({
51
53
  commandName: 'removeLink',
@@ -55,6 +57,7 @@ export const toolbarItems = [
55
57
  command: linkCommand,
56
58
  commandName: 'image',
57
59
  icon: imageIcon,
60
+ dialogTemplate: html`<dile-editor-image-dialog id="imageDialog"></dile-editor-image-dialog> `,
58
61
  }),
59
62
  new ToolbarItem({
60
63
  command: setUnorderedListCommand,
@@ -71,9 +74,10 @@ export const toolbarItems = [
71
74
  commandName: 'lift',
72
75
  icon: formatIndentDecreaseIcon,
73
76
  }),
74
- ];
77
+ ...additionalItems,
78
+ ].filter(item => config[item.commandName] !== false);
75
79
 
76
- export const undoItems = [
80
+ export const getUndoItems = (config, additionalItems) => [
77
81
  new ToolbarItem({
78
82
  command: undo,
79
83
  commandName: 'undo',
@@ -83,10 +87,15 @@ export const undoItems = [
83
87
  command: redo,
84
88
  commandName: 'redo',
85
89
  icon: redoIcon,
86
- })
87
- ];
90
+ }),
91
+ ...additionalItems,
92
+ ].filter(item => config[item.commandName] !== false);
88
93
 
89
- export const blockItems = [
94
+ export const getBlockItems = (config, additionalItems) => [
95
+ {
96
+ command: setCodeCommand,
97
+ commandName: 'code',
98
+ },
90
99
  {
91
100
  command: setParagraphCommand,
92
101
  commandName: 'paragraph',
@@ -107,9 +116,5 @@ export const blockItems = [
107
116
  command: headingCommandCreator(4),
108
117
  commandName: 'h4',
109
118
  },
110
- {
111
- command: setCodeCommand,
112
- commandName: 'code',
113
- },
114
-
115
- ];
119
+ ...additionalItems,
120
+ ].filter(item => config[item.commandName] !== false);
@@ -2,12 +2,14 @@ import { Plugin } from "prosemirror-state";
2
2
 
3
3
  const toolbarElement = 'dile-editor-toolbar';
4
4
 
5
- export const menuPlugin = () => new Plugin({
5
+ export const menuPlugin = (menuConfig, addicionalCommands) => new Plugin({
6
6
  view(editorView) {
7
7
  let toolbar;
8
8
  if (!editorView.dom.parentElement.querySelector(toolbarElement)) {
9
9
  toolbar = document.createElement(toolbarElement);
10
+ toolbar.menuConfig = menuConfig;
10
11
  toolbar.editorView = editorView;
12
+ toolbar.addicionalCommands = addicionalCommands;
11
13
  editorView.dom.parentNode.insertBefore(toolbar, editorView.dom);
12
14
  } else {
13
15
  toolbar = editorView.dom.parentElement.querySelector(toolbarElement);
@@ -11,6 +11,7 @@ export class ToolbarItem {
11
11
  this.command = config.command;
12
12
  this.commandName = config.commandName;
13
13
  this.icon = config.icon;
14
+ this.dialogTemplate = config.dialogTemplate;
14
15
  }
15
16
 
16
17
  checkActive(editorView) {