@vaadin/rich-text-editor 24.4.0-dev.b3e1d14600 → 24.5.0-alpha1
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/LICENSE +3 -1141
- package/README.md +0 -1
- package/package.json +11 -11
- package/src/vaadin-lit-rich-text-editor-popup.js +91 -0
- package/src/vaadin-lit-rich-text-editor.d.ts +1 -1
- package/src/vaadin-lit-rich-text-editor.js +48 -2
- package/src/vaadin-rich-text-editor-content-styles.js +1 -1
- package/src/vaadin-rich-text-editor-icons.js +1 -1
- package/src/vaadin-rich-text-editor-mixin.d.ts +13 -1
- package/src/vaadin-rich-text-editor-mixin.js +101 -5
- 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-styles.js +1 -1
- package/src/vaadin-rich-text-editor-toolbar-styles.js +35 -1
- package/src/vaadin-rich-text-editor.d.ts +4 -1
- package/src/vaadin-rich-text-editor.js +38 -1
- package/theme/lumo/vaadin-lit-rich-text-editor.d.ts +6 -0
- package/theme/lumo/vaadin-rich-text-editor-styles.d.ts +4 -0
- package/theme/lumo/vaadin-rich-text-editor-styles.js +47 -2
- package/theme/lumo/vaadin-rich-text-editor.d.ts +6 -0
- package/theme/material/vaadin-lit-rich-text-editor.d.ts +6 -0
- package/theme/material/vaadin-rich-text-editor-styles.d.ts +1 -0
- package/theme/material/vaadin-rich-text-editor-styles.js +40 -0
- package/theme/material/vaadin-rich-text-editor.d.ts +6 -0
- package/web-types.json +121 -0
- package/web-types.lit.json +83 -0
package/README.md
CHANGED
|
@@ -7,7 +7,6 @@ An input field web component for entering rich text.
|
|
|
7
7
|
[Documentation + Live Demo ↗](https://vaadin.com/docs/latest/components/rich-text-editor)
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@vaadin/rich-text-editor)
|
|
10
|
-
[](https://discord.gg/PHmkCKC)
|
|
11
10
|
|
|
12
11
|
```html
|
|
13
12
|
<vaadin-rich-text-editor></vaadin-rich-text-editor>
|
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-alpha1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
43
43
|
"@polymer/polymer": "^3.0.0",
|
|
44
|
-
"@vaadin/button": "24.
|
|
45
|
-
"@vaadin/component-base": "24.
|
|
46
|
-
"@vaadin/confirm-dialog": "24.
|
|
47
|
-
"@vaadin/text-field": "24.
|
|
48
|
-
"@vaadin/tooltip": "24.
|
|
49
|
-
"@vaadin/vaadin-lumo-styles": "24.
|
|
50
|
-
"@vaadin/vaadin-material-styles": "24.
|
|
51
|
-
"@vaadin/vaadin-themable-mixin": "24.
|
|
44
|
+
"@vaadin/button": "24.5.0-alpha1",
|
|
45
|
+
"@vaadin/component-base": "24.5.0-alpha1",
|
|
46
|
+
"@vaadin/confirm-dialog": "24.5.0-alpha1",
|
|
47
|
+
"@vaadin/text-field": "24.5.0-alpha1",
|
|
48
|
+
"@vaadin/tooltip": "24.5.0-alpha1",
|
|
49
|
+
"@vaadin/vaadin-lumo-styles": "24.5.0-alpha1",
|
|
50
|
+
"@vaadin/vaadin-material-styles": "24.5.0-alpha1",
|
|
51
|
+
"@vaadin/vaadin-themable-mixin": "24.5.0-alpha1",
|
|
52
52
|
"lit": "^3.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@esm-bundle/chai": "^4.3.4",
|
|
56
|
-
"@vaadin/a11y-base": "24.
|
|
56
|
+
"@vaadin/a11y-base": "24.5.0-alpha1",
|
|
57
57
|
"@vaadin/testing-helpers": "^0.6.0",
|
|
58
58
|
"gulp": "^4.0.2",
|
|
59
59
|
"gulp-cli": "^2.3.0",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"web-types.json",
|
|
66
66
|
"web-types.lit.json"
|
|
67
67
|
],
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "57806caac5468532a3b4e3dbdda730cd0fca193a"
|
|
69
69
|
}
|
|
@@ -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);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2000 -
|
|
3
|
+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
|
|
4
4
|
*
|
|
5
5
|
* This program is available under Vaadin Commercial License and Service Terms.
|
|
6
6
|
*
|
|
@@ -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';
|
|
@@ -25,7 +26,7 @@ import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
|
|
|
25
26
|
*
|
|
26
27
|
* ## Disclaimer
|
|
27
28
|
*
|
|
28
|
-
* This component is an experiment not
|
|
29
|
+
* This component is an experiment and not yet a part of Vaadin platform.
|
|
29
30
|
* There is no ETA regarding specific Vaadin version where it'll land.
|
|
30
31
|
*/
|
|
31
32
|
class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
|
|
@@ -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;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2000 -
|
|
3
|
+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
|
|
4
4
|
*
|
|
5
5
|
* This program is available under Vaadin Commercial License and Service Terms.
|
|
6
6
|
*
|
|
@@ -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),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2000 -
|
|
3
|
+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
|
|
4
4
|
*
|
|
5
5
|
* This program is available under Vaadin Commercial License and Service Terms.
|
|
6
6
|
*
|
|
@@ -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
|
|
|
@@ -315,6 +363,15 @@ export const RichTextEditorMixin = (superClass) =>
|
|
|
315
363
|
});
|
|
316
364
|
});
|
|
317
365
|
|
|
366
|
+
this._editor.on('editor-change', () => {
|
|
367
|
+
const selection = this._editor.getSelection();
|
|
368
|
+
if (selection) {
|
|
369
|
+
const format = this._editor.getFormat(selection.index, selection.length);
|
|
370
|
+
this._toolbar.style.setProperty('--_color-value', format.color || null);
|
|
371
|
+
this._toolbar.style.setProperty('--_background-value', format.background || null);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
318
375
|
const TAB_KEY = 9;
|
|
319
376
|
|
|
320
377
|
editorContent.addEventListener('keydown', (e) => {
|
|
@@ -345,8 +402,9 @@ export const RichTextEditorMixin = (superClass) =>
|
|
|
345
402
|
});
|
|
346
403
|
|
|
347
404
|
editorContent.addEventListener('focus', () => {
|
|
348
|
-
//
|
|
349
|
-
|
|
405
|
+
// When editing link, editor gets focus while dialog is still open.
|
|
406
|
+
// Keep toolbar state as clicked in this case to fire change event.
|
|
407
|
+
if (this._toolbarState === STATE.CLICKED && !this._linkEditing) {
|
|
350
408
|
this._cleanToolbarState();
|
|
351
409
|
}
|
|
352
410
|
});
|
|
@@ -366,6 +424,9 @@ export const RichTextEditorMixin = (superClass) =>
|
|
|
366
424
|
|
|
367
425
|
this._addToolbarListeners();
|
|
368
426
|
|
|
427
|
+
this.$.backgroundPopup.target = this.shadowRoot.querySelector('#btn-background');
|
|
428
|
+
this.$.colorPopup.target = this.shadowRoot.querySelector('#btn-color');
|
|
429
|
+
|
|
369
430
|
requestAnimationFrame(() => {
|
|
370
431
|
this.$.linkDialog.$.dialog.$.overlay.addEventListener('vaadin-overlay-open', () => {
|
|
371
432
|
this.$.linkUrl.focus();
|
|
@@ -667,15 +728,50 @@ export const RichTextEditorMixin = (superClass) =>
|
|
|
667
728
|
}
|
|
668
729
|
}
|
|
669
730
|
|
|
731
|
+
/** @private */
|
|
732
|
+
__onColorClick() {
|
|
733
|
+
this._colorEditing = true;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/** @private */
|
|
737
|
+
__onColorSelected(event) {
|
|
738
|
+
const color = event.detail.color;
|
|
739
|
+
this._colorValue = color === '#000000' ? null : color;
|
|
740
|
+
this._markToolbarClicked();
|
|
741
|
+
this._editor.format('color', this._colorValue, SOURCE.USER);
|
|
742
|
+
this._toolbar.style.setProperty('--_color-value', this._colorValue);
|
|
743
|
+
this._colorEditing = false;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/** @private */
|
|
747
|
+
__onBackgroundClick() {
|
|
748
|
+
this._backgroundEditing = true;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/** @private */
|
|
752
|
+
__onBackgroundSelected(event) {
|
|
753
|
+
const color = event.detail.color;
|
|
754
|
+
this._backgroundValue = color === '#ffffff' ? null : color;
|
|
755
|
+
this._markToolbarClicked();
|
|
756
|
+
this._editor.format('background', this._backgroundValue, SOURCE.USER);
|
|
757
|
+
this._toolbar.style.setProperty('--_background-value', this._backgroundValue);
|
|
758
|
+
this._backgroundEditing = false;
|
|
759
|
+
}
|
|
760
|
+
|
|
670
761
|
/** @private */
|
|
671
762
|
__updateHtmlValue() {
|
|
672
763
|
const editor = this.shadowRoot.querySelector('.ql-editor');
|
|
673
764
|
let content = editor.innerHTML;
|
|
674
765
|
|
|
675
766
|
// Remove Quill classes, e.g. ql-syntax, except for align
|
|
676
|
-
content = content.replace(
|
|
767
|
+
content = content.replace(/class="([^"]*)"/gu, (match, group1) => {
|
|
768
|
+
const classes = group1.split(' ').filter((className) => {
|
|
769
|
+
return !className.startsWith('ql-') || className.startsWith('ql-align');
|
|
770
|
+
});
|
|
771
|
+
return `class="${classes.join(' ')}"`;
|
|
772
|
+
});
|
|
677
773
|
// Remove meta spans, e.g. cursor which are empty after Quill classes removed
|
|
678
|
-
content = content.replace(
|
|
774
|
+
content = content.replace(/<span[^>]*><\/span>/gu, '');
|
|
679
775
|
|
|
680
776
|
// Replace Quill align classes with inline styles
|
|
681
777
|
[this.__dir === 'rtl' ? 'left' : 'right', 'center', 'justify'].forEach((align) => {
|
|
@@ -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);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2000 -
|
|
3
|
+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
|
|
4
4
|
*
|
|
5
5
|
* This program is available under Vaadin Commercial License and Service Terms.
|
|
6
6
|
*
|
|
@@ -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];
|