@nuxt/ui 4.5.1 → 4.6.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 (177) hide show
  1. package/dist/module.d.mts +7 -0
  2. package/dist/module.json +2 -2
  3. package/dist/module.mjs +78 -67
  4. package/dist/runtime/components/Avatar.vue +10 -12
  5. package/dist/runtime/components/Banner.vue +1 -1
  6. package/dist/runtime/components/BlogPost.vue +3 -2
  7. package/dist/runtime/components/Calendar.d.vue.ts +4 -4
  8. package/dist/runtime/components/Calendar.vue.d.ts +4 -4
  9. package/dist/runtime/components/ChangelogVersion.vue +3 -2
  10. package/dist/runtime/components/ChangelogVersions.vue +1 -1
  11. package/dist/runtime/components/ChatMessage.d.vue.ts +4 -1
  12. package/dist/runtime/components/ChatMessage.vue +5 -0
  13. package/dist/runtime/components/ChatMessage.vue.d.ts +4 -1
  14. package/dist/runtime/components/ChatReasoning.d.vue.ts +78 -0
  15. package/dist/runtime/components/ChatReasoning.vue +162 -0
  16. package/dist/runtime/components/ChatReasoning.vue.d.ts +78 -0
  17. package/dist/runtime/components/ChatShimmer.d.vue.ts +34 -0
  18. package/dist/runtime/components/ChatShimmer.vue +37 -0
  19. package/dist/runtime/components/ChatShimmer.vue.d.ts +34 -0
  20. package/dist/runtime/components/ChatTool.d.vue.ts +88 -0
  21. package/dist/runtime/components/ChatTool.vue +105 -0
  22. package/dist/runtime/components/ChatTool.vue.d.ts +88 -0
  23. package/dist/runtime/components/Checkbox.d.vue.ts +22 -19
  24. package/dist/runtime/components/Checkbox.vue +9 -8
  25. package/dist/runtime/components/Checkbox.vue.d.ts +22 -19
  26. package/dist/runtime/components/DashboardGroup.d.vue.ts +1 -1
  27. package/dist/runtime/components/DashboardGroup.vue.d.ts +1 -1
  28. package/dist/runtime/components/DashboardSearchButton.vue +2 -2
  29. package/dist/runtime/components/Drawer.vue +1 -1
  30. package/dist/runtime/components/DropdownMenu.d.vue.ts +29 -3
  31. package/dist/runtime/components/DropdownMenu.vue +9 -0
  32. package/dist/runtime/components/DropdownMenu.vue.d.ts +29 -3
  33. package/dist/runtime/components/DropdownMenuContent.d.vue.ts +9 -3
  34. package/dist/runtime/components/DropdownMenuContent.vue +62 -9
  35. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +9 -3
  36. package/dist/runtime/components/EditorDragHandle.d.vue.ts +4 -4
  37. package/dist/runtime/components/EditorDragHandle.vue.d.ts +4 -4
  38. package/dist/runtime/components/Error.vue +5 -5
  39. package/dist/runtime/components/FileUpload.d.vue.ts +6 -0
  40. package/dist/runtime/components/FileUpload.vue +11 -7
  41. package/dist/runtime/components/FileUpload.vue.d.ts +6 -0
  42. package/dist/runtime/components/Icon.d.vue.ts +2 -1
  43. package/dist/runtime/components/Icon.vue +1 -1
  44. package/dist/runtime/components/Icon.vue.d.ts +2 -1
  45. package/dist/runtime/components/InputDate.d.vue.ts +4 -4
  46. package/dist/runtime/components/InputDate.vue.d.ts +4 -4
  47. package/dist/runtime/components/InputMenu.d.vue.ts +7 -1
  48. package/dist/runtime/components/InputMenu.vue +67 -48
  49. package/dist/runtime/components/InputMenu.vue.d.ts +7 -1
  50. package/dist/runtime/components/InputTime.d.vue.ts +53 -27
  51. package/dist/runtime/components/InputTime.vue +52 -27
  52. package/dist/runtime/components/InputTime.vue.d.ts +53 -27
  53. package/dist/runtime/components/Kbd.vue +1 -1
  54. package/dist/runtime/components/Modal.vue +1 -1
  55. package/dist/runtime/components/NavigationMenu.vue +1 -0
  56. package/dist/runtime/components/Popover.vue +1 -1
  57. package/dist/runtime/components/Progress.d.vue.ts +1 -1
  58. package/dist/runtime/components/Progress.vue.d.ts +1 -1
  59. package/dist/runtime/components/SelectMenu.d.vue.ts +1 -1
  60. package/dist/runtime/components/SelectMenu.vue +1 -1
  61. package/dist/runtime/components/SelectMenu.vue.d.ts +1 -1
  62. package/dist/runtime/components/Sidebar.d.vue.ts +131 -0
  63. package/dist/runtime/components/Sidebar.vue +222 -0
  64. package/dist/runtime/components/Sidebar.vue.d.ts +131 -0
  65. package/dist/runtime/components/Slideover.vue +1 -1
  66. package/dist/runtime/components/Switch.d.vue.ts +22 -19
  67. package/dist/runtime/components/Switch.vue +7 -6
  68. package/dist/runtime/components/Switch.vue.d.ts +22 -19
  69. package/dist/runtime/components/Table.d.vue.ts +1 -1
  70. package/dist/runtime/components/Table.vue +12 -4
  71. package/dist/runtime/components/Table.vue.d.ts +1 -1
  72. package/dist/runtime/components/Tooltip.d.vue.ts +2 -0
  73. package/dist/runtime/components/Tooltip.vue +3 -2
  74. package/dist/runtime/components/Tooltip.vue.d.ts +2 -0
  75. package/dist/runtime/components/color-mode/ColorModeSelect.d.vue.ts +1 -1
  76. package/dist/runtime/components/color-mode/ColorModeSelect.vue.d.ts +1 -1
  77. package/dist/runtime/components/color-mode/ColorModeSwitch.vue +3 -1
  78. package/dist/runtime/components/content/ContentNavigation.vue +9 -2
  79. package/dist/runtime/components/content/ContentSurround.vue +6 -2
  80. package/dist/runtime/components/content/ContentToc.d.vue.ts +5 -0
  81. package/dist/runtime/components/content/ContentToc.vue +57 -11
  82. package/dist/runtime/components/content/ContentToc.vue.d.ts +5 -0
  83. package/dist/runtime/components/locale/LocaleSelect.d.vue.ts +1 -1
  84. package/dist/runtime/components/locale/LocaleSelect.vue.d.ts +1 -1
  85. package/dist/runtime/components/prose/Pre.vue +0 -4
  86. package/dist/runtime/composables/index.d.ts +11 -0
  87. package/dist/runtime/composables/index.js +11 -0
  88. package/dist/runtime/composables/useEditorMenu.js +1 -1
  89. package/dist/runtime/composables/useFileUpload.d.ts +2 -2
  90. package/dist/runtime/composables/useFileUpload.js +3 -3
  91. package/dist/runtime/composables/{internal/useFilter.js → useFilter.js} +1 -1
  92. package/dist/runtime/composables/useScrollShadow.d.ts +23 -0
  93. package/dist/runtime/composables/useScrollShadow.js +36 -0
  94. package/dist/runtime/index.css +1 -1
  95. package/dist/runtime/keyframes.css +1 -1
  96. package/dist/runtime/locale/ar.js +13 -0
  97. package/dist/runtime/locale/az.js +13 -0
  98. package/dist/runtime/locale/be.js +13 -0
  99. package/dist/runtime/locale/bg.js +13 -0
  100. package/dist/runtime/locale/bn.js +13 -0
  101. package/dist/runtime/locale/ca.js +13 -0
  102. package/dist/runtime/locale/ckb.js +13 -0
  103. package/dist/runtime/locale/cs.js +13 -0
  104. package/dist/runtime/locale/da.js +13 -0
  105. package/dist/runtime/locale/de.js +13 -0
  106. package/dist/runtime/locale/de_ch.js +13 -0
  107. package/dist/runtime/locale/el.js +13 -0
  108. package/dist/runtime/locale/en.js +13 -0
  109. package/dist/runtime/locale/es.js +13 -0
  110. package/dist/runtime/locale/et.js +13 -0
  111. package/dist/runtime/locale/eu.js +13 -0
  112. package/dist/runtime/locale/fa_ir.js +13 -0
  113. package/dist/runtime/locale/fi.js +13 -0
  114. package/dist/runtime/locale/fr.js +13 -0
  115. package/dist/runtime/locale/gl.js +13 -0
  116. package/dist/runtime/locale/he.js +13 -0
  117. package/dist/runtime/locale/hi.js +13 -0
  118. package/dist/runtime/locale/hr.js +13 -0
  119. package/dist/runtime/locale/hu.js +13 -0
  120. package/dist/runtime/locale/hy.js +13 -0
  121. package/dist/runtime/locale/id.js +13 -0
  122. package/dist/runtime/locale/index.d.ts +1 -0
  123. package/dist/runtime/locale/index.js +1 -0
  124. package/dist/runtime/locale/is.d.ts +3 -0
  125. package/dist/runtime/locale/is.js +142 -0
  126. package/dist/runtime/locale/it.js +13 -0
  127. package/dist/runtime/locale/ja.js +13 -0
  128. package/dist/runtime/locale/ka.js +13 -0
  129. package/dist/runtime/locale/kk.js +13 -0
  130. package/dist/runtime/locale/km.js +13 -0
  131. package/dist/runtime/locale/ko.js +13 -0
  132. package/dist/runtime/locale/ky.js +13 -0
  133. package/dist/runtime/locale/lb.js +13 -0
  134. package/dist/runtime/locale/lo.js +13 -0
  135. package/dist/runtime/locale/lt.js +13 -0
  136. package/dist/runtime/locale/mn.js +13 -0
  137. package/dist/runtime/locale/ms.js +13 -0
  138. package/dist/runtime/locale/nb_no.js +13 -0
  139. package/dist/runtime/locale/nl.js +13 -0
  140. package/dist/runtime/locale/pl.js +13 -0
  141. package/dist/runtime/locale/pt.js +13 -0
  142. package/dist/runtime/locale/pt_br.js +13 -0
  143. package/dist/runtime/locale/ro.js +13 -0
  144. package/dist/runtime/locale/ru.js +13 -0
  145. package/dist/runtime/locale/sk.js +13 -0
  146. package/dist/runtime/locale/sl.js +13 -0
  147. package/dist/runtime/locale/sq.js +13 -0
  148. package/dist/runtime/locale/sv.js +13 -0
  149. package/dist/runtime/locale/th.js +13 -0
  150. package/dist/runtime/locale/tj.js +13 -0
  151. package/dist/runtime/locale/tr.js +13 -0
  152. package/dist/runtime/locale/ug_cn.js +13 -0
  153. package/dist/runtime/locale/uk.js +13 -0
  154. package/dist/runtime/locale/ur.js +13 -0
  155. package/dist/runtime/locale/uz.js +13 -0
  156. package/dist/runtime/locale/vi.js +13 -0
  157. package/dist/runtime/locale/zh_cn.js +13 -0
  158. package/dist/runtime/locale/zh_tw.js +13 -0
  159. package/dist/runtime/types/index.d.ts +4 -0
  160. package/dist/runtime/types/index.js +4 -0
  161. package/dist/runtime/types/locale.d.ts +13 -0
  162. package/dist/runtime/utils/ai.d.ts +18 -0
  163. package/dist/runtime/utils/ai.js +13 -0
  164. package/dist/runtime/utils/editor.js +17 -5
  165. package/dist/runtime/vue/components/Icon.d.vue.ts +1 -4
  166. package/dist/runtime/vue/components/Icon.vue +28 -3
  167. package/dist/runtime/vue/components/Icon.vue.d.ts +1 -4
  168. package/dist/runtime/vue/components/color-mode/ColorModeSelect.d.vue.ts +1 -1
  169. package/dist/runtime/vue/components/color-mode/ColorModeSelect.vue.d.ts +1 -1
  170. package/dist/runtime/vue/components/color-mode/ColorModeSwitch.vue +3 -1
  171. package/dist/shared/{ui.DI_ypO2T.mjs → ui.DJUbBpE2.mjs} +298 -39
  172. package/dist/unplugin.d.mts +15 -5
  173. package/dist/unplugin.mjs +53 -30
  174. package/dist/vite.d.mts +1 -0
  175. package/dist/vite.mjs +1 -1
  176. package/package.json +49 -46
  177. /package/dist/runtime/composables/{internal/useFilter.d.ts → useFilter.d.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import type { CheckboxRootProps } from 'reka-ui';
1
+ import type { CheckboxRootProps, CheckboxRootEmits } from 'reka-ui';
2
2
  import type { VNode } from 'vue';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import theme from '#build/ui/checkbox';
@@ -6,7 +6,7 @@ import type { IconProps } from '../types';
6
6
  import type { ButtonHTMLAttributes } from '../types/html';
7
7
  import type { ComponentConfig } from '../types/tv';
8
8
  type Checkbox = ComponentConfig<typeof theme, AppConfig, 'checkbox'>;
9
- export interface CheckboxProps extends Pick<CheckboxRootProps, 'disabled' | 'required' | 'name' | 'value' | 'id' | 'defaultValue'>, /** @vue-ignore */ Omit<ButtonHTMLAttributes, 'type' | 'disabled' | 'name'> {
9
+ export interface CheckboxProps<T = boolean> extends Pick<CheckboxRootProps<T>, 'disabled' | 'required' | 'name' | 'value' | 'id' | 'defaultValue' | 'modelValue' | 'trueValue' | 'falseValue'>, /** @vue-ignore */ Omit<ButtonHTMLAttributes, 'type' | 'disabled' | 'name'> {
10
10
  /**
11
11
  * The element or component this component should render as.
12
12
  * @defaultValue 'div'
@@ -46,9 +46,9 @@ export interface CheckboxProps extends Pick<CheckboxRootProps, 'disabled' | 'req
46
46
  class?: any;
47
47
  ui?: Checkbox['slots'];
48
48
  }
49
- export type CheckboxEmits = {
49
+ export interface CheckboxEmits<T = boolean> extends CheckboxRootEmits<T> {
50
50
  change: [event: Event];
51
- };
51
+ }
52
52
  export interface CheckboxSlots {
53
53
  label?(props: {
54
54
  label: string | undefined;
@@ -59,19 +59,22 @@ export interface CheckboxSlots {
59
59
  }
60
60
  declare const _default: typeof __VLS_export;
61
61
  export default _default;
62
- declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<CheckboxProps & {
63
- modelValue?: boolean | "indeterminate";
64
- }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
65
- change: (event: Event) => any;
66
- "update:modelValue": (value: boolean | "indeterminate") => any;
67
- }, string, import("vue").PublicProps, Readonly<CheckboxProps & {
68
- modelValue?: boolean | "indeterminate";
69
- }> & Readonly<{
70
- onChange?: ((event: Event) => any) | undefined;
71
- "onUpdate:modelValue"?: ((value: boolean | "indeterminate") => any) | undefined;
72
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, CheckboxSlots>;
73
- type __VLS_WithSlots<T, S> = T & {
74
- new (): {
75
- $slots: S;
76
- };
62
+ declare const __VLS_export: <T = boolean>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
63
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<CheckboxProps<T> & {
64
+ onChange?: ((event: Event) => any) | undefined;
65
+ "onUpdate:modelValue"?: ((value: "indeterminate" | T) => any) | undefined;
66
+ }> & (typeof globalThis extends {
67
+ __VLS_PROPS_FALLBACK: infer P;
68
+ } ? P : {});
69
+ expose: (exposed: {}) => void;
70
+ attrs: any;
71
+ slots: CheckboxSlots;
72
+ emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: "indeterminate" | T) => void);
73
+ }>) => import("vue").VNode & {
74
+ __ctx?: Awaited<typeof __VLS_setup>;
77
75
  };
76
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
77
+ [K in keyof T]: T[K];
78
+ } : {
79
+ [K in keyof T as K]: T[K];
80
+ }) & {};
@@ -4,7 +4,7 @@ import theme from "#build/ui/checkbox";
4
4
 
5
5
  <script setup>
6
6
  import { computed, useAttrs, useId } from "vue";
7
- import { Primitive, CheckboxRoot, CheckboxIndicator, Label, useForwardProps } from "reka-ui";
7
+ import { Primitive, CheckboxRoot, CheckboxIndicator, Label, useForwardPropsEmits } from "reka-ui";
8
8
  import { reactivePick } from "@vueuse/core";
9
9
  import { useAppConfig } from "#imports";
10
10
  import { useComponentUI } from "../composables/useComponentUI";
@@ -29,14 +29,16 @@ const props = defineProps({
29
29
  name: { type: String, required: false },
30
30
  value: { type: null, required: false },
31
31
  id: { type: String, required: false },
32
- defaultValue: { type: [Boolean, String], required: false }
32
+ defaultValue: { type: null, required: false },
33
+ modelValue: { type: null, required: false },
34
+ trueValue: { type: null, required: false },
35
+ falseValue: { type: null, required: false }
33
36
  });
34
37
  const slots = defineSlots();
35
- const emits = defineEmits(["change"]);
36
- const modelValue = defineModel({ type: [Boolean, String], ...{ default: void 0 } });
38
+ const emits = defineEmits(["change", "update:modelValue"]);
37
39
  const appConfig = useAppConfig();
38
40
  const uiProp = useComponentUI("checkbox", props);
39
- const rootProps = useForwardProps(reactivePick(props, "required", "value", "defaultValue"));
41
+ const rootProps = useForwardPropsEmits(reactivePick(props, "required", "value", "defaultValue", "modelValue", "trueValue", "falseValue"), emits);
40
42
  const { id: _id, emitFormChange, emitFormInput, size, color, name, disabled, ariaAttrs } = useFormField(props);
41
43
  const id = _id.value ?? useId();
42
44
  const attrs = useAttrs();
@@ -66,16 +68,15 @@ function onUpdate(value) {
66
68
  <CheckboxRoot
67
69
  :id="id"
68
70
  v-bind="{ ...rootProps, ...forwardedAttrs, ...ariaAttrs }"
69
- v-model="modelValue"
70
71
  :name="name"
71
72
  :disabled="disabled"
72
73
  data-slot="base"
73
74
  :class="ui.base({ class: uiProp?.base })"
74
75
  @update:model-value="onUpdate"
75
76
  >
76
- <template #default="{ modelValue }">
77
+ <template #default="{ state }">
77
78
  <CheckboxIndicator data-slot="indicator" :class="ui.indicator({ class: uiProp?.indicator })">
78
- <UIcon v-if="modelValue === 'indeterminate'" :name="indeterminateIcon || appConfig.ui.icons.minus" data-slot="icon" :class="ui.icon({ class: uiProp?.icon })" />
79
+ <UIcon v-if="state === 'indeterminate'" :name="indeterminateIcon || appConfig.ui.icons.minus" data-slot="icon" :class="ui.icon({ class: uiProp?.icon })" />
79
80
  <UIcon v-else :name="icon || appConfig.ui.icons.check" data-slot="icon" :class="ui.icon({ class: uiProp?.icon })" />
80
81
  </CheckboxIndicator>
81
82
  </template>
@@ -1,4 +1,4 @@
1
- import type { CheckboxRootProps } from 'reka-ui';
1
+ import type { CheckboxRootProps, CheckboxRootEmits } from 'reka-ui';
2
2
  import type { VNode } from 'vue';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import theme from '#build/ui/checkbox';
@@ -6,7 +6,7 @@ import type { IconProps } from '../types';
6
6
  import type { ButtonHTMLAttributes } from '../types/html';
7
7
  import type { ComponentConfig } from '../types/tv';
8
8
  type Checkbox = ComponentConfig<typeof theme, AppConfig, 'checkbox'>;
9
- export interface CheckboxProps extends Pick<CheckboxRootProps, 'disabled' | 'required' | 'name' | 'value' | 'id' | 'defaultValue'>, /** @vue-ignore */ Omit<ButtonHTMLAttributes, 'type' | 'disabled' | 'name'> {
9
+ export interface CheckboxProps<T = boolean> extends Pick<CheckboxRootProps<T>, 'disabled' | 'required' | 'name' | 'value' | 'id' | 'defaultValue' | 'modelValue' | 'trueValue' | 'falseValue'>, /** @vue-ignore */ Omit<ButtonHTMLAttributes, 'type' | 'disabled' | 'name'> {
10
10
  /**
11
11
  * The element or component this component should render as.
12
12
  * @defaultValue 'div'
@@ -46,9 +46,9 @@ export interface CheckboxProps extends Pick<CheckboxRootProps, 'disabled' | 'req
46
46
  class?: any;
47
47
  ui?: Checkbox['slots'];
48
48
  }
49
- export type CheckboxEmits = {
49
+ export interface CheckboxEmits<T = boolean> extends CheckboxRootEmits<T> {
50
50
  change: [event: Event];
51
- };
51
+ }
52
52
  export interface CheckboxSlots {
53
53
  label?(props: {
54
54
  label: string | undefined;
@@ -59,19 +59,22 @@ export interface CheckboxSlots {
59
59
  }
60
60
  declare const _default: typeof __VLS_export;
61
61
  export default _default;
62
- declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<CheckboxProps & {
63
- modelValue?: boolean | "indeterminate";
64
- }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
65
- change: (event: Event) => any;
66
- "update:modelValue": (value: boolean | "indeterminate") => any;
67
- }, string, import("vue").PublicProps, Readonly<CheckboxProps & {
68
- modelValue?: boolean | "indeterminate";
69
- }> & Readonly<{
70
- onChange?: ((event: Event) => any) | undefined;
71
- "onUpdate:modelValue"?: ((value: boolean | "indeterminate") => any) | undefined;
72
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, CheckboxSlots>;
73
- type __VLS_WithSlots<T, S> = T & {
74
- new (): {
75
- $slots: S;
76
- };
62
+ declare const __VLS_export: <T = boolean>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
63
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<CheckboxProps<T> & {
64
+ onChange?: ((event: Event) => any) | undefined;
65
+ "onUpdate:modelValue"?: ((value: "indeterminate" | T) => any) | undefined;
66
+ }> & (typeof globalThis extends {
67
+ __VLS_PROPS_FALLBACK: infer P;
68
+ } ? P : {});
69
+ expose: (exposed: {}) => void;
70
+ attrs: any;
71
+ slots: CheckboxSlots;
72
+ emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: "indeterminate" | T) => void);
73
+ }>) => import("vue").VNode & {
74
+ __ctx?: Awaited<typeof __VLS_setup>;
77
75
  };
76
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
77
+ [K in keyof T]: T[K];
78
+ } : {
79
+ [K in keyof T as K]: T[K];
80
+ }) & {};
@@ -18,9 +18,9 @@ declare const _default: typeof __VLS_export;
18
18
  export default _default;
19
19
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<DashboardGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DashboardGroupProps> & Readonly<{}>, {
20
20
  storage: "cookie" | "local";
21
+ unit: "%" | "rem" | "px";
21
22
  storageKey: string;
22
23
  persistent: boolean;
23
- unit: "%" | "rem" | "px";
24
24
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, DashboardGroupSlots>;
25
25
  type __VLS_WithSlots<T, S> = T & {
26
26
  new (): {
@@ -18,9 +18,9 @@ declare const _default: typeof __VLS_export;
18
18
  export default _default;
19
19
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<DashboardGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DashboardGroupProps> & Readonly<{}>, {
20
20
  storage: "cookie" | "local";
21
+ unit: "%" | "rem" | "px";
21
22
  storageKey: string;
22
23
  persistent: boolean;
23
- unit: "%" | "rem" | "px";
24
24
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, DashboardGroupSlots>;
25
25
  type __VLS_WithSlots<T, S> = T & {
26
26
  new (): {
@@ -85,13 +85,13 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.dashboardSear
85
85
  </template>
86
86
 
87
87
  <template #trailing="{ ui: uiProxy }">
88
- <div data-slot="trailing" :class="ui.trailing({ class: uiProp?.trailing })">
88
+ <span data-slot="trailing" :class="ui.trailing({ class: uiProp?.trailing })">
89
89
  <slot name="trailing" :ui="uiProxy">
90
90
  <template v-if="kbds?.length">
91
91
  <UKbd v-for="(kbd, index) in kbds" :key="index" variant="subtle" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
92
92
  </template>
93
93
  </slot>
94
- </div>
94
+ </span>
95
95
  </template>
96
96
  </UButton>
97
97
  </DefineButtonTemplate>
@@ -49,7 +49,7 @@ const portalProps = usePortal(toRef(() => props.portal));
49
49
  const contentProps = toRef(() => props.content);
50
50
  const contentEvents = computed(() => {
51
51
  if (!props.dismissible) {
52
- const events = ["pointerDownOutside", "interactOutside", "escapeKeyDown"];
52
+ const events = ["interactOutside", "escapeKeyDown"];
53
53
  return events.reduce((acc, curr) => {
54
54
  acc[curr] = (e) => {
55
55
  e.preventDefault();
@@ -2,7 +2,7 @@ import type { DropdownMenuRootProps, DropdownMenuRootEmits, DropdownMenuContentP
2
2
  import type { VNode } from 'vue';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import theme from '#build/ui/dropdown-menu';
5
- import type { AvatarProps, IconProps, KbdProps, LinkProps } from '../types';
5
+ import type { AvatarProps, IconProps, InputProps, KbdProps, LinkProps } from '../types';
6
6
  import type { ArrayOrNested, DynamicSlots, GetItemKeys, MergeTypes, NestedItem, EmitsToProps } from '../types/utils';
7
7
  import type { ComponentConfig } from '../types/tv';
8
8
  type DropdownMenu = ComponentConfig<typeof theme, AppConfig, 'dropdownMenu'>;
@@ -30,6 +30,9 @@ export interface DropdownMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cust
30
30
  checked?: boolean;
31
31
  open?: boolean;
32
32
  defaultOpen?: boolean;
33
+ filter?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
34
+ filterFields?: string[];
35
+ ignoreFilter?: boolean;
33
36
  children?: ArrayOrNested<DropdownMenuItem>;
34
37
  onSelect?: (e: Event) => void;
35
38
  onUpdateChecked?: (checked: boolean) => void;
@@ -88,6 +91,23 @@ export interface DropdownMenuProps<T extends ArrayOrNested<DropdownMenuItem> = A
88
91
  * @defaultValue 'description'
89
92
  */
90
93
  descriptionKey?: GetItemKeys<T>;
94
+ /**
95
+ * Whether to display a filter input or not.
96
+ * Can be an object to pass additional props to the input.
97
+ * `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
98
+ * @defaultValue false
99
+ */
100
+ filter?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
101
+ /**
102
+ * The fields to filter by.
103
+ * @defaultValue [labelKey]
104
+ */
105
+ filterFields?: string[];
106
+ /**
107
+ * When `true`, items will not be filtered which is useful for custom filtering.
108
+ * @defaultValue false
109
+ */
110
+ ignoreFilter?: boolean;
91
111
  disabled?: boolean;
92
112
  class?: any;
93
113
  ui?: DropdownMenu['slots'];
@@ -117,6 +137,9 @@ export type DropdownMenuSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayO
117
137
  index: number;
118
138
  }) => VNode[];
119
139
  'item-trailing'?: SlotProps<T>;
140
+ 'empty'?(props: {
141
+ searchTerm: string;
142
+ }): VNode[];
120
143
  'content-top'?: (props: {
121
144
  sub: boolean;
122
145
  }) => VNode[];
@@ -134,15 +157,18 @@ export type DropdownMenuSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayO
134
157
  declare const _default: typeof __VLS_export;
135
158
  export default _default;
136
159
  declare const __VLS_export: <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_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
137
- props: import("vue").PublicProps & __VLS_PrettifyLocal<DropdownMenuProps<T> & {
160
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<(DropdownMenuProps<T> & {
161
+ searchTerm?: string;
162
+ }) & {
138
163
  "onUpdate:open"?: ((payload: boolean) => any) | undefined;
164
+ "onUpdate:searchTerm"?: ((value: string) => any) | undefined;
139
165
  }> & (typeof globalThis extends {
140
166
  __VLS_PROPS_FALLBACK: infer P;
141
167
  } ? P : {});
142
168
  expose: (exposed: {}) => void;
143
169
  attrs: any;
144
170
  slots: DropdownMenuSlots<T, NestedItem<T>>;
145
- emit: (evt: "update:open", payload: boolean) => void;
171
+ emit: ((evt: "update:open", payload: boolean) => void) & ((event: "update:searchTerm", value: string) => void);
146
172
  }>) => import("vue").VNode & {
147
173
  __ctx?: Awaited<typeof __VLS_setup>;
148
174
  };
@@ -23,6 +23,9 @@ const props = defineProps({
23
23
  portal: { type: [Boolean, String], required: false, skipCheck: true, default: true },
24
24
  labelKey: { type: null, required: false, default: "label" },
25
25
  descriptionKey: { type: null, required: false, default: "description" },
26
+ filter: { type: [Boolean, Object], required: false, default: false },
27
+ filterFields: { type: Array, required: false },
28
+ ignoreFilter: { type: Boolean, required: false, default: false },
26
29
  disabled: { type: Boolean, required: false },
27
30
  class: { type: null, required: false },
28
31
  ui: { type: Object, required: false },
@@ -32,6 +35,7 @@ const props = defineProps({
32
35
  });
33
36
  const emits = defineEmits(["update:open"]);
34
37
  const slots = defineSlots();
38
+ const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" } });
35
39
  const appConfig = useAppConfig();
36
40
  const uiProp = useComponentUI("dropdownMenu", props);
37
41
  const rootProps = useForwardPropsEmits(reactivePick(props, "defaultOpen", "open", "modal"), emits);
@@ -50,6 +54,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.dropdownMenu
50
54
  </DropdownMenuTrigger>
51
55
 
52
56
  <UDropdownMenuContent
57
+ v-model:search-term="searchTerm"
53
58
  :class="ui.content({ class: [!slots.default && props.class, uiProp?.content] })"
54
59
  :ui="ui"
55
60
  :ui-override="uiProp"
@@ -61,6 +66,10 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.dropdownMenu
61
66
  :checked-icon="checkedIcon"
62
67
  :loading-icon="loadingIcon"
63
68
  :external-icon="externalIcon"
69
+ :size="size"
70
+ :filter="filter"
71
+ :filter-fields="filterFields"
72
+ :ignore-filter="ignoreFilter"
64
73
  >
65
74
  <template v-for="(_, name) in getProxySlots()" #[name]="slotData">
66
75
  <slot :name="name" v-bind="slotData" />
@@ -2,7 +2,7 @@ import type { DropdownMenuRootProps, DropdownMenuRootEmits, DropdownMenuContentP
2
2
  import type { VNode } from 'vue';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import theme from '#build/ui/dropdown-menu';
5
- import type { AvatarProps, IconProps, KbdProps, LinkProps } from '../types';
5
+ import type { AvatarProps, IconProps, InputProps, KbdProps, LinkProps } from '../types';
6
6
  import type { ArrayOrNested, DynamicSlots, GetItemKeys, MergeTypes, NestedItem, EmitsToProps } from '../types/utils';
7
7
  import type { ComponentConfig } from '../types/tv';
8
8
  type DropdownMenu = ComponentConfig<typeof theme, AppConfig, 'dropdownMenu'>;
@@ -30,6 +30,9 @@ export interface DropdownMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cust
30
30
  checked?: boolean;
31
31
  open?: boolean;
32
32
  defaultOpen?: boolean;
33
+ filter?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
34
+ filterFields?: string[];
35
+ ignoreFilter?: boolean;
33
36
  children?: ArrayOrNested<DropdownMenuItem>;
34
37
  onSelect?: (e: Event) => void;
35
38
  onUpdateChecked?: (checked: boolean) => void;
@@ -88,6 +91,23 @@ export interface DropdownMenuProps<T extends ArrayOrNested<DropdownMenuItem> = A
88
91
  * @defaultValue 'description'
89
92
  */
90
93
  descriptionKey?: GetItemKeys<T>;
94
+ /**
95
+ * Whether to display a filter input or not.
96
+ * Can be an object to pass additional props to the input.
97
+ * `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
98
+ * @defaultValue false
99
+ */
100
+ filter?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
101
+ /**
102
+ * The fields to filter by.
103
+ * @defaultValue [labelKey]
104
+ */
105
+ filterFields?: string[];
106
+ /**
107
+ * When `true`, items will not be filtered which is useful for custom filtering.
108
+ * @defaultValue false
109
+ */
110
+ ignoreFilter?: boolean;
91
111
  disabled?: boolean;
92
112
  class?: any;
93
113
  ui?: DropdownMenu['slots'];
@@ -117,6 +137,9 @@ export type DropdownMenuSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayO
117
137
  index: number;
118
138
  }) => VNode[];
119
139
  'item-trailing'?: SlotProps<T>;
140
+ 'empty'?(props: {
141
+ searchTerm: string;
142
+ }): VNode[];
120
143
  'content-top'?: (props: {
121
144
  sub: boolean;
122
145
  }) => VNode[];
@@ -134,15 +157,18 @@ export type DropdownMenuSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayO
134
157
  declare const _default: typeof __VLS_export;
135
158
  export default _default;
136
159
  declare const __VLS_export: <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_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
137
- props: import("vue").PublicProps & __VLS_PrettifyLocal<DropdownMenuProps<T> & {
160
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<(DropdownMenuProps<T> & {
161
+ searchTerm?: string;
162
+ }) & {
138
163
  "onUpdate:open"?: ((payload: boolean) => any) | undefined;
164
+ "onUpdate:searchTerm"?: ((value: string) => any) | undefined;
139
165
  }> & (typeof globalThis extends {
140
166
  __VLS_PROPS_FALLBACK: infer P;
141
167
  } ? P : {});
142
168
  expose: (exposed: {}) => void;
143
169
  attrs: any;
144
170
  slots: DropdownMenuSlots<T, NestedItem<T>>;
145
- emit: (evt: "update:open", payload: boolean) => void;
171
+ emit: ((evt: "update:open", payload: boolean) => void) & ((event: "update:searchTerm", value: string) => void);
146
172
  }>) => import("vue").VNode & {
147
173
  __ctx?: Awaited<typeof __VLS_setup>;
148
174
  };
@@ -3,7 +3,7 @@ import type { DropdownMenuContentProps as RekaDropdownMenuContentProps } from 'r
3
3
  import type { VNode } from 'vue';
4
4
  import type { AppConfig } from '@nuxt/schema';
5
5
  import type theme from '#build/ui/dropdown-menu';
6
- import type { DropdownMenuItem, DropdownMenuSlots, IconProps } from '../types';
6
+ import type { DropdownMenuItem, DropdownMenuSlots, IconProps, InputProps } from '../types';
7
7
  import type { ArrayOrNested, GetItemKeys, NestedItem, DynamicSlots, MergeTypes } from '../types/utils';
8
8
  import type { ComponentConfig } from '../types/tv';
9
9
  type DropdownMenu = ComponentConfig<typeof theme, AppConfig, 'dropdownMenu'>;
@@ -25,11 +25,16 @@ interface DropdownMenuContentProps<T extends ArrayOrNested<DropdownMenuItem>> ex
25
25
  * @IconifyIcon
26
26
  */
27
27
  externalIcon?: boolean | IconProps['name'];
28
+ size?: DropdownMenu['variants']['size'];
29
+ filter?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
30
+ filterFields?: string[];
31
+ ignoreFilter?: boolean;
32
+ searchTerm?: string;
28
33
  class?: any;
29
34
  ui: DropdownMenu['ui'];
30
35
  uiOverride?: DropdownMenu['slots'];
31
36
  }
32
- type DropdownMenuContentSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayOrNested<DropdownMenuItem>, T extends NestedItem<A> = NestedItem<A>> = Pick<DropdownMenuSlots<A>, 'item' | 'item-leading' | 'item-label' | 'item-description' | 'item-trailing' | 'content-top' | 'content-bottom'> & {
37
+ type DropdownMenuContentSlots<A extends ArrayOrNested<DropdownMenuItem> = ArrayOrNested<DropdownMenuItem>, T extends NestedItem<A> = NestedItem<A>> = Pick<DropdownMenuSlots<A>, 'item' | 'item-leading' | 'item-label' | 'item-description' | 'item-trailing' | 'empty' | 'content-top' | 'content-bottom'> & {
33
38
  default?(props?: {}): VNode[];
34
39
  } & DynamicSlots<MergeTypes<T>, 'label' | 'description', {
35
40
  active: boolean;
@@ -44,6 +49,7 @@ export default _default;
44
49
  declare const __VLS_export: <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_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
45
50
  props: import("vue").PublicProps & __VLS_PrettifyLocal<DropdownMenuContentProps<T> & {
46
51
  onEscapeKeyDown?: ((event: KeyboardEvent) => any) | undefined;
52
+ "onUpdate:searchTerm"?: ((value: string) => any) | undefined;
47
53
  onPointerDownOutside?: ((event: import("reka-ui").PointerDownOutsideEvent) => any) | undefined;
48
54
  onFocusOutside?: ((event: import("reka-ui").FocusOutsideEvent) => any) | undefined;
49
55
  onInteractOutside?: ((event: import("reka-ui").PointerDownOutsideEvent | import("reka-ui").FocusOutsideEvent) => any) | undefined;
@@ -54,7 +60,7 @@ declare const __VLS_export: <T extends ArrayOrNested<DropdownMenuItem>>(__VLS_pr
54
60
  expose: (exposed: {}) => void;
55
61
  attrs: any;
56
62
  slots: DropdownMenuContentSlots<T, NestedItem<T>>;
57
- 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);
63
+ emit: ((evt: "escapeKeyDown", event: KeyboardEvent) => void) & ((evt: "update:searchTerm", value: string) => 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);
58
64
  }>) => import("vue").VNode & {
59
65
  __ctx?: Awaited<typeof __VLS_setup>;
60
66
  };
@@ -3,11 +3,13 @@
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed, toRef } from "vue";
6
+ import { computed, ref, toRef } from "vue";
7
+ import { defu } from "defu";
7
8
  import { DropdownMenu } from "reka-ui/namespaced";
8
9
  import { useForwardPropsEmits } from "reka-ui";
9
10
  import { reactiveOmit, createReusableTemplate } from "@vueuse/core";
10
11
  import { useAppConfig } from "#imports";
12
+ import { useFilter } from "../composables/useFilter";
11
13
  import { useLocale } from "../composables/useLocale";
12
14
  import { usePortal } from "../composables/usePortal";
13
15
  import { omit, get, isArrayOfArray } from "../utils";
@@ -16,6 +18,7 @@ import ULinkBase from "./LinkBase.vue";
16
18
  import ULink from "./Link.vue";
17
19
  import UAvatar from "./Avatar.vue";
18
20
  import UIcon from "./Icon.vue";
21
+ import UInput from "./Input.vue";
19
22
  import UKbd from "./Kbd.vue";
20
23
  import UDropdownMenuContent from "./DropdownMenuContent.vue";
21
24
  const props = defineProps({
@@ -27,6 +30,11 @@ const props = defineProps({
27
30
  checkedIcon: { type: null, required: false },
28
31
  loadingIcon: { type: null, required: false },
29
32
  externalIcon: { type: [Boolean, String], required: false, skipCheck: true },
33
+ size: { type: null, required: false },
34
+ filter: { type: [Boolean, Object], required: false },
35
+ filterFields: { type: Array, required: false },
36
+ ignoreFilter: { type: Boolean, required: false },
37
+ searchTerm: { type: String, required: false },
30
38
  class: { type: null, required: false },
31
39
  ui: { type: null, required: true },
32
40
  uiOverride: { type: null, required: false },
@@ -50,18 +58,41 @@ const props = defineProps({
50
58
  prioritizePosition: { type: Boolean, required: false },
51
59
  reference: { type: null, required: false }
52
60
  });
53
- const emits = defineEmits(["escapeKeyDown", "pointerDownOutside", "focusOutside", "interactOutside", "closeAutoFocus"]);
61
+ const emits = defineEmits(["update:searchTerm", "escapeKeyDown", "pointerDownOutside", "focusOutside", "interactOutside", "closeAutoFocus"]);
54
62
  const slots = defineSlots();
55
- const { dir } = useLocale();
63
+ const { t, dir } = useLocale();
56
64
  const appConfig = useAppConfig();
65
+ const { filterGroups } = useFilter();
66
+ const _searchTerm = ref("");
67
+ const searchTerm = computed({
68
+ get: () => props.searchTerm ?? _searchTerm.value,
69
+ set: (value) => {
70
+ _searchTerm.value = value;
71
+ emits("update:searchTerm", value);
72
+ }
73
+ });
74
+ const inputProps = toRef(() => defu(props.filter, { placeholder: t("dropdownMenu.search"), variant: "none" }));
57
75
  const portalProps = usePortal(toRef(() => props.portal));
58
- const contentProps = useForwardPropsEmits(reactiveOmit(props, "sub", "items", "portal", "labelKey", "descriptionKey", "checkedIcon", "loadingIcon", "externalIcon", "class", "ui", "uiOverride"), emits);
76
+ const contentProps = useForwardPropsEmits(reactiveOmit(props, "sub", "items", "portal", "labelKey", "descriptionKey", "checkedIcon", "loadingIcon", "externalIcon", "size", "filter", "filterFields", "ignoreFilter", "searchTerm", "class", "ui", "uiOverride"), emits);
59
77
  const getProxySlots = () => omit(slots, ["default"]);
60
78
  const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate();
61
79
  const childrenIcon = computed(() => dir.value === "rtl" ? appConfig.ui.icons.chevronLeft : appConfig.ui.icons.chevronRight);
62
- const groups = computed(
63
- () => props.items?.length ? isArrayOfArray(props.items) ? props.items : [props.items] : []
64
- );
80
+ const groups = computed(() => {
81
+ if (!props.items?.length) return [];
82
+ return isArrayOfArray(props.items) ? props.items : [props.items];
83
+ });
84
+ const isStructuralItem = (item) => !!item.type && ["label", "separator"].includes(item.type);
85
+ const filteredGroups = computed(() => {
86
+ if (!props.filter || props.ignoreFilter || !searchTerm.value) {
87
+ return groups.value;
88
+ }
89
+ const fields = Array.isArray(props.filterFields) && props.filterFields.length ? props.filterFields : [props.labelKey];
90
+ return filterGroups(groups.value, searchTerm.value, {
91
+ fields,
92
+ isStructural: isStructuralItem
93
+ });
94
+ });
95
+ const hasFilteredItems = computed(() => filteredGroups.value.some((group) => group.some((item) => !isStructuralItem(item))));
65
96
  </script>
66
97
 
67
98
  <template>
@@ -106,10 +137,22 @@ const groups = computed(
106
137
 
107
138
  <DropdownMenu.Portal v-bind="portalProps">
108
139
  <component :is="sub ? DropdownMenu.SubContent : DropdownMenu.Content" data-slot="content" :class="ui.content({ class: [uiOverride?.content, props.class] })" v-bind="contentProps">
140
+ <DropdownMenu.Filter v-if="!!filter" v-model="searchTerm" as-child>
141
+ <UInput
142
+ autofocus
143
+ autocomplete="off"
144
+ :size="size"
145
+ v-bind="inputProps"
146
+ data-slot="input"
147
+ :class="ui.input({ class: uiOverride?.input })"
148
+ @change.stop
149
+ />
150
+ </DropdownMenu.Filter>
151
+
109
152
  <slot name="content-top" :sub="sub ?? false" />
110
153
 
111
- <div role="presentation" data-slot="viewport" :class="ui.viewport({ class: uiOverride?.viewport })">
112
- <DropdownMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" data-slot="group" :class="ui.group({ class: uiOverride?.group })">
154
+ <div v-if="!searchTerm || hasFilteredItems" role="presentation" data-slot="viewport" :class="ui.viewport({ class: uiOverride?.viewport })">
155
+ <DropdownMenu.Group v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" data-slot="group" :class="ui.group({ class: uiOverride?.group })">
113
156
  <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
114
157
  <DropdownMenu.Label v-if="item.type === 'label'" data-slot="label" :class="ui.label({ class: [uiOverride?.label, item.ui?.label, item.class] })">
115
158
  <ReuseItemTemplate :item="item" :index="index" />
@@ -142,6 +185,10 @@ const groups = computed(
142
185
  :checked-icon="checkedIcon"
143
186
  :loading-icon="loadingIcon"
144
187
  :external-icon="externalIcon"
188
+ :size="size"
189
+ :filter="item.filter"
190
+ :filter-fields="item.filterFields || filterFields"
191
+ :ignore-filter="item.ignoreFilter ?? ignoreFilter"
145
192
  v-bind="item.content"
146
193
  >
147
194
  <template v-for="(_, name) in getProxySlots()" #[name]="slotData">
@@ -177,6 +224,12 @@ const groups = computed(
177
224
  </DropdownMenu.Group>
178
225
  </div>
179
226
 
227
+ <div v-if="searchTerm && !hasFilteredItems" data-slot="empty" :class="ui.empty({ class: uiOverride?.empty })">
228
+ <slot name="empty" :search-term="searchTerm">
229
+ {{ t("dropdownMenu.noMatch", { searchTerm }) }}
230
+ </slot>
231
+ </div>
232
+
180
233
  <slot />
181
234
 
182
235
  <slot name="content-bottom" :sub="sub ?? false" />