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

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 (174) hide show
  1. package/.nuxt/ui/accordion.ts +2 -2
  2. package/.nuxt/ui/alert.ts +47 -37
  3. package/.nuxt/ui/avatar-group.ts +1 -1
  4. package/.nuxt/ui/avatar.ts +4 -4
  5. package/.nuxt/ui/badge.ts +37 -28
  6. package/.nuxt/ui/breadcrumb.ts +5 -5
  7. package/.nuxt/ui/button.ts +42 -43
  8. package/.nuxt/ui/calendar.ts +15 -15
  9. package/.nuxt/ui/card.ts +27 -1
  10. package/.nuxt/ui/carousel.ts +2 -2
  11. package/.nuxt/ui/checkbox.ts +18 -18
  12. package/.nuxt/ui/chip.ts +8 -8
  13. package/.nuxt/ui/color-picker.ts +2 -2
  14. package/.nuxt/ui/command-palette.ts +12 -12
  15. package/.nuxt/ui/container.ts +1 -1
  16. package/.nuxt/ui/context-menu.ts +32 -32
  17. package/.nuxt/ui/drawer.ts +72 -11
  18. package/.nuxt/ui/dropdown-menu.ts +33 -33
  19. package/.nuxt/ui/form-field.ts +6 -6
  20. package/.nuxt/ui/input-menu.ts +41 -41
  21. package/.nuxt/ui/input-number.ts +20 -20
  22. package/.nuxt/ui/input.ts +23 -23
  23. package/.nuxt/ui/kbd.ts +4 -4
  24. package/.nuxt/ui/link.ts +3 -3
  25. package/.nuxt/ui/modal.ts +5 -5
  26. package/.nuxt/ui/navigation-menu.ts +144 -77
  27. package/.nuxt/ui/pin-input.ts +20 -20
  28. package/.nuxt/ui/popover.ts +2 -2
  29. package/.nuxt/ui/progress.ts +17 -17
  30. package/.nuxt/ui/radio-group.ts +20 -20
  31. package/.nuxt/ui/select-menu.ts +33 -32
  32. package/.nuxt/ui/select.ts +31 -31
  33. package/.nuxt/ui/separator.ts +8 -8
  34. package/.nuxt/ui/skeleton.ts +1 -1
  35. package/.nuxt/ui/slideover.ts +4 -4
  36. package/.nuxt/ui/slider.ts +16 -16
  37. package/.nuxt/ui/stepper.ts +18 -18
  38. package/.nuxt/ui/switch.ts +20 -20
  39. package/.nuxt/ui/table.ts +16 -16
  40. package/.nuxt/ui/tabs.ts +33 -33
  41. package/.nuxt/ui/textarea.ts +23 -23
  42. package/.nuxt/ui/toast.ts +42 -32
  43. package/.nuxt/ui/toaster.ts +4 -4
  44. package/.nuxt/ui/tooltip.ts +2 -2
  45. package/.nuxt/ui.css +90 -0
  46. package/README.md +2 -2
  47. package/cli/package.json +2 -2
  48. package/cli/templates.mjs +7 -7
  49. package/dist/chunks/component-meta.cjs +2590 -2511
  50. package/dist/chunks/component-meta.mjs +2590 -2511
  51. package/dist/client/devtools/200.html +1 -1
  52. package/dist/client/devtools/404.html +1 -1
  53. package/dist/client/devtools/_nuxt/CG6Dc4jp.js +1 -0
  54. package/dist/client/devtools/_nuxt/{Dtz-o9GB.js → DrNJgD08.js} +1 -1
  55. package/dist/client/devtools/_nuxt/{DNZFyo26.js → ElqrUh1r.js} +1 -1
  56. package/dist/client/devtools/_nuxt/builds/latest.json +1 -1
  57. package/dist/client/devtools/_nuxt/builds/meta/255c8d0b-7281-4d74-b4b6-ec96e6721aa0.json +1 -0
  58. package/dist/client/devtools/_nuxt/entry.Hn8drx4g.css +1 -0
  59. package/dist/client/devtools/_nuxt/error-404.Dew7w9Ee.css +1 -0
  60. package/dist/client/devtools/_nuxt/error-500.Dep59i31.css +1 -0
  61. package/dist/client/devtools/_nuxt/mC2e7kOs.js +57 -0
  62. package/dist/client/devtools/index.html +1 -1
  63. package/dist/devtools/runtime/examples/CardExample.vue +3 -3
  64. package/dist/devtools/runtime/examples/CollapsibleExample.vue +1 -1
  65. package/dist/devtools/runtime/examples/ContainerExample.vue +1 -1
  66. package/dist/devtools/runtime/examples/ContextMenuExample.vue +1 -1
  67. package/dist/devtools/runtime/examples/PopoverExample.vue +1 -1
  68. package/dist/devtools/runtime/examples/TooltipExample.vue +1 -1
  69. package/dist/module.cjs +2 -1
  70. package/dist/module.json +1 -1
  71. package/dist/module.mjs +2 -1
  72. package/dist/runtime/components/Accordion.vue +2 -2
  73. package/dist/runtime/components/Alert.vue +15 -12
  74. package/dist/runtime/components/App.vue +3 -3
  75. package/dist/runtime/components/Avatar.vue +31 -10
  76. package/dist/runtime/components/AvatarGroup.vue +2 -2
  77. package/dist/runtime/components/Badge.vue +7 -3
  78. package/dist/runtime/components/Breadcrumb.vue +2 -2
  79. package/dist/runtime/components/Button.vue +2 -2
  80. package/dist/runtime/components/ButtonGroup.vue +2 -2
  81. package/dist/runtime/components/Calendar.vue +6 -3
  82. package/dist/runtime/components/Card.vue +8 -4
  83. package/dist/runtime/components/Carousel.vue +2 -2
  84. package/dist/runtime/components/Checkbox.vue +4 -4
  85. package/dist/runtime/components/Chip.vue +2 -2
  86. package/dist/runtime/components/Collapsible.vue +2 -2
  87. package/dist/runtime/components/ColorPicker.vue +46 -15
  88. package/dist/runtime/components/CommandPalette.vue +48 -41
  89. package/dist/runtime/components/Container.vue +2 -2
  90. package/dist/runtime/components/ContextMenu.vue +10 -2
  91. package/dist/runtime/components/ContextMenuContent.vue +4 -2
  92. package/dist/runtime/components/Drawer.vue +9 -3
  93. package/dist/runtime/components/DropdownMenu.vue +10 -2
  94. package/dist/runtime/components/DropdownMenuContent.vue +4 -2
  95. package/dist/runtime/components/Form.vue +46 -17
  96. package/dist/runtime/components/FormField.vue +12 -6
  97. package/dist/runtime/components/Input.vue +5 -4
  98. package/dist/runtime/components/InputMenu.vue +6 -5
  99. package/dist/runtime/components/InputNumber.vue +10 -6
  100. package/dist/runtime/components/Kbd.vue +2 -2
  101. package/dist/runtime/components/Link.vue +2 -2
  102. package/dist/runtime/components/Modal.vue +17 -3
  103. package/dist/runtime/components/NavigationMenu.vue +110 -67
  104. package/dist/runtime/components/Pagination.vue +2 -2
  105. package/dist/runtime/components/PinInput.vue +5 -4
  106. package/dist/runtime/components/Popover.vue +2 -2
  107. package/dist/runtime/components/Progress.vue +2 -2
  108. package/dist/runtime/components/RadioGroup.vue +4 -4
  109. package/dist/runtime/components/Select.vue +9 -7
  110. package/dist/runtime/components/SelectMenu.vue +67 -64
  111. package/dist/runtime/components/Separator.vue +2 -2
  112. package/dist/runtime/components/Skeleton.vue +2 -2
  113. package/dist/runtime/components/Slideover.vue +17 -3
  114. package/dist/runtime/components/Slider.vue +4 -4
  115. package/dist/runtime/components/Stepper.vue +3 -3
  116. package/dist/runtime/components/Switch.vue +4 -4
  117. package/dist/runtime/components/Table.vue +96 -18
  118. package/dist/runtime/components/Tabs.vue +2 -2
  119. package/dist/runtime/components/Textarea.vue +7 -5
  120. package/dist/runtime/components/Toast.vue +28 -16
  121. package/dist/runtime/components/Toaster.vue +4 -4
  122. package/dist/runtime/components/Tooltip.vue +2 -2
  123. package/dist/runtime/composables/useFormField.d.ts +6 -2
  124. package/dist/runtime/composables/useFormField.js +18 -11
  125. package/dist/runtime/composables/useToast.d.ts +4 -3
  126. package/dist/runtime/composables/useToast.js +20 -6
  127. package/dist/runtime/index.css +1 -1
  128. package/dist/runtime/locale/az.js +54 -0
  129. package/dist/runtime/locale/bn.js +54 -0
  130. package/dist/runtime/locale/es.js +2 -2
  131. package/dist/runtime/locale/he.d.ts +2 -0
  132. package/dist/runtime/locale/he.js +53 -0
  133. package/dist/runtime/locale/hi.d.ts +2 -0
  134. package/dist/runtime/locale/hi.js +54 -0
  135. package/dist/runtime/locale/hu.d.ts +2 -0
  136. package/dist/runtime/locale/hu.js +54 -0
  137. package/dist/runtime/locale/index.d.ts +8 -2
  138. package/dist/runtime/locale/index.js +8 -2
  139. package/dist/runtime/locale/km.d.ts +2 -0
  140. package/dist/runtime/locale/km.js +54 -0
  141. package/dist/runtime/locale/nb_no.d.ts +2 -0
  142. package/dist/runtime/locale/nb_no.js +54 -0
  143. package/dist/runtime/locale/zh_cn.d.ts +2 -0
  144. package/dist/runtime/locale/{zh_hans.js → zh_cn.js} +1 -1
  145. package/dist/runtime/locale/zh_tw.d.ts +2 -0
  146. package/dist/runtime/locale/{zh_hant.js → zh_tw.js} +1 -1
  147. package/dist/runtime/plugins/colors.js +8 -5
  148. package/dist/runtime/types/form.d.ts +21 -12
  149. package/dist/runtime/types/index.d.ts +1 -0
  150. package/dist/runtime/types/index.js +1 -0
  151. package/dist/runtime/types/utils.d.ts +5 -0
  152. package/dist/runtime/utils/form.js +3 -5
  153. package/dist/runtime/utils/tv.js +2 -2
  154. package/dist/runtime/vue/components/Link.vue +77 -18
  155. package/dist/shared/{ui.DCjJwb6l.cjs → ui.C5FzRWM5.cjs} +529 -366
  156. package/dist/shared/{ui.BKsd22-Q.mjs → ui.DCZM2pl8.mjs} +525 -366
  157. package/dist/unplugin.cjs +44 -20
  158. package/dist/unplugin.d.cts +10 -0
  159. package/dist/unplugin.d.mts +10 -0
  160. package/dist/unplugin.d.ts +10 -0
  161. package/dist/unplugin.mjs +43 -19
  162. package/dist/vite.cjs +3 -2
  163. package/dist/vite.d.cts +2 -0
  164. package/dist/vite.d.mts +2 -0
  165. package/dist/vite.d.ts +2 -0
  166. package/dist/vite.mjs +3 -2
  167. package/package.json +67 -41
  168. package/dist/client/devtools/_nuxt/CQ-XZFu7.js +0 -54
  169. package/dist/client/devtools/_nuxt/builds/meta/1f5fbd7b-9d97-480e-9ae4-e02b4ff7018b.json +0 -1
  170. package/dist/client/devtools/_nuxt/entry.qOdop8tq.css +0 -1
  171. package/dist/client/devtools/_nuxt/error-404.D-rS9BDk.css +0 -1
  172. package/dist/client/devtools/_nuxt/error-500.CfcCHs91.css +0 -1
  173. /package/dist/runtime/locale/{zh_hans.d.ts → az.d.ts} +0 -0
  174. /package/dist/runtime/locale/{zh_hant.d.ts → bn.d.ts} +0 -0
