@vaadin/rich-text-editor 24.4.6 → 24.5.0-alpha10

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/README.md CHANGED
@@ -53,7 +53,7 @@ import '@vaadin/rich-text-editor/src/vaadin-rich-text-editor.js';
53
53
 
54
54
  ## Contributing
55
55
 
56
- Read the [contributing guide](https://vaadin.com/docs/latest/contributing/overview) to learn about our development process, how to propose bugfixes and improvements, and how to test your changes to Vaadin components.
56
+ Read the [contributing guide](https://vaadin.com/docs/latest/contributing) to learn about our development process, how to propose bugfixes and improvements, and how to test your changes to Vaadin components.
57
57
 
58
58
  ## License
59
59
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/rich-text-editor",
3
- "version": "24.4.6",
3
+ "version": "24.5.0-alpha10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -41,29 +41,30 @@
41
41
  "dependencies": {
42
42
  "@open-wc/dedupe-mixin": "^1.3.0",
43
43
  "@polymer/polymer": "^3.0.0",
44
- "@vaadin/button": "~24.4.6",
45
- "@vaadin/component-base": "~24.4.6",
46
- "@vaadin/confirm-dialog": "~24.4.6",
47
- "@vaadin/text-field": "~24.4.6",
48
- "@vaadin/tooltip": "~24.4.6",
49
- "@vaadin/vaadin-lumo-styles": "~24.4.6",
50
- "@vaadin/vaadin-material-styles": "~24.4.6",
51
- "@vaadin/vaadin-themable-mixin": "~24.4.6",
44
+ "@vaadin/button": "24.5.0-alpha10",
45
+ "@vaadin/component-base": "24.5.0-alpha10",
46
+ "@vaadin/confirm-dialog": "24.5.0-alpha10",
47
+ "@vaadin/overlay": "24.5.0-alpha10",
48
+ "@vaadin/text-field": "24.5.0-alpha10",
49
+ "@vaadin/tooltip": "24.5.0-alpha10",
50
+ "@vaadin/vaadin-lumo-styles": "24.5.0-alpha10",
51
+ "@vaadin/vaadin-material-styles": "24.5.0-alpha10",
52
+ "@vaadin/vaadin-themable-mixin": "24.5.0-alpha10",
52
53
  "lit": "^3.0.0"
53
54
  },
54
55
  "devDependencies": {
55
- "@esm-bundle/chai": "^4.3.4",
56
- "@vaadin/a11y-base": "~24.4.6",
57
- "@vaadin/testing-helpers": "^0.6.0",
56
+ "@vaadin/a11y-base": "24.5.0-alpha10",
57
+ "@vaadin/chai-plugins": "24.5.0-alpha10",
58
+ "@vaadin/testing-helpers": "^1.0.0",
58
59
  "gulp": "^4.0.2",
59
60
  "gulp-cli": "^2.3.0",
60
61
  "gulp-iconfont": "^11.0.0",
61
- "sinon": "^13.0.2"
62
+ "sinon": "^18.0.0"
62
63
  },
63
64
  "cvdlName": "vaadin-rich-text-editor",
64
65
  "web-types": [
65
66
  "web-types.json",
66
67
  "web-types.lit.json"
67
68
  ],
68
- "gitHead": "46d3cdb72eb99d544c7bb86c3de95043b9e5857f"
69
+ "gitHead": "6f9c37308031af872a98017bfab4de89aeacda51"
69
70
  }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2024 Vaadin Ltd.
4
+ *
5
+ * This program is available under Vaadin Commercial License and Service Terms.
6
+ *
7
+ *
8
+ * See https://vaadin.com/commercial-license-and-service-terms for the full
9
+ * license.
10
+ */
11
+ import { css, html, LitElement } from 'lit';
12
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
13
+ import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
14
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
15
+ import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
16
+ import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
17
+ import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
18
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
19
+ import { RichTextEditorPopupMixin } from './vaadin-rich-text-editor-popup-mixin.js';
20
+
21
+ /**
22
+ * An element used internally by `<vaadin-rich-text-editor>`. Not intended to be used separately.
23
+ * @private
24
+ */
25
+ class RichTextEditorPopup extends RichTextEditorPopupMixin(PolylitMixin(LitElement)) {
26
+ static get is() {
27
+ return 'vaadin-rich-text-editor-popup';
28
+ }
29
+
30
+ static get styles() {
31
+ return css`
32
+ :host {
33
+ display: none;
34
+ }
35
+ `;
36
+ }
37
+
38
+ /** @protected */
39
+ render() {
40
+ return html`
41
+ <vaadin-rich-text-editor-popup-overlay
42
+ .renderer="${this.renderer}"
43
+ .opened="${this.opened}"
44
+ .positionTarget="${this.target}"
45
+ no-vertical-overlap
46
+ horizontal-align="start"
47
+ vertical-align="top"
48
+ focus-trap
49
+ @opened-changed="${this._onOpenedChanged}"
50
+ @vaadin-overlay-escape-press="${this._onOverlayEscapePress}"
51
+ ></vaadin-rich-text-editor-popup-overlay>
52
+ `;
53
+ }
54
+
55
+ /** @private */
56
+ _onOpenedChanged(event) {
57
+ this.opened = event.detail.value;
58
+ }
59
+ }
60
+
61
+ defineCustomElement(RichTextEditorPopup);
62
+
63
+ export { RichTextEditorPopup };
64
+
65
+ /**
66
+ * An element used internally by `<vaadin-rich-text-editor>`. Not intended to be used separately.
67
+ * @private
68
+ */
69
+ class RichTextEditorPopupOverlay extends PositionMixin(
70
+ OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement)))),
71
+ ) {
72
+ static get is() {
73
+ return 'vaadin-rich-text-editor-popup-overlay';
74
+ }
75
+
76
+ static get styles() {
77
+ return overlayStyles;
78
+ }
79
+
80
+ /** @protected */
81
+ render() {
82
+ return html`
83
+ <div id="backdrop" part="backdrop" hidden></div>
84
+ <div part="overlay" id="overlay">
85
+ <div part="content" id="content"><slot></slot></div>
86
+ </div>
87
+ `;
88
+ }
89
+ }
90
+
91
+ defineCustomElement(RichTextEditorPopupOverlay);
@@ -12,6 +12,7 @@ import '@vaadin/button/src/vaadin-lit-button.js';
12
12
  import '@vaadin/confirm-dialog/src/vaadin-lit-confirm-dialog.js';
13
13
  import '@vaadin/text-field/src/vaadin-lit-text-field.js';
14
14
  import '@vaadin/tooltip/src/vaadin-lit-tooltip.js';
15
+ import './vaadin-lit-rich-text-editor-popup.js';
15
16
  import { html, LitElement } from 'lit';
16
17
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
17
18
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
@@ -84,6 +85,25 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
84
85
  <vaadin-tooltip for="btn-strike" .text="${this.i18n.strike}"></vaadin-tooltip>
85
86
  </span>
86
87
 
88
+ <span part="toolbar-group toolbar-group-style">
89
+ <!-- Color -->
90
+ <button
91
+ id="btn-color"
92
+ type="button"
93
+ part="toolbar-button toolbar-button-color"
94
+ @click="${this.__onColorClick}"
95
+ ></button>
96
+ <vaadin-tooltip for="btn-color" .text="${this.i18n.color}"></vaadin-tooltip>
97
+ <!-- Background -->
98
+ <button
99
+ id="btn-background"
100
+ type="button"
101
+ part="toolbar-button toolbar-button-background"
102
+ @click="${this.__onBackgroundClick}"
103
+ ></button>
104
+ <vaadin-tooltip for="btn-background" .text="${this.i18n.background}"></vaadin-tooltip>
105
+ </span>
106
+
87
107
  <span part="toolbar-group toolbar-group-heading">
