@vaadin/rich-text-editor 25.0.0-alpha12 → 25.0.0-alpha14

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": "@vaadin/rich-text-editor",
3
- "version": "25.0.0-alpha12",
3
+ "version": "25.0.0-alpha14",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,21 +35,21 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@open-wc/dedupe-mixin": "^1.3.0",
38
- "@vaadin/button": "25.0.0-alpha12",
39
- "@vaadin/component-base": "25.0.0-alpha12",
40
- "@vaadin/confirm-dialog": "25.0.0-alpha12",
41
- "@vaadin/overlay": "25.0.0-alpha12",
42
- "@vaadin/text-field": "25.0.0-alpha12",
43
- "@vaadin/tooltip": "25.0.0-alpha12",
44
- "@vaadin/vaadin-themable-mixin": "25.0.0-alpha12",
38
+ "@vaadin/button": "25.0.0-alpha14",
39
+ "@vaadin/component-base": "25.0.0-alpha14",
40
+ "@vaadin/confirm-dialog": "25.0.0-alpha14",
41
+ "@vaadin/overlay": "25.0.0-alpha14",
42
+ "@vaadin/text-field": "25.0.0-alpha14",
43
+ "@vaadin/tooltip": "25.0.0-alpha14",
44
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha14",
45
45
  "lit": "^3.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@vaadin/a11y-base": "25.0.0-alpha12",
49
- "@vaadin/chai-plugins": "25.0.0-alpha12",
50
- "@vaadin/test-runner-commands": "25.0.0-alpha12",
48
+ "@vaadin/a11y-base": "25.0.0-alpha14",
49
+ "@vaadin/chai-plugins": "25.0.0-alpha14",
50
+ "@vaadin/test-runner-commands": "25.0.0-alpha14",
51
51
  "@vaadin/testing-helpers": "^2.0.0",
52
- "@vaadin/vaadin-lumo-styles": "25.0.0-alpha12",
52
+ "@vaadin/vaadin-lumo-styles": "25.0.0-alpha14",
53
53
  "sinon": "^18.0.0"
54
54
  },
55
55
  "cvdlName": "vaadin-rich-text-editor",
@@ -57,5 +57,5 @@
57
57
  "web-types.json",
58
58
  "web-types.lit.json"
59
59
  ],
60
- "gitHead": "e75527348f9ba7c363d068c868b9f030c15b84a1"
60
+ "gitHead": "8ebeeeca4b5b6564eff954d6582d0d6760464e51"
61
61
  }
@@ -15,7 +15,7 @@ const base = css`
15
15
  :host {
16
16
  background: var(--vaadin-rich-text-editor-background, var(--vaadin-background-color));
17
17
  border: var(--vaadin-input-field-border-width, 1px) solid
18
- var(--vaadin-input-field-border-color, var(--vaadin-border-color-strong));
18
+ var(--vaadin-input-field-border-color, var(--vaadin-border-color));
19
19
  border-radius: var(--vaadin-input-field-border-radius, var(--vaadin-radius-m));
20
20
  box-sizing: border-box;
21
21
  display: flex;
@@ -118,30 +118,61 @@ export const content = css`
118
118
  .ql-align-right {
119
119
  text-align: right;
120
120
  }
121
+
122
+ .ql-code-block-container {
123
+ font-family: monospace;
124
+ background-color: var(--vaadin-background-container);
125
+ border-radius: var(--vaadin-radius-s);
126
+ white-space: pre-wrap;
127
+ margin-block: var(--vaadin-padding-s);
128
+ padding: var(--vaadin-padding-container);
129
+ }
130
+
131
+ .ql-editor li {
132
+ list-style-type: none;
133
+ position: relative;
134
+ }
135
+
136
+ .ql-editor li > .ql-ui::before {
137
+ display: inline-block;
138
+ margin-left: -1.5em;
139
+ margin-right: 0.3em;
140
+ text-align: right;
141
+ white-space: nowrap;
142
+ width: 1.2em;
143
+ }
144
+
145
+ .ql-editor li[data-list='bullet'] {
146
+ list-style-type: disc;
147
+ }
148
+
149
+ .ql-editor li[data-list='ordered'] {
150
+ counter-increment: list-0;
151
+ }
152
+
153
+ .ql-editor li[data-list='ordered'] > .ql-ui::before {
154
+ content: counter(list-0, decimal) '. ';
155
+ }
121
156
  /* quill core end */
