@nuxt/ui 3.2.0 → 3.3.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.
Files changed (175) hide show
  1. package/.nuxt/ui/button.ts +42 -42
  2. package/.nuxt/ui/command-palette.ts +2 -1
  3. package/.nuxt/ui/file-upload.ts +290 -0
  4. package/.nuxt/ui/index.ts +1 -0
  5. package/.nuxt/ui/kbd.ts +167 -3
  6. package/.nuxt/ui/table.ts +8 -0
  7. package/.nuxt/ui/tabs.ts +4 -2
  8. package/.nuxt/ui/toast.ts +8 -15
  9. package/.nuxt/ui/tooltip.ts +1 -1
  10. package/cli/templates.mjs +4 -3
  11. package/dist/module.d.mts +15 -1
  12. package/dist/module.json +1 -1
  13. package/dist/module.mjs +3 -3
  14. package/dist/runtime/components/Accordion.vue.d.ts +1 -1
  15. package/dist/runtime/components/Alert.vue.d.ts +2 -2
  16. package/dist/runtime/components/App.vue.d.ts +1 -1
  17. package/dist/runtime/components/Avatar.vue.d.ts +1 -1
  18. package/dist/runtime/components/AvatarGroup.vue.d.ts +1 -1
  19. package/dist/runtime/components/Badge.vue.d.ts +1 -1
  20. package/dist/runtime/components/Breadcrumb.vue.d.ts +1 -1
  21. package/dist/runtime/components/Button.vue +6 -6
  22. package/dist/runtime/components/Button.vue.d.ts +1 -5
  23. package/dist/runtime/components/ButtonGroup.vue.d.ts +1 -1
  24. package/dist/runtime/components/Calendar.vue.d.ts +1 -1
  25. package/dist/runtime/components/Card.vue.d.ts +1 -1
  26. package/dist/runtime/components/Carousel.vue +18 -14
  27. package/dist/runtime/components/Carousel.vue.d.ts +1 -1
  28. package/dist/runtime/components/Checkbox.vue.d.ts +1 -1
  29. package/dist/runtime/components/CheckboxGroup.vue.d.ts +1 -1
  30. package/dist/runtime/components/Chip.vue.d.ts +2 -2
  31. package/dist/runtime/components/Collapsible.vue.d.ts +1 -1
  32. package/dist/runtime/components/ColorPicker.vue +1 -2
  33. package/dist/runtime/components/ColorPicker.vue.d.ts +1 -1
  34. package/dist/runtime/components/CommandPalette.vue +4 -0
  35. package/dist/runtime/components/CommandPalette.vue.d.ts +6 -1
  36. package/dist/runtime/components/Container.vue.d.ts +1 -1
  37. package/dist/runtime/components/ContextMenu.vue.d.ts +1 -1
  38. package/dist/runtime/components/ContextMenuContent.vue.d.ts +1 -1
  39. package/dist/runtime/components/Drawer.vue +4 -4
  40. package/dist/runtime/components/Drawer.vue.d.ts +6 -1
  41. package/dist/runtime/components/DropdownMenu.vue.d.ts +1 -1
  42. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +8 -5
  43. package/dist/runtime/components/FileUpload.vue +242 -0
  44. package/dist/runtime/components/FileUpload.vue.d.ts +167 -0
  45. package/dist/runtime/components/Form.vue.d.ts +6 -5
  46. package/dist/runtime/components/FormField.vue +2 -2
  47. package/dist/runtime/components/FormField.vue.d.ts +4 -4
  48. package/dist/runtime/components/Icon.vue.d.ts +1 -1
  49. package/dist/runtime/components/Input.vue +10 -7
  50. package/dist/runtime/components/Input.vue.d.ts +9 -9
  51. package/dist/runtime/components/InputMenu.vue +17 -10
  52. package/dist/runtime/components/InputMenu.vue.d.ts +15 -12
  53. package/dist/runtime/components/InputNumber.vue.d.ts +4 -4
  54. package/dist/runtime/components/InputTags.vue +2 -0
  55. package/dist/runtime/components/InputTags.vue.d.ts +5 -3
  56. package/dist/runtime/components/Kbd.vue +2 -1
  57. package/dist/runtime/components/Kbd.vue.d.ts +5 -1
  58. package/dist/runtime/components/Link.vue +6 -5
  59. package/dist/runtime/components/Link.vue.d.ts +1 -3
  60. package/dist/runtime/components/LinkBase.vue.d.ts +1 -1
  61. package/dist/runtime/components/Modal.vue.d.ts +2 -2
  62. package/dist/runtime/components/NavigationMenu.vue +3 -2
  63. package/dist/runtime/components/NavigationMenu.vue.d.ts +1 -1
  64. package/dist/runtime/components/OverlayProvider.vue.d.ts +1 -1
  65. package/dist/runtime/components/Pagination.vue.d.ts +1 -1
  66. package/dist/runtime/components/PinInput.vue.d.ts +1 -1
  67. package/dist/runtime/components/Popover.vue +2 -1
  68. package/dist/runtime/components/Popover.vue.d.ts +8 -2
  69. package/dist/runtime/components/Progress.vue.d.ts +1 -1
  70. package/dist/runtime/components/RadioGroup.vue +1 -1
  71. package/dist/runtime/components/RadioGroup.vue.d.ts +5 -4
  72. package/dist/runtime/components/Select.vue.d.ts +1 -1
  73. package/dist/runtime/components/SelectMenu.vue +9 -6
  74. package/dist/runtime/components/SelectMenu.vue.d.ts +1 -1
  75. package/dist/runtime/components/Separator.vue.d.ts +1 -1
  76. package/dist/runtime/components/Skeleton.vue.d.ts +1 -1
  77. package/dist/runtime/components/Slideover.vue.d.ts +2 -2
  78. package/dist/runtime/components/Slider.vue.d.ts +5 -5
  79. package/dist/runtime/components/Stepper.vue.d.ts +1 -1
  80. package/dist/runtime/components/Switch.vue.d.ts +1 -1
  81. package/dist/runtime/components/Table.vue +83 -8
  82. package/dist/runtime/components/Table.vue.d.ts +20 -4
  83. package/dist/runtime/components/Tabs.vue +11 -2
  84. package/dist/runtime/components/Tabs.vue.d.ts +8 -3
  85. package/dist/runtime/components/Textarea.vue +10 -7
  86. package/dist/runtime/components/Textarea.vue.d.ts +10 -9
  87. package/dist/runtime/components/Timeline.vue.d.ts +1 -1
  88. package/dist/runtime/components/Toast.vue +12 -4
  89. package/dist/runtime/components/Toast.vue.d.ts +14 -13
  90. package/dist/runtime/components/Toaster.vue.d.ts +1 -1
  91. package/dist/runtime/components/Tooltip.vue +2 -1
  92. package/dist/runtime/components/Tooltip.vue.d.ts +8 -2
  93. package/dist/runtime/components/Tree.vue +3 -2
  94. package/dist/runtime/components/Tree.vue.d.ts +1 -1
  95. package/dist/runtime/composables/defineShortcuts.js +5 -3
  96. package/dist/runtime/composables/useAvatarGroup.d.ts +1 -1
  97. package/dist/runtime/composables/useComponentIcons.d.ts +1 -1
  98. package/dist/runtime/composables/useFileUpload.d.ts +19 -0
  99. package/dist/runtime/composables/useFileUpload.js +63 -0
  100. package/dist/runtime/composables/useFormField.d.ts +3 -6
  101. package/dist/runtime/composables/useFormField.js +5 -2
  102. package/dist/runtime/composables/useKbd.d.ts +1 -1
  103. package/dist/runtime/composables/useLocale.js +2 -2
  104. package/dist/runtime/composables/useOverlay.d.ts +28 -1
  105. package/dist/runtime/composables/useOverlay.js +4 -4
  106. package/dist/runtime/composables/usePortal.d.ts +1 -1
  107. package/dist/runtime/inertia/components/Link.vue.d.ts +1 -1
  108. package/dist/runtime/inertia/components/LinkBase.vue.d.ts +1 -1
  109. package/dist/runtime/inertia/stubs.d.ts +1 -0
  110. package/dist/runtime/inertia/stubs.js +4 -2
  111. package/dist/runtime/locale/ar.js +2 -1
  112. package/dist/runtime/locale/az.js +1 -0
  113. package/dist/runtime/locale/bg.js +1 -0
  114. package/dist/runtime/locale/bn.js +1 -0
  115. package/dist/runtime/locale/ca.js +1 -0
  116. package/dist/runtime/locale/ckb.js +2 -1
  117. package/dist/runtime/locale/cs.js +1 -0
  118. package/dist/runtime/locale/da.js +1 -0
  119. package/dist/runtime/locale/de.js +1 -0
  120. package/dist/runtime/locale/el.js +1 -0
  121. package/dist/runtime/locale/en.js +1 -0
  122. package/dist/runtime/locale/es.js +1 -0
  123. package/dist/runtime/locale/et.js +1 -0
  124. package/dist/runtime/locale/fa_ir.js +1 -0
  125. package/dist/runtime/locale/fi.js +1 -0
  126. package/dist/runtime/locale/fr.js +1 -0
  127. package/dist/runtime/locale/he.js +1 -0
  128. package/dist/runtime/locale/hi.js +2 -1
  129. package/dist/runtime/locale/hu.js +1 -0
  130. package/dist/runtime/locale/hy.js +1 -0
  131. package/dist/runtime/locale/id.js +1 -0
  132. package/dist/runtime/locale/it.js +1 -0
  133. package/dist/runtime/locale/ja.js +1 -0
  134. package/dist/runtime/locale/kk.js +1 -0
  135. package/dist/runtime/locale/km.js +2 -1
  136. package/dist/runtime/locale/ko.js +1 -0
  137. package/dist/runtime/locale/ky.js +1 -0
  138. package/dist/runtime/locale/lb.js +1 -0
  139. package/dist/runtime/locale/lt.js +1 -0
  140. package/dist/runtime/locale/mn.js +1 -0
  141. package/dist/runtime/locale/ms.js +1 -0
  142. package/dist/runtime/locale/nb_no.js +1 -0
  143. package/dist/runtime/locale/nl.js +1 -0
  144. package/dist/runtime/locale/pl.js +1 -0
  145. package/dist/runtime/locale/pt.js +1 -0
  146. package/dist/runtime/locale/pt_br.js +1 -0
  147. package/dist/runtime/locale/ro.js +1 -0
  148. package/dist/runtime/locale/ru.js +1 -0
  149. package/dist/runtime/locale/sk.js +1 -0
  150. package/dist/runtime/locale/sl.js +1 -0
  151. package/dist/runtime/locale/sv.js +1 -0
  152. package/dist/runtime/locale/th.js +1 -0
  153. package/dist/runtime/locale/tj.js +1 -0
  154. package/dist/runtime/locale/tr.js +1 -0
  155. package/dist/runtime/locale/ug_cn.js +1 -0
  156. package/dist/runtime/locale/uk.js +1 -0
  157. package/dist/runtime/locale/ur.js +1 -0
  158. package/dist/runtime/locale/uz.js +1 -0
  159. package/dist/runtime/locale/vi.js +1 -0
  160. package/dist/runtime/locale/zh_cn.js +1 -0
  161. package/dist/runtime/locale/zh_tw.js +1 -0
  162. package/dist/runtime/types/index.d.ts +1 -0
  163. package/dist/runtime/types/index.js +1 -0
  164. package/dist/runtime/types/locale.d.ts +1 -0
  165. package/dist/runtime/utils/index.d.ts +1 -0
  166. package/dist/runtime/utils/index.js +9 -0
  167. package/dist/runtime/vue/components/Icon.vue.d.ts +1 -1
  168. package/dist/runtime/vue/components/Link.vue.d.ts +1 -1
  169. package/dist/runtime/vue/stubs.d.ts +1 -0
  170. package/dist/runtime/vue/stubs.js +3 -1
  171. package/dist/shared/{ui.BPVxSPGY.mjs → ui.BkSj2DmF.mjs} +278 -29
  172. package/dist/unplugin.d.mts +2 -0
  173. package/dist/unplugin.mjs +6 -3
  174. package/dist/vite.mjs +1 -1
  175. package/package.json +24 -24
