UNPKG

@salla.sa/twilight-components

Version:
326 lines (325 loc) 12.7 kB
/*! * Crafted with ❤ by Salla */ import { Host, h } from "@stencil/core"; export class SallaTelInput { /** * Lazy load intl-tel-input library * This reduces initial bundle size by ~80-90KB */ async loadTelInput() { if (this.TelInput) return; try { const telInputModule = await import('intl-tel-input'); this.TelInput = telInputModule.default; } catch (error) { console.error('Failed to load Tel Input:', error); salla.notify?.error?.('Failed to load phone input. Please refresh the page.'); throw error; } } constructor() { /** * input name */ this.name = 'phone'; /** * input name */ this.disabled = false; /** * Current country_code */ this.countryCode = salla.config.get('user.country_code', 'SA') || 'SA'; this.countryCodeLabel = salla.lang.get('common.country_code'); this.mobileLabel = salla.lang.get('common.elements.mobile'); this.tooShort = salla.lang.get('common.errors.too_short', { attribute: this.mobileLabel }); this.tooLong = salla.lang.get('common.errors.too_long', { attribute: this.mobileLabel }); this.invalidCountryCode = salla.lang.get('common.errors.invalid_value', { attribute: this.countryCodeLabel }); this.invalidNumber = salla.lang.get('common.errors.invalid_value', { attribute: this.mobileLabel }); this.errorMap = [this.invalidNumber, this.invalidCountryCode, this.tooShort, this.tooLong, this.invalidNumber]; salla.lang.onLoaded(() => { this.mobileLabel = salla.lang.get('common.elements.mobile'); this.countryCodeLabel = salla.lang.get('common.elements.country_code'); this.invalidNumber = salla.lang.get('common.errors.invalid_value', { attribute: this.mobileLabel }); this.invalidCountryCode = salla.lang.get('common.errors.invalid_value', { attribute: this.countryCodeLabel }); this.tooShort = salla.lang.get('common.errors.too_short', { attribute: this.mobileLabel }); this.tooLong = salla.lang.get('common.errors.too_long', { attribute: this.mobileLabel }); this.mobileRequired = salla.lang.get('common.errors.field_required', { attribute: this.mobileLabel }); this.errorMap = [this.invalidNumber, this.invalidCountryCode, this.tooShort, this.tooLong, this.invalidNumber]; }); } /** * Get current values * @return {{mobile:number,countryCode:'SA'|string}} */ async getValues() { return { [this.name]: this.phone = this.phoneInput.value, countryCode: this.countryCode = this.countryCodeInput.value, countryKey: this.host.querySelector('.iti__selected-dial-code').innerText }; } /** * Is current data valid or not * @return {boolean} */ async isValid() { this.reset(); if (this.iti.isValidNumber()) return true; if (!this.phoneInput.value.trim()) { this.phoneInput.classList.add("s-has-error"); this.errorMsg.innerText = this.mobileRequired || 'The mobile is required'; return; } this.phoneInput.classList.add("s-has-error"); let errorCode = this.iti.getValidationError(); this.errorMsg.innerText = this.errorMap[errorCode] || ''; salla.logger.info('Phone number (' + this.countryCode + ' - ' + this.phone + ') is not valid, error code ' + errorCode); return false; } async initTelInput() { // Load intl-tel-input before initializing await this.loadTelInput(); salla.helpers.inputDigitsOnly(this.phoneInput); this.iti = this.TelInput(this.phoneInput, { initialCountry: this.countryCode?.toLowerCase() || 'sa', preferredCountries: ['sa', 'ae', 'kw', 'bh', 'qa', 'iq', 'om', 'ye', 'eg', 'jo', 'ps', 'sd', 'lb', 'dz', 'tn', 'ma', 'ly'], excludeCountries: ['sy', 'ir', 'cu', 'kp'], formatOnDisplay: false, separateDialCode: true, autoPlaceholder: 'aggressive', utilsScript: 'https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/21.2.7/js/utils.min.js', dropdownContainer: this.host }); this.autofocus && this.phoneInput.focus(); this.phoneInput.addEventListener("countrychange", () => { let data = this.iti.getSelectedCountryData(); let value = data.iso2.toUpperCase(); this.countryCodeInput.value = value; this.countryCode = value; this.phoneEntered.emit({ number: this.phone, country_code: value }); }); // on blur: validate // this.phoneInput.addEventListener('blur', () => this.isValid()); // on keyup / change flag: reset this.phoneInput.addEventListener('input', (e) => { salla.helpers.inputDigitsOnly(e.target); this.reset(); this.phoneEntered.emit({ number: e.target.value, country_code: this.countryCode }); }); } reset() { this.phoneInput.classList.remove("s-has-error"); this.errorMsg.innerHTML = ""; } ; handleCountryInput(event) { if (!!this.phone) { this.phoneEntered.emit({ number: event.target.value, country_code: this.countryCode }); } } render() { return (h(Host, { key: '5b795b0844e986b7d0593b186eaf855ea1ad5823', class: "s-tel-input" }, h("input", { key: '699ff801a8b2effdadcbcf6f9389e20e621a9e91', type: "tel", disabled: this.disabled, name: this.name, value: this.phone, onChange: (event) => this.handleCountryInput(event), ref: el => this.phoneInput = el, enterkeyhint: "next", autocomplete: "tel", class: "s-tel-input-control tel-input s-ltr" }), h("span", { key: 'cdb37fbc3f0d914de7a70bf2cf6daddc0f46e739', class: "s-tel-input-error-msg", ref: el => this.errorMsg = el }), h("input", { key: '1a3a004ef9e663c040c7fb6b7c9fad55cfef67c3', type: "hidden", name: "country_code", value: this.countryCode, ref: el => this.countryCodeInput = el, class: "country_code" }))); } componentDidLoad() { this.initTelInput(); } static get is() { return "salla-tel-input"; } static get originalStyleUrls() { return { "$": ["salla-tel-input.scss"] }; } static get styleUrls() { return { "$": ["salla-tel-input.css"] }; } static get properties() { return { "phone": { "type": "string", "attribute": "phone", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Current mobile number" }, "getter": false, "setter": false, "reflect": false }, "autofocus": { "type": "boolean", "attribute": "autofocus", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Automatically focus telephone input" }, "getter": false, "setter": false, "reflect": true }, "name": { "type": "string", "attribute": "name", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "input name" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "'phone'" }, "disabled": { "type": "boolean", "attribute": "disabled", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "input name" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "countryCode": { "type": "string", "attribute": "country-code", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Current country_code" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "salla.config.get('user.country_code', 'SA') || 'SA'" } }; } static get states() { return { "mobileRequired": {}, "countryCodeLabel": {}, "mobileLabel": {}, "tooShort": {}, "tooLong": {}, "invalidCountryCode": {}, "invalidNumber": {}, "errorMap": {} }; } static get events() { return [{ "method": "phoneEntered", "name": "phoneEntered", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event emmitted when user enters a phone number." }, "complexType": { "original": "Phone", "resolved": "Phone", "references": { "Phone": { "location": "import", "path": "./interfaces", "id": "src/components/salla-tel-input/interfaces.ts::Phone" } } } }]; } static get methods() { return { "getValues": { "complexType": { "signature": "() => Promise<{ [x: string]: any; countryCode: string; countryKey: any; }>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<{ [x: string]: any; countryCode: string; countryKey: any; }>" }, "docs": { "text": "Get current values", "tags": [{ "name": "return", "text": undefined }] } }, "isValid": { "complexType": { "signature": "() => Promise<boolean>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<boolean>" }, "docs": { "text": "Is current data valid or not", "tags": [{ "name": "return", "text": undefined }] } } }; } static get elementRef() { return "host"; } }