design-system-next 2.14.1 → 2.15.0
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.
- package/dist/design-system-next.es.js +9970 -12704
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +14 -18
- package/dist/design-system-next.umd.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/dist/package.json.d.ts +4 -3
- package/package.json +4 -3
- package/src/App.vue +4 -1678
- package/src/assets/styles/tailwind.css +6 -19
- package/src/components/date-picker/date-picker.ts +0 -1
- package/src/components/date-picker/date-picker.vue +2 -2
- package/src/components/date-picker/date-range-picker/date-range-picker.vue +59 -36
- package/src/components/dropdown/dropdown.ts +8 -1
- package/src/components/dropdown/dropdown.vue +3 -1
- package/src/components/input/input-contact-number/input-contact-number.ts +6 -8
- package/src/components/input/input-contact-number/input-contact-number.vue +6 -5
- package/src/components/input/input-contact-number/use-input-contact-number.ts +61 -26
- package/src/components/input/input-currency/input-currency.ts +100 -0
- package/src/components/input/input-currency/input-currency.vue +60 -0
- package/src/components/input/input-currency/use-input-currency.ts +538 -0
- package/src/components/input/input.ts +0 -1
- package/src/components/input/input.vue +1 -1
- package/src/components/select/select-ladderized/select-ladderized.ts +5 -2
- package/src/components/select/select-ladderized/select-ladderized.vue +31 -31
- package/src/components/select/select-ladderized/use-select-ladderized.ts +1 -13
- package/src/components/select/select-multiple/select-multiple.ts +6 -3
- package/src/components/select/select-multiple/select-multiple.vue +70 -64
- package/src/components/select/select.ts +4 -1
- package/src/components/select/select.vue +1 -1
- package/src/components/table/table.ts +12 -12
- package/src/components/table/table.vue +128 -147
- package/src/components/table/use-draggable-table-rows.ts +57 -0
- package/src/components/table/use-table.ts +103 -23
- package/src/components/textarea/textarea.vue +7 -1
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
|
|
69
69
|
.v-popper__wrapper {
|
|
70
70
|
.v-popper__inner {
|
|
71
|
-
@apply spr-overflow-hidden spr-rounded-none spr-border-none spr-bg-transparent spr-shadow-
|
|
71
|
+
@apply spr-overflow-hidden spr-rounded-none spr-border-none spr-bg-transparent spr-shadow-drop;
|
|
72
72
|
|
|
73
73
|
.slide-fade-enter-active {
|
|
74
74
|
@apply spr-duration-300 spr-ease-out;
|
|
@@ -89,7 +89,6 @@
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
93
92
|
/* #endregion - Sidenav */
|
|
94
93
|
|
|
95
94
|
/* #region - Tooltips */
|
|
@@ -97,7 +96,7 @@
|
|
|
97
96
|
#tooltip-full-width-wrapper {
|
|
98
97
|
.v-popper__wrapper {
|
|
99
98
|
.v-popper__inner {
|
|
100
|
-
@apply spr-background-color-inverted spr-text-color-inverted-strong spr-body-xs-regular spr-break-all spr-rounded-border-radius-md spr-px-2 spr-py-1.5 spr-font-main spr-opacity-100;
|
|
99
|
+
@apply spr-background-color-inverted spr-text-color-inverted-strong spr-body-xs-regular spr-break-all spr-rounded-border-radius-md spr-px-2 spr-py-1.5 spr-font-main spr-opacity-100 spr-shadow-drop;
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
.v-popper__arrow-outer {
|
|
@@ -109,7 +108,7 @@
|
|
|
109
108
|
#tooltip-wrapper {
|
|
110
109
|
.v-popper__wrapper {
|
|
111
110
|
.v-popper__inner {
|
|
112
|
-
@apply spr-max-w-full;
|
|
111
|
+
@apply spr-max-w-full spr-shadow-drop;
|
|
113
112
|
}
|
|
114
113
|
}
|
|
115
114
|
}
|
|
@@ -117,7 +116,7 @@
|
|
|
117
116
|
#tooltip-full-width-wrapper {
|
|
118
117
|
.v-popper__wrapper {
|
|
119
118
|
.v-popper__inner {
|
|
120
|
-
@apply spr-max-w-[280px];
|
|
119
|
+
@apply spr-max-w-[280px] spr-shadow-drop;
|
|
121
120
|
}
|
|
122
121
|
}
|
|
123
122
|
}
|
|
@@ -129,7 +128,7 @@
|
|
|
129
128
|
|
|
130
129
|
.v-popper__wrapper {
|
|
131
130
|
.v-popper__inner {
|
|
132
|
-
@apply spr-border-color-weak spr-w-full spr-rounded-xl spr-border spr-border-solid spr-font-main spr-shadow-
|
|
131
|
+
@apply spr-border-color-weak spr-w-full spr-rounded-xl spr-border spr-border-solid spr-font-main spr-shadow-drop;
|
|
133
132
|
|
|
134
133
|
&::-webkit-scrollbar-track {
|
|
135
134
|
@apply spr-rounded-br-xl spr-rounded-tr-xl;
|
|
@@ -141,18 +140,6 @@
|
|
|
141
140
|
}
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
|
-
|
|
145
|
-
#contact-number-country-dropdown {
|
|
146
|
-
#dropdown-wrapper[data-popper-placement='top-start'] {
|
|
147
|
-
margin-top: -4px;
|
|
148
|
-
margin-left: -8px;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
#dropdown-wrapper[data-popper-placement='bottom-start'] {
|
|
152
|
-
margin-top: 4px;
|
|
153
|
-
margin-left: -8px;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
143
|
/* #endregion - Dropdown */
|
|
157
144
|
|
|
158
145
|
/* #region - Select */
|
|
@@ -198,7 +185,7 @@
|
|
|
198
185
|
}
|
|
199
186
|
tbody::-webkit-scrollbar {
|
|
200
187
|
@apply spr-h-0 spr-w-0; /* Hides the scrollbar in WebKit browsers */
|
|
201
|
-
}
|
|
188
|
+
}
|
|
202
189
|
|
|
203
190
|
.empty-table-dropzone-dragged-class {
|
|
204
191
|
@apply spr-hidden;
|
|
@@ -266,7 +266,7 @@
|
|
|
266
266
|
</Menu>
|
|
267
267
|
<div v-if="props.displayHelper" :class="datePickerClasses.datePickerInputHelperClasses">
|
|
268
268
|
<slot name="helperMessage">
|
|
269
|
-
<Icon v-if="props.helperIcon" :icon="props.helperIcon"
|
|
269
|
+
<Icon v-if="props.helperIcon" class="spr-h-5 spr-min-h-5 spr-w-5 spr-min-w-5" :icon="props.helperIcon" />
|
|
270
270
|
<span>{{ props.helperText }}</span>
|
|
271
271
|
</slot>
|
|
272
272
|
</div>
|
|
@@ -330,7 +330,7 @@ const {
|
|
|
330
330
|
handleTabClick,
|
|
331
331
|
handleBackspace,
|
|
332
332
|
clearDate,
|
|
333
|
-
handleSlotClick
|
|
333
|
+
handleSlotClick,
|
|
334
334
|
} = useDatePicker(props, emit);
|
|
335
335
|
|
|
336
336
|
defineExpose({
|
|
@@ -1,42 +1,49 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<Menu
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
4
|
+
v-model:shown="datePopperState"
|
|
5
|
+
aria-id="date-range-picker-wrapper"
|
|
6
|
+
distance="4"
|
|
7
|
+
:placement="finalPlacement"
|
|
8
|
+
:triggers="[]"
|
|
9
|
+
:popper-hide-triggers="[]"
|
|
10
|
+
:auto-hide="false"
|
|
11
|
+
:disabled="isDateRangePickerPopperDisabled"
|
|
12
|
+
:container="`#${props.id}`"
|
|
13
|
+
:reference="activeInputRef"
|
|
14
|
+
:strategy="
|
|
15
|
+
props.popperStrategy === 'fixed' || props.popperStrategy === 'absolute' ? props.popperStrategy : 'absolute'
|
|
16
|
+
"
|
|
17
|
+
:delay="0"
|
|
18
|
+
:auto-placement="!isUsingCustomSlot"
|
|
19
|
+
:style="{
|
|
20
|
+
width: props.width,
|
|
21
|
+
}"
|
|
22
|
+
>
|
|
23
23
|
<div :id="props.id" class="spr-grid spr-gap-size-spacing-4xs">
|
|
24
24
|
<label v-if="props.label" :for="props.id" :class="dateRangePickerClasses.labelClasses">
|
|
25
25
|
{{ props.label }}
|
|
26
26
|
</label>
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
<!-- Date Range Input Container -->
|
|
29
|
-
<div class="spr-flex spr-items-center spr-gap-2
|
|
29
|
+
<div class="spr-flex spr-w-full spr-items-center spr-gap-2">
|
|
30
30
|
<slot :handle-click="handleCustomComponentClick">
|
|
31
31
|
<!-- fallback: original input fields -->
|
|
32
32
|
<!-- Start Date Input -->
|
|
33
|
-
<div
|
|
33
|
+
<div
|
|
34
|
+
ref="startDateContainerRef"
|
|
35
|
+
:class="['spr-flex-1', dateRangePickerClasses.dateRangePickerBaseInputClasses]"
|
|
36
|
+
@click.stop="handleStartDateClick"
|
|
37
|
+
>
|
|
34
38
|
<div class="spr-flex spr-h-full spr-items-center spr-gap-1.5">
|
|
35
39
|
<input
|
|
36
40
|
:id="`${props.id}-start-month`"
|
|
37
41
|
ref="startMonthInputRef"
|
|
38
42
|
v-model="startMonthInput"
|
|
39
|
-
:class="[
|
|
43
|
+
:class="[
|
|
44
|
+
'spr-w-[38px] spr-min-w-[38px] spr-uppercase',
|
|
45
|
+
dateRangePickerClasses.dateRangePickerInputClasses,
|
|
46
|
+
]"
|
|
40
47
|
type="text"
|
|
41
48
|
placeholder="MMM"
|
|
42
49
|
maxlength="3"
|
|
@@ -51,7 +58,10 @@
|
|
|
51
58
|
:id="`${props.id}-start-date`"
|
|
52
59
|
ref="startDateInputRef"
|
|
53
60
|
v-model="startDateInput"
|
|
54
|
-
:class="[
|
|
61
|
+
:class="[
|
|
62
|
+
'spr-w-[24px] spr-min-w-[24px] spr-text-center',
|
|
63
|
+
dateRangePickerClasses.dateRangePickerInputClasses,
|
|
64
|
+
]"
|
|
55
65
|
type="text"
|
|
56
66
|
placeholder="DD"
|
|
57
67
|
maxlength="2"
|
|
@@ -84,13 +94,20 @@
|
|
|
84
94
|
<!-- Separator -->
|
|
85
95
|
<span class="spr-text-color-strong spr-font-size-200 spr-text-color-weak">{{ props.separator }}</span>
|
|
86
96
|
<!-- End Date Input -->
|
|
87
|
-
<div
|
|
97
|
+
<div
|
|
98
|
+
ref="endDateContainerRef"
|
|
99
|
+
:class="['spr-flex-1', dateRangePickerClasses.dateRangePickerBaseInputClasses]"
|
|
100
|
+
@click.stop="handleEndDateClick"
|
|
101
|
+
>
|
|
88
102
|
<div class="spr-flex spr-h-full spr-items-center spr-gap-1.5">
|
|
89
103
|
<input
|
|
90
104
|
:id="`${props.id}-end-month`"
|
|
91
105
|
ref="endMonthInputRef"
|
|
92
106
|
v-model="endMonthInput"
|
|
93
|
-
:class="[
|
|
107
|
+
:class="[
|
|
108
|
+
'spr-w-[38px] spr-min-w-[38px] spr-uppercase',
|
|
109
|
+
dateRangePickerClasses.dateRangePickerInputClasses,
|
|
110
|
+
]"
|
|
94
111
|
type="text"
|
|
95
112
|
placeholder="MMM"
|
|
96
113
|
maxlength="3"
|
|
@@ -105,7 +122,10 @@
|
|
|
105
122
|
:id="`${props.id}-end-date`"
|
|
106
123
|
ref="endDateInputRef"
|
|
107
124
|
v-model="endDateInput"
|
|
108
|
-
:class="[
|
|
125
|
+
:class="[
|
|
126
|
+
'spr-w-[24px] spr-min-w-[24px] spr-text-center',
|
|
127
|
+
dateRangePickerClasses.dateRangePickerInputClasses,
|
|
128
|
+
]"
|
|
109
129
|
type="text"
|
|
110
130
|
placeholder="DD"
|
|
111
131
|
maxlength="2"
|
|
@@ -244,11 +264,11 @@
|
|
|
244
264
|
'spr-text-color-disabled': calendarTabIsInactiveMonthDates(day),
|
|
245
265
|
|
|
246
266
|
// Selected Date (Start or End) - Use brand color scheme from date picker
|
|
247
|
-
'spr-background-color-brand-base active:spr-background-color-brand-pressed spr-text-color-inverted-strong !spr-text-white-50 active:spr-scale-95
|
|
267
|
+
'spr-background-color-brand-base active:spr-background-color-brand-pressed spr-text-color-inverted-strong spr-font-medium !spr-text-white-50 active:spr-scale-95':
|
|
248
268
|
calendarTabIsSelectedDate(day),
|
|
249
269
|
|
|
250
270
|
// In Range (between start and end) - Light green background with brand outline, no border, using spr- prefix
|
|
251
|
-
'spr-bg-green-100 spr-
|
|
271
|
+
'spr-cursor-pointer spr-bg-green-100 spr-outline spr-outline-1 spr-outline-offset-[-0.5px] spr-outline-kangkong-700':
|
|
252
272
|
calendarTabIsInRange(day),
|
|
253
273
|
|
|
254
274
|
// Unselected Date - Gray border, no hover effects
|
|
@@ -264,7 +284,7 @@
|
|
|
264
284
|
<span>{{ day.date.date() }}</span>
|
|
265
285
|
<div
|
|
266
286
|
v-if="calendarTabIsTodayIndicator(day)"
|
|
267
|
-
class="spr-
|
|
287
|
+
class="spr-absolute spr-bottom-1 spr-m-auto spr-h-1 spr-w-1 spr-rounded-full spr-bg-green-600"
|
|
268
288
|
></div>
|
|
269
289
|
</div>
|
|
270
290
|
<div v-else></div>
|
|
@@ -281,9 +301,11 @@
|
|
|
281
301
|
{
|
|
282
302
|
'spr-text-color-brand-base': month.monthValue === currentDate.month(),
|
|
283
303
|
'spr-border-color-weak hover:spr-background-color-hover active:spr-background-color-pressed':
|
|
284
|
-
month.text.toLowerCase() !== startMonthInput.toLowerCase() &&
|
|
304
|
+
month.text.toLowerCase() !== startMonthInput.toLowerCase() &&
|
|
305
|
+
month.text.toLowerCase() !== endMonthInput.toLowerCase(),
|
|
285
306
|
'spr-border-color-brand-base spr-background-color-single-active':
|
|
286
|
-
month.text.toLowerCase() === startMonthInput.toLowerCase() ||
|
|
307
|
+
month.text.toLowerCase() === startMonthInput.toLowerCase() ||
|
|
308
|
+
month.text.toLowerCase() === endMonthInput.toLowerCase(),
|
|
287
309
|
},
|
|
288
310
|
]"
|
|
289
311
|
@click="monthTabHandleSelectedMonth(month)"
|
|
@@ -308,7 +330,8 @@
|
|
|
308
330
|
'spr-text-color-brand-base': year === currentDate.year(),
|
|
309
331
|
'spr-border-color-weak hover:spr-background-color-hover active:spr-background-color-pressed':
|
|
310
332
|
year !== Number(startYearInput) && year !== Number(endYearInput),
|
|
311
|
-
'spr-border-color-brand-base spr-background-color-single-active':
|
|
333
|
+
'spr-border-color-brand-base spr-background-color-single-active':
|
|
334
|
+
year === Number(startYearInput) || year === Number(endYearInput),
|
|
312
335
|
},
|
|
313
336
|
]"
|
|
314
337
|
@click="yearTabHandleSelectedYear(String(year))"
|
|
@@ -324,10 +347,10 @@
|
|
|
324
347
|
</div>
|
|
325
348
|
</template>
|
|
326
349
|
</Menu>
|
|
327
|
-
|
|
350
|
+
|
|
328
351
|
<div v-if="props.displayHelper" :class="dateRangePickerClasses.dateRangePickerInputHelperClasses">
|
|
329
352
|
<slot name="helperMessage">
|
|
330
|
-
<Icon v-if="props.helperIcon" :icon="props.helperIcon"
|
|
353
|
+
<Icon v-if="props.helperIcon" class="spr-h-5 spr-min-h-5 spr-w-5 spr-min-w-5" :icon="props.helperIcon" />
|
|
331
354
|
<span>{{ props.helperText }}</span>
|
|
332
355
|
</slot>
|
|
333
356
|
</div>
|
|
@@ -409,4 +432,4 @@ const {
|
|
|
409
432
|
handleEndDateClick,
|
|
410
433
|
handleCustomComponentClick,
|
|
411
434
|
} = useDateRangePicker(props, emit);
|
|
412
|
-
</script>
|
|
435
|
+
</script>
|
|
@@ -42,6 +42,10 @@ export const dropdownPropTypes = {
|
|
|
42
42
|
required: true,
|
|
43
43
|
default: [],
|
|
44
44
|
},
|
|
45
|
+
searchableMenu: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: false,
|
|
48
|
+
},
|
|
45
49
|
textField: {
|
|
46
50
|
type: String,
|
|
47
51
|
default: 'text',
|
|
@@ -65,6 +69,10 @@ export const dropdownPropTypes = {
|
|
|
65
69
|
validator: (value: (typeof PLACEMENTS_TYPES)[number]) => PLACEMENTS_TYPES.includes(value),
|
|
66
70
|
default: 'bottom',
|
|
67
71
|
},
|
|
72
|
+
distance: {
|
|
73
|
+
type: Number,
|
|
74
|
+
default: 6,
|
|
75
|
+
},
|
|
68
76
|
groupItemsBy: {
|
|
69
77
|
type: String as PropType<(typeof GROUPED_ITEMS_BY_TYPES)[number]>,
|
|
70
78
|
validator: (value: (typeof GROUPED_ITEMS_BY_TYPES)[number] | undefined) => {
|
|
@@ -112,7 +120,6 @@ export const dropdownPropTypes = {
|
|
|
112
120
|
type: Boolean,
|
|
113
121
|
default: false,
|
|
114
122
|
},
|
|
115
|
-
// Enable lozenge style for dropdown items
|
|
116
123
|
lozenge: {
|
|
117
124
|
type: Boolean,
|
|
118
125
|
default: false,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<Menu
|
|
3
3
|
v-model:shown="dropdownPopperState"
|
|
4
4
|
aria-id="dropdown-wrapper"
|
|
5
|
-
distance="
|
|
5
|
+
:distance="props.distance"
|
|
6
6
|
:placement="props.placement"
|
|
7
7
|
:triggers="props.triggers"
|
|
8
8
|
:popper-triggers="props.popperTriggers"
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
v-if="!props.ladderized || isLadderizedSearch"
|
|
46
46
|
v-model="selectedListItems"
|
|
47
47
|
:menu-list="dropdownMenuList"
|
|
48
|
+
:searchable-menu="props.searchableMenu"
|
|
48
49
|
:group-items-by="props.groupItemsBy"
|
|
49
50
|
:multi-select="props.multiSelect"
|
|
50
51
|
:pre-selected-items="dropdownValue"
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
:ladderized="props.ladderized"
|
|
60
61
|
:dropdown="props.dropdown"
|
|
61
62
|
:menu-list="dropdownMenuList"
|
|
63
|
+
:searchable-menu="props.searchableMenu"
|
|
62
64
|
:remove-current-level-in-back-label="removeCurrentLevelInBackLabel"
|
|
63
65
|
@update:model-value="handleSelectedLadderizedItem"
|
|
64
66
|
/>
|
|
@@ -23,9 +23,13 @@ export const COUNTRY_OPTIONS: CountryOption[] = getCountries().map((countryCode)
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export const inputContactNumberPropTypes = {
|
|
26
|
+
id: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: '',
|
|
29
|
+
},
|
|
26
30
|
modelValue: {
|
|
27
31
|
type: String,
|
|
28
|
-
|
|
32
|
+
default: '',
|
|
29
33
|
},
|
|
30
34
|
placeholder: {
|
|
31
35
|
type: String,
|
|
@@ -69,13 +73,7 @@ export const inputContactNumberEmitTypes = {
|
|
|
69
73
|
|
|
70
74
|
export interface InputContactNumberEmit {
|
|
71
75
|
(event: 'update:modelValue', value: string): void;
|
|
72
|
-
(
|
|
73
|
-
event: 'getSelectedCountryCallingCode',
|
|
74
|
-
value: {
|
|
75
|
-
countryCode: string[];
|
|
76
|
-
countryCallingCode: string[];
|
|
77
|
-
},
|
|
78
|
-
): void;
|
|
76
|
+
(event: 'getSelectedCountryCallingCode', value: { countryCode: string; countryCallingCode: string }): void;
|
|
79
77
|
(event: 'getContactNumberErrors', value: Array<{ title: string; message: string }>): void;
|
|
80
78
|
}
|
|
81
79
|
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
>
|
|
13
13
|
<template #prefix>
|
|
14
14
|
<spr-dropdown
|
|
15
|
-
id="
|
|
15
|
+
:id="dropdownId"
|
|
16
16
|
v-model="selectedCountry.countryCode"
|
|
17
|
-
class="
|
|
17
|
+
:class="inputContactNumberClasses.dropdownBaseClasses"
|
|
18
18
|
:menu-list="COUNTRY_OPTIONS"
|
|
19
19
|
placement="bottom-start"
|
|
20
20
|
:width="!props.disabledCountryCallingCode ? '45px' : '35px'"
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
@update:model-value="handleSelectedCountryCode"
|
|
24
24
|
@get-popper-state="handlePopperState"
|
|
25
25
|
>
|
|
26
|
-
<
|
|
27
|
-
|
|
26
|
+
<div :class="inputContactNumberClasses.dropdownWrappertClasses">
|
|
27
|
+
<span>+{{ selectedCountry.countryCallingCode }}</span>
|
|
28
28
|
<icon v-if="!props.disabledCountryCallingCode" icon="ph:caret-down" width="16px" height="16px" />
|
|
29
|
-
</
|
|
29
|
+
</div>
|
|
30
30
|
</spr-dropdown>
|
|
31
31
|
</template>
|
|
32
32
|
</spr-input>
|
|
@@ -48,6 +48,7 @@ const emit = defineEmits(inputContactNumberEmitTypes);
|
|
|
48
48
|
|
|
49
49
|
const {
|
|
50
50
|
inputContactNumberClasses,
|
|
51
|
+
dropdownId,
|
|
51
52
|
formattedValue,
|
|
52
53
|
selectedCountry,
|
|
53
54
|
popperState,
|
|
@@ -8,17 +8,26 @@ import parsePhoneNumber, { getCountries, getCountryCallingCode, CountryCode } fr
|
|
|
8
8
|
import { type InputContactNumberEmitTypes, type InputContactNumberPropTypes } from './input-contact-number';
|
|
9
9
|
|
|
10
10
|
interface InputContactNumberClasses {
|
|
11
|
-
|
|
11
|
+
dropdownBaseClasses: string;
|
|
12
|
+
dropdownWrappertClasses: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export const useInputContactNumber = (
|
|
15
16
|
props: InputContactNumberPropTypes,
|
|
16
17
|
emit: SetupContext<InputContactNumberEmitTypes>['emit'],
|
|
17
18
|
) => {
|
|
18
|
-
const { preSelectedCountryCode, disabledCountryCallingCode, disabled } = toRefs(props);
|
|
19
|
+
const { id, preSelectedCountryCode, disabledCountryCallingCode, disabled } = toRefs(props);
|
|
19
20
|
|
|
20
21
|
const inputContactNumberClasses: ComputedRef<InputContactNumberClasses> = computed(() => {
|
|
21
|
-
const
|
|
22
|
+
const dropdownBaseClasses = classNames(
|
|
23
|
+
'[&_#dropdown-wrapper]:spr-my-1',
|
|
24
|
+
'[&_#dropdown-wrapper[data-popper-placement="bottom-start"]]:spr-ml-[-10px]',
|
|
25
|
+
'[&_#dropdown-wrapper[data-popper-placement="bottom-start"]]:spr-mt-[6px]',
|
|
26
|
+
'[&_#dropdown-wrapper[data-popper-placement="top-start"]]:spr-ml-[-10px]',
|
|
27
|
+
'[&_#dropdown-wrapper[data-popper-placement="top-start"]]:spr-mt-[-6px]',
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const dropdownWrappertClasses = classNames(
|
|
22
31
|
'spr-font-weight-regular spr-font-size-200 spr-line-height-500 spr-letter-spacing-none spr-font-main',
|
|
23
32
|
'spr-flex spr-items-center spr-gap-size-spacing-5xs',
|
|
24
33
|
{
|
|
@@ -29,20 +38,25 @@ export const useInputContactNumber = (
|
|
|
29
38
|
);
|
|
30
39
|
|
|
31
40
|
return {
|
|
32
|
-
|
|
41
|
+
dropdownBaseClasses,
|
|
42
|
+
dropdownWrappertClasses,
|
|
33
43
|
};
|
|
34
44
|
});
|
|
35
45
|
|
|
46
|
+
// fallback random id if user does not provide one (stable per component instance)
|
|
47
|
+
const fallbackId = ref(`currency-${Math.random().toString(36).slice(2, 8)}-dropdown`);
|
|
48
|
+
const dropdownId = computed(() => (id.value ? `${id.value}-dropdown` : fallbackId.value));
|
|
49
|
+
|
|
36
50
|
const formattedValue = useVModel(props, 'modelValue', emit);
|
|
37
51
|
|
|
38
52
|
const selectedCountry = ref({
|
|
39
|
-
countryCode:
|
|
40
|
-
countryCallingCode:
|
|
53
|
+
countryCode: 'PH',
|
|
54
|
+
countryCallingCode: '63',
|
|
41
55
|
});
|
|
42
56
|
|
|
43
57
|
const popperState = ref(false);
|
|
44
58
|
|
|
45
|
-
const
|
|
59
|
+
const setSelectedCountry = (selectedCountryCode: string) => {
|
|
46
60
|
const countryCallingCode = getCountryCallingCode(selectedCountryCode as CountryCode);
|
|
47
61
|
|
|
48
62
|
const countryCode = getCountries().find((country) => {
|
|
@@ -51,8 +65,8 @@ export const useInputContactNumber = (
|
|
|
51
65
|
|
|
52
66
|
if (countryCode && countryCallingCode) {
|
|
53
67
|
selectedCountry.value = {
|
|
54
|
-
countryCode:
|
|
55
|
-
countryCallingCode:
|
|
68
|
+
countryCode: countryCode,
|
|
69
|
+
countryCallingCode: countryCallingCode,
|
|
56
70
|
};
|
|
57
71
|
|
|
58
72
|
formatContactNumber();
|
|
@@ -81,10 +95,10 @@ export const useInputContactNumber = (
|
|
|
81
95
|
}
|
|
82
96
|
};
|
|
83
97
|
|
|
84
|
-
const handleSelectedCountryCode = (countryCode: string
|
|
98
|
+
const handleSelectedCountryCode = (countryCode: string) => {
|
|
85
99
|
selectedCountry.value = {
|
|
86
|
-
countryCode:
|
|
87
|
-
countryCallingCode:
|
|
100
|
+
countryCode: countryCode,
|
|
101
|
+
countryCallingCode: getCountryCallingCode(countryCode as CountryCode),
|
|
88
102
|
};
|
|
89
103
|
|
|
90
104
|
emit('getContactNumberErrors', []);
|
|
@@ -92,27 +106,46 @@ export const useInputContactNumber = (
|
|
|
92
106
|
formatContactNumber();
|
|
93
107
|
|
|
94
108
|
emit('getSelectedCountryCallingCode', {
|
|
95
|
-
countryCode: selectedCountry.value.countryCode
|
|
96
|
-
countryCallingCode: selectedCountry.value.countryCallingCode
|
|
109
|
+
countryCode: selectedCountry.value.countryCode,
|
|
110
|
+
countryCallingCode: selectedCountry.value.countryCallingCode,
|
|
97
111
|
});
|
|
98
112
|
};
|
|
99
113
|
|
|
100
114
|
const formatContactNumber = () => {
|
|
101
|
-
if (!formattedValue.value)
|
|
102
|
-
|
|
103
|
-
|
|
115
|
+
if (!formattedValue.value) {
|
|
116
|
+
emit('getContactNumberErrors', []);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
104
119
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
120
|
+
const original = formattedValue.value.trim();
|
|
121
|
+
const hasPlus = original.startsWith('+');
|
|
122
|
+
const normalizedNumber = hasPlus ? `+${original.replace(/[^0-9]/g, '')}` : original.replace(/\D/g, '');
|
|
123
|
+
|
|
124
|
+
let phoneNumber;
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
phoneNumber = hasPlus
|
|
128
|
+
? parsePhoneNumber(normalizedNumber)
|
|
129
|
+
: parsePhoneNumber(normalizedNumber, {
|
|
130
|
+
defaultCountry: selectedCountry.value.countryCode as CountryCode,
|
|
131
|
+
extract: false,
|
|
132
|
+
});
|
|
133
|
+
} catch {
|
|
134
|
+
phoneNumber = undefined;
|
|
135
|
+
}
|
|
109
136
|
|
|
110
137
|
if (phoneNumber && phoneNumber.isValid()) {
|
|
111
138
|
let formattedNumber = phoneNumber.formatInternational();
|
|
112
139
|
|
|
113
|
-
|
|
140
|
+
const prefix = `+${selectedCountry.value.countryCallingCode} `;
|
|
141
|
+
|
|
142
|
+
if (formattedNumber.startsWith(prefix)) {
|
|
143
|
+
formattedNumber = formattedNumber.slice(prefix.length);
|
|
144
|
+
}
|
|
114
145
|
|
|
115
146
|
formattedValue.value = formattedNumber;
|
|
147
|
+
|
|
148
|
+
emit('getContactNumberErrors', []);
|
|
116
149
|
} else {
|
|
117
150
|
emit('getContactNumberErrors', [
|
|
118
151
|
{
|
|
@@ -133,23 +166,24 @@ export const useInputContactNumber = (
|
|
|
133
166
|
|
|
134
167
|
watch(preSelectedCountryCode, (newValue) => {
|
|
135
168
|
if (newValue) {
|
|
136
|
-
|
|
169
|
+
setSelectedCountry(newValue);
|
|
137
170
|
}
|
|
138
171
|
});
|
|
139
172
|
|
|
140
173
|
onMounted(() => {
|
|
141
174
|
emit('getSelectedCountryCallingCode', {
|
|
142
|
-
countryCode: selectedCountry.value.countryCode
|
|
143
|
-
countryCallingCode: selectedCountry.value.countryCallingCode
|
|
175
|
+
countryCode: selectedCountry.value.countryCode,
|
|
176
|
+
countryCallingCode: selectedCountry.value.countryCallingCode,
|
|
144
177
|
});
|
|
145
178
|
|
|
146
179
|
if (preSelectedCountryCode.value) {
|
|
147
|
-
|
|
180
|
+
setSelectedCountry(preSelectedCountryCode.value);
|
|
148
181
|
}
|
|
149
182
|
});
|
|
150
183
|
|
|
151
184
|
return {
|
|
152
185
|
inputContactNumberClasses,
|
|
186
|
+
dropdownId,
|
|
153
187
|
formattedValue,
|
|
154
188
|
selectedCountry,
|
|
155
189
|
popperState,
|
|
@@ -158,5 +192,6 @@ export const useInputContactNumber = (
|
|
|
158
192
|
formatContactNumber,
|
|
159
193
|
handleUpdateModelValue,
|
|
160
194
|
handlePopperState,
|
|
195
|
+
setSelectedCountry,
|
|
161
196
|
};
|
|
162
197
|
};
|