feat(textarea): add types
This commit is contained in:
parent
06123918d0
commit
98fa7ad6b5
5 changed files with 55 additions and 8 deletions
5
.changeset/young-camels-appear.md
Normal file
5
.changeset/young-camels-appear.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/textarea': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add types for textarea package
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lion/core": "0.12.0",
|
"@lion/core": "0.12.0",
|
||||||
"@lion/form-core": "0.6.1",
|
"@lion/form-core": "0.6.1",
|
||||||
|
"@types/autosize": "^3.0.7",
|
||||||
"autosize": "4.0.2"
|
"autosize": "4.0.2"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// @ts-expect-error https://github.com/jackmoore/autosize/pull/384 wait for this, then we can switch to just 'autosize'; and then types will work!
|
||||||
import autosize from 'autosize/src/autosize.js';
|
import autosize from 'autosize/src/autosize.js';
|
||||||
import { LionField } from '@lion/form-core';
|
import { LionField } from '@lion/form-core';
|
||||||
import { css } from '@lion/core';
|
import { css } from '@lion/core';
|
||||||
|
|
@ -8,6 +9,7 @@ import { css } from '@lion/core';
|
||||||
* @customElement lion-textarea
|
* @customElement lion-textarea
|
||||||
* @extends {LionField}
|
* @extends {LionField}
|
||||||
*/
|
*/
|
||||||
|
// @ts-expect-error false positive for incompatible static get properties. Lit-element merges super properties already for you.
|
||||||
export class LionTextarea extends LionField {
|
export class LionTextarea extends LionField {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -47,11 +49,23 @@ export class LionTextarea extends LionField {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input node here is the textarea, which is not compatible with LionField _inputNode --> HTMLInputElement
|
||||||
|
* Therefore we do a full override and typecast to an intersection type that includes HTMLTextAreaElement
|
||||||
|
* @returns {HTMLTextAreaElement & HTMLInputElement}
|
||||||
|
*/
|
||||||
|
get _inputNode() {
|
||||||
|
return /** @type {HTMLTextAreaElement & HTMLInputElement} */ (Array.from(this.children).find(
|
||||||
|
el => el.slot === 'input',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.rows = 2;
|
this.rows = 2;
|
||||||
this.maxRows = 6;
|
this.maxRows = 6;
|
||||||
this.readOnly = false;
|
this.readOnly = false;
|
||||||
|
this.placeholder = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
|
@ -61,12 +75,11 @@ export class LionTextarea extends LionField {
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
if (super.disconnectedCallback) {
|
super.disconnectedCallback();
|
||||||
super.disconnectedCallback();
|
|
||||||
}
|
|
||||||
autosize.destroy(this._inputNode);
|
autosize.destroy(this._inputNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {import('lit-element').PropertyValues } changedProperties */
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
if (changedProperties.has('rows')) {
|
if (changedProperties.has('rows')) {
|
||||||
|
|
@ -121,7 +134,7 @@ export class LionTextarea extends LionField {
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [
|
||||||
...super.styles,
|
super.styles,
|
||||||
css`
|
css`
|
||||||
.input-group__container > .input-group__input ::slotted(.form-control) {
|
.input-group__container > .input-group__input ::slotted(.form-control) {
|
||||||
overflow-x: hidden; /* for FF adds height to the TextArea to reserve place for scroll-bars */
|
overflow-x: hidden; /* for FF adds height to the TextArea to reserve place for scroll-bars */
|
||||||
|
|
@ -142,6 +155,7 @@ export class LionTextarea extends LionField {
|
||||||
}
|
}
|
||||||
|
|
||||||
__initializeAutoresize() {
|
__initializeAutoresize() {
|
||||||
|
// @ts-ignore this property is added by webcomponentsjs polyfill for old browsers
|
||||||
if (this.__shady_native_contains) {
|
if (this.__shady_native_contains) {
|
||||||
this.__textareaUpdateComplete = this.__waitForTextareaRenderedInRealDOM().then(() => {
|
this.__textareaUpdateComplete = this.__waitForTextareaRenderedInRealDOM().then(() => {
|
||||||
this.__startAutoresize();
|
this.__startAutoresize();
|
||||||
|
|
@ -154,6 +168,7 @@ export class LionTextarea extends LionField {
|
||||||
|
|
||||||
async __waitForTextareaRenderedInRealDOM() {
|
async __waitForTextareaRenderedInRealDOM() {
|
||||||
let count = 3; // max tasks to wait for
|
let count = 3; // max tasks to wait for
|
||||||
|
// @ts-ignore this property is added by webcomponentsjs polyfill for old browsers
|
||||||
while (count !== 0 && !this.__shady_native_contains(this._inputNode)) {
|
while (count !== 0 && !this.__shady_native_contains(this._inputNode)) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await new Promise(resolve => setTimeout(resolve));
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
import { expect, fixture, html } from '@open-wc/testing';
|
import { expect, fixture as _fixture, html } from '@open-wc/testing';
|
||||||
import '../lion-textarea.js';
|
import '../lion-textarea.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../src/LionTextarea').LionTextarea} LionTextarea
|
||||||
|
* @typedef {import('lit-html').TemplateResult} TemplateResult
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fixture = /** @type {(arg: TemplateResult|string) => Promise<LionTextarea>} */ (_fixture);
|
||||||
|
|
||||||
function hasBrowserResizeSupport() {
|
function hasBrowserResizeSupport() {
|
||||||
const textarea = document.createElement('textarea');
|
const textarea = document.createElement('textarea');
|
||||||
return textarea.style.resize !== undefined;
|
return textarea.style.resize !== undefined;
|
||||||
|
|
@ -12,7 +19,7 @@ describe('<lion-textarea>', () => {
|
||||||
<lion-textarea></lion-textarea>
|
<lion-textarea></lion-textarea>
|
||||||
~~~`, async () => {
|
~~~`, async () => {
|
||||||
const el = await fixture(`<lion-textarea></lion-textarea>`);
|
const el = await fixture(`<lion-textarea></lion-textarea>`);
|
||||||
expect(el.querySelector('textarea').nodeName).to.equal('TEXTAREA');
|
expect(el.querySelector('textarea')?.nodeName).to.equal('TEXTAREA');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has .rows=2 and .maxRows=6', async () => {
|
it('has .rows=2 and .maxRows=6', async () => {
|
||||||
|
|
@ -42,7 +49,7 @@ describe('<lion-textarea>', () => {
|
||||||
it('sync readOnly to the native textarea', async () => {
|
it('sync readOnly to the native textarea', async () => {
|
||||||
const el = await fixture(`<lion-textarea readonly>foo</lion-textarea>`);
|
const el = await fixture(`<lion-textarea readonly>foo</lion-textarea>`);
|
||||||
expect(el.readOnly).to.be.true;
|
expect(el.readOnly).to.be.true;
|
||||||
expect(el.querySelector('textarea').readOnly).to.be.true;
|
expect(el.querySelector('textarea')?.readOnly).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables user resize behavior', async () => {
|
it('disables user resize behavior', async () => {
|
||||||
|
|
@ -59,7 +66,7 @@ describe('<lion-textarea>', () => {
|
||||||
const el = await fixture(
|
const el = await fixture(
|
||||||
html`<lion-textarea .modelValue="${'From value attribute'}"></lion-textarea>`,
|
html`<lion-textarea .modelValue="${'From value attribute'}"></lion-textarea>`,
|
||||||
);
|
);
|
||||||
expect(el.querySelector('textarea').value).to.equal('From value attribute');
|
expect(el.querySelector('textarea')?.value).to.equal('From value attribute');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adjusts height based on content', async () => {
|
it('adjusts height based on content', async () => {
|
||||||
|
|
|
||||||
19
yarn.lock
19
yarn.lock
|
|
@ -2057,6 +2057,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/autosize@^3.0.7":
|
||||||
|
version "3.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/autosize/-/autosize-3.0.7.tgz#f5da28d7ea4532c8b60573d67ec04fc866fa13db"
|
||||||
|
integrity sha512-D46m3aBNg81QKk9ZigmDFuhXUkD4IpBSrkGUKpYo2QBETbUjqEe8msXNCcECaXLXv1O4ppdMpizgFRzpfrgOxA==
|
||||||
|
dependencies:
|
||||||
|
"@types/jquery" "*"
|
||||||
|
|
||||||
"@types/babel__code-frame@^7.0.1":
|
"@types/babel__code-frame@^7.0.1":
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.1.tgz#baf2529c4abbfb5e4008c845efcfe39a187e2f99"
|
resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.1.tgz#baf2529c4abbfb5e4008c845efcfe39a187e2f99"
|
||||||
|
|
@ -2253,6 +2260,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
||||||
integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==
|
integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==
|
||||||
|
|
||||||
|
"@types/jquery@*":
|
||||||
|
version "3.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.1.tgz#cebb057acf5071c40e439f30e840c57a30d406c3"
|
||||||
|
integrity sha512-Tyctjh56U7eX2b9udu3wG853ASYP0uagChJcQJXLUXEU6C/JiW5qt5dl8ao01VRj1i5pgXPAf8f1mq4+FDLRQg==
|
||||||
|
dependencies:
|
||||||
|
"@types/sizzle" "*"
|
||||||
|
|
||||||
"@types/json5@^0.0.29":
|
"@types/json5@^0.0.29":
|
||||||
version "0.0.29"
|
version "0.0.29"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
|
|
@ -2455,6 +2469,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
|
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
|
||||||
integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
|
integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
|
||||||
|
|
||||||
|
"@types/sizzle@*":
|
||||||
|
version "2.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
|
||||||
|
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
|
||||||
|
|
||||||
"@types/uglify-js@*":
|
"@types/uglify-js@*":
|
||||||
version "3.9.3"
|
version "3.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.3.tgz#d94ed608e295bc5424c9600e6b8565407b6b4b6b"
|
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.3.tgz#d94ed608e295bc5424c9600e6b8565407b6b4b6b"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue