@nuxt/ui 4.11.1 → 4.11.3

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 (106) hide show
  1. package/README.md +3 -3
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -2
  4. package/dist/runtime/components/Accordion.d.vue.ts +1 -1
  5. package/dist/runtime/components/Accordion.vue.d.ts +1 -1
  6. package/dist/runtime/components/App.vue +2 -1
  7. package/dist/runtime/components/AuthForm.d.vue.ts +4 -0
  8. package/dist/runtime/components/AuthForm.vue.d.ts +4 -0
  9. package/dist/runtime/components/Breadcrumb.d.vue.ts +1 -1
  10. package/dist/runtime/components/Breadcrumb.vue.d.ts +1 -1
  11. package/dist/runtime/components/Carousel.d.vue.ts +1 -1
  12. package/dist/runtime/components/Carousel.vue.d.ts +1 -1
  13. package/dist/runtime/components/ChatPrompt.vue +1 -1
  14. package/dist/runtime/components/CheckboxGroup.d.vue.ts +1 -1
  15. package/dist/runtime/components/CheckboxGroup.vue.d.ts +1 -1
  16. package/dist/runtime/components/CommandPalette.d.vue.ts +1 -1
  17. package/dist/runtime/components/CommandPalette.vue.d.ts +1 -1
  18. package/dist/runtime/components/ContextMenu.d.vue.ts +1 -1
  19. package/dist/runtime/components/ContextMenu.vue.d.ts +1 -1
  20. package/dist/runtime/components/DashboardNavbar.vue +1 -1
  21. package/dist/runtime/components/DashboardSearch.vue +3 -3
  22. package/dist/runtime/components/DashboardSidebar.vue +3 -3
  23. package/dist/runtime/components/DropdownMenu.d.vue.ts +1 -1
  24. package/dist/runtime/components/DropdownMenu.vue.d.ts +1 -1
  25. package/dist/runtime/components/EditorToolbar.vue +6 -5
  26. package/dist/runtime/components/FooterColumns.d.vue.ts +1 -1
  27. package/dist/runtime/components/FooterColumns.vue.d.ts +1 -1
  28. package/dist/runtime/components/Form.d.vue.ts +2 -0
  29. package/dist/runtime/components/Form.vue +57 -30
  30. package/dist/runtime/components/Form.vue.d.ts +2 -0
  31. package/dist/runtime/components/Header.vue +3 -3
  32. package/dist/runtime/components/Input.vue +5 -5
  33. package/dist/runtime/components/InputDate.vue +12 -6
  34. package/dist/runtime/components/InputMenu.d.vue.ts +1 -1
  35. package/dist/runtime/components/InputMenu.vue +18 -7
  36. package/dist/runtime/components/InputMenu.vue.d.ts +1 -1
  37. package/dist/runtime/components/InputTime.vue +12 -6
  38. package/dist/runtime/components/LinkBase.vue +3 -1
  39. package/dist/runtime/components/Listbox.d.vue.ts +1 -1
  40. package/dist/runtime/components/Listbox.vue.d.ts +1 -1
  41. package/dist/runtime/components/NavigationMenu.d.vue.ts +1 -1
  42. package/dist/runtime/components/NavigationMenu.vue.d.ts +1 -1
  43. package/dist/runtime/components/PageAnchors.d.vue.ts +1 -1
  44. package/dist/runtime/components/PageAnchors.vue.d.ts +1 -1
  45. package/dist/runtime/components/PageLinks.d.vue.ts +1 -1
  46. package/dist/runtime/components/PageLinks.vue.d.ts +1 -1
  47. package/dist/runtime/components/PinInput.d.vue.ts +5 -3
  48. package/dist/runtime/components/PinInput.vue +15 -7
  49. package/dist/runtime/components/PinInput.vue.d.ts +5 -3
  50. package/dist/runtime/components/ProgressGroup.d.vue.ts +1 -1
  51. package/dist/runtime/components/ProgressGroup.vue.d.ts +1 -1
  52. package/dist/runtime/components/RadioGroup.d.vue.ts +1 -1
  53. package/dist/runtime/components/RadioGroup.vue.d.ts +1 -1
  54. package/dist/runtime/components/Select.d.vue.ts +1 -1
  55. package/dist/runtime/components/Select.vue +7 -1
  56. package/dist/runtime/components/Select.vue.d.ts +1 -1
  57. package/dist/runtime/components/SelectMenu.d.vue.ts +1 -1
  58. package/dist/runtime/components/SelectMenu.vue +22 -3
  59. package/dist/runtime/components/SelectMenu.vue.d.ts +1 -1
  60. package/dist/runtime/components/Splitter.d.vue.ts +1 -1
  61. package/dist/runtime/components/Splitter.vue.d.ts +1 -1
  62. package/dist/runtime/components/Stepper.d.vue.ts +1 -1
  63. package/dist/runtime/components/Stepper.vue.d.ts +1 -1
  64. package/dist/runtime/components/Table.vue +24 -2
  65. package/dist/runtime/components/Tabs.d.vue.ts +1 -1
  66. package/dist/runtime/components/Tabs.vue.d.ts +1 -1
  67. package/dist/runtime/components/Textarea.vue +5 -5
  68. package/dist/runtime/components/Timeline.d.vue.ts +1 -1
  69. package/dist/runtime/components/Timeline.vue.d.ts +1 -1
  70. package/dist/runtime/components/Toaster.vue +1 -1
  71. package/dist/runtime/components/Tree.d.vue.ts +1 -1
  72. package/dist/runtime/components/Tree.vue +1 -1
  73. package/dist/runtime/components/Tree.vue.d.ts +1 -1
  74. package/dist/runtime/components/content/ContentNavigation.d.vue.ts +1 -1
  75. package/dist/runtime/components/content/ContentNavigation.vue.d.ts +1 -1
  76. package/dist/runtime/components/content/ContentSearch.vue +3 -3
  77. package/dist/runtime/components/content/ContentSurround.d.vue.ts +1 -1
  78. package/dist/runtime/components/content/ContentSurround.vue.d.ts +1 -1
  79. package/dist/runtime/components/content/ContentToc.d.vue.ts +1 -1
  80. package/dist/runtime/components/content/ContentToc.vue.d.ts +1 -1
  81. package/dist/runtime/composables/useFilter.js +7 -1
  82. package/dist/runtime/composables/useFormField.d.ts +1 -1
  83. package/dist/runtime/composables/useFormField.js +8 -4
  84. package/dist/runtime/composables/useForwardProps.js +2 -2
  85. package/dist/runtime/composables/useOverlay.d.ts +2 -2
  86. package/dist/runtime/composables/useOverlay.js +5 -5
  87. package/dist/runtime/composables/useResizable.js +1 -1
  88. package/dist/runtime/index.css +1 -1
  89. package/dist/runtime/types/form.d.ts +3 -0
  90. package/dist/runtime/utils/form.js +3 -20
  91. package/dist/runtime/utils/index.js +22 -18
  92. package/dist/runtime/utils/virtualizer.d.ts +1 -1
  93. package/dist/runtime/utils/virtualizer.js +9 -11
  94. package/dist/runtime/vue/overrides/inertia/LinkBase.vue +3 -1
  95. package/dist/shared/{ui.DCJ9twx8.mjs → ui.CNAeRcb0.mjs} +45 -13
  96. package/dist/unplugin.d.mts +2 -1
  97. package/dist/unplugin.mjs +22 -10
  98. package/dist/vite.mjs +1 -1
  99. package/package.json +57 -60
  100. package/cli/commands/make/component.mjs +0 -86
  101. package/cli/commands/make/index.mjs +0 -14
  102. package/cli/commands/make/locale.mjs +0 -93
  103. package/cli/index.mjs +0 -15
  104. package/cli/package.json +0 -13
  105. package/cli/templates.mjs +0 -256
  106. package/cli/utils.mjs +0 -50
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/91ceab67-89ce-4ef4-8678-4402a92baca5">
3
- <source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/51526d6d-e5ec-41b4-aa37-242dec1cdb27">
4
- <img alt="Nuxt UI" width="830" height="436" src="https://github.com/user-attachments/assets/51526d6d-e5ec-41b4-aa37-242dec1cdb27">
2
+ <source media="(prefers-color-scheme: dark)" srcset=".github/assets/banner-dark.png">
3
+ <source media="(prefers-color-scheme: light)" srcset=".github/assets/banner-light.png">
4
+ <img alt="Nuxt UI" width="900" height="472" src=".github/assets/banner-light.png">
5
5
  </picture>