88
108
  <!-- Header buttons -->
89
109
  <button
@@ -265,9 +285,35 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
265
285
  ${this.i18n.cancel}
266
286
  </vaadin-button>
267
287
  </vaadin-confirm-dialog>
288
+
289
+ <vaadin-rich-text-editor-popup
290
+ id="colorPopup"
291
+ .colors="${this.colorOptions}"
292
+ .opened="${this._colorEditing}"
293
+ @color-selected="${this.__onColorSelected}"
294
+ @opened-changed="${this.__onColorEditingChanged}"
295
+ ></vaadin-rich-text-editor-popup>
296
+
297
+ <vaadin-rich-text-editor-popup
298
+ id="backgroundPopup"
299
+ .colors="${this.colorOptions}"
300
+ .opened="${this._backgroundEditing}"
301
+ @color-selected="${this.__onBackgroundSelected}"
302
+ @opened-changed="${this.__onBackgroundEditingChanged}"
303
+ ></vaadin-rich-text-editor-popup>
268
304
  `;
269
305
  }
270
306
 
307
+ /** @private */
308
+ __onBackgroundEditingChanged(event) {
309
+ this._backgroundEditing = event.detail.value;
310
+ }
311
+
312
+ /** @private */
313
+ __onColorEditingChanged(event) {
314
+ this._colorEditing = event.detail.value;
315
+ }
316
+
271
317
  /** @private */
272
318
  _onLinkEditingChanged(event) {
273
319
  this._linkEditing = event.detail.value;
@@ -17,6 +17,8 @@ export interface RichTextEditorI18n {
17
17
  italic: string;
18
18
  underline: string;
19
19
  strike: string;
20
+ color: string;
21
+ background: string;
20
22
  h1: string;
21
23
  h2: string;
22
24
  h3: string;
@@ -96,6 +98,16 @@ export declare class RichTextEditorMixinClass {
96
98
  */
97
99
  i18n: RichTextEditorI18n;
98
100
 
101
+ /**
102
+ * The list of colors used by the background and text color
103
+ * selection controls. Should contain an array of HEX strings.
104
+ *
105
+ * When user selects `#000000` (black) as a text color,
106
+ * or `#ffffff` (white) as a background color, it resets
107
+ * the corresponding format for the selected text.
108
+ */
109
+ colorOptions: string[];
110
+
99
111
  /**
100
112
  * Sets content represented by HTML snippet into the editor.
101
113
  * The snippet is interpreted by [Quill's Clipboard matchers](https://quilljs.com/docs/modules/clipboard/#matchers),
@@ -146,6 +146,8 @@ export const RichTextEditorMixin = (superClass) =>
146
146
  italic: 'italic',
147
147
  underline: 'underline',
148
148
  strike: 'strike',
149
+ color: 'color',
150
+ background: 'background',
149
151
  h1: 'h1',
150
152
  h2: 'h2',
151
153
  h3: 'h3',
@@ -169,6 +171,28 @@ export const RichTextEditorMixin = (superClass) =>
169
171
  },
170
172
  },
171
173
 
174
+ /**
175
+ * The list of colors used by the background and text color
176
+ * selection controls. Should contain an array of HEX strings.
177
+ *
178
+ * When user selects `#000000` (black) as a text color,
179
+ * or `#ffffff` (white) as a background color, it resets
180
+ * the corresponding format for the selected text.
181
+ */
182
+ colorOptions: {
183
+ type: Array,
184
+ value: () => {
185
+ /* prettier-ignore */
186
+ return [
187
+ '#000000', '#e60000', '#ff9900', '#ffff00', '#008a00', '#0066cc', '#9933ff',
188
+ '#ffffff', '#facccc', '#ffebcc', '#ffffcc', '#cce8cc', '#cce0f5', '#ebd6ff',
189
+ '#bbbbbb', '#f06666', '#ffc266', '#ffff66', '#66b966', '#66a3e0', '#c285ff',
190
+ '#888888', '#a10000', '#b26b00', '#b2b200', '#006100', '#0047b2', '#6b24b2',
191
+ '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466'
192
+ ];
193
+ },
194
+ },
195
+
172
196
  /** @private */
173
197
  _editor: {
174
198
  type: Object,
@@ -210,6 +234,30 @@ export const RichTextEditorMixin = (superClass) =>
210
234
  type: String,
211
235
  value: '',
212
236
  },
237
+
238
+ /** @private */
239
+ _colorEditing: {
240
+ type: Boolean,
241
+ value: false,
242
+ },
243
+
244
+ /** @private */
245
+ _colorValue: {
246
+ type: String,
247
+ value: '',
248
+ },
249
+
250
+ /** @private */
251
+ _backgroundEditing: {
252
+ type: Boolean,
253
+ value: false,
254
+ },
255
+
256
+ /** @private */
257
+ _backgroundValue: {
258
+ type: String,
259
+ value: '',
260
+ },
213
261
  };
214
262
  }
215
263
 
@@ -320,6 +368,15 @@ export const RichTextEditorMixin = (superClass) =>
320
368
  });
321
369
  });
322
370
 
371
+ this._editor.on('editor-change', () => {
372
+ const selection = this._editor.getSelection();
373
+ if (selection) {
374
+ const format = this._editor.getFormat(selection.index, selection.length);
375
+ this._toolbar.style.setProperty('--_color-value', format.color || null);
376
+ this._toolbar.style.setProperty('--_background-value', format.background || null);
377
+ }
378
+ });
379
+
323
380
  const TAB_KEY = 9;
324
381
 
