diff --git a/textfield/lib/text-field.ts b/textfield/lib/text-field.ts
index 48b8885416..24d2995c37 100644
--- a/textfield/lib/text-field.ts
+++ b/textfield/lib/text-field.ts
@@ -145,6 +145,12 @@ export abstract class TextField extends LitElement {
}
// properties
+ /**
+ * Defines the greatest value in the range of permitted values.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#max
+ */
+ @property({type: String}) max = '';
/**
* The maximum number of characters a user can enter into the text field. Set
* to -1 for none.
@@ -152,6 +158,12 @@ export abstract class TextField extends LitElement {
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#maxlength
*/
@property({type: Number}) maxLength = -1;
+ /**
+ * Defines the most negative value in the range of permitted values.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#min
+ */
+ @property({type: String}) min = '';
/**
* The minimum number of characters a user can enter into the text field. Set
* to -1 for none.
@@ -193,6 +205,14 @@ export abstract class TextField extends LitElement {
this.getInput().selectionStart = value;
}
+ /**
+ * Returns or sets the element's step attribute, which works with min and max
+ * to limit the increments at which a numeric or date-time value can be set.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#step
+ */
+ @property({type: String}) step = '';
+
// TODO(b/237284412): replace with exported types
@property({type: String, reflect: true})
type: 'email'|'number'|'password'|'search'|'tel'|'text'|'url'|'color'|'date'|
@@ -379,6 +399,34 @@ export abstract class TextField extends LitElement {
this.getInput().setSelectionRange(start, end, direction);
}
+ /**
+ * Decrements the value of a numeric type text field by `step` or `n` `step`
+ * number of times.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/stepDown
+ *
+ * @param stepDecrement The number of steps to decrement, defaults to 1.
+ */
+ stepDown(stepDecrement?: number) {
+ const input = this.getInput();
+ input.stepDown(stepDecrement);
+ this.value = input.value;
+ }
+
+ /**
+ * Increments the value of a numeric type text field by `step` or `n` `step`
+ * number of times.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/stepUp
+ *
+ * @param stepIncrement The number of steps to increment, defaults to 1.
+ */
+ stepUp(stepIncrement?: number) {
+ const input = this.getInput();
+ input.stepUp(stepIncrement);
+ this.value = input.value;
+ }
+
/**
* Reset the text field to its default value.
*/
@@ -465,10 +513,15 @@ export abstract class TextField extends LitElement {
const ariaExpandedValue = this.ariaExpanded || undefined;
const ariaLabelValue = this.ariaLabel || this.label || undefined;
const ariaLabelledByValue = this.ariaLabelledBy || undefined;
+ const maxValue = this.max || undefined;
const maxLengthValue = this.maxLength > -1 ? this.maxLength : undefined;
+ const minValue = this.min || undefined;
const minLengthValue = this.minLength > -1 ? this.minLength : undefined;
const roleValue = this.role || undefined;
+ const stepValue = this.step || undefined;
+ // TODO(b/243805848): remove `as unknown as number` once lit analyzer is
+ // fixed
return html` {
.toBeFalse();
});
});
+
+ describe('min, max, and step', () => {
+ it('should set attribute on input', async () => {
+ const {testElement, input} = await setupTest();
+ testElement.type = 'number';
+ testElement.min = '2';
+ testElement.max = '5';
+ testElement.step = '1';
+ await env.waitForStability();
+
+ expect(input.getAttribute('min')).withContext('min').toEqual('2');
+ expect(input.getAttribute('max')).withContext('max').toEqual('5');
+ expect(input.getAttribute('step')).withContext('step').toEqual('1');
+ });
+
+ it('should not set attribute if value is empty', async () => {
+ const {testElement, input} = await setupTest();
+ testElement.type = 'number';
+ testElement.min = '2';
+ testElement.max = '5';
+ testElement.step = '1';
+ await env.waitForStability();
+
+ expect(input.hasAttribute('min'))
+ .withContext('should have min')
+ .toBeTrue();
+ expect(input.hasAttribute('max'))
+ .withContext('should have max')
+ .toBeTrue();
+ expect(input.hasAttribute('step'))
+ .withContext('should have step')
+ .toBeTrue();
+
+ testElement.min = '';
+ testElement.max = '';
+ testElement.step = '';
+ await env.waitForStability();
+
+ expect(input.hasAttribute('min'))
+ .withContext('should not have min')
+ .toBeFalse();
+ expect(input.hasAttribute('max'))
+ .withContext('should not have max')
+ .toBeFalse();
+ expect(input.hasAttribute('step'))
+ .withContext('should not have step')
+ .toBeFalse();
+ });
+ });
+ });
+
+ describe('stepUp()', () => {
+ it('should increment the value by `step`', async () => {
+ const {testElement} = await setupTest();
+ testElement.type = 'number';
+ testElement.valueAsNumber = 10;
+ testElement.step = '5';
+
+ testElement.stepUp();
+
+ expect(testElement.valueAsNumber).toEqual(15);
+ });
+ });
+
+ describe('stepDown()', () => {
+ it('should decrement the value by `step`', async () => {
+ const {testElement} = await setupTest();
+ testElement.type = 'number';
+ testElement.valueAsNumber = 10;
+ testElement.step = '5';
+
+ testElement.stepDown();
+
+ expect(testElement.valueAsNumber).toEqual(5);
+ });
});
// TODO(b/235238545): Add shared FormController tests.