@@ -123,5 +123,5 @@ declare const _default: <T extends CarouselItem>(__VLS_props: NonNullable<Awaite
123
123
  };
124
124
  export default _default;
125
125
  type __VLS_PrettifyLocal<T> = {
126
- [K in keyof T]: T[K];
126
+ [K in keyof T as K]: T[K];
127
127
  } & {};
@@ -56,7 +56,7 @@ export interface CheckboxSlots {
56
56
  }
57
57
  declare const _default: __VLS_WithSlots<import("vue").DefineComponent<CheckboxProps & {
58
58
  modelValue?: boolean | "indeterminate";
59
- }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
59
+ }, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
60
60
  change: (payload: Event) => any;
61
61
  "update:modelValue": (value: boolean | "indeterminate") => any;
62
62
  }, string, import("vue").PublicProps, Readonly<CheckboxProps & {
@@ -80,5 +80,5 @@ declare const _default: <T extends CheckboxGroupItem>(__VLS_props: NonNullable<A
80
80
  };
81
81
  export default _default;
82
82
  type __VLS_PrettifyLocal<T> = {
83
- [K in keyof T]: T[K];
83
+ [K in keyof T as K]: T[K];
84
84
  } & {};
@@ -31,7 +31,7 @@ export interface ChipProps {
31
31
  ui?: Chip['slots'];
32
32
  }
33
33
  export interface ChipEmits {
34
- (e: 'update:show', payload: boolean): void;
34
+ 'update:show': [payload: boolean];
35
35
  }
36
36
  export interface ChipSlots {
37
37
  default(props?: {}): any;
@@ -39,7 +39,7 @@ export interface ChipSlots {
39
39
  }
40
40
  declare const _default: __VLS_WithSlots<import("vue").DefineComponent<ChipProps & {
41
41
  show?: boolean;
42
- }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
42
+ }, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
43
43
  "update:show": (value: boolean) => any;
44
44
  }, string, import("vue").PublicProps, Readonly<ChipProps & {
45
45
  show?: boolean;
@@ -20,7 +20,7 @@ export interface CollapsibleSlots {
20
20
  }): any;
