From 2a0d563338aa84b8038a969f9f0245a245bd78ba Mon Sep 17 00:00:00 2001 From: Elizabeth Mitchell Date: Fri, 29 Jul 2022 11:43:12 -0700 Subject: [PATCH] feat(controller): add stringConverter for empty reflecting attributes PiperOrigin-RevId: 464124340 --- controller/string-converter.ts | 14 +++++++++++++ controller/string-converter_test.ts | 32 +++++++++++++++++++++++++++++ textfield/lib/text-field.ts | 8 +++++--- 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 controller/string-converter.ts create mode 100644 controller/string-converter_test.ts diff --git a/controller/string-converter.ts b/controller/string-converter.ts new file mode 100644 index 0000000000..06ea147eca --- /dev/null +++ b/controller/string-converter.ts @@ -0,0 +1,14 @@ +/** + * @license + * Copyright 2022 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export const stringConverter = { + fromAttribute(value: string|null): string { + return value ?? ''; + }, + toAttribute(value: string): string|null { + return value || null; + } +}; diff --git a/controller/string-converter_test.ts b/controller/string-converter_test.ts new file mode 100644 index 0000000000..ebdefb562c --- /dev/null +++ b/controller/string-converter_test.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright 2022 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import 'jasmine'; + +import {stringConverter} from './string-converter'; + +describe('stringConverter', () => { + describe('.fromAttribute', () => { + it('should return an empty string if string is empty or null', () => { + expect(stringConverter.fromAttribute('')).toBe(''); + expect(stringConverter.fromAttribute(null)).toBe(''); + }); + + it('should return value of string if not empty', () => { + expect(stringConverter.fromAttribute('foo')).toBe('foo'); + }); + }); + + describe('.toAttribute', () => { + it('should return null if string is empty', () => { + expect(stringConverter.toAttribute('')).toBeNull(); + }); + + it('should return value of string if not empty', () => { + expect(stringConverter.toAttribute('foo')).toBe('foo'); + }); + }); +}); diff --git a/textfield/lib/text-field.ts b/textfield/lib/text-field.ts index a1326ee2a3..94d439c2ef 100644 --- a/textfield/lib/text-field.ts +++ b/textfield/lib/text-field.ts @@ -8,6 +8,7 @@ import {redispatchEvent} from '@material/web/controller/events'; import {FormController, getFormValue} from '@material/web/controller/form-controller'; +import {stringConverter} from '@material/web/controller/string-converter'; import {ariaProperty} from '@material/web/decorators/aria-property'; import {html, LitElement, PropertyValues, TemplateResult} from 'lit'; import {property, query, state} from 'lit/decorators'; @@ -33,7 +34,6 @@ export type UnsupportedTextFieldType = export type InvalidTextFieldType = 'button'|'checkbox'|'hidden'|'image'|'radio'|'range'|'reset'|'submit'; - /** @soyCompatible */ export class TextField extends LitElement { static override shadowRootOptions: @@ -84,14 +84,16 @@ export class TextField extends LitElement { return this.closest('form'); } - @property({type: String, reflect: true}) name = ''; + @property({type: String, reflect: true, converter: stringConverter}) + name = ''; [getFormValue]() { return this.value; } // properties - @property({type: String, reflect: true}) placeholder = ''; + @property({type: String, reflect: true, converter: stringConverter}) + placeholder = ''; @property({type: Boolean, reflect: true}) readonly = false; // TODO(b/237284412): replace with exported types @property({type: String, reflect: true})