@vaadin/rich-text-editor 25.0.0-alpha2 → 25.0.0-alpha21

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.
@@ -13,36 +13,37 @@ 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
15
  import './vaadin-rich-text-editor-popup.js';
16
- import { html, LitElement } from 'lit';
16
+ import { html, LitElement, render } from 'lit';
17
+ import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
17
18
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
18
19
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
19
20
  import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
21
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
20
22
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
23
+ import { richTextEditorStyles } from './styles/vaadin-rich-text-editor-base-styles.js';
21
24
  import { RichTextEditorMixin } from './vaadin-rich-text-editor-mixin.js';
22
- import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
23
25
 
24
26
  /**
25
27
  * `<vaadin-rich-text-editor>` is a Web Component for rich text editing.
26
28
  * It provides a set of toolbar controls to apply formatting on the content,
27
29
  * which is stored and can be accessed as HTML5 or JSON string.
28
30
  *
29
- * ```
31
+ * ```html
30
32
  * <vaadin-rich-text-editor></vaadin-rich-text-editor>
31
33
  * ```
32
34
  *
33
35
  * Vaadin Rich Text Editor focuses on the structure, not the styling of content.
34
- * Therefore, the semantic HTML5 tags such as <h1>, <strong> and <ul> are used,
36
+ * Therefore, the semantic HTML5 tags such as `<h1>`, `<strong>` and `<ul>` are used,
35
37
  * and CSS usage is limited to most common cases, like horizontal text alignment.
36
38
  *
37
39
  * ### Styling
38
40
  *
39
41
  * The following state attributes are available for styling:
40
42
  *
41
- * Attribute | Description | Part name
42
- * -------------|-------------|------------
43
- * `disabled` | Set to a disabled text editor | :host
44
- * `readonly` | Set to a readonly text editor | :host
45
- * `on` | Set to a toolbar button applied to the selected text | toolbar-button
43
+ * Attribute | Description
44
+ * -------------|------------------------------
45
+ * `disabled` | Set to a disabled text editor
46
+ * `readonly` | Set to a readonly text editor
46
47
  *
47
48
  * The following shadow DOM parts are available for styling:
48
49
  *
@@ -51,12 +52,13 @@ import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
51
52
  * `content` | The content wrapper
52
53
  * `toolbar` | The toolbar wrapper
53
54
  * `toolbar-group` | The group for toolbar controls
54
- * `toolbar-group-history` | The group for histroy controls
55
+ * `toolbar-group-history` | The group for history controls
55
56
  * `toolbar-group-emphasis` | The group for emphasis controls
56
57
  * `toolbar-group-heading` | The group for heading controls
57
58
  * `toolbar-group-style` | The group for style controls
58
59
  * `toolbar-group-glyph-transformation` | The group for glyph transformation controls
59
- * `toolbar-group-group-list` | The group for group list controls
60
+ * `toolbar-group-list` | The group for list controls
61
+ * `toolbar-group-indent` | The group for indentation controls
60
62
  * `toolbar-group-alignment` | The group for alignment controls
61
63
  * `toolbar-group-rich-text` | The group for rich text controls
62
64
  * `toolbar-group-block` | The group for preformatted block controls
@@ -78,6 +80,8 @@ import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
78
80
  * `toolbar-button-superscript` | The "superscript" button
79
81
  * `toolbar-button-list-ordered` | The "ordered list" button
80
82
  * `toolbar-button-list-bullet` | The "bullet list" button
83
+ * `toolbar-button-outdent` | The "decrease indentation" button
84
+ * `toolbar-button-indent` | The "increase indentation" button
81
85
  * `toolbar-button-align-left` | The "left align" button
82
86
  * `toolbar-button-align-center` | The "center align" button
83
87
  * `toolbar-button-align-right` | The "right align" button
@@ -99,7 +103,9 @@ import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
99
103
  * @mixes RichTextEditorMixin
100
104
  * @mixes ThemableMixin
101
105
  */
102
- class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
106
+ class RichTextEditor extends RichTextEditorMixin(
107
+ ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))),
108
+ ) {
103
109
  static get is() {
104
110
  return 'vaadin-rich-text-editor';
105
111
  }
@@ -112,6 +118,12 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
112
118
  return richTextEditorStyles;
113
119
  }
114
120
 
121
+ static get lumoInjector() {
122
+ return {
123
+ includeBaseStyles: true,
124
+ };
125
+ }
126
+
115
127
  /** @protected */
116
128
  render() {
117
129
  return html`
@@ -124,35 +136,51 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
124
136
  id="btn-undo"
125
137
  type="button"
126
138
  part="toolbar-button toolbar-button-undo"
139
+ aria-label="${this.__effectiveI18n.undo}"
127
140
  @click="${this._undo}"
128
141
  ></button>
129
- <vaadin-tooltip for="btn-undo" .text="${this.__effectiveI18n.undo}"></vaadin-tooltip>
130
142
 
131
143
  <button
132
144
  id="btn-redo"
133
145
  type="button"
134
146
  part="toolbar-button toolbar-button-redo"
147
+ aria-label="${this.__effectiveI18n.redo}"
135
148
  @click="${this._redo}"
136
149
  ></button>
137
- <vaadin-tooltip for="btn-redo" .text="${this.__effectiveI18n.redo}"></vaadin-tooltip>
138
150
  </span>
139
151
 
140
152
  <span part="toolbar-group toolbar-group-emphasis">
141
153
  <!-- Bold -->
142
- <button id="btn-bold" class="ql-bold" part="toolbar-button toolbar-button-bold"></button>
143
- <vaadin-tooltip for="btn-bold" .text="${this.__effectiveI18n.bold}"></vaadin-tooltip>
154
+ <button
155
+ id="btn-bold"
156
+ class="ql-bold"
157
+ part="toolbar-button toolbar-button-bold"
158
+ aria-label="${this.__effectiveI18n.bold}"
159
+ ></button>
144
160
 
145
161
  <!-- Italic -->
146
- <button id="btn-italic" class="ql-italic" part="toolbar-button toolbar-button-italic"></button>
147
- <vaadin-tooltip for="btn-italic" .text="${this.__effectiveI18n.italic}"></vaadin-tooltip>
162
+ <button
163
+ id="btn-italic"
164
+ class="ql-italic"
165
+ part="toolbar-button toolbar-button-italic"
166
+ aria-label="${this.__effectiveI18n.italic}"
167
+ ></button>
148
168
 
149
169
  <!-- Underline -->
150
- <button id="btn-underline" class="ql-underline" part="toolbar-button toolbar-button-underline"></button>
151
- <vaadin-tooltip for="btn-underline" .text="${this.__effectiveI18n.underline}"></vaadin-tooltip>
170
+ <button
171
+ id="btn-underline"
172
+ class="ql-underline"
173
+ part="toolbar-button toolbar-button-underline"
174
+ aria-label="${this.__effectiveI18n.underline}"
175
+ ></button>
152
176
 
153
177
  <!-- Strike -->
154
- <button id="btn-strike" class="ql-strike" part="toolbar-button toolbar-button-strike"></button>
155
- <vaadin-tooltip for="btn-strike" .text="${this.__effectiveI18n.strike}"></vaadin-tooltip>
178
+ <button
179
+ id="btn-strike"
180
+ class="ql-strike"
181
+ part="toolbar-button toolbar-button-strike"
182
+ aria-label="${this.__effectiveI18n.strike}"
183
+ ></button>
156
184
  </span>
157
185
 
158
186
  <span part="toolbar-group toolbar-group-style">
@@ -161,17 +189,17 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
161
189
  id="btn-color"
162
190
  type="button"
163
191
  part="toolbar-button toolbar-button-color"
192
+ aria-label="${this.__effectiveI18n.color}"
164
193
  @click="${this.__onColorClick}"
165
194
  ></button>
166
- <vaadin-tooltip for="btn-color" .text="${this.__effectiveI18n.color}"></vaadin-tooltip>
167
195
  <!-- Background -->
168
196
  <button
169
197
  id="btn-background"
170
198
  type="button"
171
199
  part="toolbar-button toolbar-button-background"
200
+ aria-label="${this.__effectiveI18n.background}"
172
201
  @click="${this.__onBackgroundClick}"
173
202
  ></button>
174
- <vaadin-tooltip for="btn-background" .text="${this.__effectiveI18n.background}"></vaadin-tooltip>
175
203
  </span>
176
204
 
177
205
  <span part="toolbar-group toolbar-group-heading">
@@ -182,24 +210,24 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
182
210
  class="ql-header"
183
211
  value="1"
184
212
  part="toolbar-button toolbar-button-h1"
213
+ aria-label="${this.__effectiveI18n.h1}"
185
214
  ></button>
186
- <vaadin-tooltip for="btn-h1" .text="${this.__effectiveI18n.h1}"></vaadin-tooltip>
187
215
  <button
188
216
  id="btn-h2"
189
217
  type="button"
190
218
  class="ql-header"
191
219
  value="2"
192
220
  part="toolbar-button toolbar-button-h2"
221
+ aria-label="${this.__effectiveI18n.h2}"
193
222
  ></button>
194
- <vaadin-tooltip for="btn-h2" .text="${this.__effectiveI18n.h2}"></vaadin-tooltip>
195
223
  <button
196
224
  id="btn-h3"
197
225
  type="button"
198
226
  class="ql-header"
199
227
  value="3"
200
228
  part="toolbar-button toolbar-button-h3"
229
+ aria-label="${this.__effectiveI18n.h3}"
201
230
  ></button>
202
- <vaadin-tooltip for="btn-h3" .text="${this.__effectiveI18n.h3}"></vaadin-tooltip>
203
231
  </span>
204
232
 
205
233
  <span part="toolbar-group toolbar-group-glyph-transformation">
@@ -209,15 +237,15 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
209
237
  class="ql-script"
210
238
  value="sub"
211
239
  part="toolbar-button toolbar-button-subscript"
240
+ aria-label="${this.__effectiveI18n.subscript}"
212
241
  ></button>
213
- <vaadin-tooltip for="btn-subscript" .text="${this.__effectiveI18n.subscript}"></vaadin-tooltip>
214
242
  <button
215
243
  id="btn-superscript"
216
244
  class="ql-script"
217
245
  value="super"
218
246
  part="toolbar-button toolbar-button-superscript"
247
+ aria-label="${this.__effectiveI18n.superscript}"
219
248
  ></button>
220
- <vaadin-tooltip for="btn-superscript" text="${this.__effectiveI18n.superscript}"></vaadin-tooltip>
221
249
  </span>
222
250
 
223
251
  <span part="toolbar-group toolbar-group-list">
@@ -228,16 +256,37 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
228
256
  class="ql-list"
229
257
  value="ordered"
230
258
  part="toolbar-button toolbar-button-list-ordered"
259
+ aria-label="${this.__effectiveI18n.listOrdered}"
231
260
  ></button>
232
- <vaadin-tooltip for="btn-ol" text="${this.__effectiveI18n.listOrdered}"></vaadin-tooltip>
233
261
  <button
234
262
  id="btn-ul"
235
263
  type="button"
236
264
  class="ql-list"
237
265
  value="bullet"
238
266
  part="toolbar-button toolbar-button-list-bullet"
267
+ aria-label="${this.__effectiveI18n.listBullet}"
268
+ ></button>
269
+ </span>
270
+
271
+ <span part="toolbar-group toolbar-group-indent">
272
+ <!-- Decrease -->
273
+ <button
274
+ id="btn-outdent"
275
+ type="button"
276
+ class="ql-indent"
277
+ value="-1"
278
+ part="toolbar-button toolbar-button-outdent"
279
+ aria-label="${this.__effectiveI18n.outdent}"
280
+ ></button>
281
+ <!-- Increase -->
282
+ <button
283
+ id="btn-indent"
284
+ type="button"
285
+ class="ql-indent"
286
+ value="+1"
287
+ part="toolbar-button toolbar-button-indent"
288
+ aria-label="${this.__effectiveI18n.indent}"
239
289
  ></button>
240
- <vaadin-tooltip for="btn-ul" text="${this.__effectiveI18n.listBullet}"></vaadin-tooltip>
241
290
  </span>
242
291
 
243
292
  <span part="toolbar-group toolbar-group-alignment">
@@ -248,24 +297,24 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
248
297
  class="ql-align"
249
298
  value=""
250
299
  part="toolbar-button toolbar-button-align-left"
300
+ aria-label="${this.__effectiveI18n.alignLeft}"
251
301
  ></button>
252
- <vaadin-tooltip for="btn-left" .text="${this.__effectiveI18n.alignLeft}"></vaadin-tooltip>
253
302
  <button
254
303
  id="btn-center"
255
304
  type="button"
256
305
  class="ql-align"
257
306
  value="center"
258
307
  part="toolbar-button toolbar-button-align-center"
308
+ aria-label="${this.__effectiveI18n.alignCenter}"
259
309
  ></button>
260
- <vaadin-tooltip for="btn-center" .text="${this.__effectiveI18n.alignCenter}"></vaadin-tooltip>
261
310
  <button
262
311
  id="btn-right"
263
312
  type="button"
264
313
  class="ql-align"
265
314
  value="right"
266
315
  part="toolbar-button toolbar-button-align-right"
316
+ aria-label="${this.__effectiveI18n.alignRight}"
267
317
  ></button>
268
- <vaadin-tooltip for="btn-right" .text="${this.__effectiveI18n.alignRight}"></vaadin-tooltip>
269
318
  </span>
270
319
 
271
320
  <span part="toolbar-group toolbar-group-rich-text">
@@ -274,18 +323,18 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
274
323
  id="btn-image"
275
324
  type="button"
276
325
  part="toolbar-button toolbar-button-image"
326
+ aria-label="${this.__effectiveI18n.image}"
277
327
  @touchend="${this._onImageTouchEnd}"
278
328
  @click="${this._onImageClick}"
279
329
  ></button>
280
- <vaadin-tooltip for="btn-image" .text="${this.__effectiveI18n.image}"></vaadin-tooltip>
281
330
  <!-- Link -->
282
331
  <button
283
332
  id="btn-link"
284
333
  type="button"
285
334
  part="toolbar-button toolbar-button-link"
335
+ aria-label="${this.__effectiveI18n.link}"
286
336
  @click="${this._onLinkClick}"
287
337
  ></button>
288
- <vaadin-tooltip for="btn-link" .text="${this.__effectiveI18n.link}"></vaadin-tooltip>
289
338
  </span>
290
339
 
291
340
  <span part="toolbar-group toolbar-group-block">
@@ -295,22 +344,27 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
295
344
  type="button"
296
345
  class="ql-blockquote"
297
346
  part="toolbar-button toolbar-button-blockquote"
347
+ aria-label="${this.__effectiveI18n.blockquote}"
298
348
  ></button>
299
- <vaadin-tooltip for="btn-blockquote" .text="${this.__effectiveI18n.blockquote}"></vaadin-tooltip>
300
349
  <!-- Code block -->
301
350
  <button
302
351
  id="btn-code"
303
352
  type="button"
304
353
  class="ql-code-block"
305
354
  part="toolbar-button toolbar-button-code-block"
355
+ aria-label="${this.__effectiveI18n.codeBlock}"
306
356
  ></button>
307
- <vaadin-tooltip for="btn-code" .text="${this.__effectiveI18n.codeBlock}"></vaadin-tooltip>
308
357
  </span>
309
358
 
310
359
  <span part="toolbar-group toolbar-group-format">
311
360
  <!-- Clean -->
312
- <button id="btn-clean" type="button" class="ql-clean" part="toolbar-button toolbar-button-clean"></button>
313
- <vaadin-tooltip for="btn-clean" .text="${this.__effectiveI18n.clean}"></vaadin-tooltip>
361
+ <button
362
+ id="btn-clean"
363
+ type="button"
364
+ class="ql-clean"
365
+ part="toolbar-button toolbar-button-clean"
366
+ aria-label="${this.__effectiveI18n.clean}"
367
+ ></button>
314
368
  </span>
315
369
 
316
370
  <input
@@ -326,54 +380,75 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
326
380
  <div class="announcer" aria-live="polite"></div>
327
381
  </div>
328
382
 
329
- <vaadin-confirm-dialog
330
- id="linkDialog"
331
- .opened="${this._linkEditing}"
332
- .header="${this.__effectiveI18n.linkDialogTitle}"
333
- @opened-changed="${this._onLinkEditingChanged}"
334
- >
335
- <vaadin-text-field
336
- id="linkUrl"
337
- .value="${this._linkUrl}"
338
- style="width: 100%;"
339
- @keydown="${this._onLinkKeydown}"
340
- @value-changed="${this._onLinkUrlChanged}"
341
- ></vaadin-text-field>
342
- <vaadin-button id="confirmLink" slot="confirm-button" theme="primary" @click="${this._onLinkEditConfirm}">
343
- ${this.__effectiveI18n.ok}
344
- </vaadin-button>
345
- <vaadin-button
346
- id="removeLink"
347
- slot="reject-button"
348
- theme="error"
349
- @click="${this._onLinkEditRemove}"
350
- ?hidden="${!this._linkRange}"
351
- >
352
- ${this.__effectiveI18n.remove}
353
- </vaadin-button>
354
- <vaadin-button id="cancelLink" slot="cancel-button" @click="${this._onLinkEditCancel}">
355
- ${this.__effectiveI18n.cancel}
356
- </vaadin-button>
357
- </vaadin-confirm-dialog>
358
-
359
- <vaadin-rich-text-editor-popup
360
- id="colorPopup"
361
- .colors="${this.colorOptions}"
362
- .opened="${this._colorEditing}"
363
- @color-selected="${this.__onColorSelected}"
364
- @opened-changed="${this.__onColorEditingChanged}"
365
- ></vaadin-rich-text-editor-popup>
366
-
367
- <vaadin-rich-text-editor-popup
368
- id="backgroundPopup"
369
- .colors="${this.colorOptions}"
370
- .opened="${this._backgroundEditing}"
371
- @color-selected="${this.__onBackgroundSelected}"
372
- @opened-changed="${this.__onBackgroundEditingChanged}"
373
- ></vaadin-rich-text-editor-popup>
383
+ <slot name="tooltip"></slot>
384
+
385
+ <slot name="link-dialog"></slot>
386
+
387
+ <slot name="color-popup"></slot>
388
+
389
+ <slot name="background-popup"></slot>
374
390
  `;
375
391
  }
376
392
 
393
+ /**
394
+ * Override update to render slotted overlays into light DOM after rendering shadow DOM.
395
+ * @param changedProperties
396
+ * @protected
397
+ */
398
+ update(changedProperties) {
399
+ super.update(changedProperties);
400
+
401
+ this.__renderSlottedOverlays();
402
+ }
403
+
404
+ /** @private */
405
+ __renderSlottedOverlays() {
406
+ render(
407
+ html`
408
+ <vaadin-confirm-dialog
409
+ slot="link-dialog"
410
+ cancel-button-visible
411
+ reject-theme="error"
412
+ .opened="${this._linkEditing}"
413
+ .header="${this.__effectiveI18n.linkDialogTitle}"
414
+ .confirmText="${this.__effectiveI18n.ok}"
415
+ .rejectText="${this.__effectiveI18n.remove}"
416
+ .cancelText="${this.__effectiveI18n.cancel}"
417
+ .rejectButtonVisible="${!!this._linkRange}"
418
+ @confirm="${this._onLinkEditConfirm}"
419
+ @cancel="${this._onLinkEditCancel}"
420
+ @reject="${this._onLinkEditRemove}"
421
+ @opened-changed="${this._onLinkEditingChanged}"
422
+ >
423
+ <vaadin-text-field
424
+ .value="${this._linkUrl}"
425
+ style="width: 100%;"
426
+ @keydown="${this._onLinkKeydown}"
427
+ @value-changed="${this._onLinkUrlChanged}"
428
+ ></vaadin-text-field>
429
+ </vaadin-confirm-dialog>
430
+
431
+ <vaadin-rich-text-editor-popup
432
+ slot="color-popup"
433
+ .colors="${this.colorOptions}"
434
+ .opened="${this._colorEditing}"
435
+ @color-selected="${this.__onColorSelected}"
436
+ @opened-changed="${this.__onColorEditingChanged}"
437
+ ></vaadin-rich-text-editor-popup>
438
+
439
+ <vaadin-rich-text-editor-popup
440
+ slot="background-popup"
441
+ .colors="${this.colorOptions}"
442
+ .opened="${this._backgroundEditing}"
443
+ @color-selected="${this.__onBackgroundSelected}"
444
+ @opened-changed="${this.__onBackgroundEditingChanged}"
445
+ ></vaadin-rich-text-editor-popup>
446
+ `,
447
+ this,
448
+ { host: this },
449
+ );
450
+ }
451
+
377
452
  /** @private */
378
453
  __onBackgroundEditingChanged(event) {
379
454
  this._backgroundEditing = event.detail.value;
@@ -386,6 +461,18 @@ class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(Poly
386
461
 
387
462
  /** @private */
388
463
  _onLinkEditingChanged(event) {
464
+ // Autofocus the URL field when the dialog opens
465
+ if (event.detail.value) {
466
+ const confirmDialog = event.target;
467
+ const urlField = confirmDialog.querySelector('vaadin-text-field');
468
+ confirmDialog.$.overlay.addEventListener(
469
+ 'vaadin-overlay-open',
470
+ () => {
471
+ urlField.focus({ focusVisible: isKeyboardActive() });
472
+ },
473
+ { once: true },
474
+ );
475
+ }
389
476
  this._linkEditing = event.detail.value;
390
477
  }
391
478
 
@@ -1,2 +1,2 @@
1
- import './theme/lumo/vaadin-rich-text-editor.js';
1
+ import './src/vaadin-rich-text-editor.js';
2
2
  export * from './src/vaadin-rich-text-editor.js';