122
157
 
123
158
  blockquote {
124
- border-inline-start: 4px solid var(--vaadin-border-color);
159
+ border-inline-start: 4px solid var(--vaadin-border-color-subtle);
125
160
  margin: var(--vaadin-padding-container);
126
- padding-inline-start: var(--vaadin-padding);
161
+ padding-inline-start: var(--vaadin-padding-s);
127
162
  }
128
163
 
129
- code,
130
- pre {
164
+ code {
131
165
  background-color: var(--vaadin-background-container);
132
166
  border-radius: var(--vaadin-radius-s);
167
+ padding: 0.125rem 0.25rem;
133
168
  }
134
169
 
135
170
  pre {
136
171
  white-space: pre-wrap;
137
- margin-block: var(--vaadin-padding);
172
+ margin-block: var(--vaadin-padding-s);
138
173
  padding: var(--vaadin-padding-container);
139
174
  }
140
175
 
141
- code {
142
- padding: 0.125rem 0.25rem;
143
- }
144
-
145
176
  img {
146
177
  max-width: 100%;
147
178
  }
@@ -159,8 +190,8 @@ const toolbar = css`
159
190
  display: flex;
160
191
  flex-shrink: 0;
161
192
  flex-wrap: wrap;
162
- gap: var(--vaadin-rich-text-editor-toolbar-gap, var(--vaadin-gap-container-inline));
163
- padding: var(--vaadin-rich-text-editor-toolbar-padding, var(--vaadin-padding));
193
+ gap: var(--vaadin-rich-text-editor-toolbar-gap, var(--vaadin-gap-s));
194
+ padding: var(--vaadin-rich-text-editor-toolbar-padding, var(--vaadin-padding-s));
164
195
  }
165
196
 
166
197
  [part~='toolbar-group'] {
@@ -18,7 +18,7 @@ export const richTextEditorPopupOverlay = css`
18
18
 
19
19
  [part='content'] {
20
20
  display: grid;
21
- gap: var(--vaadin-rich-text-editor-overlay-gap, var(--vaadin-gap-container-inline));
21
+ gap: var(--vaadin-rich-text-editor-overlay-gap, var(--vaadin-gap-s));
22
22
  grid-template-columns: repeat(7, minmax(0, 1fr));
23
23
  }
24
24
 
@@ -15,34 +15,26 @@ import { I18nMixin } from '@vaadin/component-base/src/i18n-mixin.js';
15
15
 
16
16
  const Quill = window.Quill;
17
17
 
18
- // Workaround for text disappearing when accepting spellcheck suggestion
19
- // See https://github.com/quilljs/quill/issues/2096#issuecomment-399576957
20
- const Inline = Quill.import('blots/inline');
21
-
22
- class CustomColor extends Inline {
23
- constructor(domNode, value) {
24
- super(domNode, value);
25
-
26
- // Map <font> properties
27
- domNode.style.color = domNode.color;
28
-
29
- const span = this.replaceWith(new Inline(Inline.create()));
30
-
31
- span.children.forEach((child) => {
32
- if (child.attributes) child.attributes.copy(span);
33
- if (child.unwrap) child.unwrap();
34
- });
35
-
36
- this.remove();
37
-
38
- return span; // eslint-disable-line no-constructor-return
18
+ // There are some issues e.g. `spellcheck="false"` not preserved
19
+ // See https://github.com/slab/quill/issues/4289
20
+ // Fix to add `spellcheck="false"` on the `<pre>` tag removed by Quill
21
+ const QuillCodeBlockContainer = Quill.import('formats/code-block-container');
22
+
23
+ class CodeBlockContainer extends QuillCodeBlockContainer {
24
+ html(index, length) {
25
+ const markup = super.html(index, length);
26
+ const tempDiv = document.createElement('div');
27
+ tempDiv.innerHTML = markup;
28
+ const preTag = tempDiv.querySelector('pre');
29
+ if (preTag) {
30
+ preTag.setAttribute('spellcheck', 'false');
31
+ return preTag.outerHTML;
32
+ }
33
+ return markup; // fallback
39
34
  }
40
35
  }
41
36
 
42
- CustomColor.blotName = 'customColor';
43
- CustomColor.tagName = 'FONT';
44
-
45
- Quill.register(CustomColor, true);
37
+ Quill.register('formats/code-block-container', CodeBlockContainer, true);
46
38
 
47
39
  const HANDLERS = [
48
40
  'bold',
@@ -69,8 +61,6 @@ const STATE = {
69
61
  CLICKED: 2,
70
62
  };
71
63
 
72
- const TAB_KEY = 9;
73
-
74
64
  const DEFAULT_I18N = {
75
65
  undo: 'undo',
76
66
  redo: 'redo',
@@ -374,23 +364,21 @@ export const RichTextEditorMixin = (superClass) =>
374
364
  }
375
365
  });
376
366
 
377
- const TAB_KEY = 9;
378
-
379
367
  editorContent.addEventListener('keydown', (e) => {
380
368
  if (e.key === 'Escape') {
381
369
  if (!this.__tabBindings) {
382
- this.__tabBindings = this._editor.keyboard.bindings[TAB_KEY];
383
- this._editor.keyboard.bindings[TAB_KEY] = null;
370
+ this.__tabBindings = this._editor.keyboard.bindings.Tab;
371
+ this._editor.keyboard.bindings.Tab = null;
384
372
  }
385
373
  } else if (this.__tabBindings) {
386
- this._editor.keyboard.bindings[TAB_KEY] = this.__tabBindings;
374
+ this._editor.keyboard.bindings.Tab = this.__tabBindings;
387
375
  this.__tabBindings = null;
388
376
  }
389
377
  });
390
378
 
391
379
  editorContent.addEventListener('blur', () => {
392
380
  if (this.__tabBindings) {
393
- this._editor.keyboard.bindings[TAB_KEY] = this.__tabBindings;
381
+ this._editor.keyboard.bindings.Tab = this.__tabBindings;
394
382
  this.__tabBindings = null;
395
383
  }
396
384
  });
@@ -496,7 +484,7 @@ export const RichTextEditorMixin = (superClass) =>
496
484
  buttons[index].focus();
497
485
  }
498
486
  // Esc and Tab focuses the content
499
- if (e.keyCode === 27 || (e.keyCode === TAB_KEY && !e.shiftKey)) {
487
+ if (e.keyCode === 27 || (e.key === 'Tab' && !e.shiftKey)) {
500
488
  e.preventDefault();
501
489
  this._editor.focus();
502
490
  }
@@ -552,19 +540,19 @@ export const RichTextEditorMixin = (superClass) =>
552
540
  this._toolbar.querySelector('button:not([tabindex])').focus();
553
541
  };
554
542
 
555
- const keyboard = this._editor.getModule('keyboard');
556
- const bindings = keyboard.bindings[TAB_KEY];
543
+ const keyboard = this._editor.keyboard;
544
+ const bindings = keyboard.bindings.Tab;
557
545
 
558
546
  // Exclude Quill shift-tab bindings, except for code block,
559
547
  // as some of those are breaking when on a newline in the list
560
548
  // https://github.com/vaadin/vaadin-rich-text-editor/issues/67
561
549
  const originalBindings = bindings.filter((b) => !b.shiftKey || (b.format && b.format['code-block']));
562
- const moveFocusBinding = { key: TAB_KEY, shiftKey: true, handler: focusToolbar };
550
+ const moveFocusBinding = { key: 'Tab', shiftKey: true, handler: focusToolbar };
563
551
 
564
- keyboard.bindings[TAB_KEY] = [...originalBindings, moveFocusBinding];
552
+ keyboard.bindings.Tab = [...originalBindings, moveFocusBinding];
565
553
 
566
554
  // Alt-f10 focuses a toolbar button
567
- keyboard.addBinding({ key: 121, altKey: true, handler: focusToolbar });
555
+ keyboard.addBinding({ key: 'F10', altKey: true, handler: focusToolbar });
568
556
  }
569
557
 
570
558
  /** @private */
@@ -603,6 +591,7 @@ export const RichTextEditorMixin = (superClass) =>
603
591
  _applyLink(link) {
604
592
  if (link) {
605
593
  this._markToolbarClicked();
594
+ this._editor.focus();
606
595
  this._editor.format('link', link, SOURCE.USER);
607
596
  this._editor.getModule('toolbar').update(this._editor.selection.savedRange);
608
597
  }
@@ -686,6 +675,7 @@ export const RichTextEditorMixin = (superClass) =>
686
675
  const color = event.detail.color;
687
676
  this._colorValue = color === '#000000' ? null : color;
688
677
  this._markToolbarClicked();
678
+ this._editor.focus();
689
679
  this._editor.format('color', this._colorValue, SOURCE.USER);
690
680
  this._toolbar.style.setProperty('--_color-value', this._colorValue);
691
681
  this._colorEditing = false;
@@ -701,6 +691,7 @@ export const RichTextEditorMixin = (superClass) =>
701
691
  const color = event.detail.color;
702
692
  this._backgroundValue = color === '#ffffff' ? null : color;
703
693
  this._markToolbarClicked();
694
+ this._editor.focus();
704
695
  this._editor.format('background', this._backgroundValue, SOURCE.USER);
705
696
  this._toolbar.style.setProperty('--_background-value', this._backgroundValue);
706
697
  this._backgroundEditing = false;
@@ -708,19 +699,8 @@ export const RichTextEditorMixin = (superClass) =>
708
699
 
709
700
  /** @private */
710
701
  __updateHtmlValue() {
711
- const editor = this.shadowRoot.querySelector('.ql-editor');
712
- let content = editor.innerHTML;
713
-
714
- // Remove Quill classes, e.g. ql-syntax, except for align
715
- content = content.replace(/class="([^"]*)"/gu, (_match, group1) => {
716
- const classes = group1.split(' ').filter((className) => {
717
- return !className.startsWith('ql-') || className.startsWith('ql-align');
718
- });
719
- return `class="${classes.join(' ')}"`;
720
- });
721
- // Remove meta spans, e.g. cursor which are empty after Quill classes removed
722
- content = content.replace(/<span[^>]*><\/span>/gu, '');
723
-
702
+ // We have to use this instead of `innerHTML` to get correct tags like `<pre>` etc.
703
+ let content = this._editor.getSemanticHTML();
724
704
  // Replace Quill align classes with inline styles