21
21
  content(props?: {}): any;
22
22
  }
23
- declare const _default: __VLS_WithSlots<import("vue").DefineComponent<CollapsibleProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
23
+ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<CollapsibleProps, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
24
24
  "update:open": (value: boolean) => any;
25
25
  }, string, import("vue").PublicProps, Readonly<CollapsibleProps> & Readonly<{
26
26
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
@@ -14,7 +14,7 @@ function HSVtoHSL(hsv) {
14
14
  return {
15
15
  H: hsv.h,
16
16
  S: x === 0 || x === 200 ? 0 : Math.round(hsv.s * hsv.v / (x <= 100 ? x : 200 - x)),
17
- L: Math.round(x / 2)
17
+ L: x / 2
18
18
  };
19
19
  }
20
20
  </script>
@@ -53,7 +53,6 @@ const pickedColor = computed({
53
53
  },
54
54
  set(value) {
55
55
  const color = new ColorTranslator(HSVtoHSL(value), {
56
- decimals: 2,
57
56
  labUnit: "percent",
58
57
  cmykUnit: "percent",
59
58
  cmykFunction: "cmyk"
@@ -34,7 +34,7 @@ export type ColorPickerProps = {
34
34
  };
35
35
  declare const _default: import("vue").DefineComponent<ColorPickerProps & {
36
36
  modelValue?: string;
37
- }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
37
+ }, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
38
38
  "update:modelValue": (value: string | undefined) => any;
39
39
  }, string, import("vue").PublicProps, Readonly<ColorPickerProps & {
40
40
  modelValue?: string;
@@ -271,5 +271,9 @@ function onSelect(e, item) {
271
271
  </slot>
272
272
  </div>
273
273
  </ListboxContent>
274
+
275
+ <div v-if="!!slots.footer" :class="ui.footer({ class: props.ui?.footer })">
276
+ <slot name="footer" :ui="ui" />
277
+ </div>
274
278
  </ListboxRoot>
275
279
  </template>
@@ -142,6 +142,11 @@ export type CommandPaletteSlots<G extends CommandPaletteGroup<T> = CommandPalett
142
142
  'empty'(props: {
143
143
  searchTerm?: string;
144
144
  }): any;
145
+ 'footer'(props: {
146
+ ui: {
147
+ [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string;
148
+ };
149
+ }): any;
145
150
  'back'(props: {
146
151
  ui: {
147
152
  [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string;
@@ -183,5 +188,5 @@ declare const _default: <G extends CommandPaletteGroup<T>, T extends CommandPale
183
188
  };
184
189
  export default _default;
185
190
  type __VLS_PrettifyLocal<T> = {
186
- [K in keyof T]: T[K];
191
+ [K in keyof T as K]: T[K];
187
192
  } & {};
@@ -9,7 +9,7 @@ export interface ContainerProps {
9
9
  export interface ContainerSlots {
10
10
  default(props?: {}): any;
11
11
  }
12
- declare const _default: __VLS_WithSlots<import("vue").DefineComponent<ContainerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ContainerProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ContainerSlots>;
12
+ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<ContainerProps, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ContainerProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ContainerSlots>;
13
13
  export default _default;
14
14
  type __VLS_WithSlots<T, S> = T & {
15
15
  new (): {
@@ -105,5 +105,5 @@ declare const _default: <T extends ArrayOrNested<ContextMenuItem>>(__VLS_props:
105
105
  };
106
106
  export default _default;
107
107
  type __VLS_PrettifyLocal<T> = {
108
- [K in keyof T]: T[K];
108
+ [K in keyof T as K]: T[K];
109
109
  } & {};
@@ -45,5 +45,5 @@ declare const _default: <T extends ArrayOrNested<ContextMenuItem>>(__VLS_props:
45
45
  };
46
46
  export default _default;
47
47
  type __VLS_PrettifyLocal<T> = {
48
- [K in keyof T]: T[K];
48
+ [K in keyof T as K]: T[K];
49
49
  } & {};
@@ -5,7 +5,7 @@ import theme from "#build/ui/drawer";
5
5
  <script setup>
6
6
  import { computed, toRef } from "vue";
7
7
  import { VisuallyHidden, useForwardPropsEmits } from "reka-ui";
8
- import { DrawerRoot, DrawerTrigger, DrawerPortal, DrawerOverlay, DrawerContent, DrawerTitle, DrawerDescription, DrawerHandle } from "vaul-vue";
8
+ import { DrawerRoot, DrawerRootNested, DrawerTrigger, DrawerPortal, DrawerOverlay, DrawerContent, DrawerTitle, DrawerDescription, DrawerHandle } from "vaul-vue";
9
9
  import { reactivePick } from "@vueuse/core";
10
10
  import { useAppConfig } from "#imports";
11
11
  import { usePortal } from "../composables/usePortal";
@@ -19,6 +19,7 @@ const props = defineProps({
19
19
  overlay: { type: Boolean, required: false, default: true },
20
20
  handle: { type: Boolean, required: false, default: true },
21
21
  portal: { type: [Boolean, String], required: false, skipCheck: true, default: true },
22
+ nested: { type: Boolean, required: false },
22
23
  class: { type: null, required: false },
23
24
  ui: { type: null, required: false },
24
25
  activeSnapPoint: { type: [Number, String, null], required: false },
@@ -31,7 +32,6 @@ const props = defineProps({
31
32
  modal: { type: Boolean, required: false, default: true },
32
33
  open: { type: Boolean, required: false },
33
34
  defaultOpen: { type: Boolean, required: false },
34
- nested: { type: Boolean, required: false },
35
35
  direction: { type: String, required: false, default: "bottom" },
36
36
  noBodyStyles: { type: Boolean, required: false },
37
37
  handleOnly: { type: Boolean, required: false },
@@ -54,7 +54,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.drawer || {}
54
54
  </script>
55
55
 
56
56
  <template>
57
- <DrawerRoot v-bind="rootProps">
57
+ <component :is="nested ? DrawerRootNested : DrawerRoot" v-bind="rootProps">
58
58
  <DrawerTrigger v-if="!!slots.default" as-child :class="props.class">
59
59
  <slot />
60
60
  </DrawerTrigger>
@@ -108,5 +108,5 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.drawer || {}
108
108
  </slot>
109
109
  </DrawerContent>
110
110
  </DrawerPortal>
111
- </DrawerRoot>
111
+ </component>
112
112
  </template>
@@ -34,6 +34,11 @@ export interface DrawerProps extends Pick<DrawerRootProps, 'activeSnapPoint' | '
34
34
  * @defaultValue true
35
35
  */
36
36
  portal?: boolean | string | HTMLElement;
37
+ /**
38
+ * Whether the drawer is nested in another drawer.
39
+ * @defaultValue false
40
+ */
41
+ nested?: boolean;
37
42
  class?: any;
38
43
  ui?: Drawer['slots'];
39
44
  }
@@ -48,7 +53,7 @@ export interface DrawerSlots {
48
53
  body(props?: {}): any;
49
54
  footer(props?: {}): any;
50
55
  }
51
- declare const _default: __VLS_WithSlots<import("vue").DefineComponent<DrawerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
56
+ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<DrawerProps, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
52
57
  close: () => any;
53
58
  drag: (percentageDragged: number) => any;
54
59
  "update:open": (open: boolean) => any;
@@ -115,5 +115,5 @@ declare const _default: <T extends ArrayOrNested<DropdownMenuItem>>(__VLS_props:
115
115
  };
116
116
  export default _default;
117
117
  type __VLS_PrettifyLocal<T> = {
118
- [K in keyof T]: T[K];
118
+ [K in keyof T as K]: T[K];
119
119
  } & {};
@@ -2,7 +2,7 @@ import { DropdownMenu } from 'reka-ui/namespaced';
2
2
  import type { DropdownMenuContentProps as RekaDropdownMenuContentProps } from 'reka-ui';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import type theme from '#build/ui/dropdown-menu';
5
- import type { DropdownMenuItem, DropdownMenuSlots } from '../types';
5
+ import type { DropdownMenuItem, DropdownMenuSlots, DynamicSlots, MergeTypes } from '../types';
6
6
  import type { ArrayOrNested, NestedItem, ComponentConfig } from '../types/utils';
7
7
  type DropdownMenu = ComponentConfig<typeof theme, AppConfig, 'dropdownMenu'>;
8
8
  interface DropdownMenuContentProps<T extends ArrayOrNested<DropdownMenuItem>> extends Omit<RekaDropdownMenuContentProps, 'as' | 'asChild' | 'forceMount'> {
@@ -28,9 +28,12 @@ interface DropdownMenuContentProps<T extends ArrayOrNested<DropdownMenuItem>> ex
28
28
  };
29
29
  uiOverride?: DropdownMenu['slots'];
30
30
  }
31
- type DropdownMenuContentSlots<T extends ArrayOrNested<DropdownMenuItem>> = Omit<DropdownMenuSlots<T>, 'default'> & {
31
+ type DropdownMenuContentSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayOrNested<DropdownMenuItem>, T extends NestedItem<A> = NestedItem<A>> = Pick<DropdownMenuSlots<A>, 'item' | 'item-leading' | 'item-label' | 'item-trailing' | 'content-top' | 'content-bottom'> & {
32
32
  default(props?: {}): any;
33
- };
33
+ } & DynamicSlots<MergeTypes<T>, 'leading' | 'label' | 'trailing', {
34
+ active?: boolean;
35
+ index: number;
36
+ }>;
34
37
  declare const _default: <T extends ArrayOrNested<DropdownMenuItem>>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
35
38
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
36
39
  readonly onEscapeKeyDown?: ((event: KeyboardEvent) => any) | undefined;
@@ -41,12 +44,12 @@ declare const _default: <T extends ArrayOrNested<DropdownMenuItem>>(__VLS_props:
41
44
  } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onEscapeKeyDown" | "onPointerDownOutside" | "onFocusOutside" | "onInteractOutside" | "onCloseAutoFocus"> & DropdownMenuContentProps<T> & Partial<{}>> & import("vue").PublicProps;
42
45
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
43
46
  attrs: any;
44
- slots: DropdownMenuContentSlots<T>;
47
+ slots: DropdownMenuContentSlots<T, NestedItem<T>>;
45
48
  emit: ((evt: "escapeKeyDown", event: KeyboardEvent) => void) & ((evt: "pointerDownOutside", event: import("reka-ui").PointerDownOutsideEvent) => void) & ((evt: "focusOutside", event: import("reka-ui").FocusOutsideEvent) => void) & ((evt: "interactOutside", event: import("reka-ui").PointerDownOutsideEvent | import("reka-ui").FocusOutsideEvent) => void) & ((evt: "closeAutoFocus", event: Event) => void);
46
49
  }>) => import("vue").VNode & {
47
50
  __ctx?: Awaited<typeof __VLS_setup>;
48
51
  };
49
52
  export default _default;
50
53
  type __VLS_PrettifyLocal<T> = {
51
- [K in keyof T]: T[K];
54
+ [K in keyof T as K]: T[K];
52
55
  } & {};
@@ -0,0 +1,242 @@
1
+ <script>
2
+ import theme from "#build/ui/file-upload";
3
+ </script>
4
+
5
+ <script setup>
6
+ import { computed, watch } from "vue";
7
+ import { Primitive } from "reka-ui";
8
+ import { createReusableTemplate } from "@vueuse/core";
9
+ import { useAppConfig } from "#imports";
10
+ import { useFormField } from "../composables/useFormField";
11
+ import { useFileUpload } from "../composables/useFileUpload";
12
+ import { tv } from "../utils/tv";
13
+ import UAvatar from "./Avatar.vue";
14
+ import UButton from "./Button.vue";
15
+ import UIcon from "./Icon.vue";
16
+ defineOptions({ inheritAttrs: false });
17
+ const props = defineProps({
18
+ as: { type: null, required: false },
19
+ id: { type: String, required: false },
20
+ name: { type: String, required: false },
21
+ icon: { type: String, required: false },
22
+ label: { type: String, required: false },
23
+ description: { type: String, required: false },
24
+ color: { type: null, required: false },
25
+ variant: { type: null, required: false },
26
+ size: { type: null, required: false },
27
+ layout: { type: null, required: false, default: "grid" },
28
+ position: { type: null, required: false, default: "outside" },
29
+ highlight: { type: Boolean, required: false },
30
+ accept: { type: String, required: false, default: "*" },
31
+ multiple: { type: Boolean, required: false, default: false },
32
+ reset: { type: Boolean, required: false, default: false },
33
+ dropzone: { type: Boolean, required: false, default: true },
34
+ interactive: { type: Boolean, required: false, default: true },
35
+ required: { type: Boolean, required: false },
36
+ disabled: { type: Boolean, required: false },
37
+ fileIcon: { type: String, required: false },
38
+ fileDelete: { type: [Boolean, Object], required: false },
39
+ fileDeleteIcon: { type: String, required: false },
40
+ class: { type: null, required: false },
41
+ ui: { type: null, required: false }
42
+ });
43
+ const emits = defineEmits(["update:modelValue", "change"]);
44
+ const slots = defineSlots();
45
+ const modelValue = defineModel({ type: null });
46
+ const appConfig = useAppConfig();
47
+ const [DefineFilesTemplate, ReuseFilesTemplate] = createReusableTemplate();
48
+ const { isDragging, open, inputRef, dropzoneRef } = useFileUpload({
49
+ accept: props.accept,
50
+ reset: props.reset,
51
+ multiple: props.multiple,
52
+ dropzone: props.dropzone,
53
+ onUpdate
54
+ });
55
+ const { emitFormInput, emitFormChange, id, name, disabled, ariaAttrs } = useFormField(props);
56
+ const variant = computed(() => props.multiple ? "area" : props.variant);
57
+ const layout = computed(() => props.variant === "button" && !props.multiple ? "grid" : props.layout);
58
+ const position = computed(() => {
59
+ if (layout.value === "grid" && props.multiple) {
60
+ return "inside";
61
+ }
62
+ if (variant.value === "button") {
63
+ return "outside";
64
+ }
65
+ return props.position;
66
+ });
67
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.fileUpload || {} })({
68
+ dropzone: props.dropzone,
69
+ interactive: props.interactive,
70
+ color: props.color,
71
+ size: props.size,
72
+ variant: variant.value,
73
+ layout: layout.value,
74
+ position: position.value,
75
+ multiple: props.multiple,
76
+ highlight: props.highlight,
77
+ disabled: props.disabled
78
+ }));
79
+ function createObjectUrl(file) {
80
+ return URL.createObjectURL(file);
81
+ }
82
+ function formatFileSize(bytes) {
83
+ if (bytes === 0) {
84
+ return "0B";
85
+ }
86
+ const k = 1024;
87
+ const sizes = ["B", "KB", "MB", "GB"];
88
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
89
+ const size = bytes / Math.pow(k, i);
90
+ const formattedSize = i === 0 ? size.toString() : size.toFixed(0);
91
+ return `${formattedSize}${sizes[i]}`;
92
+ }
93
+ function onUpdate(files, reset = false) {
94
+ if (props.multiple) {
95
+ if (reset) {
96
+ modelValue.value = files;
97
+ } else {
98
+ const existingFiles = modelValue.value || [];
99
+ modelValue.value = [...existingFiles, ...files || []];
100
+ }
101
+ } else {
102
+ modelValue.value = files?.[0];
103
+ }
104
+ const event = new Event("change", { target: { value: modelValue.value } });
105
+ emits("change", event);
106
+ emitFormChange();
107
+ emitFormInput();
108
+ }
109
+ function removeFile(index) {
110
+ if (!modelValue.value) {
111
+ return;
112
+ }
113
+ if (!props.multiple || index === void 0) {
114
+ onUpdate([], true);
115
+ return;
116
+ }
117
+ const files = [...modelValue.value];
118
+ files.splice(index, 1);
119
+ onUpdate(files, true);
120
+ }
121
+ watch(modelValue, (newValue) => {
122
+ const hasModelReset = !Array.isArray(newValue) || !newValue.length;
123
+ if (hasModelReset && inputRef.value) {
124
+ inputRef.value.value = "";
125
+ }
126
+ });
127
+ defineExpose({
128
+ inputRef,
129
+ dropzoneRef
130
+ });
131
+ </script>
132
+
133
+ <template>
134
+ <DefineFilesTemplate>
135
+ <template v-if="modelValue && (Array.isArray(modelValue) ? modelValue.length : true)">
136
+ <slot name="files-top" :files="modelValue" :open="open" :remove-file="removeFile" />
137
+
138
+ <div :class="ui.files({ class: props.ui?.files })">
139
+ <slot name="files" :files="modelValue">
140
+ <div v-for="(file, index) in Array.isArray(modelValue) ? modelValue : [modelValue]" :key="file.name" :class="ui.file({ class: props.ui?.file })">
141
+ <slot name="file" :file="file" :index="index">
142
+ <slot name="file-leading" :file="file" :index="index">
143
+ <UAvatar :src="createObjectUrl(file)" :icon="fileIcon || appConfig.ui.icons.file" :size="props.size" :class="ui.fileLeadingAvatar({ class: props.ui?.fileLeadingAvatar })" />
144
+ </slot>
145
+
146
+ <div :class="ui.fileWrapper({ class: props.ui?.fileWrapper })">
147
+ <span :class="ui.fileName({ class: props.ui?.fileName })">
148
+ <slot name="file-name" :file="file" :index="index">
149
+ {{ file.name }}
150
+ </slot>
151
+ </span>
152
+
153
+ <span :class="ui.fileSize({ class: props.ui?.fileSize })">
154
+ <slot name="file-size" :file="file" :index="index">
155
+ {{ formatFileSize(file.size) }}
156
+ </slot>
157
+ </span>
158
+ </div>
159
+
160
+ <slot name="file-trailing" :file="file" :index="index">
161
+ <UButton
162
+ color="neutral"
163
+ v-bind="{
164
+ ...layout === 'grid' ? {
165
+ variant: 'solid',
166
+ size: 'xs'
167
+ } : {
168
+ variant: 'link',
169
+ size
170
+ },
171
+ ...typeof fileDelete === 'object' ? fileDelete : void 0
172
+ }"
173
+ :trailing-icon="fileDeleteIcon || appConfig.ui.icons.close"
174
+ :class="ui.fileTrailingButton({ class: props.ui?.fileTrailingButton })"
175
+ @click.stop.prevent="removeFile(index)"
176
+ />
177
+ </slot>
178
+ </slot>
179
+ </div>
180
+ </slot>
181
+ </div>
182
+
183
+ <slot name="files-bottom" :files="modelValue" :open="open" :remove-file="removeFile" />
184
+ </template>
185
+ </DefineFilesTemplate>
186
+
187
+ <Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
188
+ <slot :open="open" :remove-file="removeFile">
189
+ <component
190
+ :is="variant === 'button' ? 'button' : 'div'"
191
+ ref="dropzoneRef"
192
+ :role="variant === 'button' ? void 0 : 'button'"
193
+ :data-dragging="isDragging"
194
+ :class="ui.base({ class: props.ui?.base })"
195
+ :tabindex="interactive && !disabled ? 0 : -1"
196
+ @click="interactive && !disabled && open()"
197
+ >
198
+ <ReuseFilesTemplate v-if="position === 'inside'" />
199
+
200
+ <div v-if="position === 'inside' ? multiple ? !modelValue?.length : !modelValue : true" :class="ui.wrapper({ class: props.ui?.wrapper })">
201
+ <slot name="leading">
202
+ <UIcon v-if="variant === 'button'" :name="icon || appConfig.ui.icons.upload" :class="ui.icon({ class: props.ui?.icon })" />
203
+ <UAvatar v-else :icon="icon || appConfig.ui.icons.upload" :size="props.size" :class="ui.avatar({ class: props.ui?.avatar })" />
204
+ </slot>
205
+
206
+ <template v-if="variant !== 'button'">
207
+ <div v-if="label || !!slots.label" :class="ui.label({ class: props.ui?.label })">
208
+ <slot name="label">
209
+ {{ label }}
210
+ </slot>
211
+ </div>
212
+ <div v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
213
+ <slot name="description">
214
+ {{ description }}
215
+ </slot>
216
+ </div>
217
+
218
+ <div v-if="!!slots.actions" :class="ui.actions({ class: props.ui?.actions })">
219
+ <slot name="actions" :files="modelValue" :open="open" :remove-file="removeFile" />
220
+ </div>
221
+ </template>
222
+ </div>
223
+ </component>
224
+
225
+ <ReuseFilesTemplate v-if="position === 'outside'" />
226
+ </slot>
227
+
228
+ <input
229
+ :id="id"
230
+ ref="inputRef"
231
+ type="file"
232
+ :name="name"
233
+ :accept="accept"
234
+ :multiple="multiple"
235
+ :required="required"
236
+ :disabled="disabled"
237
+ v-bind="{ ...$attrs, ...ariaAttrs }"
238
+ class="sr-only"
239
+ tabindex="-1"
240
+ >
241
+ </Primitive>
242
+ </template>
@@ -0,0 +1,167 @@
1
+ import type { AppConfig } from '@nuxt/schema';
2
+ import type { UseFileDialogReturn } from '@vueuse/core';
3
+ import theme from '#build/ui/file-upload';
4
+ import type { ButtonProps } from '../types';
5
+ import type { ComponentConfig } from '../types/utils';
6
+ type FileUpload = ComponentConfig<typeof theme, AppConfig, 'fileUpload'>;
7
+ export interface FileUploadProps<M extends boolean = false> {
8
+ /**
9
+ * The element or component this component should render as.
10
+ * @defaultValue 'div'
11
+ */
12
+ as?: any;
13
+ id?: string;
14
+ name?: string;
15
+ /**
16
+ * The icon to display.
17
+ * @defaultValue appConfig.ui.icons.upload
18
+ * @IconifyIcon
19
+ */
20
+ icon?: string;
21
+ label?: string;
22
+ description?: string;
23
+ /**
24
+ * @defaultValue 'primary'
25
+ */
26
+ color?: FileUpload['variants']['color'];
27
+ /**
28
+ * The `button` variant is only available when `multiple` is `false`.
29
+ * @defaultValue 'area'
30
+ */
31
+ variant?: FileUpload['variants']['variant'];
32
+ /**
33
+ * @defaultValue 'md'
34
+ */
35
+ size?: FileUpload['variants']['size'];
36
+ /**
37
+ * The layout of how files are displayed.
38
+ * Only works when `variant` is `area`.
39
+ * @defaultValue 'list'
40
+ */
41
+ layout?: FileUpload['variants']['layout'];
42
+ /**
43
+ * The position of the files.
44
+ * Only works when `variant` is `area` and when `layout` is `list`.
45
+ * @defaultValue 'outside'
46
+ */
47
+ position?: FileUpload['variants']['position'];
48
+ /** Highlight the ring color like a focus state. */
49
+ highlight?: boolean;
50
+ /**
51
+ * Specifies the allowed file types for the input. Provide a comma-separated list of MIME types or file extensions (e.g., "image/png,application/pdf,.jpg").
52
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/accept
53
+ * @defaultValue '*'
54
+ */
55
+ accept?: string;
56
+ multiple?: M & boolean;
57
+ /**
58
+ * Reset the file input when the dialog is opened.
59
+ * @defaultValue false
60
+ */
61
+ reset?: boolean;
62
+ /**
63
+ * Create a zone that allows the user to drop files onto it.
64
+ * @defaultValue true
65
+ */
66
+ dropzone?: boolean;
67
+ /**
68
+ * Make the dropzone interactive when the user is clicking on it.
69
+ * @defaultValue true
70
+ */
71
+ interactive?: boolean;
72
+ required?: boolean;
73
+ disabled?: boolean;
74
+ /**
75
+ * The icon to display for the file.
76
+ * @defaultValue appConfig.ui.icons.file
77
+ * @IconifyIcon
78
+ */
79
+ fileIcon?: string;
80
+ /**
81
+ * Configure the delete button for the file.
82
+ * When `layout` is `grid`, the default is `{ color: 'neutral', variant: 'solid', size: 'xs' }`{lang="ts-type"}
83
+ * When `layout` is `list`, the default is `{ color: 'neutral', variant: 'link' }`{lang="ts-type"}
84
+ */
85
+ fileDelete?: boolean | Partial<ButtonProps>;
86
+ /**
87
+ * The icon displayed to delete a file.
88
+ * @defaultValue appConfig.ui.icons.close
89
+ * @IconifyIcon
90
+ */
91
+ fileDeleteIcon?: string;
92
+ class?: any;
93
+ ui?: FileUpload['slots'];
94
+ }
95
+ export interface FileUploadEmits<M extends boolean = false> {
96
+ 'update:modelValue': [payload: M extends true ? File[] : File | null];
97
+ 'change': [event: Event];
98
+ }
99
+ type FileUploadFiles<M> = (M extends true ? File[] : File) | null;
100
+ export interface FileUploadSlots<M extends boolean = false> {
101
+ 'default'(props: {
102
+ open: UseFileDialogReturn['open'];
103
+ removeFile: (index?: number) => void;
104
+ }): any;
105
+ 'leading'(props?: {}): any;
106
+ 'label'(props?: {}): any;
107
+ 'description'(props?: {}): any;
108
+ 'actions'(props: {
109
+ files?: FileUploadFiles<M>;
110
+ open: UseFileDialogReturn['open'];
111
+ removeFile: (index?: number) => void;
112
+ }): any;
113
+ 'files'(props: {
114
+ files?: FileUploadFiles<M>;
115
+ }): any;
116
+ 'files-top'(props: {
117
+ files?: FileUploadFiles<M>;
118
+ open: UseFileDialogReturn['open'];
119
+ removeFile: (index?: number) => void;
120
+ }): any;
121
+ 'files-bottom'(props: {
122
+ files?: FileUploadFiles<M>;
123
+ open: UseFileDialogReturn['open'];
124
+ removeFile: (index?: number) => void;
125
+ }): any;
126
+ 'file'(props: {
127
+ file: File;
128
+ index: number;
129
+ }): any;
130
+ 'file-leading'(props: {
131
+ file: File;
132
+ index: number;
133
+ }): any;
134
+ 'file-name'(props: {
135
+ file: File;
136
+ index: number;
137
+ }): any;
138
+ 'file-size'(props: {
139
+ file: File;
140
+ index: number;
141
+ }): any;
142
+ 'file-trailing'(props: {
143
+ file: File;
144
+ index: number;
145
+ }): any;
146
+ }
147
+ declare const _default: <M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
148
+ props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
149
+ readonly onChange?: ((event: Event) => any) | undefined;
150
+ readonly "onUpdate:modelValue"?: ((...args: unknown[]) => any) | undefined;
151
+ } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onChange" | "onUpdate:modelValue"> & (FileUploadProps<M> & {
152
+ modelValue?: (M extends true ? File[] : File) | null;
153
+ }) & Partial<{}>> & import("vue").PublicProps;
154
+ expose(exposed: import("vue").ShallowUnwrapRef<{
155
+ inputRef: import("vue").Ref<HTMLInputElement | undefined, HTMLInputElement | undefined>;
156
+ dropzoneRef: import("vue").Ref<HTMLDivElement | undefined, HTMLDivElement | undefined>;
157
+ }>): void;
158
+ attrs: any;
159
+ slots: FileUploadSlots<M>;
160
+ emit: (((evt: "change", event: Event) => void) & ((evt: "update:modelValue", payload: M extends true ? File[] : File | null) => void)) & ((evt: "update:modelValue", value: (M extends true ? File[] : File) | null | undefined) => void);
161
+ }>) => import("vue").VNode & {
162
+ __ctx?: Awaited<typeof __VLS_setup>;
163
+ };
164
+ export default _default;
165
+ type __VLS_PrettifyLocal<T> = {
166
+ [K in keyof T as K]: T[K];
167
+ } & {};