From ea37190a5f705a70b46a654ffc5f07f51463a91d Mon Sep 17 00:00:00 2001 From: Serhii Kulykov Date: Tue, 3 Dec 2024 10:20:40 +0200 Subject: [PATCH] experiment: add LitElement based version of message-input (#8258) --- packages/message-input/package.json | 3 +- .../src/vaadin-lit-message-input.d.ts | 1 + .../src/vaadin-lit-message-input.js | 69 +++++++++++++++++++ .../src/vaadin-message-input-mixin.js | 22 ++++-- .../test/message-input-lit.test.js | 2 + .../test/message-input-polymer.test.js | 2 + ...-input.test.js => message-input.common.js} | 12 ++-- .../theme/lumo/vaadin-lit-message-input.js | 4 ++ .../material/vaadin-lit-message-input.js | 4 ++ .../vaadin-lit-message-input.d.ts | 1 + .../message-input/vaadin-lit-message-input.js | 2 + 11 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 packages/message-input/src/vaadin-lit-message-input.d.ts create mode 100644 packages/message-input/src/vaadin-lit-message-input.js create mode 100644 packages/message-input/test/message-input-lit.test.js create mode 100644 packages/message-input/test/message-input-polymer.test.js rename packages/message-input/test/{message-input.test.js => message-input.common.js} (94%) create mode 100644 packages/message-input/theme/lumo/vaadin-lit-message-input.js create mode 100644 packages/message-input/theme/material/vaadin-lit-message-input.js create mode 100644 packages/message-input/vaadin-lit-message-input.d.ts create mode 100644 packages/message-input/vaadin-lit-message-input.js diff --git a/packages/message-input/package.json b/packages/message-input/package.json index ec9d2ae3cb..93e21264ff 100644 --- a/packages/message-input/package.json +++ b/packages/message-input/package.json @@ -42,7 +42,8 @@ "@vaadin/text-area": "24.6.0-beta1", "@vaadin/vaadin-lumo-styles": "24.6.0-beta1", "@vaadin/vaadin-material-styles": "24.6.0-beta1", - "@vaadin/vaadin-themable-mixin": "24.6.0-beta1" + "@vaadin/vaadin-themable-mixin": "24.6.0-beta1", + "lit": "^3.0.0" }, "devDependencies": { "@vaadin/chai-plugins": "24.6.0-beta1", diff --git a/packages/message-input/src/vaadin-lit-message-input.d.ts b/packages/message-input/src/vaadin-lit-message-input.d.ts new file mode 100644 index 0000000000..f5ec34fdf7 --- /dev/null +++ b/packages/message-input/src/vaadin-lit-message-input.d.ts @@ -0,0 +1 @@ +export * from './vaadin-message-input.js'; diff --git a/packages/message-input/src/vaadin-lit-message-input.js b/packages/message-input/src/vaadin-lit-message-input.js new file mode 100644 index 0000000000..cd21a85122 --- /dev/null +++ b/packages/message-input/src/vaadin-lit-message-input.js @@ -0,0 +1,69 @@ +/** + * @license + * Copyright (c) 2021 - 2024 Vaadin Ltd. + * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ + */ +import '@vaadin/button/src/vaadin-lit-button.js'; +import '@vaadin/text-area/src/vaadin-lit-text-area.js'; +import { css, html, LitElement } from 'lit'; +import { defineCustomElement } from '@vaadin/component-base/src/define.js'; +import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js'; +import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js'; +import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; +import { MessageInputMixin } from './vaadin-message-input-mixin.js'; + +/** + * LitElement based version of `` web component. + * + * ## Disclaimer + * + * This component is an experiment and not yet a part of Vaadin platform. + * There is no ETA regarding specific Vaadin version where it'll land. + * Feel free to try this code in your apps as per Apache 2.0 license. + */ +class MessageInput extends MessageInputMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) { + static get is() { + return 'vaadin-message-input'; + } + + static get styles() { + return css` + :host { + align-items: flex-start; + box-sizing: border-box; + display: flex; + max-height: 50vh; + overflow: hidden; + flex-shrink: 0; + } + + :host([hidden]) { + display: none !important; + } + + ::slotted([slot='button']) { + flex-shrink: 0; + } + + ::slotted([slot='textarea']) { + align-self: stretch; + flex-grow: 1; + } + `; + } + + /** @protected */ + render() { + return html` + + + + + + `; + } +} + +defineCustomElement(MessageInput); + +export { MessageInput }; diff --git a/packages/message-input/src/vaadin-message-input-mixin.js b/packages/message-input/src/vaadin-message-input-mixin.js index b3e14c536b..d5f198904f 100644 --- a/packages/message-input/src/vaadin-message-input-mixin.js +++ b/packages/message-input/src/vaadin-message-input-mixin.js @@ -21,6 +21,7 @@ export const MessageInputMixin = (superClass) => value: { type: String, value: '', + sync: true, }, /** @@ -45,6 +46,7 @@ export const MessageInputMixin = (superClass) => */ i18n: { type: Object, + sync: true, value: () => ({ send: 'Send', message: 'Message', @@ -59,16 +61,19 @@ export const MessageInputMixin = (superClass) => type: Boolean, value: false, reflectToAttribute: true, + sync: true, }, /** @private */ _button: { type: Object, + sync: true, }, /** @private */ _textArea: { type: Object, + sync: true, }, }; } @@ -111,8 +116,16 @@ export const MessageInputMixin = (superClass) => } }); + // With Lit version, input element renders asynchronously and it will + // override the `rows` attribute set to `1` in the `minRows` observer. + // Workaround: perform update twice to run the observer synchronously. + // TODO: needs https://github.com/vaadin/web-components/pull/8168 + if (textarea.performUpdate) { + textarea.performUpdate(); + textarea.performUpdate(); + } + const input = textarea.inputElement; - input.removeAttribute('aria-labelledby'); // Set initial height to one row input.setAttribute('rows', 1); @@ -149,12 +162,7 @@ export const MessageInputMixin = (superClass) => const message = i18n.message; textArea.placeholder = message; - - if (message) { - textArea.inputElement.setAttribute('aria-label', message); - } else { - textArea.inputElement.removeAttribute('aria-label'); - } + textArea.accessibleName = message; } } diff --git a/packages/message-input/test/message-input-lit.test.js b/packages/message-input/test/message-input-lit.test.js new file mode 100644 index 0000000000..d18a5aa4b3 --- /dev/null +++ b/packages/message-input/test/message-input-lit.test.js @@ -0,0 +1,2 @@ +import '../src/vaadin-lit-message-input.js'; +import './message-input.common.js'; diff --git a/packages/message-input/test/message-input-polymer.test.js b/packages/message-input/test/message-input-polymer.test.js new file mode 100644 index 0000000000..78c186558b --- /dev/null +++ b/packages/message-input/test/message-input-polymer.test.js @@ -0,0 +1,2 @@ +import '../src/vaadin-message-input.js'; +import './message-input.common.js'; diff --git a/packages/message-input/test/message-input.test.js b/packages/message-input/test/message-input.common.js similarity index 94% rename from packages/message-input/test/message-input.test.js rename to packages/message-input/test/message-input.common.js index 7247dbfab8..a414da07b3 100644 --- a/packages/message-input/test/message-input.test.js +++ b/packages/message-input/test/message-input.common.js @@ -1,13 +1,13 @@ import { expect } from '@vaadin/chai-plugins'; -import { enterKeyDown, fixtureSync } from '@vaadin/testing-helpers'; +import { enterKeyDown, fixtureSync, nextFrame, nextRender } from '@vaadin/testing-helpers'; import sinon from 'sinon'; -import '../vaadin-message-input.js'; describe('message-input', () => { let messageInput, textArea, button; - beforeEach(() => { + beforeEach(async () => { messageInput = fixtureSync(''); + await nextRender(); textArea = messageInput.querySelector('vaadin-text-area'); button = messageInput.querySelector('vaadin-button'); }); @@ -102,13 +102,15 @@ describe('message-input', () => { expect(textArea.placeholder).to.be.equal('Viesti'); }); - it('should translate aria-label', () => { + it('should translate aria-label', async () => { messageInput.i18n = { ...messageInput.i18n, message: 'Viesti' }; + await nextFrame(); expect(textArea.inputElement.getAttribute('aria-label')).to.be.equal('Viesti'); }); - it('should remove aria-label attribute when translation not defined', () => { + it('should remove aria-label attribute when translation not defined', async () => { messageInput.i18n = {}; + await nextFrame(); expect(textArea.inputElement.hasAttribute('aria-label')).to.equal(false); }); }); diff --git a/packages/message-input/theme/lumo/vaadin-lit-message-input.js b/packages/message-input/theme/lumo/vaadin-lit-message-input.js new file mode 100644 index 0000000000..d8cc22b994 --- /dev/null +++ b/packages/message-input/theme/lumo/vaadin-lit-message-input.js @@ -0,0 +1,4 @@ +import '@vaadin/button/theme/lumo/vaadin-lit-button.js'; +import '@vaadin/text-area/theme/lumo/vaadin-lit-text-area.js'; +import './vaadin-message-input-styles.js'; +import '../../src/vaadin-lit-message-input.js'; diff --git a/packages/message-input/theme/material/vaadin-lit-message-input.js b/packages/message-input/theme/material/vaadin-lit-message-input.js new file mode 100644 index 0000000000..00a52199f8 --- /dev/null +++ b/packages/message-input/theme/material/vaadin-lit-message-input.js @@ -0,0 +1,4 @@ +import '@vaadin/button/theme/material/vaadin-lit-button.js'; +import '@vaadin/text-area/theme/material/vaadin-lit-text-area.js'; +import './vaadin-message-input-styles.js'; +import '../../src/vaadin-lit-message-input.js'; diff --git a/packages/message-input/vaadin-lit-message-input.d.ts b/packages/message-input/vaadin-lit-message-input.d.ts new file mode 100644 index 0000000000..1e5bb272d4 --- /dev/null +++ b/packages/message-input/vaadin-lit-message-input.d.ts @@ -0,0 +1 @@ +export * from './src/vaadin-message-input.js'; diff --git a/packages/message-input/vaadin-lit-message-input.js b/packages/message-input/vaadin-lit-message-input.js new file mode 100644 index 0000000000..a4484c9f18 --- /dev/null +++ b/packages/message-input/vaadin-lit-message-input.js @@ -0,0 +1,2 @@ +import './theme/lumo/vaadin-lit-message-input.js'; +export * from './src/vaadin-lit-message-input.js';