sprintify-ui 0.0.164 → 0.0.165
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/README.md +34 -1
- package/dist/sprintify-ui.es.js +2073 -2044
- package/dist/types/src/components/BaseAddressForm.vue.d.ts +45 -0
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +2 -2
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +1 -1
- package/dist/types/src/components/BaseCharacterCounter.vue.d.ts +1 -1
- package/dist/types/src/components/BaseFieldI18n.vue.d.ts +1 -1
- package/dist/types/src/components/BaseInput.vue.d.ts +1 -1
- package/dist/types/src/components/BaseInputPercent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseModalCenter.vue.d.ts +1 -1
- package/dist/types/src/components/BaseModalSide.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNumber.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +2 -2
- package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +1 -1
- package/dist/types/src/index.d.ts +34 -0
- package/dist/types/src/types/Country.d.ts +4 -0
- package/dist/types/src/types/Region.d.ts +5 -0
- package/package.json +2 -1
- package/src/components/BaseAddressForm.stories.js +63 -0
- package/src/components/BaseAddressForm.vue +303 -0
- package/src/components/BaseInput.vue +15 -1
- package/src/index.ts +14 -0
- package/src/lang/en.json +7 -0
- package/src/lang/fr.json +7 -0
- package/src/types/Country.ts +4 -0
- package/src/types/Region.ts +5 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<BaseField
|
|
3
|
+
:label="$t('sui.address')"
|
|
4
|
+
:name="`${namePrefix}address_1`"
|
|
5
|
+
class="mb-2"
|
|
6
|
+
required
|
|
7
|
+
>
|
|
8
|
+
<BaseInput
|
|
9
|
+
ref="address1Ref"
|
|
10
|
+
:model-value="normalizedModelValue.address_1 ?? ''"
|
|
11
|
+
:placeholder="$t('sui.address_1_placeholder')"
|
|
12
|
+
class="w-full"
|
|
13
|
+
prevent-submit
|
|
14
|
+
:autocomplete="false"
|
|
15
|
+
:required="false"
|
|
16
|
+
@update:model-value="update('address_1', $event)"
|
|
17
|
+
/>
|
|
18
|
+
</BaseField>
|
|
19
|
+
|
|
20
|
+
<BaseField :name="`${namePrefix}address_2`" class="mb-4">
|
|
21
|
+
<BaseInput
|
|
22
|
+
:model-value="normalizedModelValue.address_2 ?? ''"
|
|
23
|
+
:placeholder="$t('sui.address_2_description')"
|
|
24
|
+
class="w-full"
|
|
25
|
+
@update:model-value="update('address_2', $event)"
|
|
26
|
+
/>
|
|
27
|
+
</BaseField>
|
|
28
|
+
|
|
29
|
+
<div class="sm:flex sm:space-x-3">
|
|
30
|
+
<BaseField
|
|
31
|
+
:label="$t('sui.city')"
|
|
32
|
+
required
|
|
33
|
+
:name="`${namePrefix}city`"
|
|
34
|
+
class="mb-4 flex-1"
|
|
35
|
+
>
|
|
36
|
+
<BaseInput
|
|
37
|
+
:model-value="normalizedModelValue.city ?? ''"
|
|
38
|
+
class="w-full"
|
|
39
|
+
@update:model-value="update('city', $event)"
|
|
40
|
+
/>
|
|
41
|
+
</BaseField>
|
|
42
|
+
<BaseField
|
|
43
|
+
:label="$t('sui.postal_code_zip_code')"
|
|
44
|
+
required
|
|
45
|
+
:name="`${namePrefix}postal_code`"
|
|
46
|
+
class="mb-4 flex-1"
|
|
47
|
+
>
|
|
48
|
+
<BaseInput
|
|
49
|
+
:model-value="normalizedModelValue.postal_code ?? ''"
|
|
50
|
+
class="w-full"
|
|
51
|
+
@update:model-value="update('postal_code', $event)"
|
|
52
|
+
/>
|
|
53
|
+
</BaseField>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="sm:flex sm:space-x-3">
|
|
56
|
+
<BaseField
|
|
57
|
+
:label="$t('sui.country')"
|
|
58
|
+
:name="`${namePrefix}country`"
|
|
59
|
+
required
|
|
60
|
+
class="mb-4 flex-1"
|
|
61
|
+
>
|
|
62
|
+
<BaseSelect
|
|
63
|
+
:model-value="normalizedModelValue.country ?? ''"
|
|
64
|
+
class="w-full"
|
|
65
|
+
@update:model-value="update('country', $event)"
|
|
66
|
+
>
|
|
67
|
+
<option
|
|
68
|
+
v-for="country in countries"
|
|
69
|
+
:key="country.id"
|
|
70
|
+
:value="country.id"
|
|
71
|
+
>
|
|
72
|
+
{{ country.name }}
|
|
73
|
+
</option>
|
|
74
|
+
</BaseSelect>
|
|
75
|
+
</BaseField>
|
|
76
|
+
<BaseField
|
|
77
|
+
:label="$t('sui.region')"
|
|
78
|
+
:name="`${namePrefix}country`"
|
|
79
|
+
required
|
|
80
|
+
class="mb-4 flex-1"
|
|
81
|
+
>
|
|
82
|
+
<BaseSelect
|
|
83
|
+
:model-value="normalizedModelValue.region ?? ''"
|
|
84
|
+
:label="$t('sui.region')"
|
|
85
|
+
:name="`${namePrefix}region`"
|
|
86
|
+
class="w-full"
|
|
87
|
+
required
|
|
88
|
+
@update:model-value="update('region', $event)"
|
|
89
|
+
>
|
|
90
|
+
<option v-for="region in regions" :key="region.id" :value="region.id">
|
|
91
|
+
{{ region.name }}
|
|
92
|
+
</option>
|
|
93
|
+
</BaseSelect>
|
|
94
|
+
</BaseField>
|
|
95
|
+
</div>
|
|
96
|
+
</template>
|
|
97
|
+
|
|
98
|
+
<script lang="ts" setup>
|
|
99
|
+
import { ComputedRef } from 'vue';
|
|
100
|
+
import { cloneDeep, isArray } from 'lodash';
|
|
101
|
+
import { Country } from '@/types/Country';
|
|
102
|
+
import { Region } from '@/types/Region';
|
|
103
|
+
import BaseField from './BaseField.vue';
|
|
104
|
+
import BaseInput from './BaseInput.vue';
|
|
105
|
+
import BaseSelect from './BaseSelect.vue';
|
|
106
|
+
import { config } from '..';
|
|
107
|
+
|
|
108
|
+
const props = withDefaults(
|
|
109
|
+
defineProps<{
|
|
110
|
+
modelValue: Record<string, string | number | null | undefined>;
|
|
111
|
+
prefix: string | null;
|
|
112
|
+
countries?: Country[];
|
|
113
|
+
regions?: Region[];
|
|
114
|
+
}>(),
|
|
115
|
+
{
|
|
116
|
+
modelValue() {
|
|
117
|
+
return {};
|
|
118
|
+
},
|
|
119
|
+
prefix: null,
|
|
120
|
+
countries() {
|
|
121
|
+
return [];
|
|
122
|
+
},
|
|
123
|
+
regions() {
|
|
124
|
+
return [];
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const emit = defineEmits(['update:model-value']);
|
|
130
|
+
|
|
131
|
+
const normalizedModelValue = computed(
|
|
132
|
+
(): Record<string, string | number | null | undefined> => {
|
|
133
|
+
const form = cloneDeep(props.modelValue ?? {});
|
|
134
|
+
form.address_1 = form.address_1 ?? '';
|
|
135
|
+
form.address_2 = form.address_2 ?? '';
|
|
136
|
+
form.city = form.city ?? '';
|
|
137
|
+
form.postal_code = form.postal_code ?? '';
|
|
138
|
+
form.country = form.country ?? '';
|
|
139
|
+
form.region = form.region ?? '';
|
|
140
|
+
return form;
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const countries = computed((): Country[] => {
|
|
145
|
+
if (props.countries && isArray(props.countries) && props.countries.length) {
|
|
146
|
+
return props.countries;
|
|
147
|
+
}
|
|
148
|
+
return config.countries;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const allRegions = computed((): Region[] => {
|
|
152
|
+
if (props.regions && isArray(props.regions) && props.regions.length) {
|
|
153
|
+
return props.regions;
|
|
154
|
+
}
|
|
155
|
+
return config.regions;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const regions = computed((): Country[] => {
|
|
159
|
+
return allRegions.value.filter(
|
|
160
|
+
(r) => r.country_id == normalizedModelValue.value.country
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const namePrefix = computed((): string => {
|
|
165
|
+
if (props.prefix) {
|
|
166
|
+
return props.prefix + '.';
|
|
167
|
+
}
|
|
168
|
+
return '';
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
function update(field: string, value: string) {
|
|
172
|
+
const newForm = cloneDeep(normalizedModelValue.value);
|
|
173
|
+
newForm[field] = value;
|
|
174
|
+
emit('update:model-value', newForm);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Autocomplete
|
|
178
|
+
|
|
179
|
+
const address1Ref = ref<InstanceType<typeof BaseInput> | null>(null);
|
|
180
|
+
const address1Input = computed(
|
|
181
|
+
() => address1Ref.value?.$refs.input ?? null
|
|
182
|
+
) as ComputedRef<HTMLInputElement | null>;
|
|
183
|
+
|
|
184
|
+
// eslint-disable-next-line no-undef
|
|
185
|
+
let autocomplete = null as google.maps.places.Autocomplete | null;
|
|
186
|
+
|
|
187
|
+
onMounted(() => {
|
|
188
|
+
if (!window.google) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!address1Input.value) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
autocomplete = new window.google.maps.places.Autocomplete(
|
|
197
|
+
address1Input.value,
|
|
198
|
+
{
|
|
199
|
+
fields: ['address_components'],
|
|
200
|
+
types: ['address'],
|
|
201
|
+
componentRestrictions: { country: 'ca' },
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
autocomplete.addListener('place_changed', fillAddress);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
function fillAddress() {
|
|
209
|
+
if (!autocomplete) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Get the place details from the autocomplete object.
|
|
214
|
+
const place = autocomplete.getPlace();
|
|
215
|
+
let address1 = '';
|
|
216
|
+
let postcode = '';
|
|
217
|
+
|
|
218
|
+
const newForm = cloneDeep(props.modelValue);
|
|
219
|
+
|
|
220
|
+
if (!place.address_components) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Get each component of the address from the place details,
|
|
225
|
+
// and then fill-in the corresponding field on the form.
|
|
226
|
+
// place.address_components are google.maps.GeocoderAddressComponent objects
|
|
227
|
+
// which are documented at http://goo.gle/3l5i5Mr
|
|
228
|
+
// eslint-disable-next-line no-undef
|
|
229
|
+
for (const component of place.address_components as google.maps.GeocoderAddressComponent[]) {
|
|
230
|
+
const componentType = component.types[0];
|
|
231
|
+
switch (componentType) {
|
|
232
|
+
case 'street_number': {
|
|
233
|
+
address1 = `${component.long_name} ${address1}`;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case 'route': {
|
|
237
|
+
address1 += component.long_name;
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
case 'postal_code': {
|
|
241
|
+
postcode = `${component.long_name}${postcode}`;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case 'postal_code_suffix': {
|
|
245
|
+
postcode = `${postcode}-${component.long_name}`;
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case 'locality':
|
|
249
|
+
newForm.city = component.long_name;
|
|
250
|
+
break;
|
|
251
|
+
case 'administrative_area_level_1': {
|
|
252
|
+
newForm.region = component.short_name.toLowerCase();
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
case 'country':
|
|
256
|
+
newForm.country = component.short_name.toLowerCase();
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
nextTick(() => {
|
|
262
|
+
newForm.address_1 = address1;
|
|
263
|
+
|
|
264
|
+
// Force value change
|
|
265
|
+
if (address1Input.value) {
|
|
266
|
+
//address1Input.value.value = address1;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
newForm.postal_code = postcode;
|
|
270
|
+
|
|
271
|
+
emit('update:model-value', newForm);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
</script>
|
|
275
|
+
|
|
276
|
+
<style lang="postcss">
|
|
277
|
+
.pac-container {
|
|
278
|
+
@apply rounded-lg border border-gray-200 font-sans shadow-md;
|
|
279
|
+
|
|
280
|
+
& .pac-item {
|
|
281
|
+
@apply flex cursor-pointer items-center py-2 pl-2;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
& .pac-icon {
|
|
285
|
+
@apply m-0 mr-2;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
& .pac-item,
|
|
289
|
+
& .pac-item-query,
|
|
290
|
+
& .pac-matched {
|
|
291
|
+
@apply text-base;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
& .pac-matched {
|
|
295
|
+
@apply font-semibold;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
&:after {
|
|
299
|
+
background-image: none !important;
|
|
300
|
+
@apply h-0 p-0;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
</style>
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
@update:model-value="emitUpdate"
|
|
40
40
|
/>
|
|
41
41
|
<input
|
|
42
|
-
v-else
|
|
42
|
+
v-else-if="maskOptions"
|
|
43
43
|
ref="input"
|
|
44
44
|
v-maska:[maskOptions]
|
|
45
45
|
v-bind="bindings"
|
|
@@ -53,6 +53,20 @@
|
|
|
53
53
|
}"
|
|
54
54
|
@input="update"
|
|
55
55
|
/>
|
|
56
|
+
<input
|
|
57
|
+
v-else
|
|
58
|
+
ref="input"
|
|
59
|
+
v-bind="bindings"
|
|
60
|
+
:value="modelValue"
|
|
61
|
+
:type="type"
|
|
62
|
+
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
63
|
+
:class="{
|
|
64
|
+
'rounded-l': emptyLeft,
|
|
65
|
+
'rounded-r': emptyRight,
|
|
66
|
+
'w-full border-none bg-white outline-none focus:z-[1] focus:ring-2 focus:ring-primary-600 focus:ring-offset-1 disabled:cursor-not-allowed disabled:text-slate-300': true,
|
|
67
|
+
}"
|
|
68
|
+
@input="update"
|
|
69
|
+
/>
|
|
56
70
|
<div
|
|
57
71
|
v-if="suffix"
|
|
58
72
|
class="flex shrink-0 items-center justify-center border-l px-4 transition-colors"
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,8 @@ const messages = { en, fr };
|
|
|
15
15
|
|
|
16
16
|
import './assets/main.css';
|
|
17
17
|
import { Locales } from './types';
|
|
18
|
+
import { Country } from './types/Country';
|
|
19
|
+
import { Region } from './types/Region';
|
|
18
20
|
|
|
19
21
|
export interface Options {
|
|
20
22
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
@@ -24,6 +26,8 @@ export interface Options {
|
|
|
24
26
|
locales?: Locales;
|
|
25
27
|
formatQueryString?: (params: Record<string, any>) => string;
|
|
26
28
|
parseQueryString?: (params: string) => Record<string, any>;
|
|
29
|
+
countries?: Country[];
|
|
30
|
+
regions?: Region[];
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
const config = {
|
|
@@ -47,6 +51,8 @@ const config = {
|
|
|
47
51
|
parseQueryString(params: string): Record<string, any> {
|
|
48
52
|
return QueryString.parse(params);
|
|
49
53
|
},
|
|
54
|
+
countries: [] as Country[],
|
|
55
|
+
regions: [] as Region[],
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
function install(app: App, options?: Options) {
|
|
@@ -78,6 +84,14 @@ function install(app: App, options?: Options) {
|
|
|
78
84
|
if (options?.parseQueryString) {
|
|
79
85
|
config.parseQueryString = options.parseQueryString;
|
|
80
86
|
}
|
|
87
|
+
|
|
88
|
+
if (options?.countries) {
|
|
89
|
+
config.countries = options.countries;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (options?.regions) {
|
|
93
|
+
config.regions = options.regions;
|
|
94
|
+
}
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
export default { install };
|
package/src/lang/en.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sui": {
|
|
3
|
+
"address": "Address",
|
|
4
|
+
"address_1_placeholder": "Postal address",
|
|
5
|
+
"address_2_description": "Apartment, suite, unit, building",
|
|
3
6
|
"and": "and",
|
|
4
7
|
"apply_filters": "Apply filters",
|
|
5
8
|
"autocomplete_placeholder": "Type to start your search",
|
|
6
9
|
"cancel": "Cancel",
|
|
10
|
+
"city": "City",
|
|
7
11
|
"clear": "Clear",
|
|
8
12
|
"click_or_select_date": "Click or select date",
|
|
9
13
|
"click_to_copy": "Click to copy",
|
|
10
14
|
"columns": "Columns",
|
|
11
15
|
"confirm": "Confirm",
|
|
12
16
|
"copied": "Copied",
|
|
17
|
+
"country": "Country",
|
|
13
18
|
"create_new": "Create new",
|
|
14
19
|
"day": "Day",
|
|
15
20
|
"delete_record": "Delete the record",
|
|
@@ -34,9 +39,11 @@
|
|
|
34
39
|
"or": "or",
|
|
35
40
|
"page": "Page",
|
|
36
41
|
"pagination_detail": "{page} records of {total}",
|
|
42
|
+
"postal_code_zip_code": "Postal Code / Zip Code",
|
|
37
43
|
"previous": "Previous",
|
|
38
44
|
"previous_month": "Previous month",
|
|
39
45
|
"read_more": "Read more",
|
|
46
|
+
"region": "State / Province",
|
|
40
47
|
"remove": "Remove",
|
|
41
48
|
"remove_file": "Remove file?",
|
|
42
49
|
"remove_file_description": "Are you sure you want to remove the file? This action is irreversible.",
|
package/src/lang/fr.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sui": {
|
|
3
|
+
"address": "Adresse",
|
|
4
|
+
"address_1_placeholder": "Adresse postale",
|
|
5
|
+
"address_2_description": "Appartement, suite, unité, immeuble",
|
|
3
6
|
"and": "et",
|
|
4
7
|
"apply_filters": "Appliquer les filtres",
|
|
5
8
|
"autocomplete_placeholder": "Tapez pour lancer votre recherche",
|
|
6
9
|
"cancel": "Annuler",
|
|
10
|
+
"city": "Ville",
|
|
7
11
|
"clear": "Effacer",
|
|
8
12
|
"click_or_select_date": "Cliquez ou sélectionnez la date",
|
|
9
13
|
"click_to_copy": "Cliquez pour copier",
|
|
10
14
|
"columns": "Colonnes",
|
|
11
15
|
"confirm": "Confirmer",
|
|
12
16
|
"copied": "Copié",
|
|
17
|
+
"country": "Pays",
|
|
13
18
|
"create_new": "Créer un nouveau",
|
|
14
19
|
"day": "Jour",
|
|
15
20
|
"delete_record": "Supprimer l'item",
|
|
@@ -34,9 +39,11 @@
|
|
|
34
39
|
"or": "ou",
|
|
35
40
|
"page": "Page",
|
|
36
41
|
"pagination_detail": "{page} items de {total}",
|
|
42
|
+
"postal_code_zip_code": "Code postal",
|
|
37
43
|
"previous": "Précédent",
|
|
38
44
|
"previous_month": "Mois précédent",
|
|
39
45
|
"read_more": "Lire la suite",
|
|
46
|
+
"region": "État / Province",
|
|
40
47
|
"remove": "Retirer",
|
|
41
48
|
"remove_file": "Retirer le fichier?",
|
|
42
49
|
"remove_file_description": "Voulez-vous vraiment supprimer le fichier ? \nCette action est irréversible.",
|