@ozdao/prometheus-framework 0.2.35 → 0.2.36

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. package/dist/main.css +1 -1
  2. package/dist/prometheus-framework.cjs.js +18 -19
  3. package/dist/prometheus-framework.es.js +803 -1028
  4. package/package.json +1 -1
  5. package/src/components/Button/Button.vue +26 -19
  6. package/src/components/FieldBig/FieldBig.vue +1 -1
  7. package/src/components/FieldPhone/FieldPhone.vue +55 -304
  8. package/src/components/FieldPhone/FieldPhone2.vue +671 -0
  9. package/src/components/FieldPhone/click-outside.js +16 -11
  10. package/src/components/Footer/Footer.vue +4 -4
  11. package/src/components/Header/Header.vue +2 -1
  12. package/src/components/Select/Select.vue +2 -1
  13. package/src/modules/chats/components/sections/ChatWindow.vue +3 -1
  14. package/src/modules/chats/store/chat.store.js +1 -3
  15. package/src/modules/events/components/pages/EditEvent.vue +2 -1
  16. package/src/modules/events/components/pages/Event.vue +8 -2
  17. package/src/modules/events/components/sections/SectionMainGuest.vue +1 -1
  18. package/src/modules/events/components/sections/SectionSpecialGuests.vue +0 -1
  19. package/src/modules/events/store/events.js +23 -3
  20. package/src/modules/globals/mixins/mixins.js +33 -2
  21. package/src/modules/globals/store/globals.js +1 -0
  22. package/src/modules/landing/components/sections/HeroGovernance.vue +156 -0
  23. package/src/modules/marketplace/components/sections/Filters.vue +3 -0
  24. package/src/modules/marketplace/router/marketplace.js +1 -0
  25. package/src/modules/orders/components/blocks/StatusHistory.vue +8 -3
  26. package/src/modules/orders/components/pages/EditOrder.vue +9 -11
  27. package/src/modules/orders/components/pages/FormOrder.vue +58 -46
  28. package/src/modules/orders/components/pages/Order.vue +63 -42
  29. package/src/modules/orders/components/sections/FormOrderDetails.vue +50 -18
  30. package/src/modules/orders/controllers/orders.controller.js +10 -1
  31. package/src/modules/orders/models/order.model.js +1 -0
  32. package/src/modules/orders/store/orders.js +21 -27
  33. package/src/modules/orders/store/shopcart.js +14 -2
  34. package/src/modules/organizations/components/sections/DetailsTab.vue +2 -2
  35. package/src/modules/products/components/sections/FilterProducts.vue +3 -4
  36. package/src/modules/products/components/sections/HeroRecommendation.vue +29 -2
  37. package/src/modules/products/components/sections/SectionProduct.vue +14 -9
  38. package/src/modules/products/controllers/products.controller.js +26 -17
  39. package/src/modules/products/routes/products.routes.js +6 -6
  40. package/src/modules/products/store/products.js +10 -10
  41. package/src/styles/config.scss +10 -3
@@ -0,0 +1,671 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ rootClass,
5
+ classes,
6
+ $attrs.class,
7
+ { 'bg-fourth-nano': validation },
8
+ { disabled: disabled }
9
+ ]"
10
+ :style="[
11
+ rootStyle,
12
+ styles
13
+ ]"
14
+ ref="rootElement"
15
+ class="vue3-reactive-tel-input"
16
+ >
17
+ <div
18
+ v-click-outside="clickedOutside"
19
+ :class="['vti__dropdown', { open: open }]"
20
+ :style="[dropdownStyle]"
21
+ :tabindex="dropdownOptions.tabindex"
22
+ @keydown="keyboardNav"
23
+ @click="toggleDropdown"
24
+ @keydown.esc="reset"
25
+ class="br-solid br-black-transp br-1px radius-medium"
26
+ >
27
+ <span class="flex-nowrap flex flex-v-center p-medium vti__selection">
28
+ <span v-if="dropdownOptions.showFlags" v-html="activeCountryFlag" class="mn-r-thin" />
29
+ <span v-if="dropdownOptions.showDialCodeInSelection" class="vti__country-code">
30
+ +{{ activeCountry && activeCountry.dialCode }}
31
+ </span>
32
+ <!-- <slot name="arrow-icon" :open="open"> -->
33
+ <!-- <span class="vti__dropdown-arrow">{{ open ? "▲" : "▼" }}</span> -->
34
+ <!-- </slot> -->
35
+ </span>
36
+ <ul
37
+ ref="list"
38
+ class="bs-black radius-small vti__dropdown-list"
39
+ v-show="open"
40
+ :class="dropdownOpenDirection"
41
+ :style="[listStyle]"
42
+
43
+ >
44
+ <li
45
+ v-for="(pb, index) in sortedCountries"
46
+ class="flex-nowrap flex w-max"
47
+ :class="['vti__dropdown-item', getItemClass(index, pb.iso2)]"
48
+ :key="pb.iso2 + (pb.preferred ? '-preferred' : '')"
49
+ @click="choose(pb)"
50
+ @mousemove="selectedIndex = index"
51
+ >
52
+ <span v-if="dropdownOptions.showFlags" v-html="pb.flag" class="mn-r-thin"/>
53
+ <strong>{{ pb.name }}</strong>
54
+ <span v-if="dropdownOptions.showDialCodeInList"> +{{ pb.dialCode }} </span>
55
+ </li>
56
+ </ul>
57
+ </div>
58
+ <!-- <div :class="[divInputClass]" > -->
59
+ <input
60
+ v-model="phone"
61
+ inputmode="numeric"
62
+ pattern="\d*"
63
+ ref="input"
64
+ :type="inputOptions.type"
65
+ :autocomplete="inputOptions.autocomplete"
66
+ :autofocus="inputOptions.autofocus"
67
+ :class="['vti__input', inputOptions.styleClasses, inputClass, Iclasses]"
68
+ :style="[inputStyle, Istyles]"
69
+ :disabled="disabled"
70
+ :id="inputId !== ''? inputId : inputOptions.id"
71
+ :maxlength="inputOptions.maxlength"
72
+ :name="inputId !== ''? inputId : inputOptions.name"
73
+ :placeholder="parsedPlaceholder"
74
+ :readonly="inputOptions.readonly"
75
+ :required="inputOptions.required"
76
+ :tabindex="inputOptions.tabindex"
77
+ @blur="onBlur"
78
+ @focus="onFocus"
79
+ @input="onInput"
80
+ @keyup.enter="onEnter"
81
+ @keyup.space="onSpace"
82
+ />
83
+ <slot></slot> <!-- slot outlet -->
84
+ <!-- </div> -->
85
+
86
+ </div>
87
+ <!-- Validation -->
88
+ <transition name="fade">
89
+ <div v-if="validation" class="mn-t-thin mn-b-thin invalid-feedback">
90
+ * {{validation.message}}
91
+ </div>
92
+ </transition>
93
+ </template>
94
+
95
+
96
+ <script setup>
97
+ import { ref, reactive, watch, computed, onMounted, nextTick } from 'vue';
98
+ import { parsePhoneNumberFromString } from 'libphonenumber-js';
99
+
100
+ import clickOutside from './click-outside';
101
+ import allCountries from './all-countries';
102
+
103
+ let vClickOutside = clickOutside
104
+
105
+ const props = defineProps({
106
+ modelValue: { type: String, default: '',},
107
+ badClass: { type: [String, Array, Object], default: '', },
108
+ goodClass: { type: [String, Array, Object], default: '', },
109
+ badStyle: { type: [String, Array, Object], default: '', },
110
+ goodStyle: { type: [String, Array, Object], default: '', },
111
+ badInputClass: { type: [String, Array, Object], default: '', },
112
+ goodInputClass: { type: [String, Array, Object], default: '', },
113
+ badInputStyle: { type: [String, Array, Object], default: '', },
114
+ goodInputStyle: { type: [String, Array, Object], default: '', },
115
+ allCountries: { type: Array, default: () => allCountries, },
116
+ autoFormat: { type: Boolean, default: () => true, },
117
+ validation: { type: [Boolean, Object], default: false, },
118
+ customValidate: { type: [Boolean, RegExp], default: () => false, },
119
+ defaultCountry: { type: String, default: () => '', },
120
+ disabled: { type: Boolean, default: () => false, },
121
+ autoDefaultCountry: { type: Boolean, default: () => true },
122
+ ignoredCountries: { type: Array, default: () => [], },
123
+ invalidMsg: { type: String, default: () => '', },
124
+ mode: { type: String, default: () => 'auto', },
125
+ onlyCountries: { type: Array, default: () => [], },
126
+ preferredCountries: { type: Array, default: () => [], },
127
+ validCharactersOnly: { type: Boolean, default: () => false, },
128
+ rootClass: { type: [String, Array, Object], default: () => '', },
129
+ inputClass: { type: [String, Array, Object], default: () => {return ''}, },
130
+ divInputClass: { type: [String, Array, Object], default: () => {return ''}, },
131
+ rootStyle: { type: [String, Array, Object], default: () => {return ''}, },
132
+ dropdownStyle: { type: [String, Array, Object], default: () => {return ''}, },
133
+ listStyle: { type: [String, Array, Object], default: () => {return ''}, },
134
+ inputStyle: { type: [String, Array, Object], default: () => {return ''}, },
135
+ inputId: { type: [String, Array, Object], default: () => {return ''}, },
136
+ Placeholder: { type: [String, Object, Function], default: () => {return ''}, },
137
+ dropdownOptions: {
138
+ type: Object,
139
+ default: () => {
140
+ return {
141
+ showDialCodeInList: true,
142
+ showDialCodeInSelection: false,
143
+ showFlags: true,
144
+ tabindex: 0
145
+ }
146
+ }
147
+ },
148
+ inputOptions: {
149
+ type: Object,
150
+ default: () => {
151
+ return {
152
+ autocomplete: 'on',
153
+ autofocus: false,
154
+ id: '',
155
+ maxlength: 25,
156
+ name: 'telephone',
157
+ placeholder: 'Enter a phone number',
158
+ readonly: false,
159
+ required: false,
160
+ tabindex: 0,
161
+ type: 'tel',
162
+ styleClasses: ''
163
+ }
164
+ }
165
+ },
166
+ });
167
+
168
+ const emits = defineEmits([
169
+ 'update:modelValue',
170
+ 'validate',
171
+ 'country-changed',
172
+ 'open',
173
+ 'close',
174
+ 'blur',
175
+ 'focus',
176
+ 'enter',
177
+ 'space'
178
+ ]);
179
+
180
+ const counter = ref(5);
181
+ const initCounter = ref(5);
182
+ const message = reactive({
183
+ action: null,
184
+ amount: null,
185
+ });
186
+ const phone = ref(props.modelValue ? props.modelValue : '');
187
+ const activeCountryCode = ref('');
188
+ const open = ref(false);
189
+ const finishMounted = ref(false);
190
+ const selectedIndex = ref(null);
191
+ const typeToFindInput = ref('');
192
+ const typeToFindTimer = ref(null);
193
+ const dropdownOpenDirection = ref('below');
194
+ const parsedPlaceholder = ref(props.Placeholder !== '' ? props.Placeholder : props.inputOptions.placeholder);
195
+
196
+ const rootElement = ref(null)
197
+ const list = ref(null)
198
+ const input = ref(null)
199
+
200
+ // Lifecycle hooks
201
+ onMounted(async () => {
202
+ if (props.modelValue) {
203
+ phone.value = props.modelValue;
204
+ }
205
+
206
+ cleanInvalidCharacters();
207
+
208
+ initializeCountry()
209
+ .then(() => {
210
+ if (!phone.value
211
+ && props.inputOptions?.showDialCode
212
+ && activeCountryCode.value) {
213
+ phone.value = `+${activeCountryCode.value}`;
214
+ }
215
+ emits('validate', phoneObject.value);
216
+ })
217
+ .catch(console.error)
218
+ .then(() => {
219
+ finishMounted.value = true;
220
+ });
221
+ });
222
+
223
+ // Computed properties
224
+ const activeCountry = computed(() => {
225
+ return findCountry(activeCountryCode.value);
226
+ });
227
+
228
+ const activeCountryFlag = computed(() => {
229
+ return activeCountry.value ? activeCountry.value.flag : null;
230
+ });
231
+
232
+ const parsedMode = computed(() => {
233
+ if (props.mode === 'auto') {
234
+ if (!phone.value || phone.value[0] !== '+') {
235
+ return 'national';
236
+ }
237
+ return 'international';
238
+ }
239
+ if (!['international', 'national'].includes(props.mode)) {
240
+ console.error('Invalid value of prop "mode"');
241
+ return 'international';
242
+ }
243
+ return props.mode;
244
+ });
245
+
246
+ const filteredCountries = computed(() => {
247
+ if (props.onlyCountries && props.onlyCountries.length) {
248
+ return props.allCountries.filter(({ iso2 }) => props.onlyCountries.includes(iso2.toUpperCase()));
249
+ }
250
+
251
+ if (props.ignoredCountries && props.ignoredCountries.length) {
252
+ return props.allCountries.filter(({ iso2 }) =>
253
+ !props.ignoredCountries.includes(iso2.toUpperCase()) && !props.ignoredCountries.includes(iso2.toLowerCase()),
254
+ );
255
+ }
256
+
257
+ return props.allCountries;
258
+ });
259
+ const sortedCountries = computed(() => {
260
+ const preferredCountries = getCountries(props.preferredCountries)
261
+ .map(country => ({ ...country, preferred: true }));
262
+
263
+ return [...preferredCountries, ...filteredCountries.value];
264
+ });
265
+
266
+ const phoneObject = computed(() => {
267
+ let result = {};
268
+
269
+ if (phone.value?.[0] === '+') {
270
+ result = parsePhoneNumberFromString(phone.value) || {};
271
+ } else {
272
+ result = parsePhoneNumberFromString(phone.value, activeCountryCode.value) || {};
273
+ }
274
+
275
+ const { metadata, ...phoneDetails } = result;
276
+
277
+ let valid = result.isValid?.();
278
+ let formatted = phone.value;
279
+
280
+ if (valid) {
281
+ formatted = result.format?.(parsedMode.value.toUpperCase(), { nationalPrefix: false });
282
+ }
283
+
284
+ if (result.country && (props.ignoredCountries.length || props.onlyCountries.length)) {
285
+ if (!findCountry(result.country)) {
286
+ valid = false;
287
+ result = { ...result, country: null };
288
+ }
289
+ }
290
+
291
+ return {
292
+ ...phoneDetails,
293
+ countryCode: result.country,
294
+ valid,
295
+ country: activeCountry.value,
296
+ formatted,
297
+ };
298
+ });
299
+
300
+ const classes = computed(() => {
301
+ return phoneObject.value.valid === true ? props.goodClass :
302
+ phoneObject.value.valid === false ? props.badClass : undefined;
303
+ });
304
+
305
+ const styles = computed(() => {
306
+ return phoneObject.value.valid === true ? props.goodStyle :
307
+ phoneObject.value.valid === false ? props.badStyle : undefined;
308
+ });
309
+
310
+ const Iclasses = computed(() => {
311
+ return phoneObject.value.valid === true ? props.goodInputClass :
312
+ phoneObject.value.valid === false ? props.badInputClass : undefined;
313
+ });
314
+
315
+ const Istyles = computed(() => {
316
+ return phoneObject.value.valid === true ? props.goodInputStyle :
317
+ phoneObject.value.valid === false ? props.badInputStyle : undefined;
318
+ });
319
+ // ///////////
320
+ // Watchers
321
+ // ///////////
322
+ watch(activeCountry, (newValue, oldValue) => {
323
+ if (!newValue && oldValue?.iso2) {
324
+ activeCountryCode.value = oldValue.iso2;
325
+ return;
326
+ }
327
+ if (newValue?.iso2) {
328
+ emits('country-changed', newValue);
329
+ resetPlaceholder();
330
+ }
331
+ });
332
+
333
+ // Следим за изменениями countryCode в phoneObject
334
+ watch(() => phoneObject.value.countryCode, (newValue) => {
335
+ activeCountryCode.value = newValue;
336
+ });
337
+
338
+ // Следим за изменениями валидности phoneObject
339
+ watch(() => phoneObject.value.valid, () => {
340
+ emits('validate', phoneObject.value);
341
+ });
342
+
343
+ // Следим за изменениями отформатированного номера в phoneObject
344
+ watch(() => phoneObject.value.formatted, (newValue) => {
345
+ if (!props.autoFormat || props.customValidate) {
346
+ return;
347
+ }
348
+ emitInput(newValue);
349
+
350
+ nextTick(() => {
351
+ if (newValue && !props.modelValue) {
352
+ phone.value = newValue;
353
+ }
354
+ });
355
+ });
356
+
357
+ // Следим за изменениями placeholder в inputOptions
358
+ watch(() => props.inputOptions.placeholder, () => {
359
+ resetPlaceholder();
360
+ });
361
+
362
+ // Следим за внешними изменениями значения (например, через v-model)
363
+ watch(() => props.modelValue, (newValue, oldValue) => {
364
+ if (!testCharacters()) {
365
+ nextTick(() => {
366
+ phone.value = oldValue;
367
+ onInput();
368
+ });
369
+ } else {
370
+ phone.value = newValue;
371
+ }
372
+ });
373
+
374
+ // Следим за состоянием открытия/закрытия dropdown
375
+ watch(open, (isDropdownOpened) => {
376
+ if (isDropdownOpened) {
377
+ setDropdownPosition();
378
+ emits('open');
379
+ } else {
380
+ emits('close');
381
+ }
382
+ });
383
+
384
+ // Methods
385
+ function getCountry() {
386
+ return fetch('https://ip2c.org/s')
387
+ .then((response) => response.text())
388
+ .then((response) => {
389
+ const result = (response || '').toString();
390
+
391
+ if (!result || result[0] !== '1') {
392
+ throw new Error('unable to fetch the country');
393
+ }
394
+
395
+ return result.substr(2, 2);
396
+ });
397
+ }
398
+
399
+ function setCaretPosition(ctrl, pos) {
400
+ // Modern browsers
401
+ if (ctrl.setSelectionRange) {
402
+ ctrl.focus();
403
+ ctrl.setSelectionRange(pos, pos);
404
+
405
+ // IE8 and below
406
+ } else if (ctrl.createTextRange) {
407
+ const range = ctrl.createTextRange();
408
+ range.collapse(true);
409
+ range.moveEnd('character', pos);
410
+ range.moveStart('character', pos);
411
+ range.select();
412
+ }
413
+ }
414
+
415
+ function resetPlaceholder() {
416
+ parsedPlaceholder.value = props.inputOptions.placeholder;
417
+ }
418
+ function initializeCountry() {
419
+ return new Promise((resolve) => {
420
+ if (phone.value?.[0] === '+') { resolve(); return; }
421
+ if (props.defaultCountry) { choose(props.defaultCountry); resolve(); return; }
422
+ const fallbackCountry = props.preferredCountries[0] || filteredCountries.value[0];
423
+ if (props.autoDefaultCountry) {
424
+ getCountry()
425
+ .then((res) => { choose(res || activeCountryCode.value); })
426
+ .catch((error) => { console.warn(error); choose(fallbackCountry); })
427
+ .finally(() => { resolve(); });
428
+ } else {
429
+ choose(fallbackCountry);
430
+ resolve();
431
+ }
432
+ });
433
+ }
434
+
435
+ function getCountries(list = []) {
436
+ return list.map((countryCode) => findCountry(countryCode)).filter(Boolean);
437
+ }
438
+
439
+ function findCountry(iso = '') {
440
+ return filteredCountries.value.find((country) => country.iso2 === iso.toUpperCase());
441
+ }
442
+
443
+ function getItemClass(index, iso2) {
444
+ const highlighted = selectedIndex.value === index;
445
+ const lastPreferred = index === props.preferredCountries.length - 1;
446
+ const preferred = props.preferredCountries.some((c) => c.toUpperCase() === iso2);
447
+ return { highlighted, 'last-preferred': lastPreferred, preferred };
448
+ }
449
+
450
+ function choose(country) {
451
+ let parsedCountry = typeof country === 'string' ? findCountry(country) : country;
452
+ if (!parsedCountry) return;
453
+
454
+ if (phone.value?.[0] === '+' && parsedCountry.iso2 && phoneObject.value.nationalNumber) {
455
+ activeCountryCode.value = parsedCountry.iso2;
456
+ phone.value = parsePhoneNumberFromString(phoneObject.value.nationalNumber, parsedCountry.iso2).formatInternational();
457
+ return;
458
+ }
459
+
460
+ if (props.inputOptions?.showDialCode && parsedCountry) {
461
+ phone.value = `+${parsedCountry.dialCode}`;
462
+ return;
463
+ }
464
+
465
+ activeCountryCode.value = parsedCountry.iso2;
466
+ emitInput(phone.value);
467
+ }
468
+
469
+ function cleanInvalidCharacters() {
470
+ const currentPhone = phone.value;
471
+
472
+ if (props.validCharactersOnly) {
473
+ const results = phone.value.match(/[()\-+0-9\s]*/g);
474
+ phone.value = results.join('');
475
+ }
476
+
477
+ if (props.customValidate && props.customValidate instanceof RegExp) {
478
+ const results = phone.value.match(props.customValidate);
479
+ phone.value = results ? results.join('') : '';
480
+ }
481
+
482
+ if (currentPhone !== phone.value) {
483
+ emitInput(phone.value);
484
+ }
485
+ }
486
+
487
+ function testCharacters() {
488
+ if (props.validCharactersOnly) {
489
+ const result = /^[()\-+0-9\s]*$/.test(phone.value);
490
+ if (!result) return false;
491
+ }
492
+ if (props.customValidate) {
493
+ return testCustomValidate();
494
+ }
495
+ return true;
496
+ }
497
+
498
+ function testCustomValidate() {
499
+ return props.customValidate instanceof RegExp ? props.customValidate.test(phone.value) : false;
500
+ }
501
+
502
+ function onInput() {
503
+ input.value.setCustomValidity(phoneObject.valid ? '' : props.invalidMsg);
504
+
505
+ emitInput(phone.value);
506
+ }
507
+
508
+ function emitInput(value) {
509
+ emits('update:modelValue', value);
510
+
511
+ if (phoneObject.value.valid) {
512
+ emits('country', phoneObject.value.number);
513
+ } else {
514
+ emits('country', null);
515
+ }
516
+ }
517
+
518
+ function onBlur() {
519
+ emits('blur');
520
+ }
521
+
522
+ function onFocus() {
523
+ setCaretPosition(input.value, phone.value.length);
524
+ emits('focus');
525
+ }
526
+
527
+ function onEnter() {
528
+ emits('enter');
529
+ }
530
+
531
+ function onSpace() {
532
+ emits('space');
533
+ }
534
+
535
+ function focus() {
536
+ input.value.focus();
537
+ }
538
+
539
+ function toggleDropdown() {
540
+ if (props.disabled) return;
541
+ open.value = !open.value;
542
+ }
543
+
544
+ function clickedOutside() {
545
+ open.value = false;
546
+ }
547
+
548
+ function keyboardNav(e) {
549
+ if (e.keyCode === 40) { // down arrow
550
+ e.preventDefault();
551
+ open.value = true;
552
+ selectedIndex.value = selectedIndex.value === null ? 0 : Math.min(sortedCountries.value.length - 1, selectedIndex.value + 1);
553
+ nextTick(() => {
554
+ const selEle = list.value.children[selectedIndex.value];
555
+ if (selEle.offsetTop + selEle.clientHeight > list.value.scrollTop + list.value.clientHeight) {
556
+ list.value.scrollTop = selEle.offsetTop - list.value.clientHeight + selEle.clientHeight;
557
+ }
558
+ });
559
+ } else if (e.keyCode === 38) { // up arrow
560
+ e.preventDefault();
561
+ open.value = true;
562
+ selectedIndex.value = selectedIndex.value === null ? sortedCountries.value.length - 1 : Math.max(0, selectedIndex.value - 1);
563
+ nextTick(() => {
564
+ const selEle = list.value.children[selectedIndex.value];
565
+ if (selEle.offsetTop < list.value.scrollTop) {
566
+ list.value.scrollTop = selEle.offsetTop;
567
+ }
568
+ });
569
+ } else if (e.keyCode === 13) { // enter key
570
+ e.preventDefault();
571
+ if (selectedIndex.value !== null) {
572
+ choose(sortedCountries.value[selectedIndex.value]);
573
+ }
574
+ open.value = !open.value;
575
+ } else { // typing a country's name
576
+ typeToFindInput.value += e.key;
577
+ clearTimeout(typeToFindTimer);
578
+ typeToFindTimer = setTimeout(() => {
579
+ typeToFindInput.value = '';
580
+ }, 700);
581
+ nextTick(() => {
582
+ const typedCountryI = sortedCountries.value.slice(props.preferredCountries.length).findIndex((c) => c.name.toLowerCase().startsWith(typeToFindInput.value));
583
+ if (typedCountryI >= 0) {
584
+ selectedIndex.value = props.preferredCountries.length + typedCountryI;
585
+ const selEle = list.value.children[selectedIndex.value];
586
+ const needToScroll = selEle.offsetTop < list.value.scrollTop || selEle.offsetTop + selEle.clientHeight > list.value.scrollTop + list.value.clientHeight;
587
+ if (needToScroll) {
588
+ list.value.scrollTop = selEle.offsetTop - list.value.clientHeight / 2;
589
+ }
590
+ }
591
+ });
592
+ }
593
+ }
594
+
595
+ function reset() {
596
+ selectedIndex.value = sortedCountries.value.map(c => c.iso2).indexOf(activeCountryCode.value);
597
+ open.value = false;
598
+ }
599
+
600
+ function setDropdownPosition() {
601
+ const spaceBelow = window.innerHeight - rootElement.value.getBoundingClientRect().bottom;
602
+ const hasEnoughSpaceBelow = spaceBelow > 200;
603
+ dropdownOpenDirection.value = hasEnoughSpaceBelow ? 'below' : 'above';
604
+ }
605
+ </script>
606
+
607
+ <style scoped>
608
+ .vue3-reactive-tel-input{
609
+ display:flex
610
+ }
611
+ .vue3-reactive-tel-input.disabled .dropdown,.vue3-reactive-tel-input.disabled .selection,.vue3-reactive-tel-input.disabled input{
612
+ cursor:no-drop
613
+ }
614
+ .vti__dropdown{
615
+ display:flex;
616
+ flex-direction:column;
617
+ align-content:center;
618
+ justify-content:center;
619
+ position:relative;
620
+ padding:7px;
621
+ cursor:pointer
622
+ }
623
+ .vti__dropdown.show{
624
+ max-height:300px;
625
+ overflow:scroll
626
+ }
627
+ .vti__dropdown-list{
628
+ z-index:1;
629
+ padding:0;
630
+ margin:0;
631
+ text-align:left;
632
+ list-style:none;
633
+ max-height:200px;
634
+ overflow-y:scroll;
635
+ position:absolute;
636
+ left:-1px;
637
+ background-color:#fff;
638
+ width:fit-content
639
+ }
640
+ .vti__dropdown-list.below{
641
+ top:33px
642
+ }
643
+ .vti__dropdown-list.above{
644
+ top:auto;
645
+ bottom:100%
646
+ }
647
+ .vti__dropdown-arrow{
648
+ transform:scaleY(.5);
649
+ display:inline-block;
650
+ color:#666
651
+ }
652
+ .vti__dropdown-item{
653
+ cursor:pointer;
654
+ padding:4px 15px
655
+ }
656
+ .vti__dropdown-item.last-preferred{
657
+ border-bottom:1px solid #cacaca
658
+ }
659
+ .vti__dropdown-item .vti__flag{
660
+ display:inline-block;
661
+ margin-right:5px
662
+ }
663
+ .vti__input{
664
+ color: inherit;
665
+ border:none;
666
+ border-radius:0 2px 2px 0;
667
+ width:100%;
668
+ outline:0;
669
+ padding-left:7px
670
+ }
671
+ </style>
@@ -1,23 +1,28 @@
1
1
  export default {
2
- beforeMount(el, binding, vNode) { // (el, binding, vNode)
3
- // Provided expression must evaluate to a function.
2
+ beforeMount(el, binding, vNode) {
4
3
  if (typeof binding.value !== 'function') {
5
- const compName = vNode.context.name;
6
- let warn = `[Vue-click-outside:] provided expression ${binding.expression}
7
- is not a function, but has to be`;
4
+ let warn = `[Vue-click-outside:] provided expression ${binding.expression} is not a function, but has to be`;
5
+ const compName = vNode.component?.name;
8
6
  if (compName) {
9
- warn += `Found in component ${compName}`;
7
+ warn += ` Found in component ${compName}`;
10
8
  }
11
9
  console.warn(warn);
12
10
  }
13
- el.clickOutsideEvent = function (event) {
11
+
12
+ el.clickOutsideEvent = function(event) {
13
+ // Проверка, что клик был сделан за пределами элемента и не на самом элементе
14
14
  if (!(el === event.target || el.contains(event.target))) {
15
- binding.value(event, el);
15
+ // Вызов переданной функции, если условие выполняется
16
+ binding.value(event);
16
17
  }
17
18
  };
18
- document.body.addEventListener('click', el.clickOutsideEvent);
19
+
20
+ // Использование document вместо document.body может помочь в некоторых случаях,
21
+ // особенно если событие stopPropagation используется в дочерних элементах
22
+ document.addEventListener('click', el.clickOutsideEvent, true); // true для использования в фазе перехвата
19
23
  },
20
24
  unmounted(el) {
21
- document.body.removeEventListener('click', el.clickOutsideEvent);
25
+ // Убедитесь, что используете тот же флаг при удалении обработчика
26
+ document.removeEventListener('click', el.clickOutsideEvent, true);
22
27
  },
23
- };
28
+ };