diff --git a/change/@fluentui-web-components-7901265e-589d-4d51-8bb8-320a376cb79d.json b/change/@fluentui-web-components-7901265e-589d-4d51-8bb8-320a376cb79d.json new file mode 100644 index 00000000000000..238972491fccce --- /dev/null +++ b/change/@fluentui-web-components-7901265e-589d-4d51-8bb8-320a376cb79d.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "add current-value attribute to text-input", + "packageName": "@fluentui/web-components", + "email": "863023+radium-v@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/web-components/docs/api-report.md b/packages/web-components/docs/api-report.md index 6a49a130b20222..34a685264c2c0d 100644 --- a/packages/web-components/docs/api-report.md +++ b/packages/web-components/docs/api-report.md @@ -792,6 +792,9 @@ export class BaseTextInput extends FASTElement { control: HTMLInputElement; // @internal controlLabel: HTMLLabelElement; + currentValue: string; + // @internal + currentValueChanged(prev: string, next: string): void; // @internal defaultSlottedNodes: Node[]; // @internal diff --git a/packages/web-components/src/text-input/text-input.spec.ts b/packages/web-components/src/text-input/text-input.spec.ts index f16fa96736308c..839ec937ef5a7b 100644 --- a/packages/web-components/src/text-input/text-input.spec.ts +++ b/packages/web-components/src/text-input/text-input.spec.ts @@ -833,4 +833,85 @@ test.describe('TextInput', () => { await expect(control).toBeFocused(); }); }); + + test('should reset the value to an empty string when the form is reset', async ({ page }) => { + const element = page.locator('fluent-text-input'); + const control = element.locator('input'); + const reset = page.locator('button'); + + await page.setContent(/* html */ ` +
+ + +
+ `); + + await expect(control).toHaveValue(''); + + await control.fill('hello'); + + await reset.click(); + + await expect(control).toHaveValue(''); + }); + + test('should change the `value` property when the `current-value` attribute changes', async ({ page }) => { + const element = page.locator('fluent-text-input'); + + await page.setContent(/* html */ ` + + `); + + await element.evaluate(node => { + node.setAttribute('current-value', 'foo'); + }); + + await expect(element).toHaveJSProperty('value', 'foo'); + }); + + test('should change the `value` property when the `currentValue` property changes', async ({ page }) => { + const element = page.locator('fluent-text-input'); + + await page.setContent(/* html */ ` + + `); + + await element.evaluate((node: TextInput) => { + node.currentValue = 'foo'; + }); + + await expect(element).toHaveJSProperty('value', 'foo'); + }); + + test('should set the `current-value` attribute to match the `value` property', async ({ page }) => { + const element = page.locator('fluent-text-input'); + + await page.setContent(/* html */ ` + + `); + + await expect(element).not.toHaveAttribute('current-value'); + + await element.evaluate((node: TextInput) => { + node.value = 'foo'; + }); + + await expect(element).toHaveAttribute('current-value', 'foo'); + }); + + test('should set the `currentValue` property to match the `value` property', async ({ page }) => { + const element = page.locator('fluent-text-input'); + + await page.setContent(/* html */ ` + + `); + + await expect(element).toHaveJSProperty('currentValue', undefined); + + await element.evaluate((node: TextInput) => { + node.value = 'foo'; + }); + + await expect(element).toHaveJSProperty('currentValue', 'foo'); + }); }); diff --git a/packages/web-components/src/text-input/text-input.ts b/packages/web-components/src/text-input/text-input.ts index 0d844c5e3d52e5..ab4e16b6e97154 100644 --- a/packages/web-components/src/text-input/text-input.ts +++ b/packages/web-components/src/text-input/text-input.ts @@ -44,6 +44,27 @@ export class BaseTextInput extends FASTElement { @attr({ mode: 'boolean' }) public autofocus!: boolean; + /** + * The current value of the input. + * @public + * @remarks + * HTML Attribute: `current-value` + */ + @attr({ attribute: 'current-value' }) + public currentValue!: string; + + /** + * Tracks the current value of the input. + * + * @param prev - the previous value + * @param next - the next value + * + * @internal + */ + currentValueChanged(prev: string, next: string): void { + this.value = next; + } + /** * The default slotted content. This is the content that appears in the text field label. * @@ -274,13 +295,6 @@ export class BaseTextInput extends FASTElement { @attr public type: TextInputType = TextInputType.text; - /** - * The current value of the input. - * - * @internal - */ - private _value: string = this.initialValue; - /** * A reference to the internal input element. * @@ -346,14 +360,14 @@ export class BaseTextInput extends FASTElement { */ public get value(): string { Observable.track(this, 'value'); - return this._value; + return this.currentValue; } public set value(value: string) { - this._value = value; + this.currentValue = value; if (this.$fastController.isConnected) { - this.control.value = value; + this.control.value = value ?? ''; this.setFormValue(value); this.setValidity(); Observable.notify(this, 'value');