@@ -6,9 +6,9 @@ import theme from '#build/ui/form-field'
6
6
  import { tv } from '../utils/tv'
7
7
  import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
 
9
- const appConfig = _appConfig as AppConfig & { ui: { formField: Partial<typeof theme> } }
9
+ const appConfigFormField = _appConfig as AppConfig & { ui: { formField: Partial<typeof theme> } }
10
10
 
11
- const formField = tv({ extend: tv(theme), ...(appConfig.ui?.formField || {}) })
11
+ const formField = tv({ extend: tv(theme), ...(appConfigFormField.ui?.formField || {}) })
12
12
 
13
13
  type FormFieldVariants = VariantProps<typeof formField>
14
14
 
@@ -66,6 +66,9 @@ const formErrors = inject<Ref<FormError[]> | null>('form-errors', null)
66
66
  const error = computed(() => props.error || formErrors?.value?.find(error => error.name === props.name || (props.errorPattern && error.name.match(props.errorPattern)))?.message)
67
67
 
68
68
  const id = ref(useId())
69
+ // Copies id's initial value to bind aria-attributes such as aria-describedby.
70
+ // This is required for the RadioGroup component which unsets the id value.
71
+ const ariaId = id.value
69
72
 
70
73
  provide(inputIdInjectionKey, id)
71
74
 
@@ -75,7 +78,10 @@ provide(formFieldInjectionKey, computed(() => ({
75
78
  size: props.size,
76
79
  eagerValidation: props.eagerValidation,
77
80
  validateOnInputDelay: props.validateOnInputDelay,
78
- errorPattern: props.errorPattern
81
+ errorPattern: props.errorPattern,
82
+ hint: props.hint,
83
+ description: props.description,
84
+ ariaId
79
85
  }) as FormFieldInjectedOptions<FormFieldProps>))
80
86
  </script>
81
87
 
@@ -88,14 +94,14 @@ provide(formFieldInjectionKey, computed(() => ({
88
94
  {{ label }}
89
95
  </slot>
90
96
  </Label>
91
- <span v-if="hint || !!slots.hint" :class="ui.hint({ class: props.ui?.hint })">
97
+ <span v-if="hint || !!slots.hint" :id="`${ariaId}-hint`" :class="ui.hint({ class: props.ui?.hint })">
92
98
  <slot name="hint" :hint="hint">
93
99
  {{ hint }}
94
100
  </slot>
95
101
  </span>
96
102
  </div>
97
103
 
98
- <p v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
104
+ <p v-if="description || !!slots.description" :id="`${ariaId}-description`" :class="ui.description({ class: props.ui?.description })">
99
105
  <slot name="description" :description="description">
100
106
  {{ description }}
101
107
  </slot>
@@ -105,7 +111,7 @@ provide(formFieldInjectionKey, computed(() => ({
105
111
  <div :class="[(label || !!slots.label || description || !!slots.description) && ui.container({ class: props.ui?.container })]">
106
112
  <slot :error="error" />
107
113
 
108
- <p v-if="(typeof error === 'string' && error) || !!slots.error" :class="ui.error({ class: props.ui?.error })">
114
+ <p v-if="(typeof error === 'string' && error) || !!slots.error" :id="`${ariaId}-error`" :class="ui.error({ class: props.ui?.error })">
109
115
  <slot name="error" :error="error">
110
116
  {{ error }}
111
117
  </slot>
@@ -9,9 +9,9 @@ import { tv } from '../utils/tv'
9
9
  import type { AvatarProps } from '../types'
10
10
  import type { PartialString } from '../types/utils'
11
11
 
12
- const appConfig = _appConfig as AppConfig & { ui: { input: Partial<typeof theme> } }
12
+ const appConfigInput = _appConfig as AppConfig & { ui: { input: Partial<typeof theme> } }
13
13
 
14
- const input = tv({ extend: tv(theme), ...(appConfig.ui?.input || {}) })
14
+ const input = tv({ extend: tv(theme), ...(appConfigInput.ui?.input || {}) })
15
15
 
16
16
  type InputVariants = VariantProps<typeof input>
17
17
 
@@ -75,7 +75,7 @@ const slots = defineSlots<InputSlots>()
75
75
 
76
76
  const [modelValue, modelModifiers] = defineModel<string | number>()
77
77
 
78
- const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props, { deferInputValidation: true })
78
+ const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, emitFormFocus, ariaAttrs } = useFormField<InputProps>(props, { deferInputValidation: true })
79
79
  const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
80
80
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)
81
81
 
@@ -166,10 +166,11 @@ onMounted(() => {
166
166
  :disabled="disabled"
167
167
  :required="required"
168
168
  :autocomplete="autocomplete"
169
- v-bind="$attrs"
169
+ v-bind="{ ...$attrs, ...ariaAttrs }"
170
170
  @input="onInput"
171
171
  @blur="onBlur"
172
172
  @change="onChange"
173
+ @focus="emitFormFocus"
173
174
  >
174
175
 
175
176
  <slot />
@@ -11,9 +11,9 @@ import { tv } from '../utils/tv'
11
11
  import type { AvatarProps, ChipProps, InputProps } from '../types'
12
12
  import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
13
13
 
14
- const appConfig = _appConfig as AppConfig & { ui: { inputMenu: Partial<typeof theme> } }
14
+ const appConfigInputMenu = _appConfig as AppConfig & { ui: { inputMenu: Partial<typeof theme> } }
15
15
 
16
- const inputMenu = tv({ extend: tv(theme), ...(appConfig.ui?.inputMenu || {}) })
16
+ const inputMenu = tv({ extend: tv(theme), ...(appConfigInputMenu.ui?.inputMenu || {}) })
17
17
 
18
18
  export interface InputMenuItem {
19
19
  label?: string
@@ -178,7 +178,7 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', '
178
178
  const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
179
179
  const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
180
180
 
181
- const { emitFormBlur, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
181
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
182
182
  const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
183
183
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
184
184
 
@@ -279,6 +279,7 @@ function onBlur(event: FocusEvent) {
279
279
 
280
280
  function onFocus(event: FocusEvent) {
281
281
  emits('focus', event)
282
+ emitFormFocus()
282
283
  }
283
284
 
284
285
  function onUpdateOpen(value: boolean) {
@@ -365,7 +366,7 @@ defineExpose({
365
366
  <ComboboxInput v-model="searchTerm" :display-value="displayValue" as-child>
366
367
  <TagsInputInput
367
368
  ref="inputRef"
368
- v-bind="$attrs"
369
+ v-bind="{ ...$attrs, ...ariaAttrs }"
369
370
  :placeholder="placeholder"
370
371
  :required="required"
371
372
  :class="ui.tagsInput({ class: props.ui?.tagsInput })"
@@ -379,7 +380,7 @@ defineExpose({
379
380
  ref="inputRef"
380
381
  v-model="searchTerm"
381
382
  :display-value="displayValue"
382
- v-bind="$attrs"
383
+ v-bind="{ ...$attrs, ...ariaAttrs }"
383
384
  :type="type"
384
385
  :placeholder="placeholder"
385
386
  :required="required"
@@ -6,10 +6,11 @@ import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/input-number'
7
7
  import { tv } from '../utils/tv'
8
8
  import type { ButtonProps } from '../types'
9
+ import type { PartialString } from '../types/utils'
9
10
 
10
- const appConfig = _appConfig as AppConfig & { ui: { inputNumber: Partial<typeof theme> } }
11
+ const appConfigInputNumber = _appConfig as AppConfig & { ui: { inputNumber: Partial<typeof theme> } }
11
12
 
12
- const inputNumber = tv({ extend: tv(theme), ...(appConfig.ui?.inputNumber || {}) })
13
+ const inputNumber = tv({ extend: tv(theme), ...(appConfigInputNumber.ui?.inputNumber || {}) })
13
14
 
14
15
  type InputNumberVariants = VariantProps<typeof inputNumber>
15
16
 
@@ -19,10 +20,8 @@ export interface InputNumberProps extends Pick<NumberFieldRootProps, 'modelValue
19
20
  * @defaultValue 'div'
20
21
  */
21
22
  as?: any
22
- class?: any
23
23
  /** The placeholder text when the input is empty. */
24
24
  placeholder?: string
25
- ui?: Partial<typeof inputNumber.slots>
26
25
  color?: InputNumberVariants['color']
27
26
  variant?: InputNumberVariants['variant']
28
27
  size?: InputNumberVariants['size']
@@ -60,6 +59,8 @@ export interface InputNumberProps extends Pick<NumberFieldRootProps, 'modelValue
60
59
  * @defaultValue UApp.locale.code
61
60
  */
62
61
  locale?: string
62
+ class?: any
63
+ ui?: PartialString<typeof inputNumber.slots>
63
64
  }
64
65
 
65
66
  export interface InputNumberEmits {
@@ -78,6 +79,7 @@ export interface InputNumberSlots {
78
79
  import { onMounted, ref, computed } from 'vue'
79
80
  import { NumberFieldRoot, NumberFieldInput, NumberFieldDecrement, NumberFieldIncrement, useForwardPropsEmits } from 'reka-ui'
80
81
  import { reactivePick } from '@vueuse/core'
82
+ import { useAppConfig } from '#imports'
81
83
  import { useFormField } from '../composables/useFormField'
82
84
  import { useLocale } from '../composables/useLocale'
83
85
  import UButton from './Button.vue'
@@ -92,7 +94,8 @@ defineSlots<InputNumberSlots>()
92
94
 
93
95
  const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'min', 'max', 'step', 'formatOptions'), emits)
94
96
 
95
- const { emitFormBlur, emitFormChange, emitFormInput, id, color, size, name, highlight, disabled } = useFormField<InputNumberProps>(props)
97
+ const appConfig = useAppConfig()
98
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, id, color, size, name, highlight, disabled, ariaAttrs } = useFormField<InputNumberProps>(props)
96
99
 
97
100
  const { t, code: codeLocale } = useLocale()
98
101
  const locale = computed(() => props.locale || codeLocale.value)
@@ -152,12 +155,13 @@ defineExpose({
152
155
  @update:model-value="onUpdate"
153
156
  >
154
157
  <NumberFieldInput
155
- v-bind="$attrs"
158
+ v-bind="{ ...$attrs, ...ariaAttrs }"
156
159
  ref="inputRef"
157
160
  :placeholder="placeholder"
158
161
  :required="required"
159
162
  :class="ui.base({ class: props.ui?.base })"
160
163
  @blur="onBlur"
164
+ @focus="emitFormFocus"
161
165
  />
162
166
 
163
167
  <div :class="ui.increment({ class: props.ui?.increment })">
@@ -7,9 +7,9 @@ import type { KbdKey } from '../composables/useKbd'
7
7
  import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import { tv } from '../utils/tv'
9
9
 
10
- const appConfig = _appConfig as AppConfig & { ui: { kbd: Partial<typeof theme> } }
10
+ const appConfigKbd = _appConfig as AppConfig & { ui: { kbd: Partial<typeof theme> } }
11
11
 
12
- const kbd = tv({ extend: tv(theme), ...(appConfig.ui?.kbd || {}) })
12
+ const kbd = tv({ extend: tv(theme), ...(appConfigKbd.ui?.kbd || {}) })
13
13
 
14
14
  type KbdVariants = VariantProps<typeof kbd>
15
15
 
@@ -53,9 +53,9 @@ interface NuxtLinkProps extends Omit<RouterLinkProps, 'to'> {
53
53
  noPrefetch?: boolean
54
54
  }
55
55
 
56
- const appConfig = _appConfig as AppConfig & { ui: { link: Partial<typeof theme> } }
56
+ const appConfigLink = _appConfig as AppConfig & { ui: { link: Partial<typeof theme> } }
57
57
 
58
- const link = tv({ extend: tv(theme), ...(appConfig.ui?.link || {}) })
58
+ const link = tv({ extend: tv(theme), ...(appConfigLink.ui?.link || {}) })
59
59
 
60
60
  export interface LinkProps extends NuxtLinkProps {
61
61
  /**
@@ -7,9 +7,9 @@ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
7
7
  import { tv } from '../utils/tv'
8
8
  import type { ButtonProps } from '../types'
9
9
 
10
- const appConfig = _appConfig as AppConfig & { ui: { modal: Partial<typeof theme> } }
10
+ const appConfigModal = _appConfig as AppConfig & { ui: { modal: Partial<typeof theme> } }
11
11
 
12
- const modal = tv({ extend: tv(theme), ...(appConfig.ui?.modal || {}) })
12
+ const modal = tv({ extend: tv(theme), ...(appConfigModal.ui?.modal || {}) })
13
13
 
14
14
  export interface ModalProps extends DialogRootProps {
15
15
  title?: string
@@ -74,7 +74,7 @@ extendDevtoolsMeta({ example: 'ModalExample' })
74
74
 
75
75
  <script setup lang="ts">
76
76
  import { computed, toRef } from 'vue'
77
- import { DialogRoot, DialogTrigger, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose, useForwardPropsEmits } from 'reka-ui'
77
+ import { DialogRoot, DialogTrigger, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose, VisuallyHidden, useForwardPropsEmits } from 'reka-ui'
78
78
  import { reactivePick } from '@vueuse/core'
79
79
  import { useAppConfig } from '#imports'
80
80
  import { useLocale } from '../composables/useLocale'
@@ -124,6 +124,20 @@ const ui = computed(() => modal({
124
124
  <DialogOverlay v-if="overlay" :class="ui.overlay({ class: props.ui?.overlay })" />
125
125
 
126
126
  <DialogContent :class="ui.content({ class: [!slots.default && props.class, props.ui?.content] })" v-bind="contentProps" v-on="contentEvents">
127
+ <VisuallyHidden v-if="!!slots.content && ((title || !!slots.title) || (description || !!slots.description))">
128
+ <DialogTitle v-if="title || !!slots.title">
129
+ <slot name="title">
130
+ {{ title }}
131
+ </slot>
132
+ </DialogTitle>
133
+
134
+ <DialogDescription v-if="description || !!slots.description">
135
+ <slot name="description">
136
+ {{ description }}
137
+ </slot>
138
+ </DialogDescription>
139
+ </VisuallyHidden>
140
+
127
141
  <slot name="content">
128
142
  <div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description) || (close || !!slots.close)" :class="ui.header({ class: props.ui?.header })">
129
143
  <slot name="header">
@@ -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[]
@@ -47,6 +53,12 @@ export interface NavigationMenuProps<T> extends Pick<NavigationMenuRootProps, 'm
47
53
  * @defaultValue appConfig.ui.icons.chevronDown
48
54
  */
49
55
  trailingIcon?: string
56
+ /**
57
+ * The icon displayed when the item is an external link.
58
+ * Set to `false` to hide the external icon.
59
+ * @defaultValue appConfig.ui.icons.external
60
+ */
61
+ externalIcon?: boolean | string
50
62
  items?: T
51
63
  color?: NavigationMenuVariants['color']
52
64
  variant?: NavigationMenuVariants['variant']
@@ -55,11 +67,23 @@ export interface NavigationMenuProps<T> extends Pick<NavigationMenuRootProps, 'm
55
67
  * @defaultValue 'horizontal'
56
68
  */
57
69
  orientation?: NavigationMenuRootProps['orientation']
70
+ /**
71
+ * Collapse the navigation menu to only show icons.
72
+ * Only works when `orientation` is `vertical`.
73
+ * @defaultValue false
74
+ */
75
+ collapsed?: boolean
58
76
  /** Display a line next to the active item. */
59
77
  highlight?: boolean
60
78
  highlightColor?: NavigationMenuVariants['highlightColor']
61
79
  /** The content of the menu. */
62
80
  content?: Omit<NavigationMenuContentProps, 'as' | 'asChild' | 'forceMount'>
81
+ /**
82
+ * The orientation of the content.
83
+ * Only works when `orientation` is `horizontal`.
84
+ * @defaultValue 'horizontal'
85
+ */
86
+ contentOrientation?: NavigationMenuVariants['contentOrientation']
63
87
  /**
64
88
  * Display an arrow alongside the menu.
65
89
  * @defaultValue false
@@ -130,6 +154,7 @@ extendDevtoolsMeta({
130
154
  import { computed, toRef } from 'vue'
131
155
  import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, useForwardPropsEmits } from 'reka-ui'
132
156
  import { createReusableTemplate } from '@vueuse/core'
157
+ import { useAppConfig } from '#imports'
133
158
  import { get } from '../utils'
134
159
  import { pickLinkProps } from '../utils/link'
135
160
  import ULinkBase from './LinkBase.vue'
@@ -141,6 +166,8 @@ import UCollapsible from './Collapsible.vue'
141
166
 
142
167
  const props = withDefaults(defineProps<NavigationMenuProps<I>>(), {
143
168
  orientation: 'horizontal',
169
+ contentOrientation: 'horizontal',
170
+ externalIcon: true,
144
171
  delayDuration: 0,
145
172
  unmountOnHide: true,
146
173
  labelKey: 'label'
@@ -163,10 +190,20 @@ const rootProps = useForwardPropsEmits(computed(() => ({
163
190
 
164
191
  const contentProps = toRef(() => props.content)
165
192
 
166
- const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, active?: boolean, index: number }>()
193
+ const appConfig = useAppConfig()
194
+ const [DefineLinkTemplate, ReuseLinkTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, active?: boolean }>()
195
+ const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, level?: number }>({
196
+ props: {
197
+ item: Object,
198
+ index: Number,
199
+ level: Number
200
+ }
201
+ })
167
202
 
168
203
  const ui = computed(() => navigationMenu({
169
204
  orientation: props.orientation,
205
+ contentOrientation: props.contentOrientation,
206
+ collapsed: props.collapsed,
170
207
  color: props.color,
171
208
  variant: props.variant,
172
209
  highlight: props.highlight,
@@ -177,22 +214,25 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
177
214
  </script>
178
215
 
179
216
  <template>
180
- <DefineItemTemplate v-slot="{ item, active, index }">
217
+ <DefineLinkTemplate v-slot="{ item, active, index }">
181
218
  <slot :name="item.slot || 'item'" :item="(item as T)" :index="index">
182
219
  <slot :name="item.slot ? `${item.slot}-leading` : 'item-leading'" :item="(item as T)" :active="active" :index="index">
183
220
  <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
221
  <UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ class: props.ui?.linkLeadingIcon, active, disabled: !!item.disabled })" />
185
222
  </slot>
186
223
 
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 })">
224
+ <span
225
+ v-if="(!collapsed || orientation !== 'vertical') && (get(item, props.labelKey as string) || !!slots[item.slot ? `${item.slot}-label` : 'item-label'])"
226
+ :class="ui.linkLabel({ class: props.ui?.linkLabel })"
227
+ >
188
228
  <slot :name="item.slot ? `${item.slot}-label` : 'item-label'" :item="(item as T)" :active="active" :index="index">
189
229
  {{ get(item, props.labelKey as string) }}
190
230
  </slot>
191
231
 
192
- <UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.linkLabelExternalIcon({ class: props.ui?.linkLabelExternalIcon, active })" />
232
+ <UIcon v-if="item.target === '_blank' && externalIcon !== false" :name="typeof externalIcon === 'string' ? externalIcon : appConfig.ui.icons.external" :class="ui.linkLabelExternalIcon({ class: props.ui?.linkLabelExternalIcon, active })" />
193
233
  </span>
194
234
 
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 })">
235
+ <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
236
  <slot :name="item.slot ? `${item.slot}-trailing` : 'item-trailing'" :item="(item as T)" :active="active" :index="index">
197
237
  <UBadge
198
238
  v-if="item.badge"
@@ -208,77 +248,80 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
208
248
  </slot>
209
249
  </span>
210
250
  </slot>
211
- </DefineItemTemplate>
251
+ </DefineLinkTemplate>
212
252
 
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 })">
253
+ <DefineItemTemplate v-slot="{ item, index, level = 0 }">
254
+ <component
255
+ :is="(orientation === 'vertical' && item.children?.length && !collapsed) ? UCollapsible : NavigationMenuItem"
256
+ as="li"
257
+ :value="item.value || String(index)"
258
+ :default-open="item.defaultOpen"
259
+ :unmount-on-hide="(orientation === 'vertical' && item.children?.length && !collapsed) ? unmountOnHide : undefined"
260
+ :open="item.open"
261
+ >
262
+ <div v-if="orientation === 'vertical' && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
263
+ <ReuseLinkTemplate :item="(item as T)" :index="index" />
264
+ </div>
265
+ <ULink v-else-if="item.type !== 'label'" v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length && !collapsed) ? {} : pickLinkProps(item as Omit<NavigationMenuItem, 'type'>)" custom>
216
266
  <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 })"
267
+ :is="(orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) ? NavigationMenuTrigger : NavigationMenuLink"
268
+ as-child
269
+ :active="active || item.active"
270
+ :disabled="item.disabled"
271
+ @select="item.onSelect"
226
272
  >
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>
273
+ <ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: orientation === 'horizontal' || level > 0 })">
274
+ <ReuseLinkTemplate :item="(item as T)" :active="active || item.active" :index="index" />
275
+ </ULinkBase>
276
+ </component>
267
277
 
268
- <template v-if="orientation === 'vertical' && item.children?.length" #content>
278
+ <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 })">
279
+ <slot :name="item.slot ? `${item.slot}-content` : 'item-content'" :item="(item as T)" :active="active" :index="index">
269
280
  <ul :class="ui.childList({ class: props.ui?.childList })">
270
281
  <li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem({ class: props.ui?.childItem })">
271
282
  <ULink v-slot="{ active: childActive, ...childSlotProps }" v-bind="pickLinkProps(childItem)" custom>
272
283
  <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" />
284
+ <ULinkBase v-bind="childSlotProps" :class="ui.childLink({ class: [props.ui?.childLink, childItem.class], active: childActive })">
285
+ <UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ class: props.ui?.childLinkIcon, active: childActive })" />
286
+
287
+ <div :class="ui.childLinkWrapper({ class: props.ui?.childLinkWrapper })">
288
+ <p :class="ui.childLinkLabel({ class: props.ui?.childLinkLabel, active: childActive })">
289
+ {{ get(childItem, props.labelKey as string) }}
290
+
291
+ <UIcon v-if="childItem.target === '_blank' && externalIcon !== false" :name="typeof externalIcon === 'string' ? externalIcon : appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ class: props.ui?.childLinkLabelExternalIcon, active: childActive })" />
292
+ </p>
293
+ <p v-if="childItem.description" :class="ui.childLinkDescription({ class: props.ui?.childLinkDescription, active: childActive })">
294
+ {{ childItem.description }}
295
+ </p>
296
+ </div>
275
297
  </ULinkBase>
276
298
  </NavigationMenuLink>
277
299
  </ULink>
278
300
  </li>
279
301
  </ul>
280
- </template>
281
- </component>
302
+ </slot>
303
+ </NavigationMenuContent>
304
+ </ULink>
305
+
306
+ <template v-if="orientation === 'vertical' && item.children?.length && !collapsed" #content>
307
+ <ul :class="ui.childList({ class: props.ui?.childList })">
308
+ <ReuseItemTemplate
309
+ v-for="(childItem, childIndex) in item.children"
310
+ :key="childIndex"
311
+ :item="childItem"
312
+ :index="childIndex"
313
+ :level="level + 1"
314
+ :class="ui.childItem({ class: props.ui?.childItem })"
315
+ />
316
+ </ul>
317
+ </template>
318
+ </component>
319
+ </DefineItemTemplate>
320
+
321
+ <NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.class, props.ui?.root] })">
322
+ <template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
323
+ <NavigationMenuList :class="ui.list({ class: props.ui?.list })">
324
+ <ReuseItemTemplate v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :item="item" :index="index" :class="ui.item({ class: props.ui?.item })" />
282
325
  </NavigationMenuList>
283
326
 
284
327
  <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