@vaadin/rich-text-editor 25.0.0-alpha1 → 25.0.0-alpha11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/rich-text-editor",
3
- "version": "25.0.0-alpha1",
3
+ "version": "25.0.0-alpha11",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -19,12 +19,8 @@
19
19
  "main": "vaadin-rich-text-editor.js",
20
20
  "module": "vaadin-rich-text-editor.js",
21
21
  "type": "module",
22
- "scripts": {
23
- "icons": "gulp icons --gulpfile gulpfile.cjs"
24
- },
25
22
  "files": [
26
23
  "src",
27
- "theme",
28
24
  "vaadin-*.d.ts",
29
25
  "vaadin-*.js",
30
26
  "vendor",
@@ -39,24 +35,21 @@
39
35
  ],
40
36
  "dependencies": {
41
37
  "@open-wc/dedupe-mixin": "^1.3.0",
42
- "@vaadin/button": "25.0.0-alpha1",
43
- "@vaadin/component-base": "25.0.0-alpha1",
44
- "@vaadin/confirm-dialog": "25.0.0-alpha1",
45
- "@vaadin/overlay": "25.0.0-alpha1",
46
- "@vaadin/text-field": "25.0.0-alpha1",
47
- "@vaadin/tooltip": "25.0.0-alpha1",
48
- "@vaadin/vaadin-lumo-styles": "25.0.0-alpha1",
49
- "@vaadin/vaadin-themable-mixin": "25.0.0-alpha1",
38
+ "@vaadin/button": "25.0.0-alpha11",
39
+ "@vaadin/component-base": "25.0.0-alpha11",
40
+ "@vaadin/confirm-dialog": "25.0.0-alpha11",
41
+ "@vaadin/overlay": "25.0.0-alpha11",
42
+ "@vaadin/text-field": "25.0.0-alpha11",
43
+ "@vaadin/tooltip": "25.0.0-alpha11",
44
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha11",
50
45
  "lit": "^3.0.0"
51
46
  },
52
47
  "devDependencies": {
53
- "@vaadin/a11y-base": "25.0.0-alpha1",
54
- "@vaadin/chai-plugins": "25.0.0-alpha1",
55
- "@vaadin/test-runner-commands": "25.0.0-alpha1",
56
- "@vaadin/testing-helpers": "^1.1.0",
57
- "gulp": "^5.0.0",
58
- "gulp-cli": "^3.0.0",
59
- "gulp-iconfont": "^11.0.0",
48
+ "@vaadin/a11y-base": "25.0.0-alpha11",
49
+ "@vaadin/chai-plugins": "25.0.0-alpha11",
50
+ "@vaadin/test-runner-commands": "25.0.0-alpha11",
51
+ "@vaadin/testing-helpers": "^2.0.0",
52
+ "@vaadin/vaadin-lumo-styles": "25.0.0-alpha11",
60
53
  "sinon": "^18.0.0"
61
54
  },
62
55
  "cvdlName": "vaadin-rich-text-editor",
@@ -64,5 +57,5 @@
64
57
  "web-types.json",
65
58
  "web-types.lit.json"
66
59
  ],
67
- "gitHead": "b8c22a4a0c64156210d0daac96b43ae4e5526d49"
60
+ "gitHead": "abfd315ba5a7484a613e0768635a4e8fe945a44b"
68
61
  }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 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 } from 'lit';