725
705
  [this.__dir === 'rtl' ? 'left' : 'right', 'center', 'justify'].forEach((align) => {
726
706
  content = content.replace(
@@ -728,9 +708,6 @@ export const RichTextEditorMixin = (superClass) =>
728
708
  ` style="text-align: ${align}"`,
729
709
  );
730
710
  });
731
-
732
- content = content.replace(/ class=""/gu, '');
733
-
734
711
  this._setHtmlValue(content);
735
712
  }
736
713
 
@@ -778,7 +755,7 @@ export const RichTextEditorMixin = (superClass) =>
778
755
  htmlValue = htmlValue.replaceAll(/>[^<]*</gu, (match) => match.replaceAll(character, replacement)); // NOSONAR
779
756
  });
780
757
 
781
- const deltaFromHtml = this._editor.clipboard.convert(htmlValue);
758
+ const deltaFromHtml = this._editor.clipboard.convert({ html: htmlValue });
782
759
 
783
760
  // Restore whitespace characters after the conversion
784
761
  Object.entries(whitespaceCharacters).forEach(([character, replacement]) => {
@@ -59,7 +59,7 @@ export interface RichTextEditorEventMap extends HTMLElementEventMap, RichTextEdi
59
59
  * `toolbar-group-heading` | The group for heading controls
60
60
  * `toolbar-group-style` | The group for style controls
61
61
  * `toolbar-group-glyph-transformation` | The group for glyph transformation controls
62
- * `toolbar-group-group-list` | The group for group list controls
62
+ * `toolbar-group-list` | The group for list controls
63
63
  * `toolbar-group-alignment` | The group for alignment controls
64
64
  * `toolbar-group-rich-text` | The group for rich text controls
65
65
  * `toolbar-group-block` | The group for preformatted block controls
@@ -57,7 +57,7 @@ import { RichTextEditorMixin } from './vaadin-rich-text-editor-mixin.js';
57
57
  * `toolbar-group-heading` | The group for heading controls
58
58
  * `toolbar-group-style` | The group for style controls
59
59
  * `toolbar-group-glyph-transformation` | The group for glyph transformation controls
60
- * `toolbar-group-group-list` | The group for group list controls
60
+ * `toolbar-group-list` | The group for list controls
61
61
  * `toolbar-group-alignment` | The group for alignment controls
62
62
  * `toolbar-group-rich-text` | The group for rich text controls
63
63
  * `toolbar-group-block` | The group for preformatted block controls