fds-vue-core 7.2.2 → 7.2.4
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/components/Form/FdsPhonenumber/FdsPhonenumber.vue.d.ts +10 -0
- package/dist/components/Form/FdsPhonenumber/types.d.ts +10 -2
- package/dist/fds-vue-core.cjs.js +60 -21
- package/dist/fds-vue-core.cjs.js.map +1 -1
- package/dist/fds-vue-core.css +1 -1
- package/dist/fds-vue-core.es.js +61 -22
- package/dist/fds-vue-core.es.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/Form/FdsPhonenumber/FdsPhonenumber.vue +49 -6
- package/src/components/Form/FdsPhonenumber/FdsPhonenumberCountryPicker.vue +5 -9
- package/src/components/Form/FdsPhonenumber/types.ts +14 -2
- package/src/lang/en.json +1 -0
- package/src/lang/sv.json +1 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, watch } from 'vue'
|
|
2
|
+
import { computed, ref, useAttrs, watch } from 'vue'
|
|
3
3
|
import { useFdsI18n } from '../../../plugin/useFdsI18n'
|
|
4
4
|
import FdsInput from '../FdsInput/FdsInput.vue'
|
|
5
5
|
import { buildCountryOptions, sortCountryOptionsByName } from './countries'
|
|
@@ -11,8 +11,9 @@ defineOptions({
|
|
|
11
11
|
inheritAttrs: false,
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
const nationalNumber = defineModel<string>({ default: '' })
|
|
14
|
+
const [nationalNumber, modelModifiers] = defineModel<string>({ default: '' })
|
|
15
15
|
const country = defineModel<string>('country', { default: 'SE' })
|
|
16
|
+
const attrs = useAttrs()
|
|
16
17
|
|
|
17
18
|
const props = withDefaults(defineProps<FdsPhonenumberProps>(), {
|
|
18
19
|
label: undefined,
|
|
@@ -20,6 +21,16 @@ const props = withDefaults(defineProps<FdsPhonenumberProps>(), {
|
|
|
20
21
|
optional: false,
|
|
21
22
|
valid: undefined,
|
|
22
23
|
invalidMessage: undefined,
|
|
24
|
+
id: undefined,
|
|
25
|
+
autocomplete: 'tel',
|
|
26
|
+
required: false,
|
|
27
|
+
placeholder: undefined,
|
|
28
|
+
maxlength: undefined,
|
|
29
|
+
minlength: undefined,
|
|
30
|
+
name: undefined,
|
|
31
|
+
autofocus: false,
|
|
32
|
+
readonly: false,
|
|
33
|
+
pattern: undefined,
|
|
23
34
|
defaultCountry: 'SE',
|
|
24
35
|
countries: undefined,
|
|
25
36
|
locale: undefined,
|
|
@@ -35,6 +46,26 @@ const emit = defineEmits<FdsPhonenumberEmits>()
|
|
|
35
46
|
const { t, locale: fdsLocale } = useFdsI18n()
|
|
36
47
|
|
|
37
48
|
const resolvedLocale = computed(() => props.locale ?? fdsLocale.value)
|
|
49
|
+
const inputAttrs = computed(() => {
|
|
50
|
+
const { class: _class, style, ...rest } = attrs
|
|
51
|
+
return {
|
|
52
|
+
...rest,
|
|
53
|
+
...(style == null ? {} : { style: style as string | Record<string, unknown> }),
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
const forwardedInputProps = computed(() => ({
|
|
57
|
+
id: props.id,
|
|
58
|
+
autocomplete: props.autocomplete,
|
|
59
|
+
required: props.required,
|
|
60
|
+
placeholder: props.placeholder,
|
|
61
|
+
maxlength: props.maxlength,
|
|
62
|
+
minlength: props.minlength,
|
|
63
|
+
name: props.name,
|
|
64
|
+
autofocus: props.autofocus,
|
|
65
|
+
readonly: props.readonly,
|
|
66
|
+
pattern: props.pattern,
|
|
67
|
+
...inputAttrs.value,
|
|
68
|
+
}))
|
|
38
69
|
|
|
39
70
|
const countryItems = computed(() => {
|
|
40
71
|
const options = props.countries?.length
|
|
@@ -52,6 +83,12 @@ const phoneValidationOptions = computed(() => ({ numberType: props.numberType })
|
|
|
52
83
|
/** Set after the phone number field has blurred; validation does not run on input. */
|
|
53
84
|
const committedValid = ref<boolean | null>(null)
|
|
54
85
|
|
|
86
|
+
const resolvedLabel = computed(() => (props.label === undefined ? t('FdsPhonenumber.phoneNumber') : props.label))
|
|
87
|
+
|
|
88
|
+
const resolvedInvalidMessage = computed(() =>
|
|
89
|
+
props.invalidMessage === undefined ? t('FdsPhonenumber.invalidPhone') : props.invalidMessage,
|
|
90
|
+
)
|
|
91
|
+
|
|
55
92
|
const displayValid = computed((): boolean | null | undefined => {
|
|
56
93
|
if (props.valid === false) return false
|
|
57
94
|
if (props.valid === true) return true
|
|
@@ -61,7 +98,7 @@ const displayValid = computed((): boolean | null | undefined => {
|
|
|
61
98
|
})
|
|
62
99
|
|
|
63
100
|
const showInvalidMessage = computed(
|
|
64
|
-
() => displayValid.value === false && !props.optional &&
|
|
101
|
+
() => displayValid.value === false && !props.optional && !!resolvedInvalidMessage.value && !props.disabled,
|
|
65
102
|
)
|
|
66
103
|
|
|
67
104
|
const noCountryResults = ref(false)
|
|
@@ -99,8 +136,12 @@ function onNoCountryResults(value: boolean) {
|
|
|
99
136
|
|
|
100
137
|
<template>
|
|
101
138
|
<div class="w-full mb-6">
|
|
102
|
-
<label
|
|
103
|
-
|
|
139
|
+
<label
|
|
140
|
+
v-if="resolvedLabel"
|
|
141
|
+
class="block font-bold text-gray-900 cursor-pointer"
|
|
142
|
+
:class="{ 'mb-0': meta, 'mb-1': !meta }"
|
|
143
|
+
>
|
|
144
|
+
{{ resolvedLabel }}
|
|
104
145
|
</label>
|
|
105
146
|
<div v-if="meta" class="font-thin mb-1">
|
|
106
147
|
{{ meta }}
|
|
@@ -118,6 +159,7 @@ function onNoCountryResults(value: boolean) {
|
|
|
118
159
|
/>
|
|
119
160
|
<FdsInput
|
|
120
161
|
v-model="nationalNumber"
|
|
162
|
+
:modelModifiers="modelModifiers"
|
|
121
163
|
type="tel"
|
|
122
164
|
:valid="displayValid"
|
|
123
165
|
:disabled="disabled"
|
|
@@ -125,6 +167,7 @@ function onNoCountryResults(value: boolean) {
|
|
|
125
167
|
:ariaLabel="t('FdsPhonenumber.phoneNumber')"
|
|
126
168
|
:data-testid="dataTestid ? `${dataTestid}-number` : undefined"
|
|
127
169
|
:class="['mb-0! min-w-0 flex-1', inputClass ?? '']"
|
|
170
|
+
v-bind="forwardedInputProps"
|
|
128
171
|
@blur="handleBlur"
|
|
129
172
|
/>
|
|
130
173
|
</div>
|
|
@@ -132,7 +175,7 @@ function onNoCountryResults(value: boolean) {
|
|
|
132
175
|
{{ t('FdsPhonenumber.noCountryResults') }}
|
|
133
176
|
</div>
|
|
134
177
|
<div v-if="showInvalidMessage" class="text-red-700 font-bold mt-1">
|
|
135
|
-
{{
|
|
178
|
+
{{ resolvedInvalidMessage }}
|
|
136
179
|
</div>
|
|
137
180
|
</div>
|
|
138
181
|
</template>
|
|
@@ -80,10 +80,6 @@ const showActiveDialPreview = computed(
|
|
|
80
80
|
() => !showHoverDialPreview.value && !!activeCountry.value && dropdownOpen.value && !isSearching.value,
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
-
const showDialPreviewPadding = computed(
|
|
84
|
-
() => showSelectedDialPreview.value || showHoverDialPreview.value || showActiveDialPreview.value,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
83
|
const dialPreviewCountry = computed(() => {
|
|
88
84
|
if (showHoverDialPreview.value && hoveredCountry.value) {
|
|
89
85
|
return hoveredCountry.value
|
|
@@ -111,13 +107,13 @@ const dialPreviewClasses = computed(() => [
|
|
|
111
107
|
])
|
|
112
108
|
|
|
113
109
|
const inputClasses = computed(() => [
|
|
114
|
-
'block w-full h-12 rounded-md border border-gray-500 py-2 text-base leading-6 tabular-nums',
|
|
115
|
-
showDialPreviewPadding.value ? 'pl-10 pr-10' : 'px-3 pr-10',
|
|
110
|
+
'block w-full h-12 rounded-md border border-gray-500 py-2 text-base leading-6 tabular-nums px-3 pr-10',
|
|
116
111
|
'focus:outline-2 focus:outline-blue-500 -outline-offset-2 focus:border-transparent',
|
|
117
112
|
props.disabled
|
|
118
113
|
? 'text-gray-800 outline-dashed outline-2 outline-gray-400 cursor-not-allowed border-transparent bg-gray-50'
|
|
119
114
|
: 'cursor-text bg-white text-gray-900',
|
|
120
115
|
isInvalid.value && 'outline-2 -outline-offset-2 outline-red-600',
|
|
116
|
+
hasNoCountryResults.value && 'outline-red-600!',
|
|
121
117
|
])
|
|
122
118
|
|
|
123
119
|
const arrowButtonClasses = computed(() => [
|
|
@@ -341,11 +337,11 @@ onBeforeUnmount(() => {
|
|
|
341
337
|
<template>
|
|
342
338
|
<div ref="rootRef" class="relative w-32" :class="props.class">
|
|
343
339
|
<div class="relative w-full">
|
|
344
|
-
<div v-if="
|
|
340
|
+
<div v-if="!dropdownOpen" :class="dialPreviewClasses" aria-hidden="true">
|
|
345
341
|
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-xl leading-none">
|
|
346
|
-
{{ countryCodeToFlag(dialPreviewCountry
|
|
342
|
+
{{ countryCodeToFlag(dialPreviewCountry?.value ?? '') }}
|
|
347
343
|
</span>
|
|
348
|
-
{{ t('common.plus') }}{{ dialPreviewCountry
|
|
344
|
+
{{ t('common.plus') }}{{ dialPreviewCountry?.countryCode ?? '' }}
|
|
349
345
|
</div>
|
|
350
346
|
<input
|
|
351
347
|
ref="inputRef"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FdsInputProps } from '../FdsInput/types'
|
|
1
2
|
import type { CountryPhoneOption } from './countries'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -6,13 +7,18 @@ import type { CountryPhoneOption } from './countries'
|
|
|
6
7
|
*/
|
|
7
8
|
export type FdsPhonenumberNumberType = 'mobile' | 'any'
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
type FdsPhonenumberInputPassthroughProps = Pick<
|
|
11
|
+
FdsInputProps,
|
|
12
|
+
'id' | 'autocomplete' | 'required' | 'placeholder' | 'maxlength' | 'minlength' | 'name' | 'autofocus' | 'readonly' | 'pattern'
|
|
13
|
+
>
|
|
14
|
+
|
|
15
|
+
export interface FdsPhonenumberProps extends FdsPhonenumberInputPassthroughProps {
|
|
10
16
|
label?: string
|
|
11
17
|
meta?: string
|
|
12
18
|
optional?: boolean
|
|
13
19
|
valid?: boolean | null
|
|
14
20
|
invalidMessage?: string
|
|
15
|
-
/** National number (without country calling code). */
|
|
21
|
+
/** National number as typed by the user (without country calling code). */
|
|
16
22
|
modelValue?: string
|
|
17
23
|
/** ISO 3166-1 alpha-2 country code, e.g. `SE`. */
|
|
18
24
|
country?: string
|
|
@@ -28,6 +34,12 @@ export interface FdsPhonenumberProps {
|
|
|
28
34
|
dataTestid?: string
|
|
29
35
|
selectClass?: string
|
|
30
36
|
inputClass?: string
|
|
37
|
+
// Event handler props for consumer type inference
|
|
38
|
+
onValid?: ((value: boolean | null) => void) | Array<(value: boolean | null) => void>
|
|
39
|
+
onNoCountryResults?: ((value: boolean) => void) | Array<(value: boolean) => void>
|
|
40
|
+
onBlur?: ((event: FocusEvent) => void) | Array<(event: FocusEvent) => void>
|
|
41
|
+
'onUpdate:e164'?: ((value: string) => void) | Array<(value: string) => void>
|
|
42
|
+
'onUpdate:country'?: ((value: string) => void) | Array<(value: string) => void>
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
export interface FdsPhonenumberEmits {
|
package/src/lang/en.json
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"FdsPagination.nextPage": "Go to next page",
|
|
45
45
|
"FdsPagination.previousPage": "Go to previous page",
|
|
46
46
|
"FdsPhonenumber.countryCode": "Country code",
|
|
47
|
+
"FdsPhonenumber.invalidPhone": "Enter a valid phone number",
|
|
47
48
|
"FdsPhonenumber.noCountryResults": "No country matches your search",
|
|
48
49
|
"FdsPhonenumber.phoneNumber": "Phone number",
|
|
49
50
|
"FdsSearchSelectPro.loadingMore": "Loading more...",
|
package/src/lang/sv.json
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"FdsPagination.nextPage": "Gå till nästa sida",
|
|
45
45
|
"FdsPagination.previousPage": "Gå till föregående sida",
|
|
46
46
|
"FdsPhonenumber.countryCode": "Landskod",
|
|
47
|
+
"FdsPhonenumber.invalidPhone": "Ange ett giltigt telefonnummer",
|
|
47
48
|
"FdsPhonenumber.noCountryResults": "Inget land matchar sökningen",
|
|
48
49
|
"FdsPhonenumber.phoneNumber": "Telefonnummer",
|
|
49
50
|
"FdsSearchSelectPro.loadingMore": "Hämtar fler...",
|