UNPKG

22.1 kBJavaScriptView Raw
1/*!
2 * (C) Ionic http://ionicframework.com - MIT License
3 */
4import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host } from '@stencil/core/internal/client';
5import { b as getIonMode } from './ionic-global.js';
6import { k as debounceEvent, i as inheritAttributes, l as findItemLabel } from './helpers.js';
7import { c as createColorClasses } from './theme.js';
8
9const inputIosCss = ".sc-ion-input-ios-h{--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:.5;--padding-top:0;--padding-end:0;--padding-bottom:0;--padding-start:0;--background:transparent;--color:initial;display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;width:100%;padding:0 !important;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);z-index:2}ion-item.sc-ion-input-ios-h:not(.item-label),ion-item:not(.item-label) .sc-ion-input-ios-h{--padding-start:0}.ion-color.sc-ion-input-ios-h{color:var(--ion-color-base)}.native-input.sc-ion-input-ios{border-radius:var(--border-radius);padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:inline-block;-ms-flex:1;flex:1;width:100%;max-width:100%;max-height:100%;border:0;outline:none;background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.native-input.sc-ion-input-ios{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.native-input.sc-ion-input-ios::-webkit-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios::-moz-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios:-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios::-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios::placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios:-webkit-autofill{background-color:transparent}.native-input.sc-ion-input-ios:invalid{-webkit-box-shadow:none;box-shadow:none}.native-input.sc-ion-input-ios::-ms-clear{display:none}.native-input[disabled].sc-ion-input-ios{opacity:0.4}.cloned-input.sc-ion-input-ios{left:0;top:0;position:absolute;pointer-events:none}[dir=rtl].sc-ion-input-ios .cloned-input.sc-ion-input-ios,[dir=rtl].sc-ion-input-ios-h .cloned-input.sc-ion-input-ios,[dir=rtl] .sc-ion-input-ios-h .cloned-input.sc-ion-input-ios{left:unset;right:unset;right:0}.input-clear-icon.sc-ion-input-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;background-position:center;border:0;outline:none;background-color:transparent;background-repeat:no-repeat;visibility:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}.input-clear-icon.sc-ion-input-ios:focus{opacity:0.5}.has-value.sc-ion-input-ios-h .input-clear-icon.sc-ion-input-ios{visibility:visible}.has-focus.sc-ion-input-ios-h{pointer-events:none}.has-focus.sc-ion-input-ios-h input.sc-ion-input-ios,.has-focus.sc-ion-input-ios-h a.sc-ion-input-ios,.has-focus.sc-ion-input-ios-h button.sc-ion-input-ios{pointer-events:auto}.item-label-floating.item-has-placeholder.sc-ion-input-ios-h:not(.item-has-value),.item-label-floating.item-has-placeholder:not(.item-has-value) .sc-ion-input-ios-h{opacity:0}.item-label-floating.item-has-placeholder.sc-ion-input-ios-h:not(.item-has-value).item-has-focus,.item-label-floating.item-has-placeholder:not(.item-has-value).item-has-focus .sc-ion-input-ios-h{-webkit-transition:opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);opacity:1}.sc-ion-input-ios-h{--padding-top:10px;--padding-end:10px;--padding-bottom:10px;--padding-start:0;font-size:inherit}.item-label-stacked.sc-ion-input-ios-h,.item-label-stacked .sc-ion-input-ios-h,.item-label-floating.sc-ion-input-ios-h,.item-label-floating .sc-ion-input-ios-h{--padding-top:8px;--padding-bottom:8px;--padding-start:0px}.input-clear-icon.sc-ion-input-ios{background-image:url(\"data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20512%20512'><path%20fill='var(--ion-color-step-600,%20%23666666)'%20d='M403.1,108.9c-81.2-81.2-212.9-81.2-294.2,0s-81.2,212.9,0,294.2c81.2,81.2,212.9,81.2,294.2,0S484.3,190.1,403.1,108.9z%20M352,340.2L340.2,352l-84.4-84.2l-84,83.8L160,339.8l84-83.8l-84-83.8l11.8-11.8l84,83.8l84.4-84.2l11.8,11.8L267.6,256L352,340.2z'/></svg>\");width:30px;height:30px;background-size:18px}";
10
11const inputMdCss = ".sc-ion-input-md-h{--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:.5;--padding-top:0;--padding-end:0;--padding-bottom:0;--padding-start:0;--background:transparent;--color:initial;display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;width:100%;padding:0 !important;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);z-index:2}ion-item.sc-ion-input-md-h:not(.item-label),ion-item:not(.item-label) .sc-ion-input-md-h{--padding-start:0}.ion-color.sc-ion-input-md-h{color:var(--ion-color-base)}.native-input.sc-ion-input-md{border-radius:var(--border-radius);padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:inline-block;-ms-flex:1;flex:1;width:100%;max-width:100%;max-height:100%;border:0;outline:none;background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.native-input.sc-ion-input-md{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.native-input.sc-ion-input-md::-webkit-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md::-moz-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md:-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md::-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md::placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md:-webkit-autofill{background-color:transparent}.native-input.sc-ion-input-md:invalid{-webkit-box-shadow:none;box-shadow:none}.native-input.sc-ion-input-md::-ms-clear{display:none}.native-input[disabled].sc-ion-input-md{opacity:0.4}.cloned-input.sc-ion-input-md{left:0;top:0;position:absolute;pointer-events:none}[dir=rtl].sc-ion-input-md .cloned-input.sc-ion-input-md,[dir=rtl].sc-ion-input-md-h .cloned-input.sc-ion-input-md,[dir=rtl] .sc-ion-input-md-h .cloned-input.sc-ion-input-md{left:unset;right:unset;right:0}.input-clear-icon.sc-ion-input-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;background-position:center;border:0;outline:none;background-color:transparent;background-repeat:no-repeat;visibility:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}.input-clear-icon.sc-ion-input-md:focus{opacity:0.5}.has-value.sc-ion-input-md-h .input-clear-icon.sc-ion-input-md{visibility:visible}.has-focus.sc-ion-input-md-h{pointer-events:none}.has-focus.sc-ion-input-md-h input.sc-ion-input-md,.has-focus.sc-ion-input-md-h a.sc-ion-input-md,.has-focus.sc-ion-input-md-h button.sc-ion-input-md{pointer-events:auto}.item-label-floating.item-has-placeholder.sc-ion-input-md-h:not(.item-has-value),.item-label-floating.item-has-placeholder:not(.item-has-value) .sc-ion-input-md-h{opacity:0}.item-label-floating.item-has-placeholder.sc-ion-input-md-h:not(.item-has-value).item-has-focus,.item-label-floating.item-has-placeholder:not(.item-has-value).item-has-focus .sc-ion-input-md-h{-webkit-transition:opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);opacity:1}.sc-ion-input-md-h{--padding-top:10px;--padding-end:0;--padding-bottom:10px;--padding-start:8px;font-size:inherit}.item-label-stacked.sc-ion-input-md-h,.item-label-stacked .sc-ion-input-md-h,.item-label-floating.sc-ion-input-md-h,.item-label-floating .sc-ion-input-md-h{--padding-top:8px;--padding-bottom:8px;--padding-start:0}.input-clear-icon.sc-ion-input-md{background-image:url(\"data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20512%20512'><polygon%20fill='var(--ion-color-step-600,%20%23666666)'%20points='405,136.798%20375.202,107%20256,226.202%20136.798,107%20107,136.798%20226.202,256%20107,375.202%20136.798,405%20256,285.798%20375.202,405%20405,375.202%20285.798,256'/></svg>\");width:30px;height:30px;background-size:22px}";
12
13const Input = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
14 constructor() {
15 super();
16 this.__registerHost();
17 this.ionInput = createEvent(this, "ionInput", 7);
18 this.ionChange = createEvent(this, "ionChange", 7);
19 this.ionBlur = createEvent(this, "ionBlur", 7);
20 this.ionFocus = createEvent(this, "ionFocus", 7);
21 this.ionStyle = createEvent(this, "ionStyle", 7);
22 this.inputId = `ion-input-${inputIds++}`;
23 this.didBlurAfterEdit = false;
24 this.inheritedAttributes = {};
25 this.isComposing = false;
26 /**
27 * This is required for a WebKit bug which requires us to
28 * blur and focus an input to properly focus the input in
29 * an item with delegatesFocus. It will no longer be needed
30 * with iOS 14.
31 *
32 * @internal
33 */
34 this.fireFocusEvents = true;
35 this.hasFocus = false;
36 /**
37 * Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
38 * Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
39 */
40 this.autocapitalize = 'off';
41 /**
42 * Indicates whether the value of the control can be automatically completed by the browser.
43 */
44 this.autocomplete = 'off';
45 /**
46 * Whether auto correction should be enabled when the user is entering/editing the text value.
47 */
48 this.autocorrect = 'off';
49 /**
50 * This Boolean attribute lets you specify that a form control should have input focus when the page loads.
51 */
52 this.autofocus = false;
53 /**
54 * If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
55 */
56 this.clearInput = false;
57 /**
58 * Set the amount of time, in milliseconds, to wait to trigger the `ionChange` event after each keystroke. This also impacts form bindings such as `ngModel` or `v-model`.
59 */
60 this.debounce = 0;
61 /**
62 * If `true`, the user cannot interact with the input.
63 */
64 this.disabled = false;
65 /**
66 * The name of the control, which is submitted with the form data.
67 */
68 this.name = this.inputId;
69 /**
70 * If `true`, the user cannot modify the value.
71 */
72 this.readonly = false;
73 /**
74 * If `true`, the user must fill in a value before submitting a form.
75 */
76 this.required = false;
77 /**
78 * If `true`, the element will have its spelling and grammar checked.
79 */
80 this.spellcheck = false;
81 /**
82 * The type of control to display. The default type is text.
83 */
84 this.type = 'text';
85 /**
86 * The value of the input.
87 */
88 this.value = '';
89 this.onInput = (ev) => {
90 const input = ev.target;
91 if (input) {
92 this.value = input.value || '';
93 }
94 this.ionInput.emit(ev);
95 };
96 this.onBlur = (ev) => {
97 this.hasFocus = false;
98 this.focusChanged();
99 this.emitStyle();
100 if (this.fireFocusEvents) {
101 this.ionBlur.emit(ev);
102 }
103 };
104 this.onFocus = (ev) => {
105 this.hasFocus = true;
106 this.focusChanged();
107 this.emitStyle();
108 if (this.fireFocusEvents) {
109 this.ionFocus.emit(ev);
110 }
111 };
112 this.onKeydown = (ev) => {
113 if (this.shouldClearOnEdit()) {
114 // Did the input value change after it was blurred and edited?
115 // Do not clear if user is hitting Enter to submit form
116 if (this.didBlurAfterEdit && this.hasValue() && ev.key !== 'Enter') {
117 // Clear the input
118 this.clearTextInput();
119 }
120 // Reset the flag
121 this.didBlurAfterEdit = false;
122 }
123 };
124 this.onCompositionStart = () => {
125 this.isComposing = true;
126 };
127 this.onCompositionEnd = () => {
128 this.isComposing = false;
129 };
130 this.clearTextOnEnter = (ev) => {
131 if (ev.key === 'Enter') {
132 this.clearTextInput(ev);
133 }
134 };
135 this.clearTextInput = (ev) => {
136 if (this.clearInput && !this.readonly && !this.disabled && ev) {
137 ev.preventDefault();
138 ev.stopPropagation();
139 // Attempt to focus input again after pressing clear button
140 this.setFocus();
141 }
142 this.value = '';
143 /**
144 * This is needed for clearOnEdit
145 * Otherwise the value will not be cleared
146 * if user is inside the input
147 */
148 if (this.nativeInput) {
149 this.nativeInput.value = '';
150 }
151 };
152 }
153 debounceChanged() {
154 this.ionChange = debounceEvent(this.ionChange, this.debounce);
155 }
156 disabledChanged() {
157 this.emitStyle();
158 }
159 /**
160 * Update the item classes when the placeholder changes
161 */
162 placeholderChanged() {
163 this.emitStyle();
164 }
165 /**
166 * Update the native input element when the value changes
167 */
168 valueChanged() {
169 const nativeInput = this.nativeInput;
170 const value = this.getValue();
171 if (nativeInput && nativeInput.value !== value && !this.isComposing) {
172 /**
173 * Assigning the native input's value on attribute
174 * value change, allows `ionInput` implementations
175 * to override the control's value.
176 *
177 * Used for patterns such as input trimming (removing whitespace),
178 * or input masking.
179 */
180 nativeInput.value = value;
181 }
182 this.emitStyle();
183 this.ionChange.emit({ value: this.value == null ? this.value : this.value.toString() });
184 }
185 componentWillLoad() {
186 this.inheritedAttributes = inheritAttributes(this.el, ['aria-label', 'tabindex', 'title']);
187 }
188 connectedCallback() {
189 this.emitStyle();
190 this.debounceChanged();
191 if (Build.isBrowser) {
192 document.dispatchEvent(new CustomEvent('ionInputDidLoad', {
193 detail: this.el
194 }));
195 }
196 }
197 componentDidLoad() {
198 const nativeInput = this.nativeInput;
199 if (nativeInput) {
200 // TODO: FW-729 Update to JSX bindings when Stencil resolves bug with:
201 // https://github.com/ionic-team/stencil/issues/3235
202 nativeInput.addEventListener('compositionstart', this.onCompositionStart);
203 nativeInput.addEventListener('compositionend', this.onCompositionEnd);
204 }
205 }
206 disconnectedCallback() {
207 if (Build.isBrowser) {
208 document.dispatchEvent(new CustomEvent('ionInputDidUnload', {
209 detail: this.el
210 }));
211 }
212 const nativeInput = this.nativeInput;
213 if (nativeInput) {
214 nativeInput.removeEventListener('compositionstart', this.onCompositionStart);
215 nativeInput.removeEventListener('compositionEnd', this.onCompositionEnd);
216 }
217 }
218 /**
219 * Sets focus on the native `input` in `ion-input`. Use this method instead of the global
220 * `input.focus()`.
221 */
222 async setFocus() {
223 if (this.nativeInput) {
224 this.nativeInput.focus();
225 }
226 }
227 /**
228 * Sets blur on the native `input` in `ion-input`. Use this method instead of the global
229 * `input.blur()`.
230 * @internal
231 */
232 async setBlur() {
233 if (this.nativeInput) {
234 this.nativeInput.blur();
235 }
236 }
237 /**
238 * Returns the native `<input>` element used under the hood.
239 */
240 getInputElement() {
241 return Promise.resolve(this.nativeInput);
242 }
243 shouldClearOnEdit() {
244 const { type, clearOnEdit } = this;
245 return (clearOnEdit === undefined)
246 ? type === 'password'
247 : clearOnEdit;
248 }
249 getValue() {
250 return typeof this.value === 'number' ? this.value.toString() :
251 (this.value || '').toString();
252 }
253 emitStyle() {
254 this.ionStyle.emit({
255 'interactive': true,
256 'input': true,
257 'has-placeholder': this.placeholder !== undefined,
258 'has-value': this.hasValue(),
259 'has-focus': this.hasFocus,
260 'interactive-disabled': this.disabled,
261 });
262 }
263 focusChanged() {
264 // If clearOnEdit is enabled and the input blurred but has a value, set a flag
265 if (!this.hasFocus && this.shouldClearOnEdit() && this.hasValue()) {
266 this.didBlurAfterEdit = true;
267 }
268 }
269 hasValue() {
270 return this.getValue().length > 0;
271 }
272 render() {
273 const mode = getIonMode(this);
274 const value = this.getValue();
275 const labelId = this.inputId + '-lbl';
276 const label = findItemLabel(this.el);
277 if (label) {
278 label.id = labelId;
279 }
280 return (h(Host, { "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses(this.color, {
281 [mode]: true,
282 'has-value': this.hasValue(),
283 'has-focus': this.hasFocus
284 }) }, h("input", Object.assign({ class: "native-input", ref: input => this.nativeInput = input, "aria-labelledby": label ? labelId : null, disabled: this.disabled, accept: this.accept, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, size: this.size, type: this.type, value: value, onInput: this.onInput, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown }, this.inheritedAttributes)), (this.clearInput && !this.readonly && !this.disabled) && h("button", { "aria-label": "reset", type: "button", class: "input-clear-icon", onTouchStart: this.clearTextInput, onMouseDown: this.clearTextInput, onKeyDown: this.clearTextOnEnter })));
285 }
286 get el() { return this; }
287 static get watchers() { return {
288 "debounce": ["debounceChanged"],
289 "disabled": ["disabledChanged"],
290 "placeholder": ["placeholderChanged"],
291 "value": ["valueChanged"]
292 }; }
293 static get style() { return {
294 ios: inputIosCss,
295 md: inputMdCss
296 }; }
297}, [34, "ion-input", {
298 "fireFocusEvents": [4, "fire-focus-events"],
299 "color": [513],
300 "accept": [1],
301 "autocapitalize": [1],
302 "autocomplete": [1],
303 "autocorrect": [1],
304 "autofocus": [4],
305 "clearInput": [4, "clear-input"],
306 "clearOnEdit": [4, "clear-on-edit"],
307 "debounce": [2],
308 "disabled": [4],
309 "enterkeyhint": [1],
310 "inputmode": [1],
311 "max": [8],
312 "maxlength": [2],
313 "min": [8],
314 "minlength": [2],
315 "multiple": [4],
316 "name": [1],
317 "pattern": [1],
318 "placeholder": [1],
319 "readonly": [4],
320 "required": [4],
321 "spellcheck": [4],
322 "step": [1],
323 "size": [2],
324 "type": [1],
325 "value": [1032],
326 "hasFocus": [32],
327 "setFocus": [64],
328 "setBlur": [64],
329 "getInputElement": [64]
330 }]);
331let inputIds = 0;
332function defineCustomElement$1() {
333 if (typeof customElements === "undefined") {
334 return;
335 }
336 const components = ["ion-input"];
337 components.forEach(tagName => { switch (tagName) {
338 case "ion-input":
339 if (!customElements.get(tagName)) {
340 customElements.define(tagName, Input);
341 }
342 break;
343 } });
344}
345
346const IonInput = Input;
347const defineCustomElement = defineCustomElement$1;
348
349export { IonInput, defineCustomElement };