@bagelink/vue 0.0.437 → 0.0.441

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.
Files changed (57) hide show
  1. package/dist/components/AccordionItem.vue.d.ts.map +1 -1
  2. package/dist/components/DataPreview.vue.d.ts +6 -0
  3. package/dist/components/DataPreview.vue.d.ts.map +1 -1
  4. package/dist/components/Flag.vue.d.ts +16 -0
  5. package/dist/components/Flag.vue.d.ts.map +1 -0
  6. package/dist/components/Modal.vue.d.ts.map +1 -1
  7. package/dist/components/TableSchema.vue.d.ts +32 -5
  8. package/dist/components/TableSchema.vue.d.ts.map +1 -1
  9. package/dist/components/form/inputs/FileUpload.vue.d.ts +164 -2
  10. package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
  11. package/dist/components/form/inputs/SelectInput.vue.d.ts +5 -0
  12. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  13. package/dist/components/form/inputs/TelInput.vue.d.ts +165 -0
  14. package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -0
  15. package/dist/components/form/inputs/TextInput.vue.d.ts +2 -5
  16. package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
  17. package/dist/components/form/inputs/index.d.ts +1 -0
  18. package/dist/components/form/inputs/index.d.ts.map +1 -1
  19. package/dist/components/index.d.ts +1 -0
  20. package/dist/components/index.d.ts.map +1 -1
  21. package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
  22. package/dist/index.cjs +6536 -1549
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.mjs +6536 -1549
  26. package/dist/style.css +1877 -93
  27. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  28. package/dist/utils/allCountries.d.ts +11 -0
  29. package/dist/utils/allCountries.d.ts.map +1 -0
  30. package/package.json +3 -4
  31. package/src/components/AccordionItem.vue +8 -5
  32. package/src/components/DataPreview.vue +14 -4
  33. package/src/components/Flag.vue +1349 -0
  34. package/src/components/Modal.vue +26 -9
  35. package/src/components/ModalForm.vue +1 -1
  36. package/src/components/PageTitle.vue +8 -1
  37. package/src/components/TableSchema.vue +50 -6
  38. package/src/components/form/inputs/FileUpload.vue +28 -11
  39. package/src/components/form/inputs/SelectInput.vue +29 -14
  40. package/src/components/form/inputs/TelInput.vue +401 -0
  41. package/src/components/form/inputs/TextInput.vue +15 -53
  42. package/src/components/form/inputs/index.ts +1 -0
  43. package/src/components/index.ts +1 -0
  44. package/src/components/layout/Tabs.vue +1 -0
  45. package/src/index.ts +1 -0
  46. package/src/styles/appearance.css +610 -0
  47. package/src/styles/buttons.css +8 -0
  48. package/src/styles/layout.css +46 -1
  49. package/src/styles/mobilLayout.css +37 -0
  50. package/src/styles/modal.css +5 -2
  51. package/src/styles/text.css +39 -0
  52. package/src/utils/BagelFormUtils.ts +2 -0
  53. package/src/utils/allCountries.ts +337 -0
  54. package/src/components/whatsapp/form/MsgTemplate.vue +0 -224
  55. package/src/components/whatsapp/form/TextVariableExamples.vue +0 -79
  56. package/src/components/whatsapp/index.ts +0 -2
  57. package/src/components/whatsapp/interfaces.ts +0 -58
@@ -0,0 +1,401 @@
1
+ <template>
2
+ <div class="bagel-input" :class="{ disabled: disabled }">
3
+ <label>
4
+ {{ label }}
5
+ <div
6
+ dir="ltr"
7
+ class="flex gap-05 tel-input"
8
+ tabindex="-1"
9
+ aria-label="Country Code Selector"
10
+ aria-haspopup="listbox"
11
+ :aria-expanded="open"
12
+ @keydown.esc="reset"
13
+ @keydown.tab="reset"
14
+ >
15
+ <Dropdown :placement="'bottom'" @hide="open = false">
16
+ <span class="flex gap-05" @click="open = true">
17
+ <Icon :icon="open ? 'collapse_all' : 'expand_all'" />
18
+ <Flag
19
+ v-if="dropdownOptions.showFlags && activeCountryCode"
20
+ :country-code="activeCountryCode?.toLowerCase()"
21
+ />
22
+ </span>
23
+ <template #popper="{ hide }">
24
+ <div class="p-075 tel-countryp-dropdown">
25
+ <TextInput
26
+ v-if="searchable"
27
+ aria-label="Search by country name or country code"
28
+ placeholder="Search"
29
+ icon="search"
30
+ v-model="searchQuery"
31
+ />
32
+ <ul
33
+ ref="listEl"
34
+ class="overflow-y p-0"
35
+ :style="{ 'max-height': '400px' }"
36
+ :class="dropdownOpenDirection"
37
+ role="listbox"
38
+ >
39
+ <li
40
+ v-for="(pb, index) in sortedCountries"
41
+ role="option"
42
+ class="flex gap-075"
43
+ :key="pb.iso2 + isPreferred(pb)"
44
+ tabindex="-1"
45
+ @click="
46
+ () => {
47
+ chooseCountry(pb.iso2);
48
+ hide();
49
+ }
50
+ "
51
+ @mousemove="selectedIndex = index"
52
+ :aria-selected="activeCountryCode === pb.iso2 && !isPreferred(pb)"
53
+ >
54
+ <Flag v-if="dropdownOptions.showFlags" :country-code="pb.iso2.toLowerCase()" />
55
+ <p class="tel-country">{{ pb.name }}</p>
56
+ <span v-if="dropdownOptions.showDialCodeInList"> +{{ pb.dialCode }} </span>
57
+ </li>
58
+ </ul>
59
+ </div>
60
+ </template>
61
+ </Dropdown>
62
+ <input
63
+ :required="required"
64
+ :placeholder="placeholder"
65
+ :disabled="disabled"
66
+ v-model="phone"
67
+ type="tel"
68
+ ref="refInput"
69
+ :autocomplete="autocomplete"
70
+ :class="['vti__input']"
71
+ :id="id"
72
+ :maxlength="inputOptions.maxlength"
73
+ :name="inputOptions.name"
74
+ :readonly="inputOptions.readonly"
75
+ :tabindex="inputOptions.tabindex"
76
+ :aria-describedby="inputOptions['aria-describedby']"
77
+ @blur="onBlur"
78
+ @focus="onFocus"
79
+ @keyup.enter="onEnter"
80
+ @keyup.space="onSpace"
81
+ >
82
+ </div>
83
+ </label>
84
+ </div>
85
+ </template>
86
+
87
+ <script lang="ts" setup>
88
+ import {
89
+ Icon, Dropdown, TextInput, Flag,
90
+ allCountries, type Country,
91
+ } from '@bagelink/vue';
92
+ import { onMounted, watch } from 'vue';
93
+ import { parsePhoneNumberFromString, type CountryCode, type PhoneNumber } from 'libphonenumber-js';
94
+ import axios from 'axios';
95
+
96
+ async function getIp() {
97
+ const apiData = sessionStorage?.getItem('ipapi');
98
+ if (apiData) return JSON.parse(apiData);
99
+ const { data } = await axios.get('https://ipapi.co/json/');
100
+ sessionStorage.setItem('ipapi', JSON.stringify(data));
101
+ return data;
102
+ }
103
+
104
+ type DropdownOptions = {
105
+ disabled?: boolean;
106
+ showFlags?: boolean;
107
+ showDialCodeInSelection?: boolean;
108
+ showDialCodeInList?: boolean;
109
+ };
110
+
111
+ type InputOptions = {
112
+ autofocus?: boolean;
113
+ 'aria-describedby'?: string;
114
+ maxlength?: number;
115
+ name?: string;
116
+ placeholder?: string;
117
+ readonly?: boolean;
118
+ tabindex?: number;
119
+ showDialCode?: boolean;
120
+ };
121
+
122
+ type Props = {
123
+ label?: string;
124
+ id?: string;
125
+ autocomplete?: 'on' | 'off';
126
+ placeholder?: string;
127
+ required?: boolean;
128
+ modelValue: string;
129
+ allCountries?: Country[];
130
+ autoFormat?: boolean;
131
+ customValidate?: boolean | RegExp;
132
+ defaultCountry?: string | number;
133
+ disabled?: boolean;
134
+ searchable?: boolean;
135
+ autoDefaultCountry?: boolean;
136
+ dropdownOptions?: DropdownOptions;
137
+ excludeCountries?: string[];
138
+ inputOptions?: InputOptions;
139
+ invalidMsg?: string;
140
+ mode?: 'auto' | 'international' | 'national';
141
+ onlyCountries?: string[];
142
+ preferredCountries?: string[];
143
+ };
144
+
145
+ const props = withDefaults(defineProps<Props>(), {
146
+ modelValue: '',
147
+ autocomplete: 'on',
148
+ allCountries: () => allCountries,
149
+ autoFormat: true,
150
+ customValidate: false,
151
+ defaultCountry: '',
152
+ placeholder: 'Enter a phone number',
153
+ searchable: true,
154
+ dropdownOptions: () => ({
155
+ disabled: false,
156
+ showFlags: true,
157
+ showDialCodeInSelection: true,
158
+ showDialCodeInList: true,
159
+ searchable: true,
160
+ }),
161
+ disabled: false,
162
+ autoDefaultCountry: true,
163
+ excludeCountries: () => [],
164
+ inputOptions: () => ({
165
+ showDialCode: true,
166
+ autofocus: false,
167
+ 'aria-describedby': '',
168
+ id: '',
169
+ maxlength: 25,
170
+ name: '',
171
+ readonly: false,
172
+ tabindex: 0,
173
+ }),
174
+ required: false,
175
+ invalidMsg: 'Invalid phone number',
176
+ mode: 'auto',
177
+ onlyCountries: () => [],
178
+ preferredCountries: () => [],
179
+ });
180
+
181
+ let activeCountryCode = $ref<CountryCode>();
182
+ let open = $ref(false);
183
+ let selectedIndex = $ref<number>();
184
+ const dropdownOpenDirection = $ref('below');
185
+ const searchQuery = $ref('');
186
+
187
+ const refInput = $ref<HTMLInputElement | null>(null);
188
+
189
+ const emit = defineEmits([
190
+ 'update:modelValue',
191
+ 'change',
192
+ 'input',
193
+ 'blur',
194
+ 'focus',
195
+ 'country-changed',
196
+ 'enter',
197
+ 'space',
198
+ ]);
199
+
200
+ function formatPhone(val: string) {
201
+ let result: PhoneNumber | undefined;
202
+ if (val?.[0] === '+') result = parsePhoneNumberFromString(val);
203
+ else result = parsePhoneNumberFromString(val, activeCountryCode);
204
+ const valid = result?.isValid?.();
205
+ refInput?.setCustomValidity?.(valid ? '' : props.invalidMsg);
206
+ const formatted = valid ? result?.format?.(parsedMode.toUpperCase() as any) : val;
207
+ return formatted;
208
+ }
209
+
210
+ const cleanStr = (str?: string) => {
211
+ const phoneNumber = (str?.match(/[()\-+0-9\s]*/g) || []).join('');
212
+ return phoneNumber.trim();
213
+ };
214
+
215
+ let phone = $computed<string>({
216
+ get: () => props.modelValue,
217
+ set: (value) => {
218
+ const clean = cleanStr(value);
219
+ const formatted = formatPhone(clean) || '';
220
+ emit('update:modelValue', formatted);
221
+ },
222
+ });
223
+
224
+ // Computed: activeCountry
225
+ const activeCountry = $computed(() => props.allCountries.find((country) => country.iso2 === activeCountryCode?.toUpperCase()));
226
+
227
+ const isPreferred = (country?: Country) => props.preferredCountries.includes(country?.iso2 as string);
228
+
229
+ // Computed: parsedMode
230
+ const parsedMode = $computed(() => {
231
+ if (props.mode === 'auto') {
232
+ if (!phone || phone[0] !== '+') return 'national';
233
+ return 'international';
234
+ }
235
+ return props.mode || 'international';
236
+ });
237
+
238
+ const filteredCountries = $computed(() => {
239
+ if (props.onlyCountries.length) {
240
+ return props.allCountries.filter(({ iso2 }) => props.onlyCountries.some((c) => c.toUpperCase() === iso2));
241
+ }
242
+ if (props.excludeCountries.length) {
243
+ return props.allCountries.filter(
244
+ ({ iso2 }) => !props.excludeCountries.includes(iso2.toUpperCase()) &&
245
+ !props.excludeCountries.includes(iso2.toLowerCase()),
246
+ );
247
+ }
248
+ return props.allCountries;
249
+ });
250
+
251
+ const sortedCountries = $computed(() => {
252
+ const preferredCountries = getCountries(props.preferredCountries);
253
+
254
+ const countriesList = [...preferredCountries, ...filteredCountries];
255
+ const cleanInput = searchQuery.replace(/[~`!@#$%^&*()+={}\[\];:'"<>.,\/\\\?-_]/g, '');
256
+ return countriesList
257
+ .filter(
258
+ (c) => new RegExp(cleanInput, 'i').test(c?.name || '') ||
259
+ new RegExp(cleanInput, 'i').test(c?.iso2 || '') ||
260
+ new RegExp(cleanInput, 'i').test(c?.dialCode || ''),
261
+ )
262
+ .filter(Boolean);
263
+ });
264
+
265
+ // Watchers
266
+ watch(
267
+ () => activeCountry,
268
+ (value, oldValue) => {
269
+ if (!value && oldValue?.iso2) {
270
+ activeCountryCode = oldValue.iso2;
271
+ return;
272
+ }
273
+ if (value?.iso2) emit('country-changed', value);
274
+ },
275
+ );
276
+
277
+ const initializeCountry = async () => {
278
+ // if (phone?.[0] === '+') return;
279
+ // 2. Use default country if passed from parent
280
+ if (props.defaultCountry) {
281
+ if (typeof props.defaultCountry === 'string') {
282
+ chooseCountry(props.defaultCountry);
283
+ return;
284
+ }
285
+ if (typeof props.defaultCountry === 'number') {
286
+ const country = findCountryByDialCode(props.defaultCountry);
287
+ if (country) {
288
+ chooseCountry(country.iso2);
289
+ return;
290
+ }
291
+ }
292
+ }
293
+
294
+ const fallbackCountry = sortedCountries[0];
295
+
296
+ if (props.autoDefaultCountry) {
297
+ try {
298
+ const res = (await getIp()).country;
299
+ chooseCountry(res || activeCountryCode);
300
+ } catch (error) {
301
+ console.warn(error);
302
+ chooseCountry(fallbackCountry?.iso2);
303
+ }
304
+ } else {
305
+ // 4. Use the first country from preferred list (if available) or all countries list
306
+ chooseCountry(fallbackCountry?.iso2);
307
+ }
308
+ };
309
+
310
+ onMounted(initializeCountry);
311
+
312
+ const findCountry = (iso: string) => filteredCountries.find((country) => country.iso2 === iso?.toUpperCase());
313
+
314
+ const getCountries = (list: string[]): Country[] => {
315
+ const countryList: Country[] = [];
316
+ list.forEach((countryCode) => {
317
+ const country = findCountry(countryCode);
318
+ if (country) countryList.push(country);
319
+ });
320
+ return countryList;
321
+ };
322
+
323
+ const findCountryByDialCode = (dialCode: number) => filteredCountries.find((country) => Number(country.dialCode) === dialCode);
324
+
325
+ const chooseCountry = (country?: string) => {
326
+ if (!country) return;
327
+ const parsedCountry = findCountry(country);
328
+ if (!parsedCountry) return;
329
+ activeCountryCode = parsedCountry.iso2;
330
+
331
+ if (props.inputOptions?.showDialCode && parsedCountry) {
332
+ phone = `+${parsedCountry.dialCode}`;
333
+ activeCountryCode = parsedCountry.iso2 || '';
334
+ return;
335
+ }
336
+
337
+ activeCountryCode = parsedCountry.iso2 || '';
338
+ // emitInput(phone);
339
+ };
340
+
341
+ const onBlur = () => emit('blur');
342
+
343
+ const onFocus = () => emit('focus');
344
+
345
+ const onEnter = () => emit('enter');
346
+
347
+ const onSpace = () => emit('space');
348
+
349
+ // const focus = () => refInput?.focus();
350
+
351
+ // Method: reset
352
+ const reset = () => {
353
+ selectedIndex = sortedCountries.findIndex((c) => c.iso2 === activeCountryCode);
354
+ open = false;
355
+ };
356
+ </script>
357
+
358
+ <style scoped>
359
+ .tel-input {
360
+ direction: ltr;
361
+ text-align: left;
362
+ background: var(--input-bg);
363
+ border: none;
364
+ padding-inline-start: 0.7rem;
365
+ border-radius: var(--input-border-radius);
366
+ color: var(--input-color);
367
+ min-width: calc(var(--input-height) * 3);
368
+ width: 100%;
369
+ }
370
+
371
+ .tel-input:focus-within {
372
+ outline: none;
373
+ box-shadow: inset 0 0 10px #00000012;
374
+ }
375
+ .tel-input input {
376
+ background: transparent;
377
+ }
378
+ .tel-input input::placeholder {
379
+ color: transparent;
380
+ }
381
+ .tel-input input:focus-visible {
382
+ box-shadow: none;
383
+ }
384
+ .input_country-code {
385
+ font-size: var(--input-font-size);
386
+ color: var(--input-color);
387
+ }
388
+ .tel-country {
389
+ font-size: var(--input-font-size);
390
+ max-width: 200px;
391
+ white-space: nowrap;
392
+ text-overflow: ellipsis;
393
+ overflow: hidden;
394
+ margin-top: 0;
395
+ margin-bottom: 0;
396
+ }
397
+ .tel-countryp-dropdown {
398
+ direction: ltr;
399
+ text-align: left;
400
+ }
401
+ </style>
@@ -2,7 +2,7 @@
2
2
  <div
3
3
  class="bagel-input text-input"
4
4
  :class="{
5
- dense, small, shrink, toggleEdit, editMode, code,
5
+ dense, small, shrink, code,
6
6
  textInputIconWrap: icon,
7
7
  txtInputIconStart: iconStart,
8
8
  }"
@@ -20,11 +20,11 @@
20
20
  :rows="1"
21
21
  ref="input"
22
22
  :placeholder="placeholder || label"
23
- :disabled="!editMode"
23
+ :disabled
24
24
  :required="required"
25
25
  :pattern="pattern"
26
26
  v-bind="nativeInputAttrs"
27
- @dblclick="toggleEditAction"
27
+ @input="updateInputVal"
28
28
  >
29
29
  <textarea
30
30
  v-else
@@ -35,11 +35,10 @@
35
35
  :rows="rows"
36
36
  ref="input"
37
37
  :placeholder="placeholder || label"
38
- :disabled="!editMode"
38
+ :disabled
39
39
  :required="required"
40
40
  :pattern="pattern"
41
41
  v-bind="nativeInputAttrs"
42
- @dblclick="toggleEditAction"
43
42
  />
44
43
  <p v-if="helptext">{{ helptext }}</p>
45
44
  </label>
@@ -53,14 +52,6 @@
53
52
  v-if="icon"
54
53
  :icon="icon"
55
54
  />
56
- <Btn
57
- class="toggleEditBtn"
58
- v-if="toggleEdit"
59
- thin
60
- @click="toggleEditAction"
61
- :icon="editMode ? 'check' : 'edit'"
62
- flat
63
- />
64
55
  </div>
65
56
  </template>
66
57
 
@@ -87,7 +78,7 @@ const props = withDefaults(
87
78
  required?: boolean;
88
79
  pattern?: string;
89
80
  shrink?: boolean;
90
- toggleEdit?: boolean;
81
+ disabled?: boolean;
91
82
  type?: string;
92
83
  nativeInputAttrs?: Record<string, any>;
93
84
  icon?: MaterialIcons;
@@ -102,27 +93,13 @@ const props = withDefaults(
102
93
  }>(),
103
94
  {
104
95
  type: 'text',
105
- toggleEdit: false,
106
96
  modelValue: '',
107
97
  },
108
98
  );
109
99
  let inputVal = $ref<string | number>();
110
- let editMode = $ref<boolean>(!props.toggleEdit);
111
100
 
112
101
  const input = $ref<HTMLInputElement>();
113
102
 
114
- const toggleEditAction = () => {
115
- if (!props.toggleEdit) return;
116
- if (editMode) {
117
- editMode = false;
118
- emit('debounce', inputVal);
119
- emit('update:modelValue', inputVal as string);
120
- } else {
121
- editMode = true;
122
- setTimeout(() => input?.focus(), 10);
123
- }
124
- };
125
-
126
103
  const rows = $computed(() => {
127
104
  if (props.lines) return props.lines;
128
105
  if (props.autoheight) return `${inputVal}`?.split('\n').length || 1;
@@ -130,15 +107,11 @@ const rows = $computed(() => {
130
107
  return 1;
131
108
  });
132
109
 
133
- watch(
134
- () => inputVal,
135
- (newVal) => {
136
- if (props.toggleEdit) return;
137
- if (newVal === props.modelValue) return;
138
- emit('update:modelValue', newVal as string);
139
- debounce(() => emit('debounce', newVal));
140
- },
141
- );
110
+ function updateInputVal() {
111
+ if (props.disabled) return;
112
+ emit('update:modelValue', inputVal as string);
113
+ debounce(() => emit('debounce', inputVal), 300);
114
+ }
142
115
 
143
116
  watch(
144
117
  () => props.modelValue,
@@ -185,10 +158,6 @@ onMounted(() => {
185
158
  opacity: 0.3;
186
159
  }
187
160
 
188
- .bagel-input.toggleEdit:hover {
189
- background-color: var(--input-bg);
190
- }
191
-
192
161
  .bagel-input.small {
193
162
  margin-bottom: 0;
194
163
  height: 30px;
@@ -200,15 +169,13 @@ onMounted(() => {
200
169
  gap: 0.5rem;
201
170
  }
202
171
 
203
- .bagel-input label {
204
- font-size: var(--label-font-size);
172
+ .bagel-input input:disabled {
173
+ background: #f5f5f5;
174
+
205
175
  }
206
176
 
207
- .toggleEditBtn {
208
- position: absolute;
209
- right: -24px;
210
- top: 4;
211
- opacity: 0;
177
+ .bagel-input label {
178
+ font-size: var(--label-font-size);
212
179
  }
213
180
 
214
181
  .textInputIconWrap {
@@ -235,11 +202,6 @@ onMounted(() => {
235
202
  padding-inline-start: 2rem;
236
203
  }
237
204
 
238
- .bagel-input:hover .toggleEditBtn,
239
- .bagel-input.editMode .toggleEditBtn {
240
- opacity: 1;
241
- }
242
-
243
205
  .bagel-input.small textarea {
244
206
  height: 30px;
245
207
  }
@@ -11,4 +11,5 @@ export { default as RadioPillsInput } from './RadioPillsInput.vue';
11
11
  export { default as FileUpload } from './FileUpload.vue';
12
12
  export { default as ToggleInput } from './ToggleInput.vue';
13
13
  export { default as RichText } from './RichText.vue';
14
+ export { default as TelInput } from './TelInput.vue';
14
15
  export { Dropdown } from 'floating-vue';
@@ -21,6 +21,7 @@ export { default as Badge } from './Badge.vue';
21
21
  export { default as BglVideo } from './BglVideo.vue';
22
22
  export { default as Carousel } from './Carousel.vue';
23
23
  export { default as ModalConfirm } from './ModalConfirm.vue';
24
+ export { default as Flag } from './Flag.vue';
24
25
 
25
26
  export * from './form';
26
27
  export * from './dashboard';
@@ -39,6 +39,7 @@ const tabComponent = defineComponent({
39
39
  const currentTabIndex = props.tabs.findIndex(
40
40
  (tab) => tabValue(tab) === currentTab.value,
41
41
  );
42
+ if (currentTabIndex === -1) return null;
42
43
  const slotChildren = slots?.default?.()?.[1]?.children;
43
44
 
44
45
  return h('div', (slotChildren as VNode[])[currentTabIndex]);
package/src/index.ts CHANGED
@@ -5,4 +5,5 @@ export { ModalPlugin, useModal } from './plugins/modal';
5
5
  export * from './utils';
6
6
  export * from './types';
7
7
  export * from './components';
8
+ export * from './utils/allCountries';
8
9
  import './styles/bagel.css';