UNPKG

21.6 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2016 Google Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23import { __assign, __extends } from "tslib";
24import { MDCComponent } from '@material/base/component';
25import { applyPassive } from '@material/dom/events';
26import * as ponyfill from '@material/dom/ponyfill';
27import { MDCFloatingLabel } from '@material/floating-label/component';
28import { MDCLineRipple } from '@material/line-ripple/component';
29import { MDCNotchedOutline } from '@material/notched-outline/component';
30import { MDCRipple } from '@material/ripple/component';
31import { MDCRippleFoundation } from '@material/ripple/foundation';
32import { MDCTextFieldCharacterCounter } from './character-counter/component';
33import { MDCTextFieldCharacterCounterFoundation } from './character-counter/foundation';
34import { cssClasses, strings } from './constants';
35import { MDCTextFieldFoundation } from './foundation';
36import { MDCTextFieldHelperText } from './helper-text/component';
37import { MDCTextFieldHelperTextFoundation } from './helper-text/foundation';
38import { MDCTextFieldIcon } from './icon/component';
39var MDCTextField = /** @class */ (function (_super) {
40 __extends(MDCTextField, _super);
41 function MDCTextField() {
42 return _super !== null && _super.apply(this, arguments) || this;
43 }
44 MDCTextField.attachTo = function (root) {
45 return new MDCTextField(root);
46 };
47 MDCTextField.prototype.initialize = function (rippleFactory, lineRippleFactory, helperTextFactory, characterCounterFactory, iconFactory, labelFactory, outlineFactory) {
48 if (rippleFactory === void 0) { rippleFactory = function (el, foundation) { return new MDCRipple(el, foundation); }; }
49 if (lineRippleFactory === void 0) { lineRippleFactory = function (el) { return new MDCLineRipple(el); }; }
50 if (helperTextFactory === void 0) { helperTextFactory = function (el) {
51 return new MDCTextFieldHelperText(el);
52 }; }
53 if (characterCounterFactory === void 0) { characterCounterFactory = function (el) {
54 return new MDCTextFieldCharacterCounter(el);
55 }; }
56 if (iconFactory === void 0) { iconFactory = function (el) { return new MDCTextFieldIcon(el); }; }
57 if (labelFactory === void 0) { labelFactory = function (el) { return new MDCFloatingLabel(el); }; }
58 if (outlineFactory === void 0) { outlineFactory = function (el) { return new MDCNotchedOutline(el); }; }
59 this.input =
60 this.root.querySelector(strings.INPUT_SELECTOR);
61 var labelElement = this.root.querySelector(strings.LABEL_SELECTOR);
62 this.label = labelElement ? labelFactory(labelElement) : null;
63 var lineRippleElement = this.root.querySelector(strings.LINE_RIPPLE_SELECTOR);
64 this.lineRipple =
65 lineRippleElement ? lineRippleFactory(lineRippleElement) : null;
66 var outlineElement = this.root.querySelector(strings.OUTLINE_SELECTOR);
67 this.outline = outlineElement ? outlineFactory(outlineElement) : null;
68 // Helper text
69 var helperTextStrings = MDCTextFieldHelperTextFoundation.strings;
70 var nextElementSibling = this.root.nextElementSibling;
71 var hasHelperLine = (nextElementSibling && nextElementSibling.classList.contains(cssClasses.HELPER_LINE));
72 var helperTextEl = hasHelperLine && nextElementSibling && nextElementSibling.querySelector(helperTextStrings.ROOT_SELECTOR);
73 this.helperText = helperTextEl ? helperTextFactory(helperTextEl) : null;
74 // Character counter
75 var characterCounterStrings = MDCTextFieldCharacterCounterFoundation.strings;
76 var characterCounterEl = this.root.querySelector(characterCounterStrings.ROOT_SELECTOR);
77 // If character counter is not found in root element search in sibling element.
78 if (!characterCounterEl && hasHelperLine && nextElementSibling) {
79 characterCounterEl = nextElementSibling.querySelector(characterCounterStrings.ROOT_SELECTOR);
80 }
81 this.characterCounter =
82 characterCounterEl ? characterCounterFactory(characterCounterEl) : null;
83 // Leading icon
84 var leadingIconEl = this.root.querySelector(strings.LEADING_ICON_SELECTOR);
85 this.leadingIcon = leadingIconEl ? iconFactory(leadingIconEl) : null;
86 // Trailing icon
87 var trailingIconEl = this.root.querySelector(strings.TRAILING_ICON_SELECTOR);
88 this.trailingIcon = trailingIconEl ? iconFactory(trailingIconEl) : null;
89 // Prefix and Suffix
90 this.prefix = this.root.querySelector(strings.PREFIX_SELECTOR);
91 this.suffix = this.root.querySelector(strings.SUFFIX_SELECTOR);
92 this.ripple = this.createRipple(rippleFactory);
93 };
94 MDCTextField.prototype.destroy = function () {
95 if (this.ripple) {
96 this.ripple.destroy();
97 }
98 if (this.lineRipple) {
99 this.lineRipple.destroy();
100 }
101 if (this.helperText) {
102 this.helperText.destroy();
103 }
104 if (this.characterCounter) {
105 this.characterCounter.destroy();
106 }
107 if (this.leadingIcon) {
108 this.leadingIcon.destroy();
109 }
110 if (this.trailingIcon) {
111 this.trailingIcon.destroy();
112 }
113 if (this.label) {
114 this.label.destroy();
115 }
116 if (this.outline) {
117 this.outline.destroy();
118 }
119 _super.prototype.destroy.call(this);
120 };
121 /**
122 * Initializes the Text Field's internal state based on the environment's
123 * state.
124 */
125 MDCTextField.prototype.initialSyncWithDOM = function () {
126 this.disabled = this.input.disabled;
127 };
128 Object.defineProperty(MDCTextField.prototype, "value", {
129 get: function () {
130 return this.foundation.getValue();
131 },
132 /**
133 * @param value The value to set on the input.
134 */
135 set: function (value) {
136 this.foundation.setValue(value);
137 },
138 enumerable: false,
139 configurable: true
140 });
141 Object.defineProperty(MDCTextField.prototype, "disabled", {
142 get: function () {
143 return this.foundation.isDisabled();
144 },
145 /**
146 * @param disabled Sets the Text Field disabled or enabled.
147 */
148 set: function (disabled) {
149 this.foundation.setDisabled(disabled);
150 },
151 enumerable: false,
152 configurable: true
153 });
154 Object.defineProperty(MDCTextField.prototype, "valid", {
155 get: function () {
156 return this.foundation.isValid();
157 },
158 /**
159 * @param valid Sets the Text Field valid or invalid.
160 */
161 set: function (valid) {
162 this.foundation.setValid(valid);
163 },
164 enumerable: false,
165 configurable: true
166 });
167 Object.defineProperty(MDCTextField.prototype, "required", {
168 get: function () {
169 return this.input.required;
170 },
171 /**
172 * @param required Sets the Text Field to required.
173 */
174 set: function (required) {
175 this.input.required = required;
176 },
177 enumerable: false,
178 configurable: true
179 });
180 Object.defineProperty(MDCTextField.prototype, "pattern", {
181 get: function () {
182 return this.input.pattern;
183 },
184 /**
185 * @param pattern Sets the input element's validation pattern.
186 */
187 set: function (pattern) {
188 this.input.pattern = pattern;
189 },
190 enumerable: false,
191 configurable: true
192 });
193 Object.defineProperty(MDCTextField.prototype, "minLength", {
194 get: function () {
195 return this.input.minLength;
196 },
197 /**
198 * @param minLength Sets the input element's minLength.
199 */
200 set: function (minLength) {
201 this.input.minLength = minLength;
202 },
203 enumerable: false,
204 configurable: true
205 });
206 Object.defineProperty(MDCTextField.prototype, "maxLength", {
207 get: function () {
208 return this.input.maxLength;
209 },
210 /**
211 * @param maxLength Sets the input element's maxLength.
212 */
213 set: function (maxLength) {
214 // Chrome throws exception if maxLength is set to a value less than zero
215 if (maxLength < 0) {
216 this.input.removeAttribute('maxLength');
217 }
218 else {
219 this.input.maxLength = maxLength;
220 }
221 },
222 enumerable: false,
223 configurable: true
224 });
225 Object.defineProperty(MDCTextField.prototype, "min", {
226 get: function () {
227 return this.input.min;
228 },
229 /**
230 * @param min Sets the input element's min.
231 */
232 set: function (min) {
233 this.input.min = min;
234 },
235 enumerable: false,
236 configurable: true
237 });
238 Object.defineProperty(MDCTextField.prototype, "max", {
239 get: function () {
240 return this.input.max;
241 },
242 /**
243 * @param max Sets the input element's max.
244 */
245 set: function (max) {
246 this.input.max = max;
247 },
248 enumerable: false,
249 configurable: true
250 });
251 Object.defineProperty(MDCTextField.prototype, "step", {
252 get: function () {
253 return this.input.step;
254 },
255 /**
256 * @param step Sets the input element's step.
257 */
258 set: function (step) {
259 this.input.step = step;
260 },
261 enumerable: false,
262 configurable: true
263 });
264 Object.defineProperty(MDCTextField.prototype, "helperTextContent", {
265 /**
266 * Sets the helper text element content.
267 */
268 set: function (content) {
269 this.foundation.setHelperTextContent(content);
270 },
271 enumerable: false,
272 configurable: true
273 });
274 Object.defineProperty(MDCTextField.prototype, "leadingIconAriaLabel", {
275 /**
276 * Sets the aria label of the leading icon.
277 */
278 set: function (label) {
279 this.foundation.setLeadingIconAriaLabel(label);
280 },
281 enumerable: false,
282 configurable: true
283 });
284 Object.defineProperty(MDCTextField.prototype, "leadingIconContent", {
285 /**
286 * Sets the text content of the leading icon.
287 */
288 set: function (content) {
289 this.foundation.setLeadingIconContent(content);
290 },
291 enumerable: false,
292 configurable: true
293 });
294 Object.defineProperty(MDCTextField.prototype, "trailingIconAriaLabel", {
295 /**
296 * Sets the aria label of the trailing icon.
297 */
298 set: function (label) {
299 this.foundation.setTrailingIconAriaLabel(label);
300 },
301 enumerable: false,
302 configurable: true
303 });
304 Object.defineProperty(MDCTextField.prototype, "trailingIconContent", {
305 /**
306 * Sets the text content of the trailing icon.
307 */
308 set: function (content) {
309 this.foundation.setTrailingIconContent(content);
310 },
311 enumerable: false,
312 configurable: true
313 });
314 Object.defineProperty(MDCTextField.prototype, "useNativeValidation", {
315 /**
316 * Enables or disables the use of native validation. Use this for custom validation.
317 * @param useNativeValidation Set this to false to ignore native input validation.
318 */
319 set: function (useNativeValidation) {
320 this.foundation.setUseNativeValidation(useNativeValidation);
321 },
322 enumerable: false,
323 configurable: true
324 });
325 Object.defineProperty(MDCTextField.prototype, "prefixText", {
326 /**
327 * Gets the text content of the prefix, or null if it does not exist.
328 */
329 get: function () {
330 return this.prefix ? this.prefix.textContent : null;
331 },
332 /**
333 * Sets the text content of the prefix, if it exists.
334 */
335 set: function (prefixText) {
336 if (this.prefix) {
337 this.prefix.textContent = prefixText;
338 }
339 },
340 enumerable: false,
341 configurable: true
342 });
343 Object.defineProperty(MDCTextField.prototype, "suffixText", {
344 /**
345 * Gets the text content of the suffix, or null if it does not exist.
346 */
347 get: function () {
348 return this.suffix ? this.suffix.textContent : null;
349 },
350 /**
351 * Sets the text content of the suffix, if it exists.
352 */
353 set: function (suffixText) {
354 if (this.suffix) {
355 this.suffix.textContent = suffixText;
356 }
357 },
358 enumerable: false,
359 configurable: true
360 });
361 /**
362 * Focuses the input element.
363 */
364 MDCTextField.prototype.focus = function () {
365 this.input.focus();
366 };
367 /**
368 * Recomputes the outline SVG path for the outline element.
369 */
370 MDCTextField.prototype.layout = function () {
371 var openNotch = this.foundation.shouldFloat;
372 this.foundation.notchOutline(openNotch);
373 };
374 MDCTextField.prototype.getDefaultFoundation = function () {
375 // DO NOT INLINE this variable. For backward compatibility, foundations take a Partial<MDCFooAdapter>.
376 // To ensure we don't accidentally omit any methods, we need a separate, strongly typed adapter variable.
377 // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
378 var adapter = __assign(__assign(__assign(__assign(__assign({}, this.getRootAdapterMethods()), this.getInputAdapterMethods()), this.getLabelAdapterMethods()), this.getLineRippleAdapterMethods()), this.getOutlineAdapterMethods());
379 // tslint:enable:object-literal-sort-keys
380 return new MDCTextFieldFoundation(adapter, this.getFoundationMap());
381 };
382 MDCTextField.prototype.getRootAdapterMethods = function () {
383 var _this = this;
384 // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
385 return {
386 addClass: function (className) { return _this.root.classList.add(className); },
387 removeClass: function (className) { return _this.root.classList.remove(className); },
388 hasClass: function (className) { return _this.root.classList.contains(className); },
389 registerTextFieldInteractionHandler: function (evtType, handler) {
390 _this.listen(evtType, handler);
391 },
392 deregisterTextFieldInteractionHandler: function (evtType, handler) {
393 _this.unlisten(evtType, handler);
394 },
395 registerValidationAttributeChangeHandler: function (handler) {
396 var getAttributesList = function (mutationsList) {
397 return mutationsList
398 .map(function (mutation) { return mutation.attributeName; })
399 .filter(function (attributeName) { return attributeName; });
400 };
401 var observer = new MutationObserver(function (mutationsList) { return handler(getAttributesList(mutationsList)); });
402 var config = { attributes: true };
403 observer.observe(_this.input, config);
404 return observer;
405 },
406 deregisterValidationAttributeChangeHandler: function (observer) {
407 observer.disconnect();
408 },
409 };
410 // tslint:enable:object-literal-sort-keys
411 };
412 MDCTextField.prototype.getInputAdapterMethods = function () {
413 var _this = this;
414 // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
415 return {
416 getNativeInput: function () { return _this.input; },
417 setInputAttr: function (attr, value) {
418 _this.input.setAttribute(attr, value);
419 },
420 removeInputAttr: function (attr) {
421 _this.input.removeAttribute(attr);
422 },
423 isFocused: function () { return document.activeElement === _this.input; },
424 registerInputInteractionHandler: function (evtType, handler) {
425 _this.input.addEventListener(evtType, handler, applyPassive());
426 },
427 deregisterInputInteractionHandler: function (evtType, handler) {
428 _this.input.removeEventListener(evtType, handler, applyPassive());
429 },
430 };
431 // tslint:enable:object-literal-sort-keys
432 };
433 MDCTextField.prototype.getLabelAdapterMethods = function () {
434 var _this = this;
435 return {
436 floatLabel: function (shouldFloat) {
437 _this.label && _this.label.float(shouldFloat);
438 },
439 getLabelWidth: function () { return _this.label ? _this.label.getWidth() : 0; },
440 hasLabel: function () { return Boolean(_this.label); },
441 shakeLabel: function (shouldShake) {
442 _this.label && _this.label.shake(shouldShake);
443 },
444 setLabelRequired: function (isRequired) {
445 _this.label && _this.label.setRequired(isRequired);
446 },
447 };
448 };
449 MDCTextField.prototype.getLineRippleAdapterMethods = function () {
450 var _this = this;
451 return {
452 activateLineRipple: function () {
453 if (_this.lineRipple) {
454 _this.lineRipple.activate();
455 }
456 },
457 deactivateLineRipple: function () {
458 if (_this.lineRipple) {
459 _this.lineRipple.deactivate();
460 }
461 },
462 setLineRippleTransformOrigin: function (normalizedX) {
463 if (_this.lineRipple) {
464 _this.lineRipple.setRippleCenter(normalizedX);
465 }
466 },
467 };
468 };
469 MDCTextField.prototype.getOutlineAdapterMethods = function () {
470 var _this = this;
471 return {
472 closeOutline: function () {
473 _this.outline && _this.outline.closeNotch();
474 },
475 hasOutline: function () { return Boolean(_this.outline); },
476 notchOutline: function (labelWidth) {
477 _this.outline && _this.outline.notch(labelWidth);
478 },
479 };
480 };
481 /**
482 * @return A map of all subcomponents to subfoundations.
483 */
484 MDCTextField.prototype.getFoundationMap = function () {
485 return {
486 characterCounter: this.characterCounter ?
487 this.characterCounter.foundationForTextField :
488 undefined,
489 helperText: this.helperText ? this.helperText.foundationForTextField :
490 undefined,
491 leadingIcon: this.leadingIcon ? this.leadingIcon.foundationForTextField :
492 undefined,
493 trailingIcon: this.trailingIcon ?
494 this.trailingIcon.foundationForTextField :
495 undefined,
496 };
497 };
498 MDCTextField.prototype.createRipple = function (rippleFactory) {
499 var _this = this;
500 var isTextArea = this.root.classList.contains(cssClasses.TEXTAREA);
501 var isOutlined = this.root.classList.contains(cssClasses.OUTLINED);
502 if (isTextArea || isOutlined) {
503 return null;
504 }
505 // DO NOT INLINE this variable. For backward compatibility, foundations take a Partial<MDCFooAdapter>.
506 // To ensure we don't accidentally omit any methods, we need a separate, strongly typed adapter variable.
507 // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
508 var adapter = __assign(__assign({}, MDCRipple.createAdapter(this)), { isSurfaceActive: function () { return ponyfill.matches(_this.input, ':active'); }, registerInteractionHandler: function (evtType, handler) {
509 _this.input.addEventListener(evtType, handler, applyPassive());
510 }, deregisterInteractionHandler: function (evtType, handler) {
511 _this.input.removeEventListener(evtType, handler, applyPassive());
512 } });
513 // tslint:enable:object-literal-sort-keys
514 return rippleFactory(this.root, new MDCRippleFoundation(adapter));
515 };
516 return MDCTextField;
517}(MDCComponent));
518export { MDCTextField };
519//# sourceMappingURL=component.js.map
\No newline at end of file