@fy-/fws-vue 2.1.45 → 2.1.47
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.
|
@@ -3,11 +3,10 @@ import type { ErrorObject } from '@vuelidate/core'
|
|
|
3
3
|
import { computed, ref, toRef } from 'vue'
|
|
4
4
|
import { useTranslation } from '../../composables/translations'
|
|
5
5
|
import DefaultTagInput from './DefaultTagInput.vue'
|
|
6
|
-
// import VueTailwindDatepicker from "vue-tailwind-datepicker";
|
|
7
6
|
|
|
8
7
|
type modelValueType = string | number | string[] | number[] | undefined
|
|
9
|
-
|
|
10
8
|
type checkboxValueType = any[] | Set<any> | undefined | boolean
|
|
9
|
+
|
|
11
10
|
const props = withDefaults(
|
|
12
11
|
defineProps<{
|
|
13
12
|
id: string
|
|
@@ -52,29 +51,19 @@ const props = withDefaults(
|
|
|
52
51
|
dpOptions: () => ({}),
|
|
53
52
|
},
|
|
54
53
|
)
|
|
55
|
-
/* function disableDatesAdult(date: Date) {
|
|
56
|
-
if (!props.disableDatesUnder18) return false
|
|
57
|
-
const today = new Date()
|
|
58
|
-
const date18YearsAgo = new Date(
|
|
59
|
-
today.getFullYear() - 18,
|
|
60
|
-
today.getMonth(),
|
|
61
|
-
today.getDate(),
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
return date >= date18YearsAgo
|
|
65
|
-
} */
|
|
66
54
|
|
|
67
55
|
const translate = useTranslation()
|
|
68
56
|
const inputRef = ref<HTMLInputElement>()
|
|
57
|
+
|
|
69
58
|
const errorProps = toRef(props, 'error')
|
|
70
59
|
const errorVuelidateProps = toRef(props, 'errorVuelidate')
|
|
60
|
+
|
|
71
61
|
const checkErrors = computed(() => {
|
|
72
62
|
if (errorProps.value) return errorProps.value
|
|
73
63
|
if (errorVuelidateProps.value && errorVuelidateProps.value.length > 0) {
|
|
74
|
-
const
|
|
75
|
-
return translate(
|
|
64
|
+
const errKey = `vuelidate_validator_${errorVuelidateProps.value[0].$validator.toString()}`
|
|
65
|
+
return translate(errKey)
|
|
76
66
|
}
|
|
77
|
-
|
|
78
67
|
return null
|
|
79
68
|
})
|
|
80
69
|
|
|
@@ -85,39 +74,43 @@ function blur() {
|
|
|
85
74
|
if (inputRef.value) inputRef.value.blur()
|
|
86
75
|
}
|
|
87
76
|
function getInputRef() {
|
|
88
|
-
|
|
77
|
+
return inputRef.value
|
|
89
78
|
}
|
|
79
|
+
|
|
90
80
|
const emit = defineEmits([
|
|
91
81
|
'update:modelValue',
|
|
92
82
|
'update:checkboxValue',
|
|
93
83
|
'focus',
|
|
94
84
|
'blur',
|
|
95
85
|
])
|
|
86
|
+
|
|
96
87
|
function handleFocus() {
|
|
97
88
|
emit('focus', props.id)
|
|
98
89
|
}
|
|
99
|
-
|
|
100
90
|
function handleBlur() {
|
|
101
91
|
emit('blur', props.id)
|
|
102
92
|
}
|
|
103
93
|
|
|
104
|
-
const model = computed({
|
|
94
|
+
const model = computed<modelValueType>({
|
|
105
95
|
get: () => props.modelValue,
|
|
106
|
-
set: (
|
|
107
|
-
emit('update:modelValue',
|
|
96
|
+
set: (value) => {
|
|
97
|
+
emit('update:modelValue', value)
|
|
108
98
|
},
|
|
109
99
|
})
|
|
110
|
-
|
|
100
|
+
|
|
101
|
+
const modelCheckbox = computed<checkboxValueType>({
|
|
111
102
|
get: () => props.checkboxValue,
|
|
112
|
-
set: (
|
|
113
|
-
emit('update:checkboxValue',
|
|
103
|
+
set: (value) => {
|
|
104
|
+
emit('update:checkboxValue', value)
|
|
114
105
|
},
|
|
115
106
|
})
|
|
107
|
+
|
|
116
108
|
defineExpose({ focus, blur, getInputRef })
|
|
117
109
|
</script>
|
|
118
110
|
|
|
119
111
|
<template>
|
|
120
112
|
<div>
|
|
113
|
+
<!-- TEXT, PASSWORD, EMAIL, SEARCH, DATE, DATETIME, URL, TEXTAREA, SELECT, PHONE, TEL, RANGE, CHIPS, TAGS, MASK, DATEPICKER -->
|
|
121
114
|
<template
|
|
122
115
|
v-if="
|
|
123
116
|
[
|
|
@@ -142,6 +135,7 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
142
135
|
"
|
|
143
136
|
>
|
|
144
137
|
<div class="flex flex-col gap-2">
|
|
138
|
+
<!-- Basic input types -->
|
|
145
139
|
<div
|
|
146
140
|
v-if="
|
|
147
141
|
[
|
|
@@ -162,12 +156,16 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
162
156
|
class="relative"
|
|
163
157
|
>
|
|
164
158
|
<label
|
|
165
|
-
v-if="label"
|
|
159
|
+
v-if="showLabel && label"
|
|
166
160
|
:for="id"
|
|
167
161
|
class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
|
|
168
|
-
>
|
|
169
|
-
|
|
162
|
+
>
|
|
163
|
+
{{ label }}
|
|
164
|
+
<template v-if="type === 'range'">
|
|
165
|
+
({{ model }})
|
|
166
|
+
</template>
|
|
170
167
|
</label>
|
|
168
|
+
|
|
171
169
|
<input
|
|
172
170
|
:id="id"
|
|
173
171
|
ref="inputRef"
|
|
@@ -176,29 +174,33 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
176
174
|
:name="id"
|
|
177
175
|
:class="{
|
|
178
176
|
'error': checkErrors,
|
|
179
|
-
'bg-fv-neutral-50 border border-fv-neutral-300 text-fv-neutral-900 text-sm rounded-lg focus:ring-fv-primary-500 focus:border-fv-primary-500 block w-full p-2.5
|
|
180
|
-
|
|
181
|
-
'w-full h-2 bg-fv-neutral-200 rounded-lg appearance-none cursor-pointer dark:bg-fv-neutral-700':
|
|
182
|
-
type === 'range',
|
|
177
|
+
'bg-fv-neutral-50 border border-fv-neutral-300 text-fv-neutral-900 text-sm rounded-lg focus:ring-fv-primary-500 focus:border-fv-primary-500 block w-full p-2.5 dark:bg-fv-neutral-700 dark:border-fv-neutral-600 dark:placeholder-fv-neutral-400 dark:text-white dark:focus:ring-fv-primary-500 dark:focus:border-fv-primary-500': type !== 'range',
|
|
178
|
+
'w-full h-2 bg-fv-neutral-200 rounded-lg appearance-none cursor-pointer dark:bg-fv-neutral-700': type === 'range',
|
|
183
179
|
}"
|
|
184
180
|
:autocomplete="autocomplete"
|
|
185
181
|
:min="type === 'range' ? minRange : undefined"
|
|
186
182
|
:max="type === 'range' ? maxRange : undefined"
|
|
187
183
|
:placeholder="placeholder"
|
|
188
184
|
:disabled="disabled"
|
|
189
|
-
:aria-describedby="help ? `${id}-help` :
|
|
185
|
+
:aria-describedby="help ? `${id}-help` : undefined"
|
|
190
186
|
:required="req"
|
|
187
|
+
:aria-invalid="checkErrors ? 'true' : 'false'"
|
|
191
188
|
@focus="handleFocus"
|
|
192
189
|
@blur="handleBlur"
|
|
193
190
|
>
|
|
191
|
+
|
|
192
|
+
<!-- Range Input Extra Labels -->
|
|
194
193
|
<template v-if="type === 'range'">
|
|
195
194
|
<span
|
|
196
195
|
class="text-sm text-gray-500 dark:text-gray-400 absolute start-0 -bottom-6"
|
|
197
|
-
>
|
|
196
|
+
>
|
|
197
|
+
Min ({{ minRange }})
|
|
198
198
|
</span>
|
|
199
199
|
<span
|
|
200
200
|
class="text-sm text-gray-500 dark:text-gray-400 absolute start-1/3 -translate-x-1/2 rtl:translate-x-1/2 -bottom-6"
|
|
201
|
-
>
|
|
201
|
+
>
|
|
202
|
+
{{ ((maxRange - minRange) / 3 + minRange).toFixed(0) }}
|
|
203
|
+
</span>
|
|
202
204
|
<span
|
|
203
205
|
class="text-sm text-gray-500 dark:text-gray-400 absolute start-2/3 -translate-x-1/2 rtl:translate-x-1/2 -bottom-6"
|
|
204
206
|
>
|
|
@@ -206,38 +208,20 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
206
208
|
</span>
|
|
207
209
|
<span
|
|
208
210
|
class="text-sm text-gray-500 dark:text-gray-400 absolute end-0 -bottom-6"
|
|
209
|
-
>
|
|
211
|
+
>
|
|
212
|
+
Max ({{ maxRange }})
|
|
213
|
+
</span>
|
|
210
214
|
</template>
|
|
211
215
|
</div>
|
|
212
|
-
<!--
|
|
213
|
-
<div v-if="type == 'datepicker'">
|
|
214
|
-
<label
|
|
215
|
-
:for="id"
|
|
216
|
-
v-if="label || placeholder"
|
|
217
|
-
class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
|
|
218
|
-
>{{ label ? label : placeholder }}
|
|
219
|
-
</label>
|
|
220
|
-
<div class="relative">
|
|
221
|
-
<VueTailwindDatepicker
|
|
222
|
-
v-model="model"
|
|
223
|
-
:disable-date="disableDatesAdult"
|
|
224
|
-
:formatter="{
|
|
225
|
-
date: 'YYYY-MM-DD',
|
|
226
|
-
month: 'MMM',
|
|
227
|
-
}"
|
|
228
|
-
:placeholder="placeholder"
|
|
229
|
-
as-single
|
|
230
|
-
></VueTailwindDatepicker>
|
|
231
|
-
</div>
|
|
232
|
-
</div>
|
|
233
|
-
-->
|
|
234
216
|
|
|
217
|
+
<!-- CHIPS / TAGS -->
|
|
235
218
|
<div v-if="type === 'chips' || type === 'tags'">
|
|
236
219
|
<label
|
|
237
|
-
v-if="label || placeholder"
|
|
220
|
+
v-if="showLabel && (label || placeholder)"
|
|
238
221
|
:for="id"
|
|
239
222
|
class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
|
|
240
|
-
>
|
|
223
|
+
>
|
|
224
|
+
{{ label ? label : placeholder }}
|
|
241
225
|
</label>
|
|
242
226
|
<!-- @vue-skip -->
|
|
243
227
|
<DefaultTagInput
|
|
@@ -251,12 +235,16 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
251
235
|
:max-lenght-per-tag="maxLengthPerTag"
|
|
252
236
|
/>
|
|
253
237
|
</div>
|
|
238
|
+
|
|
239
|
+
<!-- TEXTAREA (AUTO-GROW) -->
|
|
254
240
|
<div v-else-if="type === 'textarea-grow'" class="group relative">
|
|
255
241
|
<label
|
|
256
|
-
v-if="label"
|
|
242
|
+
v-if="showLabel && label"
|
|
257
243
|
:for="id"
|
|
258
244
|
class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
|
|
259
|
-
>
|
|
245
|
+
>
|
|
246
|
+
{{ label }}
|
|
247
|
+
</label>
|
|
260
248
|
<div class="grow-wrap">
|
|
261
249
|
<!-- @vue-skip -->
|
|
262
250
|
<textarea
|
|
@@ -269,9 +257,13 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
269
257
|
}"
|
|
270
258
|
:placeholder="placeholder"
|
|
271
259
|
:disabled="disabled"
|
|
272
|
-
:aria-describedby="help ? `${id}-help` :
|
|
260
|
+
:aria-describedby="help ? `${id}-help` : undefined"
|
|
273
261
|
:required="req"
|
|
274
|
-
|
|
262
|
+
:aria-invalid="checkErrors ? 'true' : 'false'"
|
|
263
|
+
class="block p-2.5 w-full text-sm text-fv-neutral-900 bg-fv-neutral-50 rounded-lg
|
|
264
|
+
border border-fv-neutral-300 focus:ring-fv-primary-500 focus:border-fv-primary-500
|
|
265
|
+
dark:bg-fv-neutral-700 dark:border-fv-neutral-600 dark:placeholder-fv-neutral-400
|
|
266
|
+
dark:text-white dark:focus:ring-fv-primary-500 dark:focus:border-fv-primary-500"
|
|
275
267
|
@focus="handleFocus"
|
|
276
268
|
@blur="handleBlur"
|
|
277
269
|
/>
|
|
@@ -284,16 +276,19 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
284
276
|
model?.toString().length > dpOptions.counterMax,
|
|
285
277
|
}"
|
|
286
278
|
>
|
|
287
|
-
{{ model?.toString().length }} /
|
|
288
|
-
{{ dpOptions.counterMax }} characters
|
|
279
|
+
{{ model?.toString().length }} / {{ dpOptions.counterMax }} characters
|
|
289
280
|
</div>
|
|
290
281
|
</div>
|
|
282
|
+
|
|
283
|
+
<!-- TEXTAREA (REGULAR) -->
|
|
291
284
|
<div v-else-if="type === 'textarea'" class="group relative">
|
|
292
285
|
<label
|
|
293
|
-
v-if="label"
|
|
286
|
+
v-if="showLabel && label"
|
|
294
287
|
:for="id"
|
|
295
288
|
class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
|
|
296
|
-
>
|
|
289
|
+
>
|
|
290
|
+
{{ label }}
|
|
291
|
+
</label>
|
|
297
292
|
<!-- @vue-skip -->
|
|
298
293
|
<textarea
|
|
299
294
|
:id="id"
|
|
@@ -305,9 +300,14 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
305
300
|
}"
|
|
306
301
|
:placeholder="placeholder"
|
|
307
302
|
:disabled="disabled"
|
|
308
|
-
:aria-describedby="help ? `${id}-help` :
|
|
303
|
+
:aria-describedby="help ? `${id}-help` : undefined"
|
|
309
304
|
:required="req"
|
|
310
|
-
|
|
305
|
+
:aria-invalid="checkErrors ? 'true' : 'false'"
|
|
306
|
+
class="block p-2.5 w-full text-sm text-fv-neutral-900 bg-fv-neutral-50
|
|
307
|
+
rounded-lg border border-fv-neutral-300 focus:ring-fv-primary-500
|
|
308
|
+
focus:border-fv-primary-500 dark:bg-fv-neutral-700 dark:border-fv-neutral-600
|
|
309
|
+
dark:placeholder-fv-neutral-400 dark:text-white dark:focus:ring-fv-primary-500
|
|
310
|
+
dark:focus:border-fv-primary-500"
|
|
311
311
|
@focus="handleFocus"
|
|
312
312
|
@blur="handleBlur"
|
|
313
313
|
/>
|
|
@@ -319,34 +319,42 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
319
319
|
model?.toString().length > dpOptions.counterMax,
|
|
320
320
|
}"
|
|
321
321
|
>
|
|
322
|
-
{{ model?.toString().length }} /
|
|
323
|
-
{{ dpOptions.counterMax }} characters
|
|
322
|
+
{{ model?.toString().length }} / {{ dpOptions.counterMax }} characters
|
|
324
323
|
</div>
|
|
325
324
|
</div>
|
|
325
|
+
|
|
326
|
+
<!-- SELECT -->
|
|
326
327
|
<div v-else-if="type === 'select'" class="relative">
|
|
327
328
|
<label
|
|
328
|
-
v-if="label"
|
|
329
|
+
v-if="showLabel && label"
|
|
329
330
|
:for="id"
|
|
330
331
|
class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
|
|
331
|
-
>
|
|
332
|
+
>
|
|
333
|
+
{{ label }}
|
|
334
|
+
</label>
|
|
332
335
|
<select
|
|
333
336
|
:id="id"
|
|
334
337
|
ref="inputRef"
|
|
335
338
|
v-model="model"
|
|
336
339
|
:name="id"
|
|
337
340
|
:disabled="disabled"
|
|
338
|
-
:aria-describedby="help ? `${id}-help` :
|
|
341
|
+
:aria-describedby="help ? `${id}-help` : undefined"
|
|
339
342
|
:required="req"
|
|
340
343
|
:class="{
|
|
341
344
|
error: checkErrors,
|
|
342
345
|
}"
|
|
343
|
-
|
|
346
|
+
:aria-invalid="checkErrors ? 'true' : 'false'"
|
|
347
|
+
class="bg-fv-neutral-50 border border-fv-neutral-300 text-fv-neutral-900 text-sm
|
|
348
|
+
rounded-lg focus:ring-fv-primary-500 focus:border-fv-primary-500
|
|
349
|
+
block w-full p-2.5 dark:bg-fv-neutral-700 dark:border-fv-neutral-600
|
|
350
|
+
dark:placeholder-fv-neutral-400 dark:text-white dark:focus:ring-fv-primary-500
|
|
351
|
+
dark:focus:border-fv-primary-500"
|
|
344
352
|
@focus="handleFocus"
|
|
345
353
|
@blur="handleBlur"
|
|
346
354
|
>
|
|
347
355
|
<option
|
|
348
356
|
v-for="opt in options"
|
|
349
|
-
:key="opt[0]
|
|
357
|
+
:key="opt[0]?.toString()"
|
|
350
358
|
:value="opt[0]"
|
|
351
359
|
>
|
|
352
360
|
{{ opt[1] }}
|
|
@@ -355,6 +363,8 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
355
363
|
</div>
|
|
356
364
|
</div>
|
|
357
365
|
</template>
|
|
366
|
+
|
|
367
|
+
<!-- TOGGLE (switch) -->
|
|
358
368
|
<template v-else-if="type === 'toggle'">
|
|
359
369
|
<label
|
|
360
370
|
class="inline-flex items-center mb-5 cursor-pointer"
|
|
@@ -369,39 +379,60 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
369
379
|
:false-value="checkboxFalseValue"
|
|
370
380
|
:disabled="disabled"
|
|
371
381
|
class="sr-only peer"
|
|
382
|
+
:aria-invalid="checkErrors ? 'true' : 'false'"
|
|
383
|
+
:aria-describedby="help ? `${id}-help` : undefined"
|
|
384
|
+
:aria-checked="modelCheckbox ? 'true' : 'false'"
|
|
385
|
+
role="switch"
|
|
372
386
|
@focus="handleFocus"
|
|
373
387
|
@blur="handleBlur"
|
|
374
388
|
>
|
|
375
389
|
<div
|
|
376
|
-
class="relative flex-0 flex-shrink-0 w-11 h-6 bg-fv-neutral-200 peer-focus:outline-none
|
|
390
|
+
class="relative flex-0 flex-shrink-0 w-11 h-6 bg-fv-neutral-200 peer-focus:outline-none
|
|
391
|
+
peer-focus:ring-4 peer-focus:ring-fv-primary-300 dark:peer-focus:ring-fv-primary-800
|
|
392
|
+
rounded-full peer dark:bg-fv-neutral-700 peer-checked:after:translate-x-full
|
|
393
|
+
rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white
|
|
394
|
+
after:content-[''] after:absolute after:top-[2px] after:start-[2px]
|
|
395
|
+
after:bg-white after:border-fv-neutral-300 after:border after:rounded-full
|
|
396
|
+
after:w-5 after:h-5 after:transition-all dark:border-fv-neutral-600
|
|
397
|
+
peer-checked:bg-fv-primary-600"
|
|
377
398
|
/>
|
|
378
399
|
<span
|
|
379
400
|
class="ms-3 text-sm font-medium text-fv-neutral-900 dark:text-fv-neutral-300"
|
|
380
401
|
>
|
|
381
402
|
{{ label }}
|
|
382
403
|
<template v-if="help">
|
|
383
|
-
<p
|
|
404
|
+
<p
|
|
405
|
+
:id="help ? `${id}-help` : undefined"
|
|
406
|
+
class="text-fv-neutral-600 dark:text-fv-neutral-400 !text-sm"
|
|
407
|
+
>
|
|
384
408
|
{{ help }}
|
|
385
409
|
</p>
|
|
386
410
|
</template>
|
|
387
411
|
</span>
|
|
388
412
|
</label>
|
|
389
413
|
</template>
|
|
414
|
+
|
|
415
|
+
<!-- CHECKBOX / RADIO -->
|
|
390
416
|
<template v-else-if="type === 'checkbox' || type === 'radio'">
|
|
391
417
|
<div class="flex mb-4">
|
|
392
418
|
<div class="flex items-center h-5">
|
|
393
419
|
<input
|
|
394
420
|
:id="id"
|
|
421
|
+
ref="inputRef"
|
|
395
422
|
v-model="modelCheckbox"
|
|
396
423
|
:class="{
|
|
397
424
|
error: checkErrors,
|
|
398
425
|
}"
|
|
399
|
-
:aria-describedby="help ? `${id}-help` :
|
|
426
|
+
:aria-describedby="help ? `${id}-help` : undefined"
|
|
400
427
|
:type="type"
|
|
401
428
|
:true-value="checkboxTrueValue"
|
|
402
429
|
:false-value="checkboxFalseValue"
|
|
403
430
|
:disabled="disabled"
|
|
404
|
-
|
|
431
|
+
:aria-invalid="checkErrors ? 'true' : 'false'"
|
|
432
|
+
class="w-4 h-4 text-fv-primary-600 bg-fv-neutral-100 border-fv-neutral-300
|
|
433
|
+
rounded focus:ring-fv-primary-500 dark:focus:ring-fv-primary-600
|
|
434
|
+
dark:ring-offset-fv-neutral-800 dark:focus:ring-offset-fv-neutral-800
|
|
435
|
+
focus:ring-2 dark:bg-fv-neutral-700 dark:border-fv-neutral-600"
|
|
405
436
|
@focus="handleFocus"
|
|
406
437
|
@blur="handleBlur"
|
|
407
438
|
>
|
|
@@ -410,7 +441,9 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
410
441
|
<label
|
|
411
442
|
:for="id"
|
|
412
443
|
class="font-medium text-fv-neutral-900 dark:text-fv-neutral-300"
|
|
413
|
-
>
|
|
444
|
+
>
|
|
445
|
+
{{ label }}
|
|
446
|
+
</label>
|
|
414
447
|
<p
|
|
415
448
|
v-if="help"
|
|
416
449
|
:id="`${id}-help`"
|
|
@@ -421,10 +454,18 @@ defineExpose({ focus, blur, getInputRef })
|
|
|
421
454
|
</div>
|
|
422
455
|
</div>
|
|
423
456
|
</template>
|
|
424
|
-
|
|
457
|
+
|
|
458
|
+
<!-- Error message -->
|
|
459
|
+
<p
|
|
460
|
+
v-if="checkErrors"
|
|
461
|
+
class="mt-0.5 text-sm text-red-600 dark:text-red-300"
|
|
462
|
+
role="alert"
|
|
463
|
+
aria-live="assertive"
|
|
464
|
+
>
|
|
425
465
|
{{ checkErrors }}
|
|
426
466
|
</p>
|
|
427
467
|
|
|
468
|
+
<!-- Help text (for other input types) -->
|
|
428
469
|
<p
|
|
429
470
|
v-if="help && !['checkbox', 'radio', 'toggle'].includes(type)"
|
|
430
471
|
:id="`${id}-help`"
|
|
@@ -440,7 +481,7 @@ input,
|
|
|
440
481
|
textarea,
|
|
441
482
|
select {
|
|
442
483
|
&.error {
|
|
443
|
-
@apply border-red-500
|
|
484
|
+
@apply border-red-500 dark:border-red-400;
|
|
444
485
|
}
|
|
445
486
|
}
|
|
446
487
|
</style>
|
|
@@ -75,7 +75,6 @@ function onCall(data: NotifProps) {
|
|
|
75
75
|
if (currentNotif.value && data.time) {
|
|
76
76
|
// update progress based on a 100ms tick
|
|
77
77
|
progress.value += (100 / (data.time / 100))
|
|
78
|
-
// if progress hits or exceeds 100, hide
|
|
79
78
|
if (progress.value >= 100) {
|
|
80
79
|
hideNotif()
|
|
81
80
|
}
|
|
@@ -120,7 +119,7 @@ onUnmounted(() => {
|
|
|
120
119
|
<div
|
|
121
120
|
v-if="currentNotif !== null"
|
|
122
121
|
id="base-notif"
|
|
123
|
-
class="p-2 mb-4 fixed bottom-4 right-8 !z-[2000] bg-fv-neutral-50/[.6] dark:bg-neutral-800/[.6] rounded-lg border"
|
|
122
|
+
class="relative p-2 mb-4 fixed bottom-4 right-8 !z-[2000] bg-fv-neutral-50/[.6] dark:bg-neutral-800/[.6] rounded-lg border overflow-hidden"
|
|
124
123
|
role="alert"
|
|
125
124
|
:class="{
|
|
126
125
|
'text-fv-neutral-800 border-fv-neutral-300 dark:text-fv-neutral-400 dark:border-fv-neutral-600':
|
|
@@ -133,6 +132,14 @@ onUnmounted(() => {
|
|
|
133
132
|
currentNotif.type === 'secret',
|
|
134
133
|
}"
|
|
135
134
|
>
|
|
135
|
+
<!-- PROGRESS BAR AT TOP -->
|
|
136
|
+
<div class="absolute top-0 left-0 w-full h-[4px] bg-gray-200">
|
|
137
|
+
<div
|
|
138
|
+
class="h-full bg-current transition-[width]"
|
|
139
|
+
:style="{ width: `${progress}%` }"
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
136
143
|
<!-- Title + icon or image -->
|
|
137
144
|
<div class="flex items-center gap-2">
|
|
138
145
|
<img
|
|
@@ -156,15 +163,6 @@ onUnmounted(() => {
|
|
|
156
163
|
v-text="currentNotif.content"
|
|
157
164
|
/>
|
|
158
165
|
|
|
159
|
-
<!-- Progress bar (3px) -->
|
|
160
|
-
<div class="relative mt-3 h-[3px] bg-gray-200 rounded-full overflow-hidden">
|
|
161
|
-
<!-- We re-use text color (text-*) as background or define a custom color -->
|
|
162
|
-
<div
|
|
163
|
-
class="absolute left-0 top-0 h-full bg-current transition-[width]"
|
|
164
|
-
:style="{ width: `${progress}%` }"
|
|
165
|
-
/>
|
|
166
|
-
</div>
|
|
167
|
-
|
|
168
166
|
<!-- CTA row (if you need more buttons, just extend it) -->
|
|
169
167
|
<div class="flex justify-end gap-2 pt-3">
|
|
170
168
|
<button
|
|
@@ -350,18 +350,4 @@ function handlePaste(e: ClipboardEvent) {
|
|
|
350
350
|
.input {
|
|
351
351
|
@apply flex-grow min-w-[100px] outline-none border-none break-words;
|
|
352
352
|
}
|
|
353
|
-
|
|
354
|
-
/* Example button classes */
|
|
355
|
-
.btn {
|
|
356
|
-
@apply inline-flex items-center justify-center rounded text-sm px-3 py-1
|
|
357
|
-
border border-transparent font-medium focus:outline-none
|
|
358
|
-
focus-visible:ring-2 focus-visible:ring-offset-2;
|
|
359
|
-
}
|
|
360
|
-
.btn.small {
|
|
361
|
-
@apply text-xs px-2 py-1;
|
|
362
|
-
}
|
|
363
|
-
.btn.neutral {
|
|
364
|
-
@apply bg-fv-neutral-300 hover:bg-fv-neutral-400 text-black
|
|
365
|
-
dark:bg-fv-neutral-600 dark:hover:bg-fv-neutral-500;
|
|
366
|
-
}
|
|
367
353
|
</style>
|