@nuxt/ui 3.0.0-alpha.11 → 3.0.0-alpha.12

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 (112) hide show
  1. package/.nuxt/ui/alert.ts +1 -1
  2. package/.nuxt/ui/avatar.ts +1 -1
  3. package/.nuxt/ui/button.ts +0 -1
  4. package/.nuxt/ui/context-menu.ts +1 -1
  5. package/.nuxt/ui/dropdown-menu.ts +1 -1
  6. package/.nuxt/ui/navigation-menu.ts +79 -11
  7. package/cli/package.json +2 -2
  8. package/cli/templates.mjs +6 -6
  9. package/dist/chunks/component-meta.cjs +2590 -2511
  10. package/dist/chunks/component-meta.mjs +2590 -2511
  11. package/dist/client/devtools/200.html +1 -1
  12. package/dist/client/devtools/404.html +1 -1
  13. package/dist/client/devtools/_nuxt/{CQ-XZFu7.js → CgoQwOTV.js} +26 -23
  14. package/dist/client/devtools/_nuxt/{DNZFyo26.js → DLmPhbaq.js} +1 -1
  15. package/dist/client/devtools/_nuxt/{Dtz-o9GB.js → DYuJNiSW.js} +1 -1
  16. package/dist/client/devtools/_nuxt/builds/latest.json +1 -1
  17. package/dist/client/devtools/_nuxt/builds/meta/3184ffe2-7577-4441-af98-fe6e81c30e3a.json +1 -0
  18. package/dist/client/devtools/_nuxt/entry.ChJczkiN.css +1 -0
  19. package/dist/client/devtools/_nuxt/error-404.DyY3rYaL.css +1 -0
  20. package/dist/client/devtools/_nuxt/error-500.D_1PCaJh.css +1 -0
  21. package/dist/client/devtools/index.html +1 -1
  22. package/dist/module.cjs +1 -1
  23. package/dist/module.json +1 -1
  24. package/dist/module.mjs +1 -1
  25. package/dist/runtime/components/Accordion.vue +2 -2
  26. package/dist/runtime/components/Alert.vue +2 -2
  27. package/dist/runtime/components/Avatar.vue +31 -10
  28. package/dist/runtime/components/AvatarGroup.vue +2 -2
  29. package/dist/runtime/components/Badge.vue +2 -2
  30. package/dist/runtime/components/Breadcrumb.vue +2 -2
  31. package/dist/runtime/components/Button.vue +2 -2
  32. package/dist/runtime/components/ButtonGroup.vue +2 -2
  33. package/dist/runtime/components/Calendar.vue +4 -2
  34. package/dist/runtime/components/Card.vue +2 -2
  35. package/dist/runtime/components/Carousel.vue +2 -2
  36. package/dist/runtime/components/Checkbox.vue +4 -4
  37. package/dist/runtime/components/Chip.vue +2 -2
  38. package/dist/runtime/components/Collapsible.vue +2 -2
  39. package/dist/runtime/components/ColorPicker.vue +46 -15
  40. package/dist/runtime/components/CommandPalette.vue +2 -2
  41. package/dist/runtime/components/Container.vue +2 -2
  42. package/dist/runtime/components/ContextMenu.vue +2 -2
  43. package/dist/runtime/components/ContextMenuContent.vue +1 -1
  44. package/dist/runtime/components/Drawer.vue +2 -2
  45. package/dist/runtime/components/DropdownMenu.vue +2 -2
  46. package/dist/runtime/components/DropdownMenuContent.vue +1 -1
  47. package/dist/runtime/components/Form.vue +46 -17
  48. package/dist/runtime/components/FormField.vue +12 -6
  49. package/dist/runtime/components/Input.vue +5 -4
  50. package/dist/runtime/components/InputMenu.vue +6 -5
  51. package/dist/runtime/components/InputNumber.vue +7 -4
  52. package/dist/runtime/components/Kbd.vue +2 -2
  53. package/dist/runtime/components/Link.vue +2 -2
  54. package/dist/runtime/components/Modal.vue +2 -2
  55. package/dist/runtime/components/NavigationMenu.vue +89 -66
  56. package/dist/runtime/components/Pagination.vue +2 -2
  57. package/dist/runtime/components/PinInput.vue +5 -4
  58. package/dist/runtime/components/Popover.vue +2 -2
  59. package/dist/runtime/components/Progress.vue +2 -2
  60. package/dist/runtime/components/RadioGroup.vue +4 -4
  61. package/dist/runtime/components/Select.vue +9 -7
  62. package/dist/runtime/components/SelectMenu.vue +5 -4
  63. package/dist/runtime/components/Separator.vue +2 -2
  64. package/dist/runtime/components/Skeleton.vue +2 -2
  65. package/dist/runtime/components/Slideover.vue +2 -2
  66. package/dist/runtime/components/Slider.vue +4 -4
  67. package/dist/runtime/components/Stepper.vue +2 -2
  68. package/dist/runtime/components/Switch.vue +4 -4
  69. package/dist/runtime/components/Table.vue +2 -2
  70. package/dist/runtime/components/Tabs.vue +2 -2
  71. package/dist/runtime/components/Textarea.vue +5 -4
  72. package/dist/runtime/components/Toast.vue +2 -2
  73. package/dist/runtime/components/Toaster.vue +2 -2
  74. package/dist/runtime/components/Tooltip.vue +2 -2
  75. package/dist/runtime/composables/useFormField.d.ts +6 -2
  76. package/dist/runtime/composables/useFormField.js +18 -11
  77. package/dist/runtime/composables/useToast.d.ts +1 -1
  78. package/dist/runtime/composables/useToast.js +21 -7
  79. package/dist/runtime/index.css +1 -1
  80. package/dist/runtime/locale/es.js +2 -2
  81. package/dist/runtime/locale/he.js +53 -0
  82. package/dist/runtime/locale/hi.js +54 -0
  83. package/dist/runtime/locale/hu.d.ts +2 -0
  84. package/dist/runtime/locale/hu.js +54 -0
  85. package/dist/runtime/locale/index.d.ts +5 -2
  86. package/dist/runtime/locale/index.js +5 -2
  87. package/dist/runtime/locale/km.d.ts +2 -0
  88. package/dist/runtime/locale/km.js +54 -0
  89. package/dist/runtime/locale/nb_no.d.ts +2 -0
  90. package/dist/runtime/locale/nb_no.js +54 -0
  91. package/dist/runtime/locale/zh_cn.d.ts +2 -0
  92. package/dist/runtime/locale/{zh_hans.js → zh_cn.js} +1 -1
  93. package/dist/runtime/locale/zh_tw.d.ts +2 -0
  94. package/dist/runtime/locale/{zh_hant.js → zh_tw.js} +1 -1
  95. package/dist/runtime/plugins/colors.js +7 -4
  96. package/dist/runtime/types/form.d.ts +21 -12
  97. package/dist/runtime/utils/form.js +3 -5
  98. package/dist/runtime/utils/tv.js +2 -2
  99. package/dist/runtime/vue/components/Link.vue +2 -2
  100. package/dist/shared/{ui.BKsd22-Q.mjs → ui.CENZ17mM.mjs} +72 -16
  101. package/dist/shared/{ui.DCjJwb6l.cjs → ui.ClMXjgLK.cjs} +72 -16
  102. package/dist/unplugin.cjs +1 -1
  103. package/dist/unplugin.mjs +1 -1
  104. package/dist/vite.cjs +1 -1
  105. package/dist/vite.mjs +1 -1
  106. package/package.json +22 -23
  107. package/dist/client/devtools/_nuxt/builds/meta/1f5fbd7b-9d97-480e-9ae4-e02b4ff7018b.json +0 -1
  108. package/dist/client/devtools/_nuxt/entry.qOdop8tq.css +0 -1
  109. package/dist/client/devtools/_nuxt/error-404.D-rS9BDk.css +0 -1
  110. package/dist/client/devtools/_nuxt/error-500.CfcCHs91.css +0 -1
  111. /package/dist/runtime/locale/{zh_hans.d.ts → he.d.ts} +0 -0
  112. /package/dist/runtime/locale/{zh_hant.d.ts → hi.d.ts} +0 -0
@@ -9,16 +9,16 @@ import { tv } from '../utils/tv'
9
9
  import type { AvatarProps, BadgeProps, LinkProps } from '../types'
10
10
  import type { DynamicSlots, MaybeArrayOfArray, MaybeArrayOfArrayItem, PartialString } from '../types/utils'
11
11
 
12
- const appConfig = _appConfig as AppConfig & { ui: { navigationMenu: Partial<typeof theme> } }
12
+ const appConfigNavigationMenu = _appConfig as AppConfig & { ui: { navigationMenu: Partial<typeof theme> } }
13
13
 
14
- const navigationMenu = tv({ extend: tv(theme), ...(appConfig.ui?.navigationMenu || {}) })
14
+ const navigationMenu = tv({ extend: tv(theme), ...(appConfigNavigationMenu.ui?.navigationMenu || {}) })
15
15
 
16
- export interface NavigationMenuChildItem extends Omit<NavigationMenuItem, 'children'> {
16
+ export interface NavigationMenuChildItem extends Omit<NavigationMenuItem, 'children' | 'type'> {
17
17
  /** Description is only used when `orientation` is `horizontal`. */
18
18
  description?: string
19
19
  }
20
20
 
21
- export interface NavigationMenuItem extends Omit<LinkProps, 'raw' | 'custom'>, Pick<CollapsibleRootProps, 'defaultOpen' | 'open'> {
21
+ export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'custom'>, Pick<CollapsibleRootProps, 'defaultOpen' | 'open'> {
22
22
  label?: string
23
23
  icon?: string
24
24
  avatar?: AvatarProps
@@ -28,6 +28,12 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'raw' | 'custom'>, P
28
28
  */
29
29
  badge?: string | number | BadgeProps
30
30
  trailingIcon?: string
31
+ /**
32
+ * The type of the item.
33
+ * The `label` type only works on `vertical` orientation.
34
+ * @defaultValue 'link'
35
+ */
36
+ type?: 'label' | 'link'
31
37
  slot?: string
32
38
  value?: string
33
39
  children?: NavigationMenuChildItem[]
@@ -55,11 +61,23 @@ export interface NavigationMenuProps<T> extends Pick<NavigationMenuRootProps, 'm
55
61
  * @defaultValue 'horizontal'
56
62
  */
57
63
  orientation?: NavigationMenuRootProps['orientation']
64
+ /**
65
+ * Collapse the navigation menu to only show icons.
66
+ * Only works when `orientation` is `vertical`.
67
+ * @defaultValue false
68
+ */
69
+ collapsed?: boolean
58
70
  /** Display a line next to the active item. */
59
71
  highlight?: boolean
60
72
  highlightColor?: NavigationMenuVariants['highlightColor']
61
73
  /** The content of the menu. */
62
74
  content?: Omit<NavigationMenuContentProps, 'as' | 'asChild' | 'forceMount'>
75
+ /**
76
+ * The orientation of the content.
77
+ * Only works when `orientation` is `horizontal`.
78
+ * @defaultValue 'horizontal'
79
+ */
80
+ contentOrientation?: NavigationMenuVariants['contentOrientation']
63
81
  /**
64
82
  * Display an arrow alongside the menu.
65
83
  * @defaultValue false
@@ -130,6 +148,7 @@ extendDevtoolsMeta({
130
148
  import { computed, toRef } from 'vue'
131
149
  import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, useForwardPropsEmits } from 'reka-ui'
132
150
  import { createReusableTemplate } from '@vueuse/core'
151
+ import { useAppConfig } from '#imports'
133
152
  import { get } from '../utils'
134
153
  import { pickLinkProps } from '../utils/link'
135
154
  import ULinkBase from './LinkBase.vue'
@@ -141,6 +160,7 @@ import UCollapsible from './Collapsible.vue'
141
160
 
142
161
  const props = withDefaults(defineProps<NavigationMenuProps<I>>(), {
143
162
  orientation: 'horizontal',
163
+ contentOrientation: 'horizontal',
144
164
  delayDuration: 0,
145
165
  unmountOnHide: true,
146
166
  labelKey: 'label'
@@ -163,10 +183,14 @@ const rootProps = useForwardPropsEmits(computed(() => ({
163
183
 
164
184
  const contentProps = toRef(() => props.content)
165
185
 
166
- const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, active?: boolean, index: number }>()
186
+ const appConfig = useAppConfig()
187
+ const [DefineLinkTemplate, ReuseLinkTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, active?: boolean }>()
188
+ const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number }>()
167
189
 
168
190
  const ui = computed(() => navigationMenu({
169
191
  orientation: props.orientation,
192
+ contentOrientation: props.contentOrientation,
193
+ collapsed: props.collapsed,
170
194
  color: props.color,
171
195
  variant: props.variant,
172
196
  highlight: props.highlight,
@@ -177,14 +201,17 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
177
201
  </script>
178
202
 
179
203
  <template>
180
- <DefineItemTemplate v-slot="{ item, active, index }">
204
+ <DefineLinkTemplate v-slot="{ item, active, index }">
181
205
  <slot :name="item.slot || 'item'" :item="(item as T)" :index="index">
182
206
  <slot :name="item.slot ? `${item.slot}-leading` : 'item-leading'" :item="(item as T)" :active="active" :index="index">
183
207
  <UAvatar v-if="item.avatar" :size="((props.ui?.linkLeadingAvatarSize || ui.linkLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ class: props.ui?.linkLeadingAvatar, active, disabled: !!item.disabled })" />
184
208
  <UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ class: props.ui?.linkLeadingIcon, active, disabled: !!item.disabled })" />
185
209
  </slot>
186
210
 
187
- <span v-if="get(item, props.labelKey as string) || !!slots[item.slot ? `${item.slot}-label` : 'item-label']" :class="ui.linkLabel({ class: props.ui?.linkLabel })">
211
+ <span
212
+ v-if="(!collapsed || orientation !== 'vertical') && (get(item, props.labelKey as string) || !!slots[item.slot ? `${item.slot}-label` : 'item-label'])"
213
+ :class="ui.linkLabel({ class: props.ui?.linkLabel })"
214
+ >
188
215
  <slot :name="item.slot ? `${item.slot}-label` : 'item-label'" :item="(item as T)" :active="active" :index="index">
189
216
  {{ get(item, props.labelKey as string) }}
190
217
  </slot>
@@ -192,7 +219,7 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
192
219
  <UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.linkLabelExternalIcon({ class: props.ui?.linkLabelExternalIcon, active })" />
193
220
  </span>
194
221
 
195
- <span v-if="item.badge || (orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) || (orientation === 'vertical' && item.children?.length) || item.trailingIcon || !!slots[item.slot ? `${item.slot}-trailing` : 'item-trailing']" :class="ui.linkTrailing({ class: props.ui?.linkTrailing })">
222
+ <span v-if="(!collapsed || orientation !== 'vertical') && (item.badge || (orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) || (orientation === 'vertical' && item.children?.length) || item.trailingIcon || !!slots[item.slot ? `${item.slot}-trailing` : 'item-trailing'])" :class="ui.linkTrailing({ class: props.ui?.linkTrailing })">
196
223
  <slot :name="item.slot ? `${item.slot}-trailing` : 'item-trailing'" :item="(item as T)" :active="active" :index="index">
197
224
  <UBadge
198
225
  v-if="item.badge"
@@ -208,77 +235,73 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
208
235
  </slot>
209
236
  </span>
210
237
  </slot>
211
- </DefineItemTemplate>
238
+ </DefineLinkTemplate>
212
239
 
213
- <NavigationMenuRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
214
- <template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
215
- <NavigationMenuList :class="ui.list({ class: props.ui?.list })">
240
+ <DefineItemTemplate v-slot="{ item, index }">
241
+ <component
242
+ :is="(orientation === 'vertical' && item.children?.length) ? UCollapsible : NavigationMenuItem"
243
+ as="li"
244
+ :value="item.value || String(index)"
245
+ :default-open="item.defaultOpen"
246
+ :unmount-on-hide="(orientation === 'vertical' && item.children?.length) ? unmountOnHide : undefined"
247
+ :open="item.open"
248
+ >
249
+ <div v-if="orientation === 'vertical' && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
250
+ <ReuseLinkTemplate :item="(item as T)" :index="index" />
251
+ </div>
252
+ <ULink v-else-if="item.type !== 'label'" v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length) ? {} : pickLinkProps(item as Omit<NavigationMenuItem, 'type'>)" custom>
216
253
  <component
217
- :is="(orientation === 'vertical' && item.children?.length) ? UCollapsible : NavigationMenuItem"
218
- v-for="(item, index) in list"
219
- :key="`list-${listIndex}-${index}`"
220
- as="li"
221
- :value="item.value || String(index)"
222
- :default-open="item.defaultOpen"
223
- :unmount-on-hide="(orientation === 'vertical' && item.children?.length) ? unmountOnHide : undefined"
224
- :open="item.open"
225
- :class="ui.item({ class: props.ui?.item })"
254
+ :is="(orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) ? NavigationMenuTrigger : NavigationMenuLink"
255
+ as-child
256
+ :active="active"
257
+ :disabled="item.disabled"
258
+ @select="item.onSelect"
226
259
  >
227
- <ULink v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length) ? {} : pickLinkProps(item)" custom>
228
- <component
229
- :is="(orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) ? NavigationMenuTrigger : NavigationMenuLink"
230
- as-child
231
- :active="active"
232
- :disabled="item.disabled"
233
- @select="item.onSelect"
234
- >
235
- <ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: !(orientation === 'vertical' && item.children?.length) })">
236
- <ReuseItemTemplate :item="(item as T)" :active="active || item.active" :index="index" />
237
- </ULinkBase>
238
- </component>
239
-
240
- <NavigationMenuContent v-if="orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])" v-bind="contentProps" :class="ui.content({ class: props.ui?.content })">
241
- <slot :name="item.slot ? `${item.slot}-content` : 'item-content'" :item="(item as T)" :active="active" :index="index">
242
- <ul :class="ui.childList({ class: props.ui?.childList })">
243
- <li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem({ class: props.ui?.childItem })">
244
- <ULink v-slot="{ active: childActive, ...childSlotProps }" v-bind="pickLinkProps(childItem)" custom>
245
- <NavigationMenuLink as-child :active="childActive" @select="childItem.onSelect">
246
- <ULinkBase v-bind="childSlotProps" :class="ui.childLink({ class: [props.ui?.childLink, childItem.class], active: childActive })">
247
- <UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ class: props.ui?.childLinkIcon, active: childActive })" />
248
-
249
- <div :class="ui.childLinkWrapper({ class: props.ui?.childLinkWrapper })">
250
- <p :class="ui.childLinkLabel({ class: props.ui?.childLinkLabel, active: childActive })">
251
- {{ get(childItem, props.labelKey as string) }}
252
-
253
- <UIcon v-if="childItem.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ class: props.ui?.childLinkLabelExternalIcon, active: childActive })" />
254
- </p>
255
- <p v-if="childItem.description" :class="ui.childLinkDescription({ class: props.ui?.childLinkDescription, active: childActive })">
256
- {{ childItem.description }}
257
- </p>
258
- </div>
259
- </ULinkBase>
260
- </NavigationMenuLink>
261
- </ULink>
262
- </li>
263
- </ul>
264
- </slot>
265
- </NavigationMenuContent>
266
- </ULink>
260
+ <ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: !(orientation === 'vertical' && item.children?.length) })">
261
+ <ReuseLinkTemplate :item="(item as T)" :active="active || item.active" :index="index" />
262
+ </ULinkBase>
263
+ </component>
267
264
 
268
- <template v-if="orientation === 'vertical' && item.children?.length" #content>
265
+ <NavigationMenuContent v-if="orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])" v-bind="contentProps" :class="ui.content({ class: props.ui?.content })">
266
+ <slot :name="item.slot ? `${item.slot}-content` : 'item-content'" :item="(item as T)" :active="active" :index="index">
269
267
  <ul :class="ui.childList({ class: props.ui?.childList })">
270
268
  <li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem({ class: props.ui?.childItem })">
271
269
  <ULink v-slot="{ active: childActive, ...childSlotProps }" v-bind="pickLinkProps(childItem)" custom>
272
270
  <NavigationMenuLink as-child :active="childActive" @select="childItem.onSelect">
273
- <ULinkBase v-bind="childSlotProps" :class="ui.link({ class: [props.ui?.link, childItem.class], active: childActive, disabled: !!childItem.disabled, level: true })">
274
- <ReuseItemTemplate :item="(childItem as T)" :active="childActive" :index="childIndex" />
271
+ <ULinkBase v-bind="childSlotProps" :class="ui.childLink({ class: [props.ui?.childLink, childItem.class], active: childActive })">
272
+ <UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ class: props.ui?.childLinkIcon, active: childActive })" />
273
+
274
+ <div :class="ui.childLinkWrapper({ class: props.ui?.childLinkWrapper })">
275
+ <p :class="ui.childLinkLabel({ class: props.ui?.childLinkLabel, active: childActive })">
276
+ {{ get(childItem, props.labelKey as string) }}
277
+
278
+ <UIcon v-if="childItem.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ class: props.ui?.childLinkLabelExternalIcon, active: childActive })" />
279
+ </p>
280
+ <p v-if="childItem.description" :class="ui.childLinkDescription({ class: props.ui?.childLinkDescription, active: childActive })">
281
+ {{ childItem.description }}
282
+ </p>
283
+ </div>
275
284
  </ULinkBase>
276
285
  </NavigationMenuLink>
277
286
  </ULink>
278
287
  </li>
279
288
  </ul>
280
- </template>
281
- </component>
289
+ </slot>
290
+ </NavigationMenuContent>
291
+ </ULink>
292
+
293
+ <template v-if="orientation === 'vertical' && item.children?.length" #content>
294
+ <ul :class="ui.childList({ class: props.ui?.childList })">
295
+ <ReuseItemTemplate v-for="(childItem, childIndex) in item.children" :key="childIndex" :item="childItem" :index="childIndex" :class="ui.childItem({ class: props.ui?.childItem })" />
296
+ </ul>
297
+ </template>
298
+ </component>
299
+ </DefineItemTemplate>
300
+
301
+ <NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.class, props.ui?.root] })">
302
+ <template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
303
+ <NavigationMenuList :class="ui.list({ class: props.ui?.list })">
304
+ <ReuseItemTemplate v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :item="item" :index="index" :class="ui.item({ class: props.ui?.item })" />
282
305
  </NavigationMenuList>
283
306
 
284
307
  <div v-if="orientation === 'vertical' && listIndex < lists.length - 1" :class="ui.separator({ class: props.ui?.separator })" />
@@ -8,9 +8,9 @@ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import { tv } from '../utils/tv'
9
9
  import type { ButtonProps } from '../types'
10
10
 
11
- const appConfig = _appConfig as AppConfig & { ui: { pagination: Partial<typeof theme> } }
11
+ const appConfigPagination = _appConfig as AppConfig & { ui: { pagination: Partial<typeof theme> } }
12
12
 
13
- const pagination = tv({ extend: tv(theme), ...(appConfig.ui?.pagination || {}) })
13
+ const pagination = tv({ extend: tv(theme), ...(appConfigPagination.ui?.pagination || {}) })
14
14
 
15
15
  export interface PaginationProps extends Partial<Pick<PaginationRootProps, 'defaultPage' | 'disabled' | 'itemsPerPage' | 'page' | 'showEdges' | 'siblingCount' | 'total'>> {
16
16
  /**
@@ -7,9 +7,9 @@ import theme from '#build/ui/pin-input'
7
7
  import { tv } from '../utils/tv'
8
8
  import type { PartialString } from '../types/utils'
9
9
 
10
- const appConfig = _appConfig as AppConfig & { ui: { pinInput: Partial<typeof theme> } }
10
+ const appConfigPinInput = _appConfig as AppConfig & { ui: { pinInput: Partial<typeof theme> } }
11
11
 
12
- const pinInput = tv({ extend: tv(theme), ...(appConfig.ui?.pinInput || {}) })
12
+ const pinInput = tv({ extend: tv(theme), ...(appConfigPinInput.ui?.pinInput || {}) })
13
13
 
14
14
  type PinInputVariants = VariantProps<typeof pinInput>
15
15
 
@@ -50,7 +50,7 @@ const props = withDefaults(defineProps<PinInputProps>(), {
50
50
  const emits = defineEmits<PinInputEmits>()
51
51
 
52
52
  const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultValue', 'disabled', 'id', 'mask', 'modelValue', 'name', 'otp', 'placeholder', 'required', 'type'), emits)
53
- const { emitFormInput, emitFormChange, emitFormBlur, size, color, id, name, highlight, disabled } = useFormField<PinInputProps>(props)
53
+ const { emitFormInput, emitFormFocus, emitFormChange, emitFormBlur, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField<PinInputProps>(props)
54
54
 
55
55
  const ui = computed(() => pinInput({
56
56
  color: color.value,
@@ -77,7 +77,7 @@ function onBlur(event: FocusEvent) {
77
77
 
78
78
  <template>
79
79
  <PinInputRoot
80
- v-bind="rootProps"
80
+ v-bind="{ ...rootProps, ...ariaAttrs }"
81
81
  :id="id"
82
82
  :name="name"
83
83
  :class="ui.root({ class: [props.class, props.ui?.root] })"
@@ -92,6 +92,7 @@ function onBlur(event: FocusEvent) {
92
92
  v-bind="$attrs"
93
93
  :disabled="disabled"
94
94
  @blur="onBlur"
95
+ @focus="emitFormFocus"
95
96
  />
96
97
  </PinInputRoot>
97
98
  </template>
@@ -6,9 +6,9 @@ import theme from '#build/ui/popover'
6
6
  import { tv } from '../utils/tv'
7
7
  import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
 
9
- const appConfig = _appConfig as AppConfig & { ui: { popover: Partial<typeof theme> } }
9
+ const appConfigPopover = _appConfig as AppConfig & { ui: { popover: Partial<typeof theme> } }
10
10
 
11
- const popover = tv({ extend: tv(theme), ...(appConfig.ui?.popover || {}) })
11
+ const popover = tv({ extend: tv(theme), ...(appConfigPopover.ui?.popover || {}) })
12
12
 
13
13
  export interface PopoverProps extends PopoverRootProps, Pick<HoverCardRootProps, 'openDelay' | 'closeDelay'> {
14
14
  /**
@@ -7,9 +7,9 @@ import _appConfig from '#build/app.config'
7
7
  import theme from '#build/ui/progress'
8
8
  import { tv } from '../utils/tv'
9
9
 
10
- const appConfig = _appConfig as AppConfig & { ui: { progress: Partial<typeof theme> } }
10
+ const appConfigProgress = _appConfig as AppConfig & { ui: { progress: Partial<typeof theme> } }
11
11
 
12
- const progress = tv({ extend: tv(theme), ...(appConfig.ui?.progress || {}) })
12
+ const progress = tv({ extend: tv(theme), ...(appConfigProgress.ui?.progress || {}) })
13
13
 
14
14
  type ProgressVariants = VariantProps<typeof progress>
15
15
 
@@ -7,9 +7,9 @@ import theme from '#build/ui/radio-group'
7
7
  import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import { tv } from '../utils/tv'
9
9
 
10
- const appConfig = _appConfig as AppConfig & { ui: { radioGroup: Partial<typeof theme> } }
10
+ const appConfigRadioGroup = _appConfig as AppConfig & { ui: { radioGroup: Partial<typeof theme> } }
11
11
 
12
- const radioGroup = tv({ extend: tv(theme), ...(appConfig.ui?.radioGroup || {}) })
12
+ const radioGroup = tv({ extend: tv(theme), ...(appConfigRadioGroup.ui?.radioGroup || {}) })
13
13
 
14
14
  type RadioGroupVariants = VariantProps<typeof radioGroup>
15
15
 
@@ -87,7 +87,7 @@ const slots = defineSlots<RadioGroupSlots<T>>()
87
87
 
88
88
  const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emits)
89
89
 
90
- const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled } = useFormField<RadioGroupProps<T>>(props, { bind: false })
90
+ const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled, ariaAttrs } = useFormField<RadioGroupProps<T>>(props, { bind: false })
91
91
  const id = _id.value ?? useId()
92
92
 
93
93
  const ui = computed(() => radioGroup({
@@ -147,7 +147,7 @@ function onUpdate(value: any) {
147
147
  :class="ui.root({ class: [props.class, props.ui?.root] })"
148
148
  @update:model-value="onUpdate"
149
149
  >
150
- <fieldset :class="ui.fieldset({ class: props.ui?.fieldset })">
150
+ <fieldset :class="ui.fieldset({ class: props.ui?.fieldset })" v-bind="ariaAttrs">
151
151
  <legend v-if="legend || !!slots.legend" :class="ui.legend({ class: props.ui?.legend })">
152
152
  <slot name="legend">
153
153
  {{ legend }}
@@ -10,9 +10,9 @@ import { tv } from '../utils/tv'
10
10
  import type { AvatarProps, ChipProps, InputProps } from '../types'
11
11
  import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
12
12
 
13
- const appConfig = _appConfig as AppConfig & { ui: { select: Partial<typeof theme> } }
13
+ const appConfigSelect = _appConfig as AppConfig & { ui: { select: Partial<typeof theme> } }
14
14
 
15
- const select = tv({ extend: tv(theme), ...(appConfig.ui?.select || {}) })
15
+ const select = tv({ extend: tv(theme), ...(appConfigSelect.ui?.select || {}) })
16
16
 
17
17
  export interface SelectItem {
18
18
  label?: string
@@ -129,11 +129,11 @@ const emits = defineEmits<SelectEmits<T, V, M>>()
129
129
  const slots = defineSlots<SelectSlots<T, M>>()
130
130
 
131
131
  const appConfig = useAppConfig()
132
- const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'disabled', 'autocomplete', 'required', 'multiple'), emits)
132
+ const rootProps = useForwardPropsEmits(reactivePick(props, 'open', 'defaultOpen', 'disabled', 'autocomplete', 'required', 'multiple'), emits)
133
133
  const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as SelectContentProps)
134
134
  const arrowProps = toRef(() => props.arrow as SelectArrowProps)
135
135
 
136
- const { emitFormChange, emitFormInput, emitFormBlur, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
136
+ const { emitFormChange, emitFormInput, emitFormBlur, emitFormFocus, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
137
137
  const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
138
138
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
139
139
 
@@ -179,6 +179,7 @@ function onUpdateOpen(value: boolean) {
179
179
  } else {
180
180
  const event = new FocusEvent('focus')
181
181
  emits('focus', event)
182
+ emitFormFocus()
182
183
  }
183
184
  }
184
185
  </script>
@@ -186,16 +187,17 @@ function onUpdateOpen(value: boolean) {
186
187
  <!-- eslint-disable vue/no-template-shadow -->
187
188
  <template>
188
189
  <SelectRoot
189
- :id="id"
190
190
  v-slot="{ modelValue, open }"
191
- v-bind="rootProps"
192
191
  :name="name"
192
+ v-bind="rootProps"
193
193
  :autocomplete="autocomplete"
194
194
  :disabled="disabled"
195
+ :default-value="(defaultValue as (AcceptableValue | AcceptableValue[] | undefined))"
196
+ :model-value="(modelValue as (AcceptableValue | AcceptableValue[] | undefined))"
195
197
  @update:model-value="onUpdate"
196
198
  @update:open="onUpdateOpen"
197
199
  >
198
- <SelectTrigger :class="ui.base({ class: [props.class, props.ui?.base] })">
200
+ <SelectTrigger :id="id" :class="ui.base({ class: [props.class, props.ui?.base] })" v-bind="ariaAttrs">
199
201
  <span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
200
202
  <slot name="leading" :model-value="(modelValue as M extends true ? AcceptableValue[] : AcceptableValue)" :open="open" :ui="ui">
201
203
  <UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
@@ -10,9 +10,9 @@ import { tv } from '../utils/tv'
10
10
  import type { AvatarProps, ChipProps, InputProps } from '../types'
11
11
  import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
12
12
 
13
- const appConfig = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
13
+ const appConfigSelectMenu = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
14
14
 
15
- const selectMenu = tv({ extend: tv(theme), ...(appConfig.ui?.selectMenu || {}) })
15
+ const selectMenu = tv({ extend: tv(theme), ...(appConfigSelectMenu.ui?.selectMenu || {}) })
16
16
 
17
17
  export interface SelectMenuItem {
18
18
  label?: string
@@ -168,7 +168,7 @@ const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffse
168
168
  const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
169
169
  const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t('selectMenu.search'), variant: 'none' }) as InputProps)
170
170
 
171
- const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
171
+ const { emitFormBlur, emitFormFocus, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
172
172
  const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
173
173
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
174
174
 
@@ -272,6 +272,7 @@ function onUpdateOpen(value: boolean) {
272
272
  } else {
273
273
  const event = new FocusEvent('focus')
274
274
  emits('focus', event)
275
+ emitFormFocus()
275
276
  clearTimeout(timeoutId)
276
277
  }
277
278
  }
@@ -298,7 +299,7 @@ function onUpdateOpen(value: boolean) {
298
299
  <ComboboxRoot
299
300
  :id="id"
300
301
  v-slot="{ modelValue, open }"
301
- v-bind="rootProps"
302
+ v-bind="{ ...rootProps, ...ariaAttrs }"
302
303
  ignore-filter
303
304
  as-child
304
305
  :name="name"
@@ -7,9 +7,9 @@ import theme from '#build/ui/separator'
7
7
  import { tv } from '../utils/tv'
8
8
  import type { AvatarProps } from '../types'
9
9
 
10
- const appConfig = _appConfig as AppConfig & { ui: { separator: Partial<typeof theme> } }
10
+ const appConfigSeparator = _appConfig as AppConfig & { ui: { separator: Partial<typeof theme> } }
11
11
 
12
- const separator = tv({ extend: tv(theme), ...(appConfig.ui?.separator || {}) })
12
+ const separator = tv({ extend: tv(theme), ...(appConfigSeparator.ui?.separator || {}) })
13
13
 
14
14
  type SeparatorVariants = VariantProps<typeof separator>
15
15
 
@@ -5,9 +5,9 @@ import theme from '#build/ui/skeleton'
5
5
  import { tv } from '../utils/tv'
6
6
  import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
7
7
 
8
- const appConfig = _appConfig as AppConfig & { ui: { skeleton: Partial<typeof theme> } }
8
+ const appConfigSkeleton = _appConfig as AppConfig & { ui: { skeleton: Partial<typeof theme> } }
9
9
 
10
- const skeleton = tv({ extend: tv(theme), ...(appConfig.ui?.skeleton || {}) })
10
+ const skeleton = tv({ extend: tv(theme), ...(appConfigSkeleton.ui?.skeleton || {}) })
11
11
 
12
12
  export interface SkeletonProps {
13
13
  /**
@@ -8,9 +8,9 @@ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import { tv } from '../utils/tv'
9
9
  import type { ButtonProps } from '../types'
10
10
 
11
- const appConfig = _appConfig as AppConfig & { ui: { slideover: Partial<typeof theme> } }
11
+ const appConfigSlideover = _appConfig as AppConfig & { ui: { slideover: Partial<typeof theme> } }
12
12
 
13
- const slideover = tv({ extend: tv(theme), ...(appConfig.ui?.slideover || {}) })
13
+ const slideover = tv({ extend: tv(theme), ...(appConfigSlideover.ui?.slideover || {}) })
14
14
 
15
15
  type SlideoverVariants = VariantProps<typeof slideover>
16
16
 
@@ -6,9 +6,9 @@ import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/slider'
7
7
  import { tv } from '../utils/tv'
8
8
 
9
- const appConfig = _appConfig as AppConfig & { ui: { slider: Partial<typeof theme> } }
9
+ const appConfigSlider = _appConfig as AppConfig & { ui: { slider: Partial<typeof theme> } }
10
10
 
11
- const slider = tv({ extend: tv(theme), ...(appConfig.ui?.slider || {}) })
11
+ const slider = tv({ extend: tv(theme), ...(appConfigSlider.ui?.slider || {}) })
12
12
 
13
13
  type SliderVariants = VariantProps<typeof slider>
14
14
 
@@ -55,7 +55,7 @@ const modelValue = defineModel<number | number[]>()
55
55
 
56
56
  const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'orientation', 'min', 'max', 'step', 'minStepsBetweenThumbs', 'inverted'), emits)
57
57
 
58
- const { id, emitFormChange, emitFormInput, size, color, name, disabled } = useFormField<SliderProps>(props)
58
+ const { id, emitFormChange, emitFormInput, size, color, name, disabled, ariaAttrs } = useFormField<SliderProps>(props)
59
59
 
60
60
  const defaultSliderValue = computed(() => {
61
61
  if (typeof props.defaultValue === 'number') {
@@ -95,7 +95,7 @@ function onChange(value: any) {
95
95
 
96
96
  <template>
97
97
  <SliderRoot
98
- v-bind="rootProps"
98
+ v-bind="{ ...rootProps, ...ariaAttrs }"
99
99
  :id="id"
100
100
  v-model="sliderValue"
101
101
  :name="name"
@@ -8,9 +8,9 @@ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import { tv } from '../utils/tv'
9
9
  import type { DynamicSlots } from '../types/utils'
10
10
 
11
- const appConfig = _appConfig as AppConfig & { ui: { stepper: Partial<typeof theme> } }
11
+ const appConfigStepper = _appConfig as AppConfig & { ui: { stepper: Partial<typeof theme> } }
12
12
 
13
- const stepper = tv({ extend: tv(theme), ...(appConfig.ui?.stepper || {}) })
13
+ const stepper = tv({ extend: tv(theme), ...(appConfigStepper.ui?.stepper || {}) })
14
14
 
15
15
  type StepperVariants = VariantProps<typeof stepper>
16
16
 
@@ -8,9 +8,9 @@ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import { tv } from '../utils/tv'
9
9
  import type { PartialString } from '../types/utils'
10
10
 
11
- const appConfig = _appConfig as AppConfig & { ui: { switch: Partial<typeof theme> } }
11
+ const appConfigSwitch = _appConfig as AppConfig & { ui: { switch: Partial<typeof theme> } }
12
12
 
13
- const switchTv = tv({ extend: tv(theme), ...(appConfig.ui?.switch || {}) })
13
+ const switchTv = tv({ extend: tv(theme), ...(appConfigSwitch.ui?.switch || {}) })
14
14
 
15
15
  type SwitchVariants = VariantProps<typeof switchTv>
16
16
 
@@ -68,7 +68,7 @@ const modelValue = defineModel<boolean>({ default: undefined })
68
68
  const appConfig = useAppConfig()
69
69
  const rootProps = useForwardProps(reactivePick(props, 'required', 'value', 'defaultValue'))
70
70
 
71
- const { id: _id, emitFormChange, emitFormInput, size, color, name, disabled } = useFormField<SwitchProps>(props)
71
+ const { id: _id, emitFormChange, emitFormInput, size, color, name, disabled, ariaAttrs } = useFormField<SwitchProps>(props)
72
72
  const id = _id.value ?? useId()
73
73
 
74
74
  const ui = computed(() => switchTv({
@@ -93,7 +93,7 @@ function onUpdate(value: any) {
93
93
  <div :class="ui.container({ class: props.ui?.container })">
94
94
  <SwitchRoot
95
95
  :id="id"
96
- v-bind="rootProps"
96
+ v-bind="{ ...rootProps, ...ariaAttrs }"
97
97
  v-model="modelValue"
98
98
  :name="name"
99
99
  :disabled="disabled || loading"
@@ -38,9 +38,9 @@ declare module '@tanstack/table-core' {
38
38
  }
39
39
  }
40
40
 
41
- const appConfig = _appConfig as AppConfig & { ui: { table: Partial<typeof theme> } }
41
+ const appConfigTable = _appConfig as AppConfig & { ui: { table: Partial<typeof theme> } }
42
42
 
43
- const table = tv({ extend: tv(theme), ...(appConfig.ui?.table || {}) })
43
+ const table = tv({ extend: tv(theme), ...(appConfigTable.ui?.table || {}) })
44
44
 
45
45
  type TableVariants = VariantProps<typeof table>
46
46
 
@@ -9,9 +9,9 @@ import { tv } from '../utils/tv'
9
9
  import type { AvatarProps } from '../types'
10
10
  import type { DynamicSlots, PartialString } from '../types/utils'
11
11
 
12
- const appConfig = _appConfig as AppConfig & { ui: { tabs: Partial<typeof theme> } }
12
+ const appConfigTabs = _appConfig as AppConfig & { ui: { tabs: Partial<typeof theme> } }
13
13
 
14
- const tabs = tv({ extend: tv(theme), ...(appConfig.ui?.tabs || {}) })
14
+ const tabs = tv({ extend: tv(theme), ...(appConfigTabs.ui?.tabs || {}) })
15
15
 
16
16
  export interface TabsItem {
17
17
  label?: string
@@ -5,9 +5,9 @@ import _appConfig from '#build/app.config'
5
5
  import theme from '#build/ui/textarea'
6
6
  import { tv } from '../utils/tv'
7
7
 
8
- const appConfig = _appConfig as AppConfig & { ui: { textarea: Partial<typeof theme> } }
8
+ const appConfigTextarea = _appConfig as AppConfig & { ui: { textarea: Partial<typeof theme> } }
9
9
 
10
- const textarea = tv({ extend: tv(theme), ...(appConfig.ui?.textarea || {}) })
10
+ const textarea = tv({ extend: tv(theme), ...(appConfigTextarea.ui?.textarea || {}) })
11
11
 
12
12
  type TextareaVariants = VariantProps<typeof textarea>
13
13
 
@@ -66,7 +66,7 @@ const emits = defineEmits<TextareaEmits>()
66
66
 
67
67
  const [modelValue, modelModifiers] = defineModel<string | number>()
68
68
 
69
- const { emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled } = useFormField<TextareaProps>(props, { deferInputValidation: true })
69
+ const { emitFormFocus, emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField<TextareaProps>(props, { deferInputValidation: true })
70
70
 
71
71
  const ui = computed(() => textarea({
72
72
  color: color.value,
@@ -185,10 +185,11 @@ onMounted(() => {
185
185
  :class="ui.base({ class: props.ui?.base })"
186
186
  :disabled="disabled"
187
187
  :required="required"
188
- v-bind="$attrs"
188
+ v-bind="{ ...$attrs, ...ariaAttrs }"
189
189
  @input="onInput"
190
190
  @blur="onBlur"
191
191
  @change="onChange"
192
+ @focus="emitFormFocus"
192
193
  />
193
194
 
194
195
  <slot />