From 98fa7ad6b51738558ab55a8dfd49ae558c24d811 Mon Sep 17 00:00:00 2001 From: Joren Broekema Date: Wed, 30 Sep 2020 17:47:12 +0200 Subject: [PATCH] feat(textarea): add types --- .changeset/young-camels-appear.md | 5 +++++ packages/textarea/package.json | 1 + packages/textarea/src/LionTextarea.js | 23 ++++++++++++++++---- packages/textarea/test/lion-textarea.test.js | 15 +++++++++---- yarn.lock | 19 ++++++++++++++++ 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 .changeset/young-camels-appear.md diff --git a/.changeset/young-camels-appear.md b/.changeset/young-camels-appear.md new file mode 100644 index 000000000..ac8639be0 --- /dev/null +++ b/.changeset/young-camels-appear.md @@ -0,0 +1,5 @@ +--- +'@lion/textarea': minor +--- + +Add types for textarea package diff --git a/packages/textarea/package.json b/packages/textarea/package.json index eecc42378..cae24fde3 100644 --- a/packages/textarea/package.json +++ b/packages/textarea/package.json @@ -33,6 +33,7 @@ "dependencies": { "@lion/core": "0.12.0", "@lion/form-core": "0.6.1", + "@types/autosize": "^3.0.7", "autosize": "4.0.2" }, "keywords": [ diff --git a/packages/textarea/src/LionTextarea.js b/packages/textarea/src/LionTextarea.js index ab91cbcd7..20bf4ba92 100644 --- a/packages/textarea/src/LionTextarea.js +++ b/packages/textarea/src/LionTextarea.js @@ -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 { LionField } from '@lion/form-core'; import { css } from '@lion/core'; @@ -8,6 +9,7 @@ import { css } from '@lion/core'; * @customElement lion-textarea * @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 { static get properties() { 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() { super(); this.rows = 2; this.maxRows = 6; this.readOnly = false; + this.placeholder = ''; } connectedCallback() { @@ -61,12 +75,11 @@ export class LionTextarea extends LionField { } disconnectedCallback() { - if (super.disconnectedCallback) { - super.disconnectedCallback(); - } + super.disconnectedCallback(); autosize.destroy(this._inputNode); } + /** @param {import('lit-element').PropertyValues } changedProperties */ updated(changedProperties) { super.updated(changedProperties); if (changedProperties.has('rows')) { @@ -121,7 +134,7 @@ export class LionTextarea extends LionField { static get styles() { return [ - ...super.styles, + super.styles, css` .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 */ @@ -142,6 +155,7 @@ export class LionTextarea extends LionField { } __initializeAutoresize() { + // @ts-ignore this property is added by webcomponentsjs polyfill for old browsers if (this.__shady_native_contains) { this.__textareaUpdateComplete = this.__waitForTextareaRenderedInRealDOM().then(() => { this.__startAutoresize(); @@ -154,6 +168,7 @@ export class LionTextarea extends LionField { async __waitForTextareaRenderedInRealDOM() { 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)) { // eslint-disable-next-line no-await-in-loop await new Promise(resolve => setTimeout(resolve)); diff --git a/packages/textarea/test/lion-textarea.test.js b/packages/textarea/test/lion-textarea.test.js index 72abcbb75..4b1be9a09 100644 --- a/packages/textarea/test/lion-textarea.test.js +++ b/packages/textarea/test/lion-textarea.test.js @@ -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'; +/** + * @typedef {import('../src/LionTextarea').LionTextarea} LionTextarea + * @typedef {import('lit-html').TemplateResult} TemplateResult + */ + +const fixture = /** @type {(arg: TemplateResult|string) => Promise} */ (_fixture); + function hasBrowserResizeSupport() { const textarea = document.createElement('textarea'); return textarea.style.resize !== undefined; @@ -12,7 +19,7 @@ describe('', () => { ~~~`, async () => { const el = await fixture(``); - expect(el.querySelector('textarea').nodeName).to.equal('TEXTAREA'); + expect(el.querySelector('textarea')?.nodeName).to.equal('TEXTAREA'); }); it('has .rows=2 and .maxRows=6', async () => { @@ -42,7 +49,7 @@ describe('', () => { it('sync readOnly to the native textarea', async () => { const el = await fixture(`foo`); 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 () => { @@ -59,7 +66,7 @@ describe('', () => { const el = await fixture( html``, ); - 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 () => { diff --git a/yarn.lock b/yarn.lock index 488644a74..b908900ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2057,6 +2057,13 @@ dependencies: "@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": version "7.0.1" 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" 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": version "0.0.29" 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" 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@*": version "3.9.3" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.3.tgz#d94ed608e295bc5424c9600e6b8565407b6b4b6b"