@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 +1 -1
- package/package.json +15 -14
- package/src/vaadin-lit-rich-text-editor-popup.js +91 -0
- package/src/vaadin-lit-rich-text-editor.js +46 -0
- package/src/vaadin-rich-text-editor-mixin.d.ts +12 -0
- package/src/vaadin-rich-text-editor-mixin.js +91 -1
- package/src/vaadin-rich-text-editor-popup-mixin.js +70 -0
- package/src/vaadin-rich-text-editor-popup.js +88 -0
- package/src/vaadin-rich-text-editor-toolbar-styles.js +34 -0
- package/src/vaadin-rich-text-editor.d.ts +3 -0
- package/src/vaadin-rich-text-editor.js +37 -0
- package/theme/lumo/vaadin-rich-text-editor-styles.js +50 -3
- package/theme/material/vaadin-rich-text-editor-styles.js +40 -0
- package/vendor/vaadin-quill.js +3 -3
- package/vendor/vaadin-quill.js.map +1 -0
- package/web-types.json +13 -2
- package/web-types.lit.json +9 -2
- package/vendor/vaadin-quill.min.js.map +0 -1
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
|
|
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.
|
|
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": "
|
|
45
|
-
"@vaadin/component-base": "
|
|
46
|
-
"@vaadin/confirm-dialog": "
|
|
47
|
-
"@vaadin/
|
|
48
|
-
"@vaadin/
|
|
49
|
-
"@vaadin/
|
|
50
|
-
"@vaadin/vaadin-
|
|
51
|
-
"@vaadin/vaadin-
|
|
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
|
-
"@
|
|
56
|
-
"@vaadin/
|
|
57
|
-
"@vaadin/testing-helpers": "^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": "^
|
|
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": "
|
|
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, (
|
|
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
|
|