@falcondev-oss/nuxt-layers-base 0.22.0 → 0.23.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.
@@ -9,7 +9,7 @@ const form = useForm({
9
9
  schema: z.object({
10
10
  duration: z.number().meta({ title: 'Duration' }),
11
11
  dateIso: z.string().meta({ title: 'Datum' }),
12
- text: z.string().max(10).meta({ title: 'Text' }).optional(),
12
+ text: z.string().max(10).meta({ title: 'Text' }),
13
13
  }),
14
14
  sourceValues: () => ({
15
15
  dateIso: null,
@@ -69,86 +69,85 @@ const columns = useTableColumns<typeof data>(
69
69
  </script>
70
70
 
71
71
  <template>
72
- <LayoutDashboard
73
- :sidebar="{
74
- items: [
75
- {
76
- label: 'Home',
77
- icon: 'i-lucide-house',
78
- active: true,
79
- },
80
- {
81
- label: 'Inbox',
82
- icon: 'i-lucide-inbox',
83
- badge: '4',
84
- },
85
- {
86
- label: 'Contacts',
87
- icon: 'i-lucide-users',
88
- },
89
- {
90
- label: 'Settings',
91
- icon: 'i-lucide-settings',
92
- defaultOpen: true,
93
- children: [
94
- {
95
- label: 'General',
96
- },
97
- {
98
- label: 'Members',
99
- },
100
- {
101
- label: 'Notifications',
102
- },
103
- ],
104
- },
105
- ],
106
- bottomItems: [
107
- {
108
- label: 'Home',
109
- icon: 'i-lucide-house',
110
- active: true,
111
- },
112
- {
113
- label: 'Inbox',
114
- icon: 'i-lucide-inbox',
115
- badge: '4',
116
- },
117
- {
118
- label: 'Contacts',
119
- icon: 'i-lucide-users',
120
- },
121
- {
122
- label: 'Settings',
123
- icon: 'i-lucide-settings',
124
- defaultOpen: true,
125
- children: [
126
- {
127
- label: 'General',
128
- },
129
- {
130
- label: 'Members',
131
- },
132
- {
133
- label: 'Notifications',
134
- },
135
- ],
136
- },
137
- ],
138
- userMenu: {
139
- name: 'Benjamin Canac',
140
- avatarSrc: 'https://github.com/benjamincanac.png',
72
+ <LayoutSidebar
73
+ :items="[
74
+ {
75
+ label: 'Home',
76
+ icon: 'i-lucide-house',
77
+ active: true,
78
+ },
79
+ {
80
+ label: 'Inbox',
81
+ icon: 'i-lucide-inbox',
82
+ badge: '4',
83
+ },
84
+ {
85
+ label: 'Contacts',
86
+ icon: 'i-lucide-users',
87
+ },
88
+ {
89
+ label: 'Settings',
90
+ icon: 'i-lucide-settings',
91
+ defaultOpen: true,
92
+ children: [
93
+ {
94
+ label: 'General',
95
+ },
96
+ {
97
+ label: 'Members',
98
+ },
99
+ {
100
+ label: 'Notifications',
101
+ },
102
+ ],
103
+ },
104
+ ]"
105
+ :bottom-items="[
106
+ {
107
+ label: 'Home',
108
+ icon: 'i-lucide-house',
109
+ active: true,
110
+ },
111
+ {
112
+ label: 'Inbox',
113
+ icon: 'i-lucide-inbox',
114
+ badge: '4',
115
+ },
116
+ {
117
+ label: 'Contacts',
118
+ icon: 'i-lucide-users',
119
+ },
120
+ {
121
+ label: 'Settings',
122
+ icon: 'i-lucide-settings',
123
+ defaultOpen: true,
124
+ children: [
125
+ {
126
+ label: 'General',
127
+ },
128
+ {
129
+ label: 'Members',
130
+ },
131
+ {
132
+ label: 'Notifications',
133
+ },
134
+ ],
141
135
  },
136
+ ]"
137
+ :user-menu="{
138
+ name: 'Benjamin Canac',
139
+ avatarSrc: 'https://github.com/benjamincanac.png',
142
140
  }"
143
- :panel="{
144
- navbar: {
141
+ >
142
+ <LayoutNavbar
143
+ :navbar="{
145
144
  title: 'Dashboard',
146
145
  ui: {
147
146
  root: 'relative',
148
147
  title: 'flex-1 absolute inset-0 w-full',
149
148
  },
150
- },
151
- toolbar: {
149
+ }"
150
+ :toolbar="{
152
151
  items: [
153
152
  {
154
153
  label: 'General',
@@ -179,90 +178,90 @@ const columns = useTableColumns<typeof data>(
179
178
  icon: 'i-lucide-bell',
180
179
  },
181
180
  ],
182
- },
183
- }"
184
- >
185
- <template #navbar-title>
186
- <div class="w-full text-center">title</div>
187
- </template>
188
-
189
- <UTableCard>
190
- <UTable :data :columns @select="() => {}" />
191
- </UTableCard>
192
- <UCard
193
- :ui="{
194
- body: 'flex flex-col gap-4 items-start',
195
- }"
196
- >
197
- <UButton
198
- label="Confirm"
199
- variant="subtle"
200
- @click="
201
- () => {
202
- confirm.confirmDestructive({
203
- title: 'Are you sure?',
204
- description: 'This action cannot be undone.',
205
- submitLabel: 'Yes, delete it',
206
- })
207
- }
208
- "
209
- />
210
- <UButton
211
- label="Actions"
212
- variant="subtle"
213
- @click="
214
- () => {
215
- overlay.create(LazyOverlayModalActions, {
216
- defaultOpen: true,
217
- props: {
218
- title: 'Actions',
219
- description: 'Choose an action to perform',
220
- actions: [
221
- {
222
- label: 'Action 1',
223
- },
224
- {
225
- label: 'Action 2',
226
- },
227
- ],
228
- },
229
- })
230
- }
231
- "
232
- />
233
- </UCard>
234
- <UCard
235
- class="max-w-sm"
236
- :ui="{
237
- body: 'flex flex-col gap-4 items-start ',
238
181
  }"