325
382
  editorContent.addEventListener('keydown', (e) => {
@@ -362,6 +419,9 @@ export const RichTextEditorMixin = (superClass) =>
362
419
  // Flush pending htmlValue only once the editor is fully initialized
363
420
  this.__flushPendingHtmlValue();
364
421
 
422
+ this.$.backgroundPopup.target = this.shadowRoot.querySelector('#btn-background');
423
+ this.$.colorPopup.target = this.shadowRoot.querySelector('#btn-color');
424
+
365
425
  requestAnimationFrame(() => {
366
426
  this.$.linkDialog.$.dialog.$.overlay.addEventListener('vaadin-overlay-open', () => {
367
427
  this.$.linkUrl.focus();
@@ -663,13 +723,43 @@ export const RichTextEditorMixin = (superClass) =>
663
723
  }
664
724
  }
665
725
 
726
+ /** @private */
727
+ __onColorClick() {
728
+ this._colorEditing = true;
729
+ }
730
+
731
+ /** @private */
732
+ __onColorSelected(event) {
733
+ const color = event.detail.color;
734
+ this._colorValue = color === '#000000' ? null : color;
735
+ this._markToolbarClicked();
736
+ this._editor.format('color', this._colorValue, SOURCE.USER);
737
+ this._toolbar.style.setProperty('--_color-value', this._colorValue);
738
+ this._colorEditing = false;
739
+ }
740
+
741
+ /** @private */
742
+ __onBackgroundClick() {
743
+ this._backgroundEditing = true;
744
+ }
745
+
746
+ /** @private */
747
+ __onBackgroundSelected(event) {
748
+ const color = event.detail.color;
749
+ this._backgroundValue = color === '#ffffff' ? null : color;
750
+ this._markToolbarClicked();
751
+ this._editor.format('background', this._backgroundValue, SOURCE.USER);
752
+ this._toolbar.style.setProperty('--_background-value', this._backgroundValue);
753
+ this._backgroundEditing = false;
754
+ }
755
+
666
756
  /** @private */
667
757
  __updateHtmlValue() {
668
758
  const editor = this.shadowRoot.querySelector('.ql-editor');
669
759
  let content = editor.innerHTML;
670
760
 
671
761
  // Remove Quill classes, e.g. ql-syntax, except for align
672
- content = content.replace(/class="([^"]*)"/gu, (match, group1) => {
762
+ content = content.replace(/class="([^"]*)"/gu, (_match, group1) => {
673
763
  const classes = group1.split(' ').filter((className) => {
674
764
  return !className.startsWith('ql-') || className.startsWith('ql-align');
675
765
  });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2024 Vaadin Ltd.
4
+ *
5
+ * This program is available under Vaadin Commercial License and Service Terms.
6
+ *
7
+ *
8
+ * See https://vaadin.com/commercial-license-and-service-terms for the full
9
+ * license.
10
+ */
11
+
12
+ /**
13
+ * @polymerMixin
14
+ */
15
+ export const RichTextEditorPopupMixin = (superClass) =>
16
+ class RichTextEditorPopupMixinClass extends superClass {
17
+ static get properties() {
18
+ return {
19
+ target: {
20
+ type: Object,
21
+ },
22
+
23
+ opened: {
24
+ type: Boolean,
25
+ notify: true,
26
+ },
27
+
28
+ colors: {
29
+ type: Array,
30
+ },
31
+
32
+ renderer: {
33
+ type: Object,
34
+ },
35
+ };
36
+ }
37
+
38
+ static get observers() {
39
+ return ['__openedOrTargetChanged(opened, target)', '__colorsChanged(colors)'];
40
+ }
41
+
42
+ /** @private */
43
+ __colorsChanged(colors) {
44
+ this.renderer = (root) => {
45
+ if (!root.firstChild) {
46
+ colors.forEach((color) => {
47
+ const btn = document.createElement('button');
48
+ btn.style.background = color;
49
+ btn.dataset.color = color;
50
+ btn.addEventListener('click', () => {
51
+ this.dispatchEvent(new CustomEvent('color-selected', { detail: { color } }));
52
+ });
53
+ root.appendChild(btn);
54
+ });
55
+ }
56
+ };
57
+ }
58
+
59
+ /** @private */
60
+ __openedOrTargetChanged(opened, target) {
61
+ if (target) {
62
+ target.setAttribute('aria-expanded', opened ? 'true' : 'false');
63
+ }
64
+ }
65
+
66
+ /** @protected */
67
+ _onOverlayEscapePress() {
68
+ this.target.focus();
69
+ }
70
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2024 Vaadin Ltd.
4
+ *
5
+ * This program is available under Vaadin Commercial License and Service Terms.
6
+ *
7
+ *
8
+ * See https://vaadin.com/commercial-license-and-service-terms for the full
9
+ * license.
10
+ */
11
+ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
12
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
13
+ import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
14
+ import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
15
+ import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
16
+ import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
17
+ import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
18
+ import { RichTextEditorPopupMixin } from './vaadin-rich-text-editor-popup-mixin.js';
19
+
20
+ registerStyles('vaadin-rich-text-editor-popup-overlay', [overlayStyles], {
21
+ moduleId: 'vaadin-rich-text-editor-popup-overlay-styles',
22
+ });
23
+
24
+ /**
25
+ * An element used internally by `<vaadin-rich-text-editor>`. Not intended to be used separately.
26
+ *
27
+ * @customElement
28
+ * @extends HTMLElement
29
+ * @mixes RichTextEditorPopupMixin
30
+ * @private
31
+ */
32
+ class RichTextEditorPopup extends RichTextEditorPopupMixin(PolymerElement) {
33
+ static get is() {
34
+ return 'vaadin-rich-text-editor-popup';
35
+ }
36
+
37
+ static get template() {
38
+ return html`
39
+ <style>
40
+ :host {
41
+ display: none;
42
+ }
43
+ </style>
44
+ <vaadin-rich-text-editor-popup-overlay
45
+ renderer="[[renderer]]"
46
+ opened="{{opened}}"
47
+ position-target="[[target]]"
48
+ no-vertical-overlap
49
+ horizontal-align="start"
50
+ vertical-align="top"
51
+ on-vaadin-overlay-escape-press="_onOverlayEscapePress"
52
+ focus-trap
53
+ ></vaadin-rich-text-editor-popup-overlay>
54
+ `;
55
+ }
56
+ }
57
+
58
+ defineCustomElement(RichTextEditorPopup);
59
+
60
+ export { RichTextEditorPopup };
61
+
62
+ /**
63
+ * An element used internally by `<vaadin-rich-text-editor>`. Not intended to be used separately.
64
+ *
65
+ * @customElement
66
+ * @extends HTMLElement
67
+ * @mixes DirMixin
68
+ * @mixes ThemableMixin
69
+ * @mixes OverlayMixin
70
+ * @mixes PositionMixin
71
+ * @private
72
+ */
73
+ class RichTextEditorPopupOverlay extends PositionMixin(OverlayMixin(DirMixin(ThemableMixin(PolymerElement)))) {
74
+ static get is() {
75
+ return 'vaadin-rich-text-editor-popup-overlay';
76
+ }
77
+
78
+ static get template() {
79
+ return html`
80
+ <div id="backdrop" part="backdrop" hidden></div>
81
+ <div part="overlay" id="overlay">
82
+ <div part="content" id="content"><slot></slot></div>
83
+ </div>
84
+ `;
85
+ }
86
+ }
87
+
88
+ defineCustomElement(RichTextEditorPopupOverlay);
@@ -141,6 +141,40 @@ export const buttonsStyles = css`
141
141
  content: '</>';
142
142
  font-size: 0.875em;
143
143
  }
144
+
145
+ [part~='toolbar-button-background']::before,
146
+ [part~='toolbar-button-color']::before {
147
+ content: 'A';
148
+ font-size: 1em;
149
+ }
150
+
151
+ [part~='toolbar-button-color']::after {
152
+ content: '';
153
+ position: absolute;
154
+ bottom: 4px;
155
+ left: 25%;
156
+ right: 25%;
157
+ width: 50%;
158
+ height: 4px;
159
+ background-color: var(--_color-value, currentColor);
160
+ }
161
+
162
+ [part~='toolbar-button-background']::before {
163
+ z-index: 1;
164
+ }
165
+
166
+ [part~='toolbar-button-background']::after {
167
+ content: '';
168
+ position: absolute;
169
+ inset: 20%;
170
+ background: repeating-linear-gradient(
171
+ 135deg,
172
+ var(--_background-value, currentColor),
173
+ var(--_background-value, currentColor) 1px,
174
+ transparent 1px,
175
+ transparent 2px
176
+ );
177
+ }
144
178
  `;
145
179
 
146
180
  export const toolbarStyles = [iconsStyles, buttonsStyles];
@@ -57,6 +57,7 @@ export interface RichTextEditorEventMap extends HTMLElementEventMap, RichTextEdi
57
57
  * `toolbar-group-history` | The group for histroy controls
58
58
  * `toolbar-group-emphasis` | The group for emphasis controls
59
59
  * `toolbar-group-heading` | The group for heading controls
60
+ * `toolbar-group-style` | The group for style controls
60
61
  * `toolbar-group-glyph-transformation` | The group for glyph transformation controls
61
62
  * `toolbar-group-group-list` | The group for group list controls
62
63
  * `toolbar-group-alignment` | The group for alignment controls
@@ -71,6 +72,8 @@ export interface RichTextEditorEventMap extends HTMLElementEventMap, RichTextEdi
71
72
  * `toolbar-button-italic` | The "italic" button
72
73
  * `toolbar-button-underline` | The "underline" button
73
74
  * `toolbar-button-strike` | The "strike-through" button
75
+ * `toolbar-button-color` | The "color" button
76
+ * `toolbar-button-background` | The "background" button
74
77
  * `toolbar-button-h1` | The "header 1" button
75
78
  * `toolbar-button-h2` | The "header 2" button
76
79
  * `toolbar-button-h3` | The "header 3" button
@@ -12,6 +12,7 @@ import '@vaadin/button/src/vaadin-button.js';
12
12
  import '@vaadin/confirm-dialog/src/vaadin-confirm-dialog.js';
13
13
  import '@vaadin/text-field/src/vaadin-text-field.js';
14
14
  import '@vaadin/tooltip/src/vaadin-tooltip.js';
15
+ import './vaadin-rich-text-editor-popup.js';
15
16
  import './vaadin-rich-text-editor-toolbar-styles.js';
16
17
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
17
18
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
@@ -55,6 +56,7 @@ registerStyles('vaadin-rich-text-editor', richTextEditorStyles, { moduleId: 'vaa
55
56
  * `toolbar-group-history` | The group for histroy controls
56
57
  * `toolbar-group-emphasis` | The group for emphasis controls
57
58
  * `toolbar-group-heading` | The group for heading controls
59
+ * `toolbar-group-style` | The group for style controls
58
60
  * `toolbar-group-glyph-transformation` | The group for glyph transformation controls
59
61
  * `toolbar-group-group-list` | The group for group list controls
60
62
  * `toolbar-group-alignment` | The group for alignment controls
@@ -69,6 +71,8 @@ registerStyles('vaadin-rich-text-editor', richTextEditorStyles, { moduleId: 'vaa
69
71
  * `toolbar-button-italic` | The "italic" button
70
72
  * `toolbar-button-underline` | The "underline" button
71
73
  * `toolbar-button-strike` | The "strike-through" button
74
+ * `toolbar-button-color` | The "color" button
75
+ * `toolbar-button-background` | The "background" button
72
76
  * `toolbar-button-h1` | The "header 1" button
73
77
  * `toolbar-button-h2` | The "header 2" button
74
78
  * `toolbar-button-h3` | The "header 3" button
@@ -130,6 +134,25 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
130
134
  <vaadin-tooltip for="btn-strike" text="[[i18n.strike]]"></vaadin-tooltip>
131
135
  </span>
132
136
 
137
+ <span part="toolbar-group toolbar-group-style">
138
+ <!-- Color -->
139
+ <button
140
+ id="btn-color"
141
+ type="button"
142
+ part="toolbar-button toolbar-button-color"
143
+ on-click="__onColorClick"
144
+ ></button>
145
+ <vaadin-tooltip for="btn-color" text="[[i18n.color]]"></vaadin-tooltip>
146
+ <!-- Background -->
147
+ <button
148
+ id="btn-background"
149
+ type="button"
150
+ part="toolbar-button toolbar-button-background"
151
+ on-click="__onBackgroundClick"
152
+ ></button>
153
+ <vaadin-tooltip for="btn-background" text="[[i18n.background]]"></vaadin-tooltip>
154
+ </span>
155
+
133
156
  <span part="toolbar-group toolbar-group-heading">
134
157
  <!-- Header buttons -->
135
158
  <button
@@ -305,6 +328,20 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
305
328
  [[i18n.cancel]]
306
329
  </vaadin-button>
307
330
  </vaadin-confirm-dialog>
331
+
332
+ <vaadin-rich-text-editor-popup
333
+ id="colorPopup"
334
+ colors="[[colorOptions]]"
335
+ opened="{{_colorEditing}}"
336
+ on-color-selected="__onColorSelected"
337
+ ></vaadin-rich-text-editor-popup>
338
+
339
+ <vaadin-rich-text-editor-popup
340
+ id="backgroundPopup"
341
+ colors="[[colorOptions]]"
342
+ opened="{{_backgroundEditing}}"
343
+ on-color-selected="__onBackgroundSelected"
344
+ ></vaadin-rich-text-editor-popup>
308
345
  `;
309
346
  }
310
347