6
6
 
7
7
  # Nuxt UI
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/ui",
3
- "version": "4.11.1",
3
+ "version": "4.11.3",
4
4
  "docs": "https://ui.nuxt.com/docs/getting-started/installation/nuxt",
5
5
  "configKey": "ui",
6
6
  "compatibility": {
package/dist/module.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defu } from 'defu';
2
2
  import { defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addComponentsDir, addImportsDir, addImports } from '@nuxt/kit';
3
- import { d as defaultOptions, r as resolveColors, c as getDefaultConfig, g as getClientBundleIcons, f as publicComposables, a as addTemplates } from './shared/ui.DCJ9twx8.mjs';
3
+ import { d as defaultOptions, r as resolveColors, c as getDefaultConfig, g as getClientBundleIcons, f as publicComposables, a as addTemplates } from './shared/ui.CNAeRcb0.mjs';
4
4
  import '../dist/runtime/utils/index.js';
5
5
  import 'node:url';
6
6
  import 'scule';
@@ -14,7 +14,7 @@ import 'tinyglobby';
14
14
  import 'mlly';
15
15
 
16
16
  const name = "@nuxt/ui";
17
- const version = "4.11.1";
17
+ const version = "4.11.3";
18
18
 
19
19
  const module$1 = defineNuxtModule({
20
20
  meta: {
@@ -27,7 +27,7 @@ export interface AccordionItem {
27
27
  value?: string;
28
28
  disabled?: boolean;
29
29
  class?: any;
30
- ui?: Pick<Accordion['slots'], 'item' | 'header' | 'trigger' | 'leadingIcon' | 'label' | 'trailingIcon' | 'content' | 'body'>;
30
+ ui?: Partial<Pick<Accordion['slots'], 'item' | 'header' | 'trigger' | 'leadingIcon' | 'label' | 'trailingIcon' | 'content' | 'body'>>;
31
31
  [key: string]: any;
32
32
  }
33
33
  export interface AccordionProps<T extends AccordionItem = AccordionItem> extends Pick<AccordionRootProps, 'collapsible' | 'defaultValue' | 'modelValue' | 'type' | 'disabled' | 'unmountOnHide'> {
@@ -27,7 +27,7 @@ export interface AccordionItem {
27
27
  value?: string;
28
28
  disabled?: boolean;
29
29
  class?: any;
30
- ui?: Pick<Accordion['slots'], 'item' | 'header' | 'trigger' | 'leadingIcon' | 'label' | 'trailingIcon' | 'content' | 'body'>;
30
+ ui?: Partial<Pick<Accordion['slots'], 'item' | 'header' | 'trigger' | 'leadingIcon' | 'label' | 'trailingIcon' | 'content' | 'body'>>;
31
31
  [key: string]: any;
32
32
  }
33
33
  export interface AccordionProps<T extends AccordionItem = AccordionItem> extends Pick<AccordionRootProps, 'collapsible' | 'defaultValue' | 'modelValue' | 'type' | 'disabled' | 'unmountOnHide'> {
@@ -12,6 +12,7 @@ import { localeContextInjectionKey } from "../composables/useLocale";
12
12
  import { portalTargetInjectionKey } from "../composables/usePortal";
13
13
  import UToaster from "./Toaster.vue";
14
14
  import UOverlayProvider from "./OverlayProvider.vue";
15
+ import en from "../locale/en";
15
16
  const props = defineProps({
16
17
  tooltip: { type: Object, required: false },
17
18
  toaster: { type: [Object, null], required: false },
@@ -25,7 +26,7 @@ defineSlots();
25
26
  const configProviderProps = useForwardProps(reactivePick(props, "scrollBody"));
26
27
  const tooltipProps = toRef(() => props.tooltip);
27
28
  const toasterProps = toRef(() => props.toaster);
28
- const locale = toRef(() => props.locale);
29
+ const locale = toRef(() => props.dir ? { ...props.locale || en, dir: props.dir } : props.locale);
29
30
  provide(localeContextInjectionKey, locale);
30
31
  const portal = toRef(() => props.portal);
31
32
  provide(portalTargetInjectionKey, portal);
@@ -119,12 +119,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
119
119
  silent?: false | undefined;
120
120
  nested?: boolean;
121
121
  transform?: T_1 | undefined;
122
+ isCurrent?: (() => boolean) | undefined;
122
123
  }): Promise<FormData<T, T_1>>;
123
124
  <T_1 extends boolean>(opts: {
124
125
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
125
126
  silent?: true | undefined;
126
127
  nested?: boolean;
127
128
  transform?: T_1 | undefined;
129
+ isCurrent?: (() => boolean) | undefined;
128
130
  }): Promise<false | FormData<T, T_1>>;
129
131
  };
130
132
  errors: {
@@ -153,12 +155,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
153
155
  silent?: false | undefined;
154
156
  nested?: boolean;
155
157
  transform?: T_1 | undefined;
158
+ isCurrent?: (() => boolean) | undefined;
156
159
  }): Promise<FormData<T, T_1>>;
157
160
  <T_1 extends boolean>(opts: {
158
161
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
159
162
  silent?: true | undefined;
160
163
  nested?: boolean;
161
164
  transform?: T_1 | undefined;
165
+ isCurrent?: (() => boolean) | undefined;
162
166
  }): Promise<false | FormData<T, T_1>>;
163
167
  };
164
168
  errors: {
@@ -119,12 +119,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
119
119
  silent?: false | undefined;
120
120
  nested?: boolean;
121
121
  transform?: T_1 | undefined;
122
+ isCurrent?: (() => boolean) | undefined;
122
123
  }): Promise<FormData<T, T_1>>;
123
124
  <T_1 extends boolean>(opts: {
124
125
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
125
126
  silent?: true | undefined;
126
127
  nested?: boolean;
127
128
  transform?: T_1 | undefined;
129
+ isCurrent?: (() => boolean) | undefined;
128
130
  }): Promise<false | FormData<T, T_1>>;
129
131
  };