239
182
  >
240
- <UForm
241
- :form
242
- :success-toast="{
243
- title: 'test',
244
- description: 'wow',
183
+ <template #navbar-title>
184
+ <div class="w-full text-center">title</div>
185
+ </template>
186
+
187
+ <UTableCard>
188
+ <UTable :data :columns @select="() => {}" />
189
+ </UTableCard>
190
+ <UCard
191
+ :ui="{
192
+ body: 'flex flex-col gap-4 items-start',
245
193
  }"
246
- class="flex flex-col gap-4"
247
194
  >
248
- {{ form.data }}
249
- <UField v-slot="{ props }" :field="form.fields.text.$use()">
250
- <UInput class="w-full" v-bind="props" />
251
- </UField>
252
- <UField
253
- v-slot="{ props }"
254
- :field="
255
- form.fields.dateIso.$use({
256
- translate: dateValueIsoTranslator(),
257
- })
195
+ <UButton
196
+ label="Confirm"
197
+ variant="subtle"
198
+ @click="
199
+ () => {
200
+ confirm.confirmDestructive({
201
+ title: 'Are you sure?',
202
+ description: 'This action cannot be undone.',
203
+ submitLabel: 'Yes, delete it',
204
+ })
205
+ }
258
206
  "
207
+ />
208
+ <UButton
209
+ label="Actions"
210
+ variant="subtle"
211
+ @click="
212
+ () => {
213
+ overlay.create(LazyOverlayModalActions, {
214
+ defaultOpen: true,
215
+ props: {
216
+ title: 'Actions',
217
+ description: 'Choose an action to perform',
218
+ actions: [
219
+ {
220
+ label: 'Action 1',
221
+ },
222
+ {
223
+ label: 'Action 2',
224
+ },
225
+ ],
226
+ },
227
+ })
228
+ }
229
+ "
230
+ />
231
+ </UCard>
232
+ <UCard
233
+ class="max-w-sm"
234
+ :ui="{
235
+ body: 'flex flex-col gap-4 items-start ',
236
+ }"
237
+ >
238
+ <UForm
239
+ :form
240
+ :success-toast="{
241
+ title: 'test',
242
+ description: 'wow',
243
+ }"
244
+ class="flex flex-col gap-4"
259
245
  >
260
- <UInputDatePicker class="w-full" v-bind="props" />
261
- </UField>
262
- <UField v-slot="{ props }" :field="form.fields.duration.$use()">
263
- <UInputDurationMinutes class="w-full" v-bind="props" />
264
- </UField>
265
- </UForm>
266
- </UCard>
267
- </LayoutDashboard>
246
+ {{ form.data }}
247
+ <UField v-slot="{ props }" :field="form.fields.text.$use()">
248
+ <UInput class="w-full" v-bind="props" />
249
+ </UField>
250
+ <UField
251
+ v-slot="{ props }"
252
+ :field="
253
+ form.fields.dateIso.$use({
254
+ translate: dateValueIsoTranslator(),
255
+ })
256
+ "
257
+ >
258
+ <UInputDatePicker class="w-full" v-bind="props" />
259
+ </UField>
260
+ <UField v-slot="{ props }" :field="form.fields.duration.$use()">
261
+ <UInputDurationMinutes class="w-full" v-bind="props" />
262
+ </UField>
263
+ </UForm>
264
+ </UCard>
265
+ </LayoutNavbar>
266
+ </LayoutSidebar>
268
267
  </template>
@@ -1,19 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import { de } from '@nuxt/ui/locale'
3
3
  import { Settings } from 'luxon'
4
- import { authRedirect } from './middleware/auth.global'
5
- import { channel } from './utils/channel'
6
4
 