12
+
13
+ export const icons = css`
14
+ :host {
15
+ --_vaadin-icon-align-center: url('data:image/svg+xml;utf8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 10H6M21 6H3M21 14H3M18 18H6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
16
+ --_vaadin-icon-align-left: url('data:image/svg+xml;utf8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16 10H3M20 6H3M20 14H3M16 18H3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
17
+ --_vaadin-icon-align-right: url('data:image/svg+xml;utf8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21 10H8M21 6H4M21 14H4M21 18H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
18
+ --_vaadin-icon-background: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.6 12L12 9.4L8 13.4L10.575 16L14.6 12ZM13.425 8L16 10.575L20 6.6L17.4 4L13.425 8ZM11.325 7.275L16.725 12.675L12 17.425C11.6 17.825 11.1292 18.025 10.5875 18.025C10.0458 18.025 9.575 17.825 9.175 17.425L8.5 18H3.5L6.65 14.875C6.25 14.475 6.04167 13.9958 6.025 13.4375C6.00833 12.8792 6.2 12.4 6.6 12L11.325 7.275ZM11.325 7.275L16 2.6C16.4 2.2 16.8708 2 17.4125 2C17.9542 2 18.425 2.2 18.825 2.6L21.425 5.175C21.825 5.575 22.025 6.04583 22.025 6.5875C22.025 7.12917 21.825 7.6 21.425 8L16.725 12.675L11.325 7.275Z" fill="currentColor"/></svg>');
19
+ --_vaadin-icon-bold: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linejoin="round" d="M6.75 3.744h-.753v8.25h7.125a4.125 4.125 0 0 0 0-8.25H6.75Zm0 0v.38m0 16.122h6.747a4.5 4.5 0 0 0 0-9.001h-7.5v9h.753Zm0 0v-.37m0-15.751h6a3.75 3.75 0 1 1 0 7.5h-6m0-7.5v7.5m0 0v8.25m0-8.25h6.375a4.125 4.125 0 0 1 0 8.25H6.75m.747-15.38h4.875a3.375 3.375 0 0 1 0 6.75H7.497v-6.75Zm0 7.5h5.25a3.75 3.75 0 0 1 0 7.5h-5.25v-7.5Z" /></svg>');
20
+ --_vaadin-icon-clear: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="m528-546-93-93-121-121h486v120H568l-40 94ZM792-56 460-388l-80 188H249l119-280L56-792l56-56 736 736-56 56Z"/></svg>');
21
+ --_vaadin-icon-code: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16 18L22 12L16 6M8 6L2 12L8 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
22
+ --_vaadin-icon-color: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.5 17L10.75 3H13.25L18.5 17H16.1L14.85 13.4H9.2L7.9 17H5.5ZM9.9 11.4H14.1L12.05 5.6H11.95L9.9 11.4Z" fill="currentColor"/></svg>');
23
+ --_vaadin-icon-color-underline: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 24V20H22V24H2Z" fill="currentColor"/></svg>');
24
+ --_vaadin-icon-h1: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.243 4.493v7.5m0 0v7.502m0-7.501h10.5m0-7.5v7.5m0 0v7.501m4.501-8.627 2.25-1.5v10.126m0 0h-2.25m2.25 0h2.25" /></svg>');
25
+ --_vaadin-icon-h2: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 19.5H16.5v-1.609a2.25 2.25 0 0 1 1.244-2.012l2.89-1.445c.651-.326 1.116-.955 1.116-1.683 0-.498-.04-.987-.118-1.463-.135-.825-.835-1.422-1.668-1.489a15.202 15.202 0 0 0-3.464.12M2.243 4.492v7.5m0 0v7.502m0-7.501h10.5m0-7.5v7.5m0 0v7.501" /></svg>');
26
+ --_vaadin-icon-h3: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M20.905 14.626a4.52 4.52 0 0 1 .738 3.603c-.154.695-.794 1.143-1.504 1.208a15.194 15.194 0 0 1-3.639-.104m4.405-4.707a4.52 4.52 0 0 0 .738-3.603c-.154-.696-.794-1.144-1.504-1.209a15.19 15.19 0 0 0-3.639.104m4.405 4.708H18M2.243 4.493v7.5m0 0v7.502m0-7.501h10.5m0-7.5v7.5m0 0v7.501" /></svg>');
27
+ --_vaadin-icon-italic: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5.248 20.246H9.05m0 0h3.696m-3.696 0 5.893-16.502m0 0h-3.697m3.697 0h3.803" /></svg>');
28
+ --_vaadin-icon-list-number: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M8.242 5.992h12m-12 6.003H20.24m-12 5.999h12M4.117 7.495v-3.75H2.99m1.125 3.75H2.99m1.125 0H5.24m-1.92 2.577a1.125 1.125 0 1 1 1.591 1.59l-1.83 1.83h2.16M2.99 15.745h1.125a1.125 1.125 0 0 1 0 2.25H3.74m0-.002h.375a1.125 1.125 0 0 1 0 2.25H2.99" /></svg>');
29
+ --_vaadin-icon-list-bullet: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0ZM3.75 12h.007v.008H3.75V12Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm-.375 5.25h.007v.008H3.75v-.008Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" /></svg>');
30
+ --_vaadin-icon-quote: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M0 0h24v24H0z" fill="none"/><path d="M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z"/></svg>');
31
+ --_vaadin-icon-strikethrough: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 12a8.912 8.912 0 0 1-.318-.079c-1.585-.424-2.904-1.247-3.76-2.236-.873-1.009-1.265-2.19-.968-3.301.59-2.2 3.663-3.29 6.863-2.432A8.186 8.186 0 0 1 16.5 5.21M6.42 17.81c.857.99 2.176 1.812 3.761 2.237 3.2.858 6.274-.23 6.863-2.431.233-.868.044-1.779-.465-2.617M3.75 12h16.5" /></svg>');
32
+ --_vaadin-icon-subscript: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M760-160v-80q0-17 11.5-28.5T800-280h80v-40H760v-40h120q17 0 28.5 11.5T920-320v40q0 17-11.5 28.5T880-240h-80v40h120v40H760Zm-525-80 185-291-172-269h106l124 200h4l123-200h107L539-531l186 291H618L482-457h-4L342-240H235Z"/></svg>');
33
+ --_vaadin-icon-superscript: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M760-600v-80q0-17 11.5-28.5T800-720h80v-40H760v-40h120q17 0 28.5 11.5T920-760v40q0 17-11.5 28.5T880-680h-80v40h120v40H760ZM235-160l185-291-172-269h106l124 200h4l123-200h107L539-451l186 291H618L482-377h-4L342-160H235Z"/></svg>');
34
+ --_vaadin-icon-underline: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M17.995 3.744v7.5a6 6 0 1 1-12 0v-7.5m-2.25 16.502h16.5" /></svg>');
35
+ }
36
+ `;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 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 type { CSSResult } from 'lit';
12
+
13
+ export const richTextEditorStyles: CSSResult;
@@ -0,0 +1,346 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 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 } from 'lit';
12
+ import { icons } from './vaadin-rich-text-editor-base-icons.js';
13
+
14
+ const base = css`
15
+ :host {
16
+ background: var(--vaadin-rich-text-editor-background, var(--vaadin-background-color));
17
+ border: var(--vaadin-input-field-border-width, 1px) solid
18
+ var(--vaadin-input-field-border-color, var(--vaadin-border-color-strong));
19
+ border-radius: var(--vaadin-input-field-border-radius, var(--vaadin-radius-m));
20
+ box-sizing: border-box;
21
+ display: flex;
22
+ flex-direction: column;
23
+ overflow: hidden;
24
+ }
25
+
26
+ :host(:focus-within) {
27
+ outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
28
+ outline-offset: -1px;
29
+ }
30
+
31
+ :host([hidden]) {
32
+ display: none !important;
33
+ }
34
+
35
+ .announcer {
36
+ clip: rect(0, 0, 0, 0);
37
+ position: fixed;
38
+ }
39
+
40
+ input[type='file'] {
41
+ display: none;
42
+ }
43
+
44
+ .vaadin-rich-text-editor-container {
45
+ display: flex;
46
+ flex: auto;
47
+ flex-direction: column;
48
+ max-height: inherit;
49
+ min-height: inherit;
50
+ }
51
+ `;
52
+
53
+ export const content = css`
54
+ [part='content'] {
55
+ box-sizing: border-box;
56
+ display: flex;
57
+ flex: auto;
58
+ flex-direction: column;
59
+ overflow: hidden;
60
+ position: relative;
61
+ }
62
+
63
+ /*
64
+ Quill core styles.
65
+ CSS selectors removed: margin & padding reset, check list, indentation, video, colors, ordered & unordered list, h1-6, anchor
66
+ */
67
+ .ql-clipboard {
68
+ height: 1px;
69
+ left: -100000px;
70
+ overflow-y: hidden;
71
+ position: absolute;
72
+ top: 50%;
73
+ }
74
+
75
+ .ql-clipboard p {
76
+ margin: 0;
77
+ padding: 0;
78
+ }
79
+
80
+ .ql-editor {
81
+ box-sizing: border-box;
82
+ color: var(--vaadin-rich-text-editor-editor-color, var(--vaadin-color));
83
+ flex: 1;
84
+ font-size: var(--vaadin-rich-text-editor-editor-font-size, inherit);
85
+ height: 100%;
86
+ line-height: var(--vaadin-rich-text-editor-editor-line-height, inherit);
87
+ outline: none;
88
+ overflow-y: auto;
89
+ padding: var(--vaadin-rich-text-editor-editor-padding, var(--vaadin-padding-container));
90
+ tab-size: 4;
91
+ -moz-tab-size: 4;
92
+ text-align: left;
93
+ white-space: pre-wrap;
94
+ word-wrap: break-word;
95
+ }
96
+
97
+ .ql-editor > * {
98
+ cursor: text;
99
+ }
100
+
101
+ .ql-align-left {
102
+ text-align: left;
103
+ }
104
+
105
+ .ql-direction-rtl {
106
+ direction: rtl;
107
+ text-align: inherit;
108
+ }
109
+
110
+ .ql-align-center {
111
+ text-align: center;
112
+ }
113
+
114
+ .ql-align-justify {
115
+ text-align: justify;
116
+ }
117
+
118
+ .ql-align-right {
119
+ text-align: right;
120
+ }
121
+ /* quill core end */
122
+
123
+ blockquote {
124
+ border-inline-start: 4px solid var(--vaadin-border-color);
125
+ margin: var(--vaadin-padding-container);
126
+ padding-inline-start: var(--vaadin-padding);
127
+ }
128
+
129
+ code,
130
+ pre {
131
+ background-color: var(--vaadin-background-container);
132
+ border-radius: var(--vaadin-radius-s);
133
+ }
134
+
135
+ pre {
136
+ white-space: pre-wrap;
137
+ margin-block: var(--vaadin-padding);
138
+ padding: var(--vaadin-padding-container);
139
+ }
140
+
141
+ code {
142
+ padding: 0.125rem 0.25rem;
143
+ }
144
+
145
+ img {
146
+ max-width: 100%;
147
+ }
148
+
149
+ /* RTL specific styles */
150
+ :host([dir='rtl']) .ql-editor {
151
+ direction: rtl;
152
+ text-align: right;
153
+ }
154
+ `;
155
+
156
+ const toolbar = css`
157
+ [part='toolbar'] {
158
+ background-color: var(--vaadin-rich-text-editor-toolbar-background, var(--vaadin-background-container));
159
+ display: flex;
160
+ flex-shrink: 0;
161
+ flex-wrap: wrap;
162
+ gap: var(--vaadin-rich-text-editor-toolbar-gap, var(--vaadin-gap-container-inline));
163
+ padding: var(--vaadin-rich-text-editor-toolbar-padding, var(--vaadin-padding));
164
+ }
165
+
166
+ [part~='toolbar-group'] {
167
+ display: flex;
168
+ }
169
+
170
+ [part~='toolbar-button'] {
171
+ background: var(--vaadin-rich-text-editor-toolbar-button-background, var(--vaadin-background-container));
172
+ border: var(--vaadin-rich-text-editor-toolbar-button-border-width, 1px) solid
173
+ var(--vaadin-rich-text-editor-toolbar-button-border-color, transparent);
174
+ border-radius: var(--vaadin-rich-text-editor-toolbar-button-border-radius, var(--vaadin-radius-m));
175
+ color: var(--vaadin-rich-text-editor-toolbar-button-text-color, var(--vaadin-color));
176
+ cursor: var(--vaadin-clickable-cursor);
177
+ flex-shrink: 0;
178
+ font-family: var(--vaadin-rich-text-editor-toolbar-button-font-family, inherit);
179
+ font-size: var(--vaadin-rich-text-editor-toolbar-button-font-size, inherit);
180
+ font-weight: var(--vaadin-rich-text-editor-toolbar-button-font-weight, 500);
181
+ height: var(--vaadin-rich-text-editor-toolbar-button-height, auto);
182
+ line-height: var(--vaadin-rich-text-editor-toolbar-button-line-height, inherit);
183
+ padding: var(--vaadin-rich-text-editor-toolbar-button-padding, var(--vaadin-padding-container));
184
+ position: relative;
185
+ }
186
+
187
+ [part~='toolbar-button']::before {
188
+ background: currentcolor;
189
+ content: '';
190
+ display: block;
191
+ height: var(--vaadin-icon-size, 1lh);
192
+ width: var(--vaadin-icon-size, 1lh);
193
+ }
194
+
195
+ [part~='toolbar-button']:focus {
196
+ outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
197
+ outline-offset: 1px;
198
+ z-index: 1;
199
+ }
200
+
201
+ [part~='toolbar-button'][on],
202
+ [part~='toolbar-button'][aria-expanded='true'] {
203
+ --vaadin-rich-text-editor-toolbar-button-background: var(--vaadin-background-container-strong);
204
+ }
205
+
206
+ [part~='toolbar-button-undo']::before {
207
+ mask-image: var(--_vaadin-icon-undo);
208
+ }
209
+
210
+ [part~='toolbar-button-redo']::before {
211
+ mask-image: var(--_vaadin-icon-redo);
212
+ }
213
+
214
+ [part~='toolbar-button-bold']::before {
215
+ mask-image: var(--_vaadin-icon-bold);
216
+ }
217
+
218
+ [part~='toolbar-button-italic']::before {
219
+ mask-image: var(--_vaadin-icon-italic);
220
+ }
221
+
222
+ [part~='toolbar-button-underline']::before {
223
+ mask-image: var(--_vaadin-icon-underline);
224
+ }
225
+
226
+ [part~='toolbar-button-strike']::before {
227
+ mask-image: var(--_vaadin-icon-strikethrough);
228
+ }
229
+
230
+ [part~='toolbar-button-color']::before {
231
+ mask-image: var(--_vaadin-icon-color);
232
+ }
233
+
234
+ [part~='toolbar-button-color']::after {
235
+ background-color: var(--_color-value, currentColor);
236
+ }
237
+
238
+ [part~='toolbar-button-background']::before {
239
+ mask-image: var(--_vaadin-icon-background);
240
+ }
241
+
242
+ [part~='toolbar-button-background']::after {
243
+ background-color: var(--_background-value, currentColor);
244
+ }
245
+
246
+ [part~='toolbar-button-color']::after,
247
+ [part~='toolbar-button-background']::after {
248
+ bottom: 50%;
249
+ content: '';
250
+ display: block;
251
+ height: var(--vaadin-icon-size, 1lh);
252
+ mask-image: var(--_vaadin-icon-color-underline);
253
+ position: absolute;
254
+ transform: translateY(50%);
255
+ width: var(--vaadin-icon-size, 1lh);
256
+ }
257
+
258
+ [part~='toolbar-button-h1']::before {
259
+ mask-image: var(--_vaadin-icon-h1);
260
+ }
261
+
262
+ [part~='toolbar-button-h2']::before {
263
+ mask-image: var(--_vaadin-icon-h2);
264
+ }
265
+
266
+ [part~='toolbar-button-h3']::before {
267
+ mask-image: var(--_vaadin-icon-h3);
268
+ }
269
+
270
+ [part~='toolbar-button-subscript']::before {
271
+ mask-image: var(--_vaadin-icon-subscript);
272
+ }
273
+
274
+ [part~='toolbar-button-superscript']::before {
275
+ mask-image: var(--_vaadin-icon-superscript);
276
+ }
277
+
278
+ [part~='toolbar-button-list-ordered']::before {
279
+ mask-image: var(--_vaadin-icon-list-number);
280
+ }
281
+
282
+ [part~='toolbar-button-list-bullet']::before {
283
+ mask-image: var(--_vaadin-icon-list-bullet);
284
+ }
285
+
286
+ [part~='toolbar-button-align-left']::before {
287
+ mask-image: var(--_vaadin-icon-align-left);
288
+ }
289
+
290
+ [part~='toolbar-button-align-center']::before {
291
+ mask-image: var(--_vaadin-icon-align-center);
292
+ }
293
+
294
+ [part~='toolbar-button-align-right']::before {
295
+ mask-image: var(--_vaadin-icon-align-right);
296
+ }
297
+
298
+ [part~='toolbar-button-image']::before {
299
+ mask-image: var(--_vaadin-icon-image);
300
+ }
301
+
302
+ [part~='toolbar-button-link']::before {
303
+ mask-image: var(--_vaadin-icon-link);
304
+ }
305
+
306
+ [part~='toolbar-button-blockquote']::before {
307
+ mask-image: var(--_vaadin-icon-quote);
308
+ }
309
+
310
+ [part~='toolbar-button-code-block']::before {
311
+ mask-image: var(--_vaadin-icon-code);
312
+ }
313
+
314
+ [part~='toolbar-button-clean']::before {
315
+ mask-image: var(--_vaadin-icon-clear);
316
+ }
317
+
318
+ @media (forced-colors: active) {
319
+ [part~='toolbar-button']::before {
320
+ background: CanvasText;
321
+ }
322
+
323
+ [part~='toolbar-button'][on] {
324
+ background: Highlight;
325
+ }
326
+
327
+ [part~='toolbar-button'][on]::before {
328
+ background: HighlightText;
329
+ }
330
+ }
331
+ `;
332
+
333
+ const states = css`
334
+ :host([readonly]) [part='toolbar'] {
335
+ display: none;
336
+ }
337
+
338
+ :host([disabled]) {
339
+ pointer-events: none;
340
+ opacity: 0.5;
341
+ -webkit-user-select: none;
342
+ user-select: none;
343
+ }
344
+ `;
345
+
346
+ export const richTextEditorStyles = [icons, base, content, toolbar, states];
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 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 } from 'lit';
12
+ import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-base-styles.js';
13
+
14
+ export const richTextEditorPopupOverlay = css`
15
+ [part='overlay'] {
16
+ padding: var(--vaadin-rich-text-editor-overlay-padding, var(--vaadin-padding-container));
17
+ }
18
+
19
+ [part='content'] {
20
+ display: grid;
21
+ gap: var(--vaadin-rich-text-editor-overlay-gap, var(--vaadin-gap-container-inline));
22
+ grid-template-columns: repeat(7, minmax(0, 1fr));
23
+ }
24
+
25
+ [part='content'] ::slotted(button) {
26
+ border: var(--vaadin-rich-text-editor-overlay-color-option-border-width, 1px) solid
27
+ var(--vaadin-rich-text-editor-overlay-color-option-border-color, transparent);
28
+ border-radius: var(--vaadin-rich-text-editor-overlay-color-option-border-radius, 9999px);
29
+ cursor: var(--vaadin-clickable-cursor);
30
+ font-size: var(--vaadin-rich-text-editor-overlay-color-option-font-size, inherit);
31
+ height: var(--vaadin-rich-text-editor-overlay-color-option-height, 1lh);
32
+ line-height: var(--vaadin-rich-text-editor-overlay-color-option-line-height, inherit);
33
+ padding: var(--vaadin-rich-text-editor-overlay-color-option-padding, 0);
34
+ width: var(--vaadin-rich-text-editor-overlay-color-option-width, 1lh);
35
+ }
36
+
37
+ [part='content'] ::slotted(button:focus-visible) {
38
+ outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
39
+ outline-offset: 1px;
40
+ }
41
+ `;
42
+
43
+ export const richTextEditorPopupOverlayStyles = [overlayStyles, richTextEditorPopupOverlay];
@@ -10,7 +10,6 @@
10
10
  */