130
132
  errors: {
@@ -153,12 +155,14 @@ declare const __VLS_export: <T extends FormSchema, F extends AuthFormField>(__VL
153
155
  silent?: false | undefined;
154
156
  nested?: boolean;
155
157
  transform?: T_1 | undefined;
158
+ isCurrent?: (() => boolean) | undefined;
156
159
  }): Promise<FormData<T, T_1>>;
157
160
  <T_1 extends boolean>(opts: {
158
161
  name?: keyof InferInput<T> | (keyof InferInput<T>)[] | undefined;
159
162
  silent?: true | undefined;
160
163
  nested?: boolean;
161
164
  transform?: T_1 | undefined;
165
+ isCurrent?: (() => boolean) | undefined;
162
166
  }): Promise<false | FormData<T, T_1>>;
163
167
  };
164
168
  errors: {
@@ -16,7 +16,7 @@ export interface BreadcrumbItem extends Omit<LinkProps, 'raw' | 'custom'> {
16
16
  avatar?: AvatarProps;
17
17
  slot?: string;
18
18
  class?: any;
19
- ui?: Pick<Breadcrumb['slots'], 'item' | 'link' | 'linkLeadingIcon' | 'linkLeadingAvatar' | 'linkLabel' | 'separator' | 'separatorIcon'>;
19
+ ui?: Partial<Pick<Breadcrumb['slots'], 'item' | 'link' | 'linkLeadingIcon' | 'linkLeadingAvatar' | 'linkLabel' | 'separator' | 'separatorIcon'>>;
20
20
  [key: string]: any;
21
21
  }
22
22
  export interface BreadcrumbProps<T extends BreadcrumbItem = BreadcrumbItem> {
@@ -16,7 +16,7 @@ export interface BreadcrumbItem extends Omit<LinkProps, 'raw' | 'custom'> {
16
16
  avatar?: AvatarProps;
17
17
  slot?: string;
18
18
  class?: any;
19
- ui?: Pick<Breadcrumb['slots'], 'item' | 'link' | 'linkLeadingIcon' | 'linkLeadingAvatar' | 'linkLabel' | 'separator' | 'separatorIcon'>;
19
+ ui?: Partial<Pick<Breadcrumb['slots'], 'item' | 'link' | 'linkLeadingIcon' | 'linkLeadingAvatar' | 'linkLabel' | 'separator' | 'separatorIcon'>>;
20
20
  [key: string]: any;
21
21
  }
22
22
  export interface BreadcrumbProps<T extends BreadcrumbItem = BreadcrumbItem> {
@@ -17,7 +17,7 @@ type Carousel = ComponentConfig<typeof theme, AppConfig, 'carousel'>;
17
17
  export type CarouselValue = AcceptableValue;
18
18
  export type CarouselItem = CarouselValue | {
19
19
  class?: any;
20
- ui?: Pick<Carousel['slots'], 'item'>;
20
+ ui?: Partial<Pick<Carousel['slots'], 'item'>>;
21
21
  [key: string]: any;
22
22
  };
23
23
  export interface CarouselProps<T extends CarouselItem = CarouselItem> extends Omit<EmblaOptionsType, 'axis' | 'container' | 'slides' | 'direction'> {
@@ -17,7 +17,7 @@ type Carousel = ComponentConfig<typeof theme, AppConfig, 'carousel'>;
17
17
  export type CarouselValue = AcceptableValue;
18
18
  export type CarouselItem = CarouselValue | {
19
19
  class?: any;
20
- ui?: Pick<Carousel['slots'], 'item'>;
20
+ ui?: Partial<Pick<Carousel['slots'], 'item'>>;
21
21
  [key: string]: any;
22
22
  };
23
23
  export interface CarouselProps<T extends CarouselItem = CarouselItem> extends Omit<EmblaOptionsType, 'axis' | 'container' | 'slides' | 'direction'> {
@@ -83,7 +83,7 @@ defineExpose({
83
83
  </script>
84
84
 
85
85
  <template>
86
- <Primitive :as="props.as" :data-slot="$attrs['data-slot'] ?? 'root'" :class="ui.root({ class: [props.ui?.root, props.class] })" @submit.prevent="submit">
86
+ <Primitive :as="props.as" :method="props.as === 'form' ? 'post' : void 0" :data-slot="$attrs['data-slot'] ?? 'root'" :class="ui.root({ class: [props.ui?.root, props.class] })" @submit.prevent="submit">
87
87
  <div v-if="!!slots.header" data-slot="header" :class="ui.header({ class: props.ui?.header })">
88
88
  <slot name="header" />
89
89
  </div>
@@ -19,7 +19,7 @@ export type CheckboxGroupItem = CheckboxGroupValue | {
19
19
  */
20
20
  icon?: IconProps['name'];
21
21
  class?: any;
22
- ui?: Pick<CheckboxGroup['slots'], 'item'> & Omit<Required<CheckboxProps>['ui'], 'root'>;
22
+ ui?: Partial<Pick<CheckboxGroup['slots'], 'item'>> & Omit<Required<CheckboxProps>['ui'], 'root'>;
23
23
  [key: string]: any;
24
24
  };
25
25
  export interface CheckboxGroupProps<T extends CheckboxGroupItem[] = CheckboxGroupItem[], VK extends GetItemKeys<T> = 'value'> extends Pick<CheckboxGroupRootProps, 'disabled' | 'loop' | 'name' | 'required'>, Pick<CheckboxProps, 'color' | 'highlight' | 'indicator' | 'icon'> {
@@ -19,7 +19,7 @@ export type CheckboxGroupItem = CheckboxGroupValue | {
19
19
  */
20
20
  icon?: IconProps['name'];
21
21
  class?: any;
22
- ui?: Pick<CheckboxGroup['slots'], 'item'> & Omit<Required<CheckboxProps>['ui'], 'root'>;
22
+ ui?: Partial<Pick<CheckboxGroup['slots'], 'item'>> & Omit<Required<CheckboxProps>['ui'], 'root'>;
23
23
  [key: string]: any;
24
24
  };
25
25
  export interface CheckboxGroupProps<T extends CheckboxGroupItem[] = CheckboxGroupItem[], VK extends GetItemKeys<T> = 'value'> extends Pick<CheckboxGroupRootProps, 'disabled' | 'loop' | 'name' | 'required'>, Pick<CheckboxProps, 'color' | 'highlight' | 'indicator' | 'icon'> {
@@ -37,7 +37,7 @@ export interface CommandPaletteItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
37
37
  children?: CommandPaletteItem[];
38
38
  onSelect?: (e: Event) => void;
39
39
  class?: any;
40
- ui?: Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>;
40
+ ui?: Partial<Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>>;
41
41
  [key: string]: any;
42
42
  }
43
43
  export interface CommandPaletteGroup<T extends CommandPaletteItem = CommandPaletteItem> {
@@ -37,7 +37,7 @@ export interface CommandPaletteItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
37
37
  children?: CommandPaletteItem[];
38
38
  onSelect?: (e: Event) => void;
39
39
  class?: any;
40
- ui?: Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>;
40
+ ui?: Partial<Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>>;
41
41
  [key: string]: any;
42
42
  }
43
43
  export interface CommandPaletteGroup<T extends CommandPaletteItem = CommandPaletteItem> {
@@ -37,7 +37,7 @@ export interface ContextMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'custo
37
37
  onSelect?: (e: Event) => void;
38
38
  onUpdateChecked?: (checked: boolean) => void;
39
39
  class?: any;
40
- ui?: Pick<ContextMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>;
40
+ ui?: Partial<Pick<ContextMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>>;
41
41
  [key: string]: any;
42
42
  }
43
43
  export interface ContextMenuProps<T extends ArrayOrNested<ContextMenuItem> = ArrayOrNested<ContextMenuItem>> extends Omit<ContextMenuRootProps, 'dir'> {
@@ -37,7 +37,7 @@ export interface ContextMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'custo
37
37
  onSelect?: (e: Event) => void;
38
38
  onUpdateChecked?: (checked: boolean) => void;
39
39
  class?: any;
40
- ui?: Pick<ContextMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>;
40
+ ui?: Partial<Pick<ContextMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>>;
41
41
  [key: string]: any;
42
42
  }
43
43
  export interface ContextMenuProps<T extends ArrayOrNested<ContextMenuItem> = ArrayOrNested<ContextMenuItem>> extends Omit<ContextMenuRootProps, 'dir'> {
@@ -52,7 +52,7 @@ const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.dashboardNavbar |
52
52
  <UIcon v-if="props.icon" :name="props.icon" data-slot="icon" :class="ui.icon({ class: props.ui?.icon })" />
53
53
  </slot>
54
54
 
55
- <h1 data-slot="title" :class="ui.title({ class: props.ui?.title })">
55
+ <h1 v-if="props.title || !!slots.title" data-slot="title" :class="ui.title({ class: props.ui?.title })">
56
56
  <slot name="title">
57
57
  {{ props.title }}
58
58
  </slot>
@@ -60,7 +60,7 @@ const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" }
60
60
  useRuntimeHook("dashboard:search:toggle", () => {
61
61
  open.value = !open.value;
62
62
  });
63
- const { t } = useLocale();
63
+ const { t, locale } = useLocale();
64
64
  const colorMode = useColorMode();
65
65
  const appConfig = useAppConfig();
66
66
  const commandPaletteProps = useForwardProps(reactivePick(props, "size", "icon", "trailingIcon", "selectedIcon", "childrenIcon", "placeholder", "autofocus", "loading", "loadingIcon", "close", "closeIcon", "back", "backIcon", "disabled", "highlightOnHover", "labelKey", "descriptionKey", "preserveGroupOrder", "virtualize", "searchDelay"));
@@ -136,8 +136,8 @@ defineExpose({
136
136
  <template>
137
137
  <UModal
138
138
  v-model:open="open"
139
- :title="props.title || t('dashboardSearch.title')"
140
- :description="props.description || t('dashboardSearch.description')"
139
+ :title="props.title || locale.messages.dashboardSearch?.title || t('dashboardSearchButton.label')"
140
+ :description="props.description || locale.messages.dashboardSearch?.description"
141
141
  v-bind="modalProps"
142
142
  data-slot="modal"
143
143
  :class="ui.modal({ class: [props.ui?.modal, props.class] })"
@@ -40,7 +40,7 @@ const props = useComponentProps("dashboardSidebar", _props);
40
40
  const open = defineModel("open", { type: Boolean, ...{ default: false } });
41
41
  const collapsed = defineModel("collapsed", { type: Boolean, ...{ default: false } });
42
42
  const route = useRoute();
43
- const { t } = useLocale();
43
+ const { t, locale } = useLocale();
44
44
  const appConfig = useAppConfig();
45
45
  const dashboardContext = useDashboard({
46
46
  storageKey: "dashboard",
@@ -134,8 +134,8 @@ function toggleOpen() {
134
134
 
135
135
  <Menu
136
136
  v-model:open="open"
137
- :title="t('dashboardSidebar.title')"
138
- :description="t('dashboardSidebar.description')"
137
+ :title="locale.messages.dashboardSidebar?.title || t('dashboardSidebarToggle.open')"
138
+ :description="locale.messages.dashboardSidebar?.description"
139
139
  v-bind="menuProps"
140
140
  :ui="{
141
141
  overlay: ui.overlay({ class: props.ui?.overlay }),
@@ -41,7 +41,7 @@ export interface DropdownMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cust
41
41
  onSelect?: (e: Event) => void;
42
42
  onUpdateChecked?: (checked: boolean) => void;
43
43
  class?: any;
44
- ui?: Pick<DropdownMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>;
44
+ ui?: Partial<Pick<DropdownMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>>;
45
45
  [key: string]: any;
46
46
  }
47
47
  export interface DropdownMenuProps<T extends ArrayOrNested<DropdownMenuItem> = ArrayOrNested<DropdownMenuItem>> extends Omit<DropdownMenuRootProps, 'dir'> {
@@ -41,7 +41,7 @@ export interface DropdownMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cust
41
41
  onSelect?: (e: Event) => void;
42
42
  onUpdateChecked?: (checked: boolean) => void;
43
43
  class?: any;
44
- ui?: Pick<DropdownMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>;
44
+ ui?: Partial<Pick<DropdownMenu['slots'], 'content' | 'item' | 'label' | 'separator' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemLabelExternalIcon' | 'itemTrailing' | 'itemTrailingIcon' | 'itemTrailingKbds' | 'itemTrailingKbdsSize'>>;
45
45
  [key: string]: any;
46
46
  }
47
47
  export interface DropdownMenuProps<T extends ArrayOrNested<DropdownMenuItem> = ArrayOrNested<DropdownMenuItem>> extends Omit<DropdownMenuRootProps, 'dir'> {
@@ -138,11 +138,12 @@ function getButtonProps(item) {
138
138
  }
139
139
  }
140
140
  return defu(baseProps, {
141
- color: props.color,
142
- activeColor: props.activeColor,
143
- activeVariant: props.activeVariant,
144
- variant: props.variant,
145
- size: props.size
141
+ "aria-label": baseProps.label ? void 0 : item.tooltip?.text,
142
+ "color": props.color,
143
+ "activeColor": props.activeColor,
144
+ "activeVariant": props.activeVariant,
145
+ "variant": props.variant,
146
+ "size": props.size
146
147
  });
147
148
  }
148
149
  function getDropdownProps(item) {
@@ -12,7 +12,7 @@ export interface FooterColumnLink extends Omit<LinkProps, 'custom'> {
12
12
  */
13
13
  icon?: IconProps['name'];
14
14
  class?: any;
15
- ui?: Pick<FooterColumns['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>;
15
+ ui?: Partial<Pick<FooterColumns['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>>;
16
16
  }
17
17
  export interface FooterColumn<T extends FooterColumnLink = FooterColumnLink> {
18
18
  label: string;
@@ -12,7 +12,7 @@ export interface FooterColumnLink extends Omit<LinkProps, 'custom'> {
12
12
  */
13
13
  icon?: IconProps['name'];
14
14
  class?: any;
15
- ui?: Pick<FooterColumns['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>;
15
+ ui?: Partial<Pick<FooterColumns['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>>;
16
16
  }
17
17
  export interface FooterColumn<T extends FooterColumnLink = FooterColumnLink> {
18
18
  label: string;
@@ -79,12 +79,14 @@ declare const __VLS_export: <S extends FormSchema, T extends boolean = true, N e
79
79
  silent?: false | undefined;
80
80
  nested?: boolean;
81
81
  transform?: T_1 | undefined;
82
+ isCurrent?: () => boolean;
82
83
  }): Promise<FormData<S, T_1>>;
83
84
  <T_1 extends boolean>(opts: {
84
85
  name?: keyof InferInput<S> | (keyof InferInput<S>)[] | undefined;
85
86
  silent?: true | undefined;
86
87
  nested?: boolean;
87
88
  transform?: T_1 | undefined;
89
+ isCurrent?: () => boolean;
88
90
  }): Promise<FormData<S, T_1> | false>;
89
91
  };
90
92
  errors: import("vue").Ref<{
@@ -3,7 +3,7 @@ import theme from "#build/ui/form";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly, reactive, useTemplateRef } from "vue";
6
+ import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly, reactive, useTemplateRef, unref, toRaw } from "vue";
7
7
  import { useEventBus } from "@vueuse/core";
8
8
  import { useAppConfig } from "#imports";
9
9
  import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey, formErrorsInjectionKey, formStateInjectionKey } from "../composables/useFormField";
@@ -54,7 +54,7 @@ const nestedForms = ref(/* @__PURE__ */ new Map());
54
54
  onMounted(async () => {
55
55
  if (parentBus) {
56
56
  await nextTick();
57
- parentBus.emit({ type: "attach", validate: _validate, formId, name: props.name, api });
57
+ parentBus.emit({ type: "attach", validate: _validate, clearDirty, formId, name: props.name, api });
58
58
  }
59
59
  });
60
60
  onUnmounted(() => {
@@ -66,25 +66,37 @@ onUnmounted(() => {
66
66
  onMounted(async () => {
67
67
  bus.on(async (event) => {
68
68
  if (event.type === "attach") {
69
- nestedForms.value.set(event.formId, { validate: event.validate, name: event.name, api: event.api });
70
- } else if (event.type === "detach") {
71
- nestedForms.value.delete(event.formId);
72
- } else if (props.validateOn?.includes(event.type) && !loading.value) {
73
- if (event.type !== "input") {
74
- await _validate({ name: event.name, silent: true, nested: false });
75
- } else if (event.eager || blurredFields.has(event.name)) {
76
- await _validate({ name: event.name, silent: true, nested: false });
77
- }
69
+ nestedForms.value.set(event.formId, { validate: event.validate, clearDirty: event.clearDirty, name: event.name, api: event.api });
70
+ return;
78
71
  }
79
- if (event.type === "blur") {
80
- blurredFields.add(event.name);
72
+ if (event.type === "detach") {
73
+ nestedForms.value.delete(event.formId);
74
+ return;
81
75
  }
82
- if (event.type === "change" || event.type === "input" || event.type === "blur" || event.type === "focus") {
76
+ if (event.track !== false) {
77
+ if (event.type === "blur") {
78
+ blurredFields.add(event.name);
79
+ }
80
+ if (event.type === "change" || event.type === "input") {
81
+ dirtyFields.add(event.name);
82
+ dirtyEpochs.set(event.name, epoch);
83
+ }
84
+ if (event.type === "input") {
85
+ inputEpochs.set(event.name, epoch);
86
+ }
83
87
  touchedFields.add(event.name);
84
88
  }
85
- if (event.type === "change" || event.type === "input") {
86
- dirtyFields.add(event.name);
87
- }
89
+ if (event.validate === false || !props.validateOn?.includes(event.type) || loading.value) return;
90
+ if (event.type === "input" && (inputEpochs.get(event.name) !== epoch || !(event.eager || blurredFields.has(event.name)))) return;
91
+ const run = (validationRuns.get(event.name) ?? 0) + 1;
92
+ validationRuns.set(event.name, run);
93
+ const startEpoch = epoch;
94
+ await _validate({
95
+ name: event.name,
96
+ silent: true,
97
+ nested: false,
98
+ isCurrent: () => validationRuns.get(event.name) === run && epoch === startEpoch
99
+ });
88
100
  });
89
101
  });
90
102
  const errors = ref([]);
@@ -94,6 +106,18 @@ provide(formInputsInjectionKey, inputs);
94
106
  const dirtyFields = reactive(/* @__PURE__ */ new Set());
95
107
  const touchedFields = reactive(/* @__PURE__ */ new Set());
96
108
  const blurredFields = reactive(/* @__PURE__ */ new Set());
109
+ let epoch = 0;
110
+ const inputEpochs = /* @__PURE__ */ new Map();
111
+ const validationRuns = /* @__PURE__ */ new Map();
112
+ const dirtyEpochs = /* @__PURE__ */ new Map();
113
+ function clearDirty() {
114
+ for (const field of dirtyFields) {
115
+ if (dirtyEpochs.get(field) !== epoch) dirtyFields.delete(field);
116
+ }
117
+ for (const form of nestedForms.value.values()) {
118
+ form.clearDirty();
119
+ }
120
+ }
97
121
  function resolveErrorIds(errs) {
98
122
  return errs.map((err) => ({
99
123
  ...err,
@@ -115,6 +139,7 @@ async function getErrors() {
115
139
  }
116
140
  async function _validate(opts = { silent: false, nested: false, transform: false }) {
117
141
  const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name;
142
+ if (!names) epoch++;
118
143
  let nestedResults = [];
119
144
  let nestedErrors = [];
120
145
  if (!names && opts.nested) {
@@ -126,25 +151,30 @@ async function _validate(opts = { silent: false, nested: false, transform: false
126
151
  nestedResults = results.filter((r) => r.output !== void 0);
127
152
  }
128
153
  const currentErrors = await getErrors();
154
+ if (opts.isCurrent?.() === false) return false;
129
155
  const allErrors = [...currentErrors, ...nestedErrors];
156
+ let failedErrors = allErrors;
130
157
  if (names) {
131
- errors.value = filterErrorsByNames(allErrors, names);
158
+ const matchesNames = nameMatcher(names);
159
+ failedErrors = allErrors.filter(matchesNames);
160
+ errors.value = [...errors.value.filter((error) => !matchesNames(error)), ...failedErrors];
132
161
  } else {
133
162
  errors.value = allErrors;
134
163
  }
135
- if (errors.value?.length) {
164
+ if (failedErrors.length) {
136
165
  if (opts.silent) return false;
137
- throw new FormValidationException(formId, errors.value);
166
+ throw new FormValidationException(formId, failedErrors);
138
167
  }
139
168
  if (opts.transform) {
169
+ let output = transformedState.value;
140
170
  nestedResults.forEach((result) => {
141
171
  if (result.name) {
142
172
  setAtPath(transformedState.value, result.name, result.output);
143
173
  } else {
144
- Object.assign(transformedState.value, result.output);
174
+ output = Object.assign(output ?? { ...toRaw(state.value) }, result.output);
145
175
  }
146
176
  });
147
- return transformedState.value ?? state.value;
177
+ return output ?? state.value;
148
178
  }
149
179
  return state.value;
150
180
  }
@@ -156,7 +186,7 @@ async function onSubmitWrapper(payload) {
156
186
  try {
157
187
  event.data = await _validate({ nested: true, transform: props.transform });
158
188
  await props.onSubmit?.(event);
159
- dirtyFields.clear();
189
+ clearDirty();
160
190
  } catch (error) {
161
191
  if (!(error instanceof FormValidationException)) {
162
192
  throw error;
@@ -215,17 +245,14 @@ function getNestedTarget(target, formPath) {
215
245
  }
216
246
  return target;
217
247
  }
218
- function filterErrorsByNames(allErrors, names) {
248
+ function nameMatcher(names) {
219
249
  const nameSet = new Set(names);
220
250
  const patterns = names.map((name) => inputs.value?.[name]?.pattern).filter(Boolean);
221
- const matchesNames = (error) => {
251
+ return (error) => {
222
252
  if (!error.name) return false;
223
253
  if (nameSet.has(error.name)) return true;
224
254
  return patterns.some((pattern) => pattern.test(error.name));
225
255
  };
226
- const keepErrors = errors.value.filter((error) => !matchesNames(error));
227
- const newErrors = allErrors.filter(matchesNames);
228
- return [...keepErrors, ...newErrors];
229
256
  }
230
257
  function filterErrorsByTarget(currentErrors, target) {
231
258
  return currentErrors.filter(
@@ -273,14 +300,14 @@ const api = {
273
300
  ) : [];
274
301
  const nestedErrors = [];
275
302
  for (const form of nestedForms.value.values()) {
276
- if (matchesTarget(name, form.name)) form.api.clear();
303
+ if (matchesTarget(name, form.name)) form.api.clear(name instanceof RegExp ? void 0 : getNestedTarget(name, form.name || ""));
277
304
  nestedErrors.push(...getFormErrors(form));
278
305
  }
279
306
  errors.value = [...localErrors, ...nestedErrors];
280
307
  },
281
308
  disabled,
282
309
  loading,
283
- dirty: computed(() => !!dirtyFields.size),
310
+ dirty: computed(() => !!dirtyFields.size || Array.from(nestedForms.value.values()).some((form) => unref(form.api.dirty))),
284
311
  dirtyFields: readonly(dirtyFields),
285
312
  blurredFields: readonly(blurredFields),
286
313
  touchedFields: readonly(touchedFields)
@@ -79,12 +79,14 @@ declare const __VLS_export: <S extends FormSchema, T extends boolean = true, N e
79
79
  silent?: false | undefined;
80
80
  nested?: boolean;
81
81
  transform?: T_1 | undefined;
82
+ isCurrent?: () => boolean;
82
83
  }): Promise<FormData<S, T_1>>;
83
84
  <T_1 extends boolean>(opts: {
84
85
  name?: keyof InferInput<S> | (keyof InferInput<S>)[] | undefined;
85
86
  silent?: true | undefined;
86
87
  nested?: boolean;
87
88
  transform?: T_1 | undefined;
89
+ isCurrent?: () => boolean;
88
90
  }): Promise<FormData<S, T_1> | false>;
89
91
  };
90
92
  errors: import("vue").Ref<{
@@ -35,7 +35,7 @@ const slots = defineSlots();
35
35
  const props = useComponentProps("header", _props);
36
36
  const open = defineModel("open", { type: Boolean, ...{ default: false } });
37
37
  const route = useRoute();
38
- const { t } = useLocale();
38
+ const { t, locale } = useLocale();
39
39
  const appConfig = useAppConfig();
40
40
  const [DefineLeftTemplate, ReuseLeftTemplate] = createReusableTemplate();
41
41
  const [DefineRightTemplate, ReuseRightTemplate] = createReusableTemplate();
@@ -117,8 +117,8 @@ function toggleOpen() {
117
117
 
118
118
  <Menu
119
119
  v-model:open="open"
120
- :title="t('header.title')"
121
- :description="t('header.description')"
120
+ :title="locale.messages.header?.title || t('header.open')"
121
+ :description="locale.messages.header?.description"
122
122
  v-bind="menuProps"
123
123
  :ui="{
124
124
  overlay: ui.overlay({ class: props.ui?.overlay }),