@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.
- package/dist/components/AccordionItem.vue.d.ts.map +1 -1
- package/dist/components/DataPreview.vue.d.ts +6 -0
- package/dist/components/DataPreview.vue.d.ts.map +1 -1
- package/dist/components/Flag.vue.d.ts +16 -0
- package/dist/components/Flag.vue.d.ts.map +1 -0
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/TableSchema.vue.d.ts +32 -5
- package/dist/components/TableSchema.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/FileUpload.vue.d.ts +164 -2
- package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts +5 -0
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts +165 -0
- package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/TextInput.vue.d.ts +2 -5
- package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/index.d.ts +1 -0
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
- package/dist/index.cjs +6536 -1549
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +6536 -1549
- package/dist/style.css +1877 -93
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/allCountries.d.ts +11 -0
- package/dist/utils/allCountries.d.ts.map +1 -0
- package/package.json +3 -4
- package/src/components/AccordionItem.vue +8 -5
- package/src/components/DataPreview.vue +14 -4
- package/src/components/Flag.vue +1349 -0
- package/src/components/Modal.vue +26 -9
- package/src/components/ModalForm.vue +1 -1
- package/src/components/PageTitle.vue +8 -1
- package/src/components/TableSchema.vue +50 -6
- package/src/components/form/inputs/FileUpload.vue +28 -11
- package/src/components/form/inputs/SelectInput.vue +29 -14
- package/src/components/form/inputs/TelInput.vue +401 -0
- package/src/components/form/inputs/TextInput.vue +15 -53
- package/src/components/form/inputs/index.ts +1 -0
- package/src/components/index.ts +1 -0
- package/src/components/layout/Tabs.vue +1 -0
- package/src/index.ts +1 -0
- package/src/styles/appearance.css +610 -0
- package/src/styles/buttons.css +8 -0
- package/src/styles/layout.css +46 -1
- package/src/styles/mobilLayout.css +37 -0
- package/src/styles/modal.css +5 -2
- package/src/styles/text.css +39 -0
- package/src/utils/BagelFormUtils.ts +2 -0
- package/src/utils/allCountries.ts +337 -0
- package/src/components/whatsapp/form/MsgTemplate.vue +0 -224
- package/src/components/whatsapp/form/TextVariableExamples.vue +0 -79
- package/src/components/whatsapp/index.ts +0 -2
- 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,
|
|
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
|
|
23
|
+
:disabled
|
|
24
24
|
:required="required"
|
|
25
25
|
:pattern="pattern"
|
|
26
26
|
v-bind="nativeInputAttrs"
|
|
27
|
-
@
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
134
|
-
()
|
|
135
|
-
(
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
204
|
-
|
|
172
|
+
.bagel-input input:disabled {
|
|
173
|
+
background: #f5f5f5;
|
|
174
|
+
|
|
205
175
|
}
|
|
206
176
|
|
|
207
|
-
.
|
|
208
|
-
|
|
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';
|
package/src/components/index.ts
CHANGED
|
@@ -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]);
|