Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit d7b9345

Browse files
lynnmercierbwobrien
authored andcommitted
feat(text-field): Add properties for value, disable, value, and required (#1873)
BREAKING CHANGE: - The return type for `MDCTextFieldAdapter.getNativeInput()` has changed. See the 'NativeInputType` typedef in the adapter. - MDCTextFieldLabelFoundation has removed: - `floatAbove` - `deactivateFocus` - `setValidity` - They are replaced with methods for updating the label float and label shake styles: - `styleFloat` - `styleShake`
1 parent e9f02ed commit d7b9345

File tree

9 files changed

+488
-112
lines changed

9 files changed

+488
-112
lines changed

packages/mdc-textfield/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,10 @@ See [Importing the JS component](../../docs/importing-js.md) for more informatio
205205

206206
Property | Value Type | Description
207207
--- | --- | ---
208-
`disable` | Boolean | Proxies to the foundation's `isDisabled`/`setDisabled` methods when retrieved/set respectively
209-
`valid` | Boolean | Proxies to the foundation's `setValid` method when set
208+
`value` | String | Proxies to the foundation's `getValue`/`setValue` methods.
209+
`disabled` | Boolean | Proxies to the foundation's `isDisabled`/`setDisabled` methods.
210+
`valid` | Boolean | Proxies to the foundation's `isValid`/`setValid` methods.
211+
`required` | Boolean | Proxies to the foundation's `isRequired`/`setRequired` methods.
210212
`helperTextContent` | String | Proxies to the foundation's `setHelperTextContent` method when set
211213
`ripple` | `MDCRipple` | The `MDCRipple` instance for the root element that `MDCTextField` initializes
212214

@@ -248,9 +250,14 @@ Returns the idle outline element's computed style value of the given css propert
248250

249251
Method Signature | Description
250252
--- | ---
253+
`getValue() => string` | Returns the input's value.
254+
`setValue(value: string)` | Sets the input's value.
255+
`isValid() => boolean` | If a custom validity is set, returns that value. Otherwise, returns the result of native validity checks.
256+
`setValid(isValid: boolean)` | Sets custom validity. Once set, native validity checking is ignored.
251257
`isDisabled() => boolean` | Returns whether or not the input is disabled
252258
`setDisabled(disabled: boolean) => void` | Updates the input's disabled state
253-
`setValid(isValid: boolean) => void` | Sets the validity state of the Text Field. Triggers custom validity checking
259+
`isRequired() => boolean` | Returns whether the input is required.
260+
`setRequired(isRequired: boolean)` | Sets whether the input is required.
254261
`handleTextFieldInteraction(evt: Event) => void` | Handles click and keydown events originating from inside the Text Field component
255262
`activateFocus() => void` | Activates the focus state of the Text Field. Normally called in response to the input focus event.
256263
`deactivateFocus() => void` | Deactivates the focus state of the Text Field. Normally called in response to the input blur event.

packages/mdc-textfield/adapter.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ import MDCTextFieldLabelFoundation from './label/foundation';
2828
* value: string,
2929
* disabled: boolean,
3030
* badInput: boolean,
31-
* checkValidity: (function(): boolean)
31+
* validity: {
32+
* badInput: boolean,
33+
* valid: boolean,
34+
* },
3235
* }}
3336
*/
3437
let NativeInputType;

packages/mdc-textfield/foundation.js

Lines changed: 139 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class MDCTextFieldFoundation extends MDCFoundation {
9595
this.receivedUserInput_ = false;
9696
/** @private {boolean} */
9797
this.useCustomValidityChecking_ = false;
98+
/** @private {boolean} */
99+
this.isValid_ = true;
98100
/** @private {function(): undefined} */
99101
this.inputFocusHandler_ = () => this.activateFocus();
100102
/** @private {function(): undefined} */
@@ -112,8 +114,9 @@ class MDCTextFieldFoundation extends MDCFoundation {
112114
init() {
113115
this.adapter_.addClass(MDCTextFieldFoundation.cssClasses.UPGRADED);
114116
// Ensure label does not collide with any pre-filled value.
115-
if (this.getNativeInput_().value && this.label_) {
116-
this.label_.floatAbove();
117+
if (this.label_ && this.getValue()) {
118+
this.label_.styleFloat(
119+
this.getValue(), this.isFocused_, this.isBadInput_());
117120
}
118121

119122
if (this.adapter_.isFocused()) {
@@ -181,21 +184,22 @@ class MDCTextFieldFoundation extends MDCFoundation {
181184
* Activates the text field focus state.
182185
*/
183186
activateFocus() {
184-
const {FOCUSED} = MDCTextFieldFoundation.cssClasses;
185-
this.adapter_.addClass(FOCUSED);
187+
this.isFocused_ = true;
188+
this.styleFocused_(this.isFocused_);
186189
if (this.bottomLine_) {
187190
this.bottomLine_.activate();
188191
}
189192
if (this.outline_) {
190193
this.updateOutline();
191194
}
192195
if (this.label_) {
193-
this.label_.floatAbove();
196+
this.label_.styleShake(this.isValid(), this.isFocused_);
197+
this.label_.styleFloat(
198+
this.getValue(), this.isFocused_, this.isBadInput_());
194199
}
195200
if (this.helperText_) {
196201
this.helperText_.showToScreenReader();
197202
}
198-
this.isFocused_ = true;
199203
}
200204

201205
/**
@@ -233,54 +237,67 @@ class MDCTextFieldFoundation extends MDCFoundation {
233237
}
234238

235239
/**
236-
* Deactives the Text Field's focus state.
240+
* Deactivates the Text Field's focus state.
237241
*/
238242
deactivateFocus() {
239-
const {FOCUSED} = MDCTextFieldFoundation.cssClasses;
243+
this.isFocused_ = false;
240244
const input = this.getNativeInput_();
241245
const shouldRemoveLabelFloat = !input.value && !this.isBadInput_();
242-
243-
this.isFocused_ = false;
244-
this.adapter_.removeClass(FOCUSED);
246+
const isValid = this.isValid();
247+
this.styleValidity_(isValid);
248+
this.styleFocused_(this.isFocused_);
245249
if (this.label_) {
246-
this.label_.deactivateFocus(shouldRemoveLabelFloat);
250+
this.label_.styleShake(this.isValid(), this.isFocused_);
251+
this.label_.styleFloat(
252+
this.getValue(), this.isFocused_, this.isBadInput_());
247253
}
248254
if (shouldRemoveLabelFloat) {
249255
this.receivedUserInput_ = false;
250256
}
257+
}
251258

252-
if (!this.useCustomValidityChecking_) {
253-
this.changeValidity_(input.checkValidity());
254-
}
259+
/**
260+
* @return {string} The value of the input Element.
261+
*/
262+
getValue() {
263+
return this.getNativeInput_().value;
255264
}
256265

257266
/**
258-
* Updates the Text Field's valid state based on the supplied validity.
259-
* @param {boolean} isValid
260-
* @private
267+
* @param {string} value The value to set on the input Element.
261268
*/
262-
changeValidity_(isValid) {
263-
const {INVALID} = MDCTextFieldFoundation.cssClasses;
264-
if (isValid) {
265-
this.adapter_.removeClass(INVALID);
266-
} else {
267-
this.adapter_.addClass(INVALID);
268-
}
269-
if (this.helperText_) {
270-
this.helperText_.setValidity(isValid);
271-
}
269+
setValue(value) {
270+
this.getNativeInput_().value = value;
271+
const isValid = this.isValid();
272+
this.styleValidity_(isValid);
272273
if (this.label_) {
273-
this.label_.setValidity(isValid);
274+
this.label_.styleShake(isValid, this.isFocused_);
275+
this.label_.styleFloat(
276+
this.getValue(), this.isFocused_, this.isBadInput_());
274277
}
275278
}
276279

277280
/**
278-
* @return {boolean} True if the Text Field input fails validity checks.
279-
* @private
281+
* @return {boolean} If a custom validity is set, returns that value.
282+
* Otherwise, returns the result of native validity checks.
280283
*/
281-
isBadInput_() {
282-
const input = this.getNativeInput_();
283-
return input.validity ? input.validity.badInput : input.badInput;
284+
isValid() {
285+
return this.useCustomValidityChecking_
286+
? this.isValid_ : this.isNativeInputValid_();
287+
}
288+
289+
/**
290+
* @param {boolean} isValid Sets the validity state of the Text Field.
291+
*/
292+
setValid(isValid) {
293+
this.useCustomValidityChecking_ = true;
294+
this.isValid_ = isValid;
295+
// Retrieve from the getter to ensure correct logic is applied.
296+
isValid = this.isValid();
297+
this.styleValidity_(isValid);
298+
if (this.label_) {
299+
this.label_.styleShake(isValid, this.isFocused_);
300+
}
284301
}
285302

286303
/**
@@ -294,17 +311,25 @@ class MDCTextFieldFoundation extends MDCFoundation {
294311
* @param {boolean} disabled Sets the text-field disabled or enabled.
295312
*/
296313
setDisabled(disabled) {
297-
const {DISABLED, INVALID} = MDCTextFieldFoundation.cssClasses;
298314
this.getNativeInput_().disabled = disabled;
299-
if (disabled) {
300-
this.adapter_.addClass(DISABLED);
301-
this.adapter_.removeClass(INVALID);
302-
} else {
303-
this.adapter_.removeClass(DISABLED);
304-
}
305-
if (this.icon_) {
306-
this.icon_.setDisabled(disabled);
307-
}
315+
this.styleDisabled_(disabled);
316+
}
317+
318+
/**
319+
* @return {boolean} True if the Text Field is required.
320+
*/
321+
isRequired() {
322+
return this.getNativeInput_().required;
323+
}
324+
325+
/**
326+
* @param {boolean} isRequired Sets the text-field required or not.
327+
*/
328+
setRequired(isRequired) {
329+
this.getNativeInput_().required = isRequired;
330+
// Addition of the asterisk is automatic based on CSS, but validity checking
331+
// needs to be manually run.
332+
this.styleValidity_(this.isValid());
308333
}
309334

310335
/**
@@ -316,6 +341,72 @@ class MDCTextFieldFoundation extends MDCFoundation {
316341
}
317342
}
318343

344+
/**
345+
* @return {boolean} True if the Text Field input fails in converting the
346+
* user-supplied value.
347+
* @private
348+
*/
349+
isBadInput_() {
350+
return this.getNativeInput_().validity.badInput;
351+
}
352+
353+
/**
354+
* @return {boolean} The result of native validity checking
355+
* (ValidityState.valid).
356+
*/
357+
isNativeInputValid_() {
358+
return this.getNativeInput_().validity.valid;
359+
}
360+
361+
/**
362+
* Styles the component based on the validity state.
363+
* @param {boolean} isValid
364+
* @private
365+
*/
366+
styleValidity_(isValid) {
367+
const {INVALID} = MDCTextFieldFoundation.cssClasses;
368+
if (isValid) {
369+
this.adapter_.removeClass(INVALID);
370+
} else {
371+
this.adapter_.addClass(INVALID);
372+
}
373+
if (this.helperText_) {
374+
this.helperText_.setValidity(isValid);
375+
}
376+
}
377+
378+
/**
379+
* Styles the component based on the focused state.
380+
* @param {boolean} isFocused
381+
* @private
382+
*/
383+
styleFocused_(isFocused) {
384+
const {FOCUSED} = MDCTextFieldFoundation.cssClasses;
385+
if (isFocused) {
386+
this.adapter_.addClass(FOCUSED);
387+
} else {
388+
this.adapter_.removeClass(FOCUSED);
389+
}
390+
}
391+
392+
/**
393+
* Styles the component based on the disabled state.
394+
* @param {boolean} isDisabled
395+
* @private
396+
*/
397+
styleDisabled_(isDisabled) {
398+
const {DISABLED, INVALID} = MDCTextFieldFoundation.cssClasses;
399+
if (isDisabled) {
400+
this.adapter_.addClass(DISABLED);
401+
this.adapter_.removeClass(INVALID);
402+
} else {
403+
this.adapter_.removeClass(DISABLED);
404+
}
405+
if (this.icon_) {
406+
this.icon_.setDisabled(isDisabled);
407+
}
408+
}
409+
319410
/**
320411
* @return {!Element|!NativeInputType} The native text input from the
321412
* host environment, or a dummy if none exists.
@@ -324,20 +415,14 @@ class MDCTextFieldFoundation extends MDCFoundation {
324415
getNativeInput_() {
325416
return this.adapter_.getNativeInput() ||
326417
/** @type {!NativeInputType} */ ({
327-
checkValidity: () => true,
328418
value: '',
329419
disabled: false,
330-
badInput: false,
420+
validity: {
421+
badInput: false,
422+
valid: true,
423+
},
331424
});
332425
}
333-
334-
/**
335-
* @param {boolean} isValid Sets the validity state of the Text Field.
336-
*/
337-
setValid(isValid) {
338-
this.useCustomValidityChecking_ = true;
339-
this.changeValidity_(isValid);
340-
}
341426
}
342427

343428
export default MDCTextFieldFoundation;

packages/mdc-textfield/index.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,20 @@ class MDCTextField extends MDCComponent {
160160
this.disabled = this.input_.disabled;
161161
}
162162

163+
/**
164+
* @return {string} The value of the input.
165+
*/
166+
get value() {
167+
return this.foundation_.getValue();
168+
}
169+
170+
/**
171+
* @param {string} value The value to set on the input.
172+
*/
173+
set value(value) {
174+
this.foundation_.setValue(value);
175+
}
176+
163177
/**
164178
* @return {boolean} True if the Text Field is disabled.
165179
*/
@@ -174,13 +188,34 @@ class MDCTextField extends MDCComponent {
174188
this.foundation_.setDisabled(disabled);
175189
}
176190

191+
/**
192+
* @return {boolean} valid True if the Text Field is valid.
193+
*/
194+
get valid() {
195+
return this.foundation_.isValid();
196+
}
197+
177198
/**
178199
* @param {boolean} valid Sets the Text Field valid or invalid.
179200
*/
180201
set valid(valid) {
181202
this.foundation_.setValid(valid);
182203
}
183204

205+
/**
206+
* @return {boolean} True if the Text Field is required.
207+
*/
208+
get required() {
209+
return this.foundation_.isRequired();
210+
}
211+
212+
/**
213+
* @param {boolean} required Sets the Text Field to required.
214+
*/
215+
set required(required) {
216+
this.foundation_.setRequired(required);
217+
}
218+
184219
/**
185220
* Sets the helper text element content.
186221
* @param {string} content

packages/mdc-textfield/label/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ Method Signature | Description
8888

8989
Method Signature | Description
9090
--- | ---
91-
`floatAbove() => void` | Makes the label float above the text field
92-
`deactivateFocus(shouldRemoveLabelFloat: boolean) => void` | Deactivates the label's focus state. `shouldRemoveLabelFloat` indicates whether to also reset the label's position and size.
93-
`setValidity(isValid: boolean)` | Updates the label's valid state based on the supplied validity
9491
`getWidth() => number` | Returns the width of the label element
92+
`styleShake(isValid: boolean, isFocused: boolean)` | Styles the label to produce the shake effect when needed.
93+
`styleFloat(value: string, isFocused: boolean, isBadInput: boolean)` | Styles the label to float or defloat as necessary.

0 commit comments

Comments
 (0)