@vaadin/rich-text-editor 25.0.0-alpha3 → 25.0.0-alpha5

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-alpha3",
3
+ "version": "25.0.0-alpha5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -20,7 +20,7 @@
20
20
  "module": "vaadin-rich-text-editor.js",
21
21
  "type": "module",
22
22
  "scripts": {
23
- "icons": "gulp icons --gulpfile gulpfile.cjs"
23
+ "icons": "gulp icons"
24
24
  },
25
25
  "files": [
26
26
  "src",
@@ -39,24 +39,24 @@
39
39
  ],
40
40
  "dependencies": {
41
41
  "@open-wc/dedupe-mixin": "^1.3.0",
42
- "@vaadin/button": "25.0.0-alpha3",
43
- "@vaadin/component-base": "25.0.0-alpha3",
44
- "@vaadin/confirm-dialog": "25.0.0-alpha3",
45
- "@vaadin/overlay": "25.0.0-alpha3",
46
- "@vaadin/text-field": "25.0.0-alpha3",
47
- "@vaadin/tooltip": "25.0.0-alpha3",
48
- "@vaadin/vaadin-lumo-styles": "25.0.0-alpha3",
49
- "@vaadin/vaadin-themable-mixin": "25.0.0-alpha3",
42
+ "@vaadin/button": "25.0.0-alpha5",
43
+ "@vaadin/component-base": "25.0.0-alpha5",
44
+ "@vaadin/confirm-dialog": "25.0.0-alpha5",
45
+ "@vaadin/overlay": "25.0.0-alpha5",
46
+ "@vaadin/text-field": "25.0.0-alpha5",
47
+ "@vaadin/tooltip": "25.0.0-alpha5",
48
+ "@vaadin/vaadin-lumo-styles": "25.0.0-alpha5",
49
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha5",
50
50
  "lit": "^3.0.0"
51
51
  },
52
52
  "devDependencies": {
53
- "@vaadin/a11y-base": "25.0.0-alpha3",
54
- "@vaadin/chai-plugins": "25.0.0-alpha3",
55
- "@vaadin/test-runner-commands": "25.0.0-alpha3",
53
+ "@vaadin/a11y-base": "25.0.0-alpha5",
54
+ "@vaadin/chai-plugins": "25.0.0-alpha5",
55
+ "@vaadin/test-runner-commands": "25.0.0-alpha5",
56
56
  "@vaadin/testing-helpers": "^2.0.0",
57
- "gulp": "^5.0.0",
58
- "gulp-cli": "^3.0.0",
59
- "gulp-iconfont": "^11.0.0",
57
+ "gulp": "^5.0.1",
58
+ "gulp-cli": "^3.1.0",
59
+ "gulp-iconfont": "^12.0.0",
60
60
  "sinon": "^18.0.0"
61
61
  },
62
62
  "cvdlName": "vaadin-rich-text-editor",
@@ -64,5 +64,5 @@
64
64
  "web-types.json",
65
65
  "web-types.lit.json"
66
66
  ],
67
- "gitHead": "8367dd20a47f53ca5589ad349a8e286ec2673055"
67
+ "gitHead": "7dc87bb2a3cae81ed53259fa10b58f990d50c6fd"
68
68
  }
@@ -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;
@@ -9,9 +9,142 @@
9
9
  * license.
10
10
  */
11
11
  import { css } from 'lit';
12
- import { iconsStyles } from './vaadin-rich-text-editor-icons.js';
12
+ import { icons } from './vaadin-rich-text-editor-icons.js';
13
13
 
14
- export const buttonsStyles = css`
14
+ const base = css`
15
+ :host {
16
+ display: flex;
17
+ flex-direction: column;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ :host([hidden]) {
22
+ display: none !important;
23
+ }
24
+
25
+ .announcer {
26
+ position: fixed;
27
+ clip: rect(0, 0, 0, 0);
28
+ }
29
+
30
+ input[type='file'] {
31
+ display: none;
32
+ }
33
+
34
+ .vaadin-rich-text-editor-container {
35
+ display: flex;
36
+ flex-direction: column;
37
+ min-height: inherit;
38
+ max-height: inherit;
39
+ flex: auto;
40
+ }
41
+ `;
42
+
43
+ export const content = css`
44
+ [part='content'] {
45
+ box-sizing: border-box;
46
+ position: relative;
47
+ flex: auto;
48
+ display: flex;
49
+ flex-direction: column;
50
+ overflow: hidden;
51
+ }
52
+
53
+ /*
54
+ Quill core styles.
55
+ CSS selectors removed: margin & padding reset, check list, indentation, video, colors, ordered & unordered list, h1-6, anchor
56
+ */
57
+ .ql-clipboard {
58
+ left: -100000px;
59
+ height: 1px;
60
+ overflow-y: hidden;
61
+ position: absolute;
62
+ top: 50%;
63
+ }
64
+
65
+ .ql-clipboard p {
66
+ margin: 0;
67
+ padding: 0;
68
+ }
69
+
70
+ .ql-editor {
71
+ box-sizing: border-box;
72
+ line-height: 1.42;
73
+ height: 100%;
74
+ outline: none;
75
+ overflow-y: auto;
76
+ padding: 0.75em 1em;
77
+ -moz-tab-size: 4;
78
+ tab-size: 4;
79
+ text-align: left;
80
+ white-space: pre-wrap;
81
+ word-wrap: break-word;
82
+ flex: 1;
83
+ }
84
+
85
+ .ql-editor > * {
86
+ cursor: text;
87
+ }
88
+
89
+ .ql-align-left {
90
+ text-align: left;
91
+ }
92
+
93
+ .ql-direction-rtl {
94
+ direction: rtl;
95
+ text-align: inherit;
96
+ }
97
+
98
+ .ql-align-center {
99
+ text-align: center;
100
+ }
101
+
102
+ .ql-align-justify {
103
+ text-align: justify;
104
+ }
105
+
106
+ .ql-align-right {
107
+ text-align: right;
108
+ }
109
+ /* quill core end */
110
+
111
+ blockquote {
112
+ border-left: 0.25em solid #ccc;
113
+ margin-bottom: 0.3125em;
114
+ margin-top: 0.3125em;
115
+ padding-left: 1em;
116
+ }
117
+
118
+ code,
119
+ pre {
120
+ background-color: #f0f0f0;
121
+ border-radius: 0.1875em;
122
+ }
123
+
124
+ pre {
125
+ white-space: pre-wrap;
126
+ margin-bottom: 0.3125em;
127
+ margin-top: 0.3125em;
128
+ padding: 0.3125em 0.625em;
129
+ }
130
+
131
+ code {
132
+ font-size: 85%;
133
+ padding: 0.125em 0.25em;
134
+ }
135
+
136
+ img {
137
+ max-width: 100%;
138
+ }
139
+
140
+ /* RTL specific styles */
141
+ :host([dir='rtl']) .ql-editor {
142
+ direction: rtl;
143
+ text-align: right;
144
+ }
145
+ `;
146
+
147
+ const toolbar = css`
15
148
  [part='toolbar'] {
16
149
  display: flex;
17
150
  flex-wrap: wrap;
@@ -177,4 +310,21 @@ export const buttonsStyles = css`
177
310
  }
178
311
  `;
179
312
 
180
- export const toolbarStyles = [iconsStyles, buttonsStyles];
313
+ const states = css`
314
+ :host([readonly]) [part='toolbar'] {
315
+ display: none;
316
+ }
317
+
318
+ :host([disabled]) {
319
+ pointer-events: none;
320
+ opacity: 0.5;
321
+ -webkit-user-select: none;
322
+ user-select: none;
323
+ }
324
+
325
+ :host([disabled]) [part~='toolbar-button'] {
326
+ background-color: transparent;
327
+ }
328
+ `;
329
+
330
+ export const richTextEditorStyles = [base, content, icons, toolbar, states];
@@ -16,7 +16,7 @@ template.innerHTML = `
16
16
  <style>
17
17
  @font-face {
18
18
  font-family: 'vaadin-rte-icons';
19
- src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff');
19
+ src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff');
20
20
  font-weight: normal;
21
21
  font-style: normal;
22
22
  }
@@ -38,7 +38,7 @@ template.innerHTML = `
38
38
 
39
39
  document.head.appendChild(template.content);
40
40
 
41
- export const iconsStyles = css`
41
+ export const icons = css`
42
42
  [part~='toolbar-button-align-center']::before {
43
43
  content: var(--vaadin-rte-icons-align-center);
44
44
  }
@@ -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
 
@@ -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');
@@ -512,69 +506,6 @@ export const RichTextEditorMixin = (superClass) =>
512
506
  this._toolbarState = STATE.DEFAULT;
513
507
  }
514
508
 
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
509
  /** @private */
579
510
  __patchToolbar() {
580
511
  const toolbar = this._editor.getModule('toolbar');
@@ -8,25 +8,24 @@
8
8
  * See https://vaadin.com/commercial-license-and-service-terms for the full
9
9
  * license.
10
10
  */
11
- import { css, html, LitElement } from 'lit';
11
+ import { css, html, LitElement, render } from 'lit';
12
12
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
13
13
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
14
14
  import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
15
+ import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-core-styles.js';
15
16
  import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
16
17
  import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
17
- import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
18
+ import { CSSInjectionMixin } from '@vaadin/vaadin-themable-mixin/css-injection-mixin.js';
18
19
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
19
- import { RichTextEditorPopupMixin } from './vaadin-rich-text-editor-popup-mixin.js';
20
20
 
21
21
  /**
22
22
  * An element used internally by `<vaadin-rich-text-editor>`. Not intended to be used separately.
23
23
  *
24
24
  * @customElement
25
25
  * @extends HTMLElement
26
- * @mixes RichTextEditorPopupMixin
27
26
  * @private
28
27
  */
29
- class RichTextEditorPopup extends RichTextEditorPopupMixin(PolylitMixin(LitElement)) {
28
+ class RichTextEditorPopup extends PolylitMixin(LitElement) {
30
29
  static get is() {
31
30
  return 'vaadin-rich-text-editor-popup';
32
31
  }
@@ -39,6 +38,31 @@ class RichTextEditorPopup extends RichTextEditorPopupMixin(PolylitMixin(LitEleme
39
38
  `;
40
39
  }
41
40
 
41
+ static get properties() {
42
+ return {
43
+ target: {
44
+ type: Object,
45
+ },
46
+
47
+ opened: {
48
+ type: Boolean,
49
+ notify: true,
50
+ },
51
+
52
+ colors: {
53
+ type: Array,
54
+ },
55
+
56
+ renderer: {
57
+ type: Object,
58
+ },
59
+ };
60
+ }
61
+
62
+ static get observers() {
63
+ return ['__openedOrTargetChanged(opened, target)', '__colorsChanged(colors)'];
64
+ }
65
+
42
66
  /** @protected */
43
67
  render() {
44
68
  return html`
@@ -60,6 +84,41 @@ class RichTextEditorPopup extends RichTextEditorPopupMixin(PolylitMixin(LitEleme
60
84
  _onOpenedChanged(event) {
61
85
  this.opened = event.detail.value;
62
86
  }
87
+
88
+ /** @private */
89
+ _onOverlayEscapePress() {
90
+ this.target.focus();
91
+ }
92
+
93
+ /** @private */
94
+ _onColorClick(e) {
95
+ const { color } = e.target.dataset;
96
+ this.dispatchEvent(new CustomEvent('color-selected', { detail: { color } }));
97
+ }
98
+
99
+ /** @private */
100
+ __colorsChanged(colors) {
101
+ this.renderer = (root) => {
102
+ render(
103
+ html`
104
+ ${colors.map(
105
+ (color) => html`
106
+ <button data-color="${color}" style="background: ${color}" @click="${this._onColorClick}"></button>
107
+ `,
108
+ )}
109
+ `,
110
+ root,
111
+ { host: this },
112
+ );
113
+ };
114
+ }
115
+
116
+ /** @private */
117
+ __openedOrTargetChanged(opened, target) {
118
+ if (target) {
119
+ target.setAttribute('aria-expanded', opened ? 'true' : 'false');
120
+ }
121
+ }
63
122
  }
64
123
 
65
124
  defineCustomElement(RichTextEditorPopup);
@@ -78,7 +137,7 @@ export { RichTextEditorPopup };
78
137
  * @private
79
138
  */
80
139
  class RichTextEditorPopupOverlay extends PositionMixin(
81
- OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement)))),
140
+ OverlayMixin(DirMixin(ThemableMixin(CSSInjectionMixin(PolylitMixin(LitElement))))),
82
141
  ) {
83
142
  static get is() {
84
143
  return 'vaadin-rich-text-editor-popup-overlay';
@@ -17,9 +17,10 @@ import { html, LitElement } from 'lit';
17
17
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
18
18
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
19
19
  import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
20
+ import { CSSInjectionMixin } from '@vaadin/vaadin-themable-mixin/css-injection-mixin.js';
20
21
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
22
+ import { richTextEditorStyles } from './styles/vaadin-rich-text-editor-core-styles.js';
21
23
  import { RichTextEditorMixin } from './vaadin-rich-text-editor-mixin.js';
22
- import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
23
24
 
24
25
  /**
25
26
  * `<vaadin-rich-text-editor>` is a Web Component for rich text editing.
@@ -99,7 +100,9 @@ import { richTextEditorStyles } from './vaadin-rich-text-editor-styles.js';
99
100
  * @mixes RichTextEditorMixin
100
101
  * @mixes ThemableMixin
101
102
  */
102
- class RichTextEditor extends RichTextEditorMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
103
+ class RichTextEditor extends RichTextEditorMixin(
104
+ ElementMixin(ThemableMixin(CSSInjectionMixin(PolylitMixin(LitElement)))),
105
+ ) {
103
106
  static get is() {
104
107
  return 'vaadin-rich-text-editor';
105
108
  }
@@ -122,12 +122,14 @@ const richTextEditor = css`
122
122
  }
123
123
 
124
124
  [part~='toolbar-button-background']:hover::before {
125
- background-image: linear-gradient(var(--lumo-contrast-5pct), var(--lumo-contrast-5pct)),
125
+ background-image:
126
+ linear-gradient(var(--lumo-contrast-5pct), var(--lumo-contrast-5pct)),
126
127
  linear-gradient(var(--lumo-contrast-5pct), var(--lumo-contrast-5pct));
127
128
  }
128
129
 
129
130
  [part~='toolbar-button-background']:active::before {
130
- background-image: linear-gradient(var(--lumo-contrast-5pct), var(--lumo-contrast-5pct)),
131
+ background-image:
132
+ linear-gradient(var(--lumo-contrast-5pct), var(--lumo-contrast-5pct)),
131
133
  linear-gradient(var(--lumo-contrast-10pct), var(--lumo-contrast-10pct));
132
134
  }
133
135
 
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/rich-text-editor",
4
- "version": "25.0.0-alpha3",
4
+ "version": "25.0.0-alpha5",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/rich-text-editor",
4
- "version": "25.0.0-alpha3",
4
+ "version": "25.0.0-alpha5",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -1,115 +0,0 @@
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 contentStyles = css`
14
- [part='content'] {
15
- box-sizing: border-box;
16
- position: relative;
17
- flex: auto;
18
- display: flex;
19
- flex-direction: column;
20
- overflow: hidden;
21
- }
22
-
23
- /*
24
- Quill core styles.
25
- CSS selectors removed: margin & padding reset, check list, indentation, video, colors, ordered & unordered list, h1-6, anchor
26
- */
27
- .ql-clipboard {
28
- left: -100000px;
29
- height: 1px;
30
- overflow-y: hidden;
31
- position: absolute;
32
- top: 50%;
33
- }
34
-
35
- .ql-clipboard p {
36
- margin: 0;
37
- padding: 0;
38
- }
39
-
40
- .ql-editor {
41
- box-sizing: border-box;
42
- line-height: 1.42;
43
- height: 100%;
44
- outline: none;
45
- overflow-y: auto;
46
- padding: 0.75em 1em;
47
- -moz-tab-size: 4;
48
- tab-size: 4;
49
- text-align: left;
50
- white-space: pre-wrap;
51
- word-wrap: break-word;
52
- flex: 1;
53
- }
54
-
55
- .ql-editor > * {
56
- cursor: text;
57
- }
58
-
59
- .ql-align-left {
60
- text-align: left;
61
- }
62
-
63
- .ql-direction-rtl {
64
- direction: rtl;
65
- text-align: inherit;
66
- }
67
-
68
- .ql-align-center {
69
- text-align: center;
70
- }
71
-
72
- .ql-align-justify {
73
- text-align: justify;
74
- }
75
-
76
- .ql-align-right {
77
- text-align: right;
78
- }
79
- /* quill core end */
80
-
81
- blockquote {
82
- border-left: 0.25em solid #ccc;
83
- margin-bottom: 0.3125em;
84
- margin-top: 0.3125em;
85
- padding-left: 1em;
86
- }
87
-
88
- code,
89
- pre {
90
- background-color: #f0f0f0;
91
- border-radius: 0.1875em;
92
- }
93
-
94
- pre {
95
- white-space: pre-wrap;
96
- margin-bottom: 0.3125em;
97
- margin-top: 0.3125em;
98
- padding: 0.3125em 0.625em;
99
- }
100
-
101
- code {
102
- font-size: 85%;
103
- padding: 0.125em 0.25em;
104
- }
105
-
106
- img {
107
- max-width: 100%;
108
- }
109
-
110
- /* RTL specific styles */
111
- :host([dir='rtl']) .ql-editor {
112
- direction: rtl;
113
- text-align: right;
114
- }
115
- `;
@@ -1,70 +0,0 @@
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
-
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
- };
@@ -1,61 +0,0 @@
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 '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
- import { contentStyles } from './vaadin-rich-text-editor-content-styles.js';
13
- import { toolbarStyles } from './vaadin-rich-text-editor-toolbar-styles.js';
14
-
15
- export const baseStyles = css`
16
- :host {
17
- display: flex;
18
- flex-direction: column;
19
- box-sizing: border-box;
20
- }
21
-
22
- :host([hidden]) {
23
- display: none !important;
24
- }
25
-
26
- .announcer {
27
- position: fixed;
28
- clip: rect(0, 0, 0, 0);
29
- }
30
-
31
- input[type='file'] {
32
- display: none;
33
- }
34
-
35
- .vaadin-rich-text-editor-container {
36
- display: flex;
37
- flex-direction: column;
38
- min-height: inherit;
39
- max-height: inherit;
40
- flex: auto;
41
- }
42
- `;
43
-
44
- export const statesStyles = css`
45
- :host([readonly]) [part='toolbar'] {
46
- display: none;
47
- }
48
-
49
- :host([disabled]) {
50
- pointer-events: none;
51
- opacity: 0.5;
52
- -webkit-user-select: none;
53
- user-select: none;
54
- }
55
-
56
- :host([disabled]) [part~='toolbar-button'] {
57
- background-color: transparent;
58
- }
59
- `;
60
-
61
- export const richTextEditorStyles = [baseStyles, contentStyles, toolbarStyles, statesStyles];