11
11
  import '../vendor/vaadin-quill.js';
12
12
  import { timeOut } from '@vaadin/component-base/src/async.js';
13
- import { isFirefox } from '@vaadin/component-base/src/browser-utils.js';
14
13
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
15
14
  import { I18nMixin } from '@vaadin/component-base/src/i18n-mixin.js';
16
15
 
@@ -177,7 +176,7 @@ export const RichTextEditorMixin = (superClass) =>
177
176
  '#ffffff', '#facccc', '#ffebcc', '#ffffcc', '#cce8cc', '#cce0f5', '#ebd6ff',
178
177
  '#bbbbbb', '#f06666', '#ffc266', '#ffff66', '#66b966', '#66a3e0', '#c285ff',
179
178
  '#888888', '#a10000', '#b26b00', '#b2b200', '#006100', '#0047b2', '#6b24b2',
180
- '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466'
179
+ '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466',
181
180
  ];
182
181
  },
183
182
  },
@@ -352,11 +351,6 @@ export const RichTextEditorMixin = (superClass) =>
352
351
  this.__patchToolbar();
353
352
  this.__patchKeyboard();
354
353
 
355
- /* c8 ignore next 3 */
356
- if (isFirefox) {
357
- this.__patchFirefoxFocus();
358
- }
359
-
360
354
  this.__setDirection(this.__dir);
361
355
 
362
356
  const editorContent = editor.querySelector('.ql-editor');
@@ -422,13 +416,32 @@ export const RichTextEditorMixin = (superClass) =>
422
416
  // Flush pending htmlValue only once the editor is fully initialized
423
417
  this.__flushPendingHtmlValue();
424
418
 
425
- this.$.backgroundPopup.target = this.shadowRoot.querySelector('#btn-background');
426
- this.$.colorPopup.target = this.shadowRoot.querySelector('#btn-color');
419
+ this.querySelector('[slot="color-popup"]').target = this.shadowRoot.querySelector('#btn-color');
420
+ this.querySelector('[slot="background-popup"]').target = this.shadowRoot.querySelector('#btn-background');
421
+
422
+ // Set up tooltip to show when hovering or focusing toolbar buttons
423
+ this._tooltip = document.createElement('vaadin-tooltip');
424
+ this._tooltip.slot = 'tooltip';
425
+ // Create dummy aria target, as toolbar buttons already have aria-label, and also cannot be linked with the
426
+ // tooltip being in the light DOM
427
+ this._tooltip.ariaTarget = document.createElement('div');
428
+ this.append(this._tooltip);
429
+
430
+ const buttons = this.shadowRoot.querySelectorAll('[part~="toolbar-button"]');
431
+ buttons.forEach((button) => {
432
+ button.addEventListener('mouseenter', this.__showTooltip.bind(this));
433
+ button.addEventListener('focusin', this.__showTooltip.bind(this));
434
+ });
435
+ }
427
436
 
428
- requestAnimationFrame(() => {
429
- this.$.linkDialog.$.dialog.$.overlay.addEventListener('vaadin-overlay-open', () => {
430
- this.$.linkUrl.focus();
431
- });
437
+ /** @private */
438
+ __showTooltip(event) {
439
+ const target = event.target;
440
+ this._tooltip.target = target;
441
+ this._tooltip.text = target.ariaLabel;
442
+ this._tooltip._stateController.open({
443
+ focus: event.type === 'focusin',
444
+ hover: event.type === 'mouseenter',
432
445
  });
433
446
  }
434
447
 
@@ -512,69 +525,6 @@ export const RichTextEditorMixin = (superClass) =>
512
525
  this._toolbarState = STATE.DEFAULT;
513
526
  }
514
527
 
515
- /** @private */
516
- __createFakeFocusTarget() {
517
- const isRTL = document.documentElement.getAttribute('dir') === 'rtl';
518
- const elem = document.createElement('textarea');
519
- // Reset box model
520
- elem.style.border = '0';
521
- elem.style.padding = '0';
522
- elem.style.margin = '0';
523
- // Move element out of screen horizontally
524
- elem.style.position = 'absolute';
525
- elem.style[isRTL ? 'right' : 'left'] = '-9999px';
526
- // Move element to the same position vertically
527
- const yPosition = window.pageYOffset || document.documentElement.scrollTop;
528
- elem.style.top = `${yPosition}px`;
529
- return elem;
530
- }
531
-
532
- /** @private */
533
- __patchFirefoxFocus() {
534
- // In Firefox 63+ with native Shadow DOM, when moving focus out of
535
- // contenteditable and back again within same shadow root, cursor
536
- // disappears. See https://bugzilla.mozilla.org/show_bug.cgi?id=1496769
537
- const editorContent = this.shadowRoot.querySelector('.ql-editor');
538
- let isFake = false;
539
-
540
- const focusFake = () => {
541
- isFake = true;
542
- this.__fakeTarget = this.__createFakeFocusTarget();
543
- document.body.appendChild(this.__fakeTarget);
544
- // Let the focus step out of shadow root!
545
- this.__fakeTarget.focus();
546
- return new Promise((resolve) => {
547
- setTimeout(resolve);
548
- });
549
- };
550
-
551
- const focusBack = (offsetNode, offset) => {
552
- this._editor.focus();
553
- if (offsetNode) {
554
- this._editor.selection.setNativeRange(offsetNode, offset);
555
- }
556
- document.body.removeChild(this.__fakeTarget);
557
- delete this.__fakeTarget;
558
- isFake = false;
559
- };
560
-
561
- editorContent.addEventListener('mousedown', (e) => {
562
- if (!this._editor.hasFocus()) {
563
- const { x, y } = e;
564
- const { offset, offsetNode } = document.caretPositionFromPoint(x, y);
565
- focusFake().then(() => {
566
- focusBack(offsetNode, offset);
567
- });
568
- }
569
- });
570
-
571
- editorContent.addEventListener('focusin', () => {
572
- if (isFake === false) {
573
- focusFake().then(() => focusBack());
574
- }
575
- });
576
- }
577
-
578
528
  /** @private */
579
529
  __patchToolbar() {
580
530
  const toolbar = this._editor.getModule('toolbar');
@@ -721,7 +671,8 @@ export const RichTextEditorMixin = (superClass) =>
721
671
  if (e.keyCode === 13) {
722
672
  e.preventDefault();
723
673
  e.stopPropagation();
724
- this.$.confirmLink.click();
674
+ this._onLinkEditConfirm();
675
+ this._closeLinkDialog();
725
676
  }
726
677
  }
727
678
 
@@ -868,10 +819,7 @@ export const RichTextEditorMixin = (superClass) =>
868
819
  timeOut.after(timeout),
869
820
  () => {
870
821
  const formatting = Array.from(this.shadowRoot.querySelectorAll('[part="toolbar"] .ql-active'))
871
- .map((button) => {
872
- const tooltip = this.shadowRoot.querySelector(`[for="${button.id}"]`);
873
- return tooltip.text;
874
- })
822
+ .map((button) => button.getAttribute('aria-label'))
875
823
  .join(', ');
876
824
  announcer.textContent = formatting;
877
825
  },