edvoyui-component-library-test-flight 0.0.238 → 0.0.240

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -184,10 +184,10 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
184
184
  search: (...args: any[]) => void;
185
185
  "update:modelValue": (...args: any[]) => void;
186
186
  tag: (...args: any[]) => void;
187
+ open: (...args: any[]) => void;
187
188
  "update:searchString": (...args: any[]) => void;
188
189
  deselected: (...args: any[]) => void;
189
190
  selectedOption: (...args: any[]) => void;
190
- open: (...args: any[]) => void;
191
191
  }, string, import('../../../node_modules/vue').PublicProps, Readonly<import('../../../node_modules/vue').ExtractPropTypes<{
192
192
  clearable: {
193
193
  type: BooleanConstructor;
@@ -350,10 +350,10 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
350
350
  onSearch?: ((...args: any[]) => any) | undefined;
351
351
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
352
352
  onTag?: ((...args: any[]) => any) | undefined;
353
+ onOpen?: ((...args: any[]) => any) | undefined;
353
354
  "onUpdate:searchString"?: ((...args: any[]) => any) | undefined;
354
355
  onDeselected?: ((...args: any[]) => any) | undefined;
355
356
  onSelectedOption?: ((...args: any[]) => any) | undefined;
356
- onOpen?: ((...args: any[]) => any) | undefined;
357
357
  }>, {
358
358
  keys: string[];
359
359
  loading: boolean;
@@ -48,7 +48,7 @@
48
48
  :class="[getIconClass()]"
49
49
  @on-input="onInputChanged"
50
50
  @country-changed="onCountryChanged"
51
- @blur="$emit('blur')"
51
+ @blur="onBlur"
52
52
  ></vue-tel-input>
53
53
  </button>
54
54
 
@@ -73,9 +73,17 @@
73
73
 
74
74
  <script lang="ts" setup>
75
75
  import { computed, onUpdated, PropType, ref, toRefs, watch } from "vue";
76
- import { VueTelInput, VueTelInputCountryOption } from "vue-tel-input";
76
+ import {
77
+ VueTelInput,
78
+ type CountryObject,
79
+ type PhoneMeta,
80
+ type VueTelInputProps,
81
+ } from "vue-tel-input";
82
+ import { getExampleNumber } from "libphonenumber-js";
83
+ import mobileExamples from "libphonenumber-js/mobile/examples";
77
84
  import "vue-tel-input/vue-tel-input.css";
78
- import EUIErrorMessage from "../errorMessage/EUIErrorMessage.vue";
85
+
86
+ type TelephoneInputMeta = PhoneMeta & { number: string };
79
87
 
80
88
  const emit = defineEmits(["update:modelValue", "blur", "update:isValid"]);
81
89
 
@@ -161,16 +169,45 @@ const inputValue = computed(() => {
161
169
  return props.modelValue === 0 ? true : !!props.modelValue;
162
170
  });
163
171
 
164
- const mobile = ref(props.modelValue);
172
+ const mobile = ref(String(props.modelValue ?? ""));
173
+ const isTouched = ref(false);
174
+ const telephoneIsValid = ref(props.isValid);
175
+ const activeCountry = ref<CountryObject | null>(null);
176
+ const dynamicMaxLength = ref<number>(props.length);
177
+ const getCountryMaxLength = (
178
+ country: CountryObject | PhoneMeta["country"] | null,
179
+ ) => {
180
+ if (!country) return props.length;
181
+
182
+ const countryCode = typeof country === "string" ? country : country.iso2;
183
+ const example = getExampleNumber(countryCode, mobileExamples);
184
+ if (!example) return props.length;
185
+
186
+ return Math.max(
187
+ example.nationalNumber.length + 5,
188
+ example.formatInternational().length,
189
+ );
190
+ };
165
191
  const listener = computed(() => props.modelValue);
166
192
  watch(listener, (value) => {
167
- mobile.value = value;
193
+ mobile.value = String(value ?? "");
168
194
  });
195
+ watch(isValid, (value) => {
196
+ telephoneIsValid.value = value;
197
+ });
198
+ watch(
199
+ () => props.length,
200
+ (value) => {
201
+ if (!activeCountry.value) {
202
+ dynamicMaxLength.value = value;
203
+ }
204
+ },
205
+ );
169
206
 
170
207
  // Make bindProps a reactive computed property
171
- const bindProps = computed(() => ({
208
+ const bindProps = computed<VueTelInputProps>(() => ({
172
209
  mode: "international",
173
- autoFormat: false,
210
+ autoFormat: true,
174
211
  autoDefaultCountry: true,
175
212
  styleClasses: "eui-tel",
176
213
  invalidMsg: "Required mobile number",
@@ -183,7 +220,7 @@ const bindProps = computed(() => ({
183
220
  name: props.name,
184
221
  id: id,
185
222
  placeholder: props.placeholder,
186
- maxlength: props.length,
223
+ maxlength: dynamicMaxLength.value,
187
224
  showDialCode: true,
188
225
  tabindex: 0,
189
226
  readonly: props.readonly,
@@ -199,13 +236,29 @@ const bindProps = computed(() => ({
199
236
  },
200
237
  }));
201
238
 
202
- const onInputChanged = (_formattedNumber: string, phoneObject: any) => {
203
- hasError.value = phoneObject.valid ? true : false;
239
+ const onInputChanged = (
240
+ _formattedNumber: string,
241
+ phoneObject: TelephoneInputMeta,
242
+ ) => {
243
+ telephoneIsValid.value = Boolean(phoneObject.valid);
244
+ hasError.value = telephoneIsValid.value;
245
+
246
+ dynamicMaxLength.value = getCountryMaxLength(
247
+ activeCountry.value ?? phoneObject.country ?? null,
248
+ );
249
+
204
250
  emit("update:modelValue", phoneObject.number);
205
251
  };
206
252
 
253
+ const onBlur = () => {
254
+ isTouched.value = true;
255
+ emit("blur");
256
+ };
257
+
207
258
  const firstTime = ref(true);
208
- const onCountryChanged = (_event: VueTelInputCountryOption) => {
259
+ const onCountryChanged = (country: CountryObject) => {
260
+ activeCountry.value = country;
261
+ dynamicMaxLength.value = getCountryMaxLength(country);
209
262
  if (!firstTime.value) {
210
263
  emit("update:modelValue", "");
211
264
  }
@@ -217,7 +270,7 @@ onUpdated(() => {
217
270
  }, 1500);
218
271
  });
219
272
 
220
- const errorMessage = computed(() => {
273
+ const externalErrorMessage = computed(() => {
221
274
  if (Array.isArray(props.errors)) {
222
275
  if (typeof props.errors?.at(0) === "object") {
223
276
  return props.errors?.at(0)?.$message;
@@ -233,6 +286,19 @@ const errorMessage = computed(() => {
233
286
  }
234
287
  });
235
288
 
289
+ const internalErrorMessage = computed(() => {
290
+ if (!isTouched.value || props.readonly || props.disabled) return "";
291
+
292
+ const value = String(mobile.value ?? "").trim();
293
+ if (!value) return props.required ? "Mobile number is required" : "";
294
+
295
+ return telephoneIsValid.value ? "" : "Enter a valid phone number";
296
+ });
297
+
298
+ const errorMessage = computed(
299
+ () => externalErrorMessage.value || internalErrorMessage.value,
300
+ );
301
+
236
302
  const getIconClass = () => {
237
303
  switch (props.iconType) {
238
304
  case "startIcon":
@@ -289,4 +355,4 @@ const focusInput = () => {
289
355
  @apply rounded-md py-2;
290
356
  }
291
357
  }
292
- </style>
358
+ </style>
@@ -135,5 +135,5 @@ declare const _default: import('../../../node_modules/vue').DefineComponent<impo
135
135
  cols: number;
136
136
  }, {}, {}, {}, string, import('../../../node_modules/vue').ComponentProvideOptions, true, {
137
137
  inputRef: HTMLTextAreaElement;
138
- }, any>;
138
+ }, HTMLDivElement>;
139
139
  export default _default;
@@ -60,10 +60,10 @@
60
60
  >
61
61
  </textarea>
62
62
  </div>
63
- </div>
64
- <template v-if="errors && Object.keys(errors).length">
63
+ <template v-if="errors && Object.keys(errors).length">
65
64
  <EUIErrorMessage :errors="errors" :name="name" />
66
65
  </template>
66
+ </div>
67
67
  </template>
68
68
  <script setup lang="ts">
69
69
  import { PropType, ref, watch, computed } from "vue";