7
5
  Settings.throwOnInvalid = true
8
6
  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
7
  </script>
18
8
 
19
9
  <template>
@@ -6,5 +6,15 @@ export default defineNuxtConfig({
6
6
  projectId: 'my-project',
7
7
  },
8
8
  },
9
+ typescript: {
10
+ tsConfig: {
11
+ vueCompilerOptions: {
12
+ strictTemplates: true,
13
+ strictVModel: false,
14
+ htmlAttributes: ['aria-*'],
15
+ dataAttributes: ['data-*'],
16
+ },
17
+ },
18
+ },
9
19
  css: ['~/assets/test.css'],
10
20
  })
@@ -1,31 +1,27 @@
1
- <script setup lang="ts" generic="T">
1
+ <script setup lang="ts" generic="T, const Nullable extends boolean = false">
2
2
  import type { FormField } from '@falcondev-oss/form-core'
3
3
  import type { FormFieldProps, FormFieldSlots } from '@nuxt/ui'
4
- import type { ModelModifiers } from '@nuxt/ui/runtime/types/input.js'
5
4
  import { useForwardProps } from 'reka-ui'
6
5
  import * as R from 'remeda'
7
6
 
8
- type FieldSlotProps<T> = {
7
+ type InputSlotProps<T, Nullable extends boolean> = {
9
8
  'modelValue': T
10
9
  'onUpdate:modelValue': (value: T) => void
11
10
  'onBlur': () => void
12
11
  'disabled': boolean
13
12
  'loading': boolean
14
- 'modelModifiers'?: Pick<ModelModifiers, 'nullable'>
13
+ 'modelModifiers': true extends Nullable ? { nullable: true } : never
15
14
  'placeholder'?: string
16
15
  }
17
16
 
18
17
  const props = defineProps<
19
18
  FormFieldProps & {
20
19
  field: FormField<T>
21
- }
20
+ } & { nullable?: Nullable }
22
21
  >()
23
22
  const slots = defineSlots<
24
23
  {
25
- default: (slot: {
26
- props: Omit<FieldSlotProps<T>, 'modelModifiers'>
27
- field: FormField<T>
28
- }) => any
24
+ default: (slot: { props: InputSlotProps<T, Nullable>; field: FormField<T> }) => any
29
25
  } & Omit<FormFieldSlots, 'default'>
30
26
  >()
31
27
 
@@ -67,11 +63,11 @@ const inputProps = computed(() => {
67
63
  'onBlur': () => field.handleBlur(),
68
64
  'disabled': field.disabled,
69
65
  'loading': field.isPending,
70
- 'modelModifiers': {
71
- nullable: true,
72
- },
66
+ 'modelModifiers': (props.nullable === true
67
+ ? { nullable: true }
68
+ : undefined) as true extends Nullable ? { nullable: true } : never,
73
69
  placeholder,
74
- } satisfies FieldSlotProps<T>
70
+ } satisfies InputSlotProps<T, Nullable>
75
71
  })
76
72
  </script>
77
73
 
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.22.0",
4
+ "version": "0.23.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,11 +14,11 @@
14
14
  "pnpm": "10"
15
15
  },
16
16
  "dependencies": {
17
- "@falcondev-oss/form-core": "^0.21.0",
18
- "@falcondev-oss/form-vue": "^0.21.0",
17
+ "@falcondev-oss/form-core": "^0.21.1",
18
+ "@falcondev-oss/form-vue": "^0.21.1",
19
19
  "@falcondev-oss/trpc-typed-form-data": "^0.4.1",
20
20
  "@falcondev-oss/trpc-vue-query": "^0.5.2",
21
- "@iconify-json/lucide": "^1.2.90",
21
+ "@iconify-json/lucide": "^1.2.94",
22
22
  "@internationalized/date": "^3.11.0",
23
23
  "@nuxt/icon": "^2.2.1",
24
24
  "@nuxt/ui": "4.4.0",
@@ -34,19 +34,19 @@
34
34
  "consola": "^3.4.2",
35
35
  "defu": "^6.1.4",
36
36
  "maska": "^3.2.0",
37
- "reka-ui": "^2.8.0",
37
+ "reka-ui": "^2.8.2",
38
38
  "remeda": "^2.33.6",
39
39
  "superjson": "^2.2.6",
40
- "tailwindcss": "^4.1.18",
40
+ "tailwindcss": "^4.2.1",
41
41
  "trpc-nuxt": "^2.0.1",
42
42
  "type-fest": "^5.4.4",
43
- "vue": "^3.5.28",
43
+ "vue": "^3.5.29",
44
44
  "vue-router": "^4.6.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "nuxt": "^4.3.1",
48
48
  "typescript": "^5.9.3",
49
- "vue-tsc": "^3.2.4",
49
+ "vue-tsc": "^3.2.5",
50
50
  "zod": "^4.3.6"
51
51
  },
52
52
  "scripts": {