@falcondev-oss/nuxt-layers-base 0.21.0 → 0.22.0
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/.playground/app/pages/index.vue +13 -6
- package/.playground/app.vue +25 -0
- package/app/components/u/UField.vue +81 -20
- package/package.json +3 -3
|
@@ -7,12 +7,14 @@ const overlay = useOverlay()
|
|
|
7
7
|
|
|
8
8
|
const form = useForm({
|
|
9
9
|
schema: z.object({
|
|
10
|
-
duration: z.number(),
|
|
11
|
-
dateIso: z.string(),
|
|
10
|
+
duration: z.number().meta({ title: 'Duration' }),
|
|
11
|
+
dateIso: z.string().meta({ title: 'Datum' }),
|
|
12
|
+
text: z.string().max(10).meta({ title: 'Text' }).optional(),
|
|
12
13
|
}),
|
|
13
14
|
sourceValues: () => ({
|
|
14
15
|
dateIso: null,
|
|
15
16
|
duration: null,
|
|
17
|
+
text: '',
|
|
16
18
|
}),
|
|
17
19
|
async submit({ values }) {
|
|
18
20
|
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
@@ -230,6 +232,7 @@ const columns = useTableColumns<typeof data>(
|
|
|
230
232
|
/>
|
|
231
233
|
</UCard>
|
|
232
234
|
<UCard
|
|
235
|
+
class="max-w-sm"
|
|
233
236
|
:ui="{
|
|
234
237
|
body: 'flex flex-col gap-4 items-start ',
|
|
235
238
|
}"
|
|
@@ -240,20 +243,24 @@ const columns = useTableColumns<typeof data>(
|
|
|
240
243
|
title: 'test',
|
|
241
244
|
description: 'wow',
|
|
242
245
|
}"
|
|
246
|
+
class="flex flex-col gap-4"
|
|
243
247
|
>
|
|
244
248
|
{{ form.data }}
|
|
249
|
+
<UField v-slot="{ props }" :field="form.fields.text.$use()">
|
|
250
|
+
<UInput class="w-full" v-bind="props" />
|
|
251
|
+
</UField>
|
|
245
252
|
<UField
|
|
246
|
-
v-slot="props"
|
|
253
|
+
v-slot="{ props }"
|
|
247
254
|
:field="
|
|
248
255
|
form.fields.dateIso.$use({
|
|
249
256
|
translate: dateValueIsoTranslator(),
|
|
250
257
|
})
|
|
251
258
|
"
|
|
252
259
|
>
|
|
253
|
-
<UInputDatePicker v-bind="props" />
|
|
260
|
+
<UInputDatePicker class="w-full" v-bind="props" />
|
|
254
261
|
</UField>
|
|
255
|
-
<UField v-slot="props" :field="form.fields.duration.$use()">
|
|
256
|
-
<UInputDurationMinutes v-bind="props" />
|
|
262
|
+
<UField v-slot="{ props }" :field="form.fields.duration.$use()">
|
|
263
|
+
<UInputDurationMinutes class="w-full" v-bind="props" />
|
|
257
264
|
</UField>
|
|
258
265
|
</UForm>
|
|
259
266
|
</UCard>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { de } from '@nuxt/ui/locale'
|
|
3
|
+
import { Settings } from 'luxon'
|
|
4
|
+
import { authRedirect } from './middleware/auth.global'
|
|
5
|
+
import { channel } from './utils/channel'
|
|
6
|
+
|
|
7
|
+
Settings.throwOnInvalid = true
|
|
8
|
+
Settings.defaultLocale = 'de'
|
|
9
|
+
|
|
10
|
+
// redirect when auth status changes through broadcast channel
|
|
11
|
+
const route = useRoute()
|
|
12
|
+
useEventListener<MessageEvent>(channel, 'message', (event) => {
|
|
13
|
+
if (event.data.type === 'auth') {
|
|
14
|
+
authRedirect(route)
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<UCustomApp
|
|
21
|
+
:app="{
|
|
22
|
+
locale: de,
|
|
23
|
+
}"
|
|
24
|
+
/>
|
|
25
|
+
</template>
|
|
@@ -3,7 +3,7 @@ import type { FormField } from '@falcondev-oss/form-core'
|
|
|
3
3
|
import type { FormFieldProps, FormFieldSlots } from '@nuxt/ui'
|
|
4
4
|
import type { ModelModifiers } from '@nuxt/ui/runtime/types/input.js'
|
|
5
5
|
import { useForwardProps } from 'reka-ui'
|
|
6
|
-
import
|
|
6
|
+
import * as R from 'remeda'
|
|
7
7
|
|
|
8
8
|
type FieldSlotProps<T> = {
|
|
9
9
|
'modelValue': T
|
|
@@ -12,6 +12,7 @@ type FieldSlotProps<T> = {
|
|
|
12
12
|
'disabled': boolean
|
|
13
13
|
'loading': boolean
|
|
14
14
|
'modelModifiers'?: Pick<ModelModifiers, 'nullable'>
|
|
15
|
+
'placeholder'?: string
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const props = defineProps<
|
|
@@ -21,46 +22,106 @@ const props = defineProps<
|
|
|
21
22
|
>()
|
|
22
23
|
const slots = defineSlots<
|
|
23
24
|
{
|
|
24
|
-
default: (
|
|
25
|
+
default: (slot: {
|
|
26
|
+
props: Omit<FieldSlotProps<T>, 'modelModifiers'>
|
|
27
|
+
field: FormField<T>
|
|
28
|
+
}) => any
|
|
25
29
|
} & Omit<FormFieldSlots, 'default'>
|
|
26
30
|
>()
|
|
27
31
|
|
|
28
32
|
const forwardedProps = useForwardProps(props)
|
|
29
33
|
|
|
30
|
-
const
|
|
34
|
+
const isOverMaxLength = computed(() => {
|
|
35
|
+
const field = forwardedProps.value.field
|
|
36
|
+
|
|
37
|
+
return field.schema.maxLength === undefined || field.value == null
|
|
38
|
+
? false
|
|
39
|
+
: (field.value as string | number)?.toString().length > field.schema.maxLength
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const formFieldProps = computed<FormFieldProps>(() => {
|
|
31
43
|
const { field, ...rest } = forwardedProps.value
|
|
32
|
-
|
|
44
|
+
|
|
45
|
+
const hint =
|
|
46
|
+
field.schema.maxLength === undefined
|
|
47
|
+
? undefined
|
|
48
|
+
: `${(field.value as string | number | null)?.toString().length ?? 0}/${field.schema.maxLength}`
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
required: field.schema.required,
|
|
52
|
+
label: field.schema.title,
|
|
53
|
+
description: field.schema.description,
|
|
54
|
+
hint,
|
|
55
|
+
...R.omitBy(rest, (v) => v === undefined),
|
|
56
|
+
}
|
|
33
57
|
})
|
|
34
58
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
const inputProps = computed(() => {
|
|
60
|
+
const field = forwardedProps.value.field
|
|
61
|
+
|
|
62
|
+
const placeholder = field.errors && field.errors.join('\n')
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
'modelValue': field.value,
|
|
66
|
+
'onUpdate:modelValue': (value) => field.handleChange(value),
|
|
67
|
+
'onBlur': () => field.handleBlur(),
|
|
68
|
+
'disabled': field.disabled,
|
|
69
|
+
'loading': field.isPending,
|
|
70
|
+
'modelModifiers': {
|
|
71
|
+
nullable: true,
|
|
72
|
+
},
|
|
73
|
+
placeholder,
|
|
74
|
+
} satisfies FieldSlotProps<T>
|
|
75
|
+
})
|
|
48
76
|
</script>
|
|
49
77
|
|
|
50
78
|
<template>
|
|
51
79
|
<UFormField
|
|
52
80
|
v-bind="formFieldProps"
|
|
53
|
-
:
|
|
81
|
+
:ui="{
|
|
82
|
+
hint: isOverMaxLength ? 'text-error' : '',
|
|
83
|
+
}"
|
|
84
|
+
:error="!!field.errors"
|
|
54
85
|
>
|
|
55
|
-
<
|
|
86
|
+
<template #hint="{ hint }">
|
|
87
|
+
<span class="flex items-center gap-1.5">
|
|
88
|
+
<UPopover
|
|
89
|
+
v-if="!!field.errors"
|
|
90
|
+
mode="hover"
|
|
91
|
+
:delay-duration="0"
|
|
92
|
+
:ui="{
|
|
93
|
+
content: 'bg-error-50 ring-error-200! rounded py-1 px-2',
|
|
94
|
+
}"
|
|
95
|
+
>
|
|
96
|
+
<UIcon name="lucide:circle-alert" class="text-error" />
|
|
97
|
+
<template #content>
|
|
98
|
+
<p class="text-(--ui-color-neutral-800) max-w-sm whitespace-normal text-xs">
|
|
99
|
+
{{ field.errors.join('\n') }}
|
|
100
|
+
</p>
|
|
101
|
+
</template>
|
|
102
|
+
</UPopover>
|
|
103
|
+
|
|
104
|
+
{{ hint }}
|
|
105
|
+
</span>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<slot v-bind="{ props: inputProps, field: forwardedProps.field }">
|
|
56
109
|
<DevOnly>
|
|
57
110
|
<p class="font-black text-red-500">UField missing slot</p>
|
|
58
111
|
</DevOnly>
|
|
59
112
|
</slot>
|
|
60
113
|
|
|
61
|
-
<template v-for="(_, name) in omit(slots, ['default'])" #[name]="slotData">
|
|
114
|
+
<template v-for="(_, name) in R.omit(slots, ['default'])" #[name]="slotData">
|
|
62
115
|
<!-- @vue-ignore -->
|
|
63
116
|
<slot :name="name" v-bind="slotData || {}" />
|
|
64
117
|
</template>
|
|
65
118
|
</UFormField>
|
|
66
119
|
</template>
|
|
120
|
+
|
|
121
|
+
<style scoped>
|
|
122
|
+
:deep([aria-invalid='true']) {
|
|
123
|
+
&::placeholder {
|
|
124
|
+
color: var(--ui-color-error-400);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@falcondev-oss/nuxt-layers-base",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.22.0",
|
|
5
5
|
"description": "Nuxt layer with lots of useful helpers and @nuxt/ui components",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "github:falcondev-oss/nuxt-layers",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"pnpm": "10"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@falcondev-oss/form-core": "^0.
|
|
18
|
-
"@falcondev-oss/form-vue": "^0.
|
|
17
|
+
"@falcondev-oss/form-core": "^0.21.0",
|
|
18
|
+
"@falcondev-oss/form-vue": "^0.21.0",
|
|
19
19
|
"@falcondev-oss/trpc-typed-form-data": "^0.4.1",
|
|
20
20
|
"@falcondev-oss/trpc-vue-query": "^0.5.2",
|
|
21
21
|
"@iconify-json/lucide": "^1.2.90",
|