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

Commit 4bbe551

Browse files
refactor(textfield): Refactor foundation class
1 parent f03ffcb commit 4bbe551

File tree

2 files changed

+60
-28
lines changed

2 files changed

+60
-28
lines changed

packages/mdc-textfield/foundation.js

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class MDCTextfieldFoundation extends MDCFoundation {
7979
this.receivedUserInput_ = false;
8080
/** @private {boolean} */
8181
this.useCustomValidityChecking_ = false;
82+
/** @private {boolean} */
83+
this.labelFloatIsActive_ = false;
84+
/** @private {boolean} */
85+
this.setValueIsProcessing_ = false;
8286
/** @private {function(): undefined} */
8387
this.inputFocusHandler_ = () => this.activateFocus_();
8488
/** @private {function(): undefined} */
@@ -96,9 +100,7 @@ class MDCTextfieldFoundation extends MDCFoundation {
96100
init() {
97101
this.adapter_.addClass(MDCTextfieldFoundation.cssClasses.UPGRADED);
98102
// Ensure label does not collide with any pre-filled value.
99-
if (this.getNativeInput_().value) {
100-
this.adapter_.addClassToLabel(MDCTextfieldFoundation.cssClasses.LABEL_FLOAT_ABOVE);
101-
}
103+
this.updateLabelFloat_();
102104

103105
this.adapter_.registerInputInteractionHandler('focus', this.inputFocusHandler_);
104106
this.adapter_.registerInputInteractionHandler('blur', this.inputBlurHandler_);
@@ -155,13 +157,13 @@ class MDCTextfieldFoundation extends MDCFoundation {
155157
* @private
156158
*/
157159
activateFocus_() {
158-
const {BOTTOM_LINE_ACTIVE, FOCUSED, LABEL_FLOAT_ABOVE, LABEL_SHAKE} = MDCTextfieldFoundation.cssClasses;
160+
const {BOTTOM_LINE_ACTIVE, FOCUSED, LABEL_SHAKE} = MDCTextfieldFoundation.cssClasses;
161+
this.isFocused_ = true;
162+
this.updateLabelFloat_();
159163
this.adapter_.addClass(FOCUSED);
160164
this.adapter_.addClassToBottomLine(BOTTOM_LINE_ACTIVE);
161-
this.adapter_.addClassToLabel(LABEL_FLOAT_ABOVE);
162165
this.adapter_.removeClassFromLabel(LABEL_SHAKE);
163166
this.showHelptext_();
164-
this.isFocused_ = true;
165167
}
166168

167169
/**
@@ -196,21 +198,18 @@ class MDCTextfieldFoundation extends MDCFoundation {
196198
* @private
197199
*/
198200
updateLabelFloat_() {
199-
// Don't do anything if the input is focused.
200-
if (!this.isFocused_) {
201-
const {LABEL_FLOAT_ABOVE, LABEL_SHAKE} = MDCTextfieldFoundation.cssClasses;
202-
const input = this.getNativeInput_();
201+
const input = this.getNativeInput_();
202+
const {LABEL_FLOAT_ABOVE} = MDCTextfieldFoundation.cssClasses;
203203

204-
if (input.value) {
204+
if (this.isFocused_ || input.value) {
205+
if (!this.labelFloatIsActive_) {
206+
this.labelFloatIsActive_ = true;
205207
this.adapter_.addClassToLabel(LABEL_FLOAT_ABOVE);
206-
} else {
207-
this.adapter_.removeClassFromLabel(LABEL_FLOAT_ABOVE);
208208
}
209-
210-
if (!this.useCustomValidityChecking_) {
211-
this.adapter_.removeClassFromLabel(LABEL_SHAKE);
212-
this.showHelptext_();
213-
this.changeValidity_(input.checkValidity());
209+
} else {
210+
if (this.labelFloatIsActive_) {
211+
this.labelFloatIsActive_ = false;
212+
this.adapter_.removeClassFromLabel(LABEL_FLOAT_ABOVE);
214213
}
215214
}
216215
}
@@ -246,19 +245,24 @@ class MDCTextfieldFoundation extends MDCFoundation {
246245
* @private
247246
*/
248247
deactivateFocus_() {
249-
const {FOCUSED, LABEL_FLOAT_ABOVE, LABEL_SHAKE} = MDCTextfieldFoundation.cssClasses;
248+
const {FOCUSED, LABEL_SHAKE} = MDCTextfieldFoundation.cssClasses;
250249
const input = this.getNativeInput_();
251250

252251
this.isFocused_ = false;
253252
this.adapter_.removeClass(FOCUSED);
254253
this.adapter_.removeClassFromLabel(LABEL_SHAKE);
255254

256255
if (!input.value && !this.isBadInput_()) {
257-
this.adapter_.removeClassFromLabel(LABEL_FLOAT_ABOVE);
256+
this.updateLabelFloat_();
258257
this.receivedUserInput_ = false;
259258
}
260259

260+
this.updateDefaultValidity_();
261+
}
262+
263+
updateDefaultValidity_() {
261264
if (!this.useCustomValidityChecking_) {
265+
const input = this.getNativeInput_();
262266
this.changeValidity_(input.checkValidity());
263267
}
264268
}
@@ -273,8 +277,11 @@ class MDCTextfieldFoundation extends MDCFoundation {
273277
if (isValid) {
274278
this.adapter_.removeClass(INVALID);
275279
} else {
276-
this.adapter_.addClassToLabel(LABEL_SHAKE);
277280
this.adapter_.addClass(INVALID);
281+
282+
if (this.isFocused_) {
283+
this.adapter_.addClassToLabel(LABEL_SHAKE);
284+
}
278285
}
279286
this.updateHelptext_(isValid);
280287
}
@@ -343,6 +350,20 @@ class MDCTextfieldFoundation extends MDCFoundation {
343350
}
344351
}
345352

353+
/**
354+
* @param {string} value The value of the textfield.
355+
*/
356+
setValue(value) {
357+
this.setValueIsProcessing_ = true;
358+
359+
const input = this.getNativeInput_();
360+
input.value = value;
361+
this.updateLabelFloat_();
362+
this.updateDefaultValidity_();
363+
364+
this.setValueIsProcessing_ = false;
365+
}
366+
346367
/**
347368
* @return {!Element|!NativeInputType} The native text input from the
348369
* host environment, or a dummy if none exists.
@@ -379,8 +400,10 @@ class MDCTextfieldFoundation extends MDCFoundation {
379400
const nativeInputElementDesc = /** @type {!ObjectPropertyDescriptor} */ ({
380401
get: desc.get,
381402
set: (value) => {
382-
desc.set.call(nativeInputElement, value);
383-
this.updateLabelFloat_();
403+
if (!this.setValueIsProcessing_) {
404+
desc.set.call(nativeInputElement, value);
405+
this.setValue(value);
406+
}
384407
},
385408
configurable: desc.configurable,
386409
enumerable: desc.enumerable,

test/unit/mdc-textfield/foundation.test.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,17 +315,25 @@ test('on focus removes aria-hidden from helptext', () => {
315315
const setupBlurTest = () => {
316316
const {foundation, mockAdapter} = setupTest();
317317
let blur;
318-
td.when(mockAdapter.registerInputInteractionHandler('blur', td.matchers.isA(Function))).thenDo((evtType, handler) => {
319-
blur = handler;
320-
});
318+
td.when(mockAdapter.registerInputInteractionHandler('blur', td.matchers.isA(Function))).thenDo(
319+
(evtType, handler) => {
320+
blur = handler;
321+
}
322+
);
323+
let focus;
324+
td.when(mockAdapter.registerInputInteractionHandler('focus', td.matchers.isA(Function))).thenDo(
325+
(evtType, handler) => {
326+
focus = handler;
327+
}
328+
);
321329
const nativeInput = {
322330
value: '',
323331
checkValidity: () => true,
324332
};
325333
td.when(mockAdapter.getNativeInput()).thenReturn(nativeInput);
326334
foundation.init();
327335

328-
return {foundation, mockAdapter, blur, nativeInput};
336+
return {foundation, mockAdapter, focus, blur, nativeInput};
329337
};
330338

331339
test('on blur removes mdc-textfield--focused class', () => {
@@ -335,7 +343,8 @@ test('on blur removes mdc-textfield--focused class', () => {
335343
});
336344

337345
test('on blur removes mdc-textfield__label--float-above when no input value present', () => {
338-
const {mockAdapter, blur} = setupBlurTest();
346+
const {mockAdapter, focus, blur} = setupBlurTest();
347+
focus();
339348
blur();
340349
td.verify(mockAdapter.removeClassFromLabel(cssClasses.LABEL_FLOAT_ABOVE));
341350
});

0 commit comments

Comments
 (0)