@nuxt/ui 3.0.0-alpha.1 → 3.0.0-alpha.2

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.
package/dist/module.d.mts CHANGED
@@ -13,10 +13,17 @@ interface ModuleOptions {
13
13
  */
14
14
  colors?: string[];
15
15
  /**
16
- * Disable color transitions
16
+ * Enable or disable `@nuxt/fonts` module
17
17
  * @defaultValue true
18
18
  */
19
- transitions?: boolean;
19
+ fonts?: boolean;
20
+ theme?: {
21
+ /**
22
+ * Enable or disable transitions on components
23
+ * @defaultValue true
24
+ */
25
+ transitions?: boolean;
26
+ };
20
27
  }
21
28
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
22
29
 
package/dist/module.d.ts CHANGED
@@ -13,10 +13,17 @@ interface ModuleOptions {
13
13
  */
14
14
  colors?: string[];
15
15
  /**
16
- * Disable color transitions
16
+ * Enable or disable `@nuxt/fonts` module
17
17
  * @defaultValue true
18
18
  */
19
- transitions?: boolean;
19
+ fonts?: boolean;
20
+ theme?: {
21
+ /**
22
+ * Enable or disable transitions on components
23
+ * @defaultValue true
24
+ */
25
+ transitions?: boolean;
26
+ };
20
27
  }
21
28
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
22
29
 
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.13.1"
6
6
  },
7
- "version": "3.0.0-alpha.1",
7
+ "version": "3.0.0-alpha.2",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defuFn, defu } from 'defu';
2
- import { addTemplate, addTypeTemplate, defineNuxtModule, createResolver, addVitePlugin, installModule, addPlugin, addComponentsDir, addImportsDir } from '@nuxt/kit';
2
+ import { addTemplate, addTypeTemplate, defineNuxtModule, createResolver, addVitePlugin, hasNuxtModule, installModule, addPlugin, addComponentsDir, addImportsDir } from '@nuxt/kit';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { kebabCase } from 'scule';
5
5
 
@@ -292,7 +292,7 @@ const breadcrumb = (options) => ({
292
292
  active: false,
293
293
  to: true,
294
294
  class: {
295
- link: ["hover:text-gray-700 dark:hover:text-gray-200", options.transitions && "transition-colors"]
295
+ link: ["hover:text-gray-700 dark:hover:text-gray-200", options.theme?.transitions && "transition-colors"]
296
296
  }
297
297
  }]
298
298
  });
@@ -334,7 +334,7 @@ const buttonGroup = {
334
334
 
335
335
  const button = (options) => ({
336
336
  slots: {
337
- base: ["rounded-md font-medium inline-flex items-center focus:outline-none disabled:cursor-not-allowed disabled:opacity-75", options.transitions && "transition-colors"],
337
+ base: ["rounded-md font-medium inline-flex items-center focus:outline-none disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75", options.theme?.transitions && "transition-colors"],
338
338
  label: "truncate",
339
339
  leadingIcon: "shrink-0",
340
340
  leadingAvatar: "shrink-0",
@@ -403,51 +403,51 @@ const button = (options) => ({
403
403
  compoundVariants: [...options.colors.map((color) => ({
404
404
  color,
405
405
  variant: "solid",
406
- class: `text-white dark:text-gray-900 bg-${color}-500 hover:bg-${color}-600 disabled:bg-${color}-500 dark:bg-${color}-400 dark:hover:bg-${color}-500 dark:disabled:bg-${color}-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-${color}-500 dark:focus-visible:outline-${color}-400`
406
+ class: `text-white dark:text-gray-900 bg-${color}-500 hover:bg-${color}-600 disabled:bg-${color}-500 aria-disabled:bg-${color}-500 dark:bg-${color}-400 dark:hover:bg-${color}-500 dark:disabled:bg-${color}-400 dark:aria-disabled:bg-${color}-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-${color}-500 dark:focus-visible:outline-${color}-400`
407
407
  })), ...options.colors.map((color) => ({
408
408
  color,
409
409
  variant: "outline",
410
- class: `ring ring-inset ring-${color}-500/50 dark:ring-${color}-400/50 text-${color}-500 dark:text-${color}-400 hover:bg-${color}-500/10 disabled:bg-transparent dark:hover:bg-${color}-400/10 dark:disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
410
+ class: `ring ring-inset ring-${color}-500/50 dark:ring-${color}-400/50 text-${color}-500 dark:text-${color}-400 hover:bg-${color}-500/10 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-${color}-400/10 dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
411
411
  })), ...options.colors.map((color) => ({
412
412
  color,
413
413
  variant: "soft",
414
- class: `text-${color}-500 dark:text-${color}-400 bg-${color}-500/10 hover:bg-${color}-500/15 focus-visible:bg-${color}-500/15 disabled:bg-${color}-500/10 dark:bg-${color}-400/10 dark:hover:bg-${color}-400/15 dark:focus-visible:bg-${color}-400/15 dark:disabled:bg-${color}-400/10`
414
+ class: `text-${color}-500 dark:text-${color}-400 bg-${color}-500/10 hover:bg-${color}-500/15 focus-visible:bg-${color}-500/15 disabled:bg-${color}-500/10 aria-disabled:bg-${color}-500/10 dark:bg-${color}-400/10 dark:hover:bg-${color}-400/15 dark:focus-visible:bg-${color}-400/15 dark:disabled:bg-${color}-400/10 dark:aria-disabled:bg-${color}-400/10`
415
415
  })), ...options.colors.map((color) => ({
416
416
  color,
417
417
  variant: "subtle",
418
- class: `text-${color}-500 dark:text-${color}-400 ring ring-inset ring-${color}-500/25 dark:ring-${color}-400/25 bg-${color}-500/10 hover:bg-${color}-500/15 disabled:bg-${color}-500/10 dark:bg-${color}-400/10 dark:hover:bg-${color}-400/15 dark:disabled:bg-${color}-400/10 focus-visible:ring-2 focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
418
+ class: `text-${color}-500 dark:text-${color}-400 ring ring-inset ring-${color}-500/25 dark:ring-${color}-400/25 bg-${color}-500/10 hover:bg-${color}-500/15 disabled:bg-${color}-500/10 aria-disabled:bg-${color}-500/10 dark:bg-${color}-400/10 dark:hover:bg-${color}-400/15 dark:disabled:bg-${color}-400/10 dark:aria-disabled:bg-${color}-400/10 focus-visible:ring-2 focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
419
419
  })), ...options.colors.map((color) => ({
420
420
  color,
421
421
  variant: "ghost",
422
- class: `text-${color}-500 dark:text-${color}-400 hover:bg-${color}-500/10 focus-visible:bg-${color}-500/10 disabled:bg-transparent dark:hover:bg-${color}-400/10 dark:focus-visible:bg-${color}-400/10 dark:disabled:bg-transparent`
422
+ class: `text-${color}-500 dark:text-${color}-400 hover:bg-${color}-500/10 focus-visible:bg-${color}-500/10 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-${color}-400/10 dark:focus-visible:bg-${color}-400/10 dark:disabled:bg-transparent dark:aria-disabled:bg-transparent`
423
423
  })), ...options.colors.map((color) => ({
424
424
  color,
425
425
  variant: "link",
426
- class: `text-${color}-500 hover:text-${color}-600 disabled:text-${color}-500 dark:text-${color}-400 dark:hover:text-${color}-500 dark:disabled:text-${color}-400 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
426
+ class: `text-${color}-500 hover:text-${color}-600 disabled:text-${color}-500 aria-disabled:text-${color}-500 dark:text-${color}-400 dark:hover:text-${color}-500 dark:disabled:text-${color}-400 dark:aria-disabled:text-${color}-400 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
427
427
  })), {
428
428
  color: "gray",
429
429
  variant: "solid",
430
- class: "text-white dark:text-gray-900 bg-gray-900 hover:bg-gray-700 disabled:bg-gray-900 dark:bg-white dark:hover:bg-gray-200 dark:disabled:bg-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900 dark:focus-visible:outline-white"
430
+ class: "text-white dark:text-gray-900 bg-gray-900 hover:bg-gray-700 disabled:bg-gray-900 aria-disabled:bg-gray-900 dark:bg-white dark:hover:bg-gray-200 dark:disabled:bg-white dark:aria-disabled:bg-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900 dark:focus-visible:outline-white"
431
431
  }, {
432
432
  color: "gray",
433
433
  variant: "outline",
434
- class: "ring ring-inset ring-gray-300 dark:ring-gray-700 text-gray-700 dark:text-gray-200 bg-white hover:bg-gray-100 disabled:bg-white dark:bg-gray-900 dark:hover:bg-gray-800 dark:disabled:bg-gray-900 focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white"
434
+ class: "ring ring-inset ring-gray-300 dark:ring-gray-700 text-gray-700 dark:text-gray-200 bg-white hover:bg-gray-100 disabled:bg-white aria-disabled:bg-white dark:bg-gray-900 dark:hover:bg-gray-800 dark:disabled:bg-gray-900 dark:aria-disabled:bg-gray-900 focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white"
435
435
  }, {
436
436
  color: "gray",
437
437
  variant: "soft",
438
- class: "text-gray-700 dark:text-gray-200 bg-gray-100 hover:bg-gray-200 focus-visible:bg-gray-200 disabled:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700/50 dark:focus-visible:bg-gray-700/50 dark:disabled:bg-gray-800"
438
+ class: "text-gray-700 dark:text-gray-200 bg-gray-100 hover:bg-gray-200 focus-visible:bg-gray-200 disabled:bg-gray-100 aria-disabled:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700/50 dark:focus-visible:bg-gray-700/50 dark:disabled:bg-gray-800 dark:aria-disabled:bg-gray-800"
439
439
  }, {
440
440
  color: "gray",
441
441
  variant: "subtle",
442
- class: "ring ring-inset ring-gray-300 dark:ring-gray-700 text-gray-700 dark:text-gray-200 bg-gray-100 hover:bg-gray-200 disabled:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700/50 dark:disabled:bg-gray-800 focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white"
442
+ class: "ring ring-inset ring-gray-300 dark:ring-gray-700 text-gray-700 dark:text-gray-200 bg-gray-100 hover:bg-gray-200 disabled:bg-gray-100 aria-disabled:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700/50 dark:disabled:bg-gray-800 dark:aria-disabled:bg-gray-800 focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white"
443
443
  }, {
444
444
  color: "gray",
445
445
  variant: "ghost",
446
- class: "text-gray-700 dark:text-gray-200 hover:bg-gray-100 focus-visible:bg-gray-100 disabled:bg-transparent dark:hover:bg-gray-800 dark:focus-visible:bg-gray-800 dark:hover:disabled:bg-transparent"
446
+ class: "text-gray-700 dark:text-gray-200 hover:bg-gray-100 focus-visible:bg-gray-100 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-gray-800 dark:focus-visible:bg-gray-800 dark:hover:disabled:bg-transparent dark:hover:aria-disabled:bg-transparent"
447
447
  }, {
448
448
  color: "gray",
449
449
  variant: "link",
450
- class: "text-gray-500 hover:text-gray-700 disabled:text-gray-500 dark:text-gray-400 dark:hover:text-gray-200 dark:disabled:text-gray-400 focus-visible:ring-inset focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white"
450
+ class: "text-gray-500 hover:text-gray-700 disabled:text-gray-500 aria-disabled:text-gray-500 dark:text-gray-400 dark:hover:text-gray-200 dark:disabled:text-gray-400 dark:aria-disabled:text-gray-400 focus-visible:ring-inset focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-white"
451
451
  }, {
452
452
  size: "xs",
453
453
  square: true,
@@ -646,8 +646,8 @@ const commandPalette = (options) => ({
646
646
  group: "p-1 isolate",
647
647
  empty: "py-6 text-center text-sm",
648
648
  label: "px-2 py-1.5 text-xs font-semibold text-gray-900 dark:text-white",
649
- item: ["group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50", options.transitions && "transition-colors before:transition-colors"],
650
- itemLeadingIcon: ["shrink-0 size-5 text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200", options.transitions && "transition-colors"],
649
+ item: ["group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50", options.theme?.transitions && "transition-colors before:transition-colors"],
650
+ itemLeadingIcon: ["shrink-0 size-5 text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200", options.theme?.transitions && "transition-colors"],
651
651
  itemLeadingAvatar: "shrink-0",
652
652
  itemLeadingAvatarSize: "2xs",
653
653
  itemLeadingChip: "shrink-0 size-5",
@@ -692,8 +692,8 @@ const contextMenu = (options) => ({
692
692
  itemLeadingIcon: "text-gray-700 dark:text-gray-200"
693
693
  },
694
694
  false: {
695
- item: ["text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-[state=open]:text-gray-900 dark:data-[state=open]:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50 data-[state=open]:before:bg-gray-50 dark:data-[state=open]:before:bg-gray-800/50", options.transitions && "transition-colors before:transition-colors"],
696
- itemLeadingIcon: ["text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.transitions && "transition-colors"]
695
+ item: ["text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-[state=open]:text-gray-900 dark:data-[state=open]:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50 data-[state=open]:before:bg-gray-50 dark:data-[state=open]:before:bg-gray-800/50", options.theme?.transitions && "transition-colors before:transition-colors"],
696
+ itemLeadingIcon: ["text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.theme?.transitions && "transition-colors"]
697
697
  }
698
698
  },
699
699
  size: {
@@ -788,8 +788,8 @@ const dropdownMenu = (options) => ({
788
788
  itemLeadingIcon: "text-gray-700 dark:text-gray-200"
789
789
  },
790
790
  false: {
791
- item: ["text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-[state=open]:text-gray-900 dark:data-[state=open]:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50 data-[state=open]:before:bg-gray-50 dark:data-[state=open]:before:bg-gray-800/50", options.transitions && "transition-colors before:transition-colors"],
792
- itemLeadingIcon: ["text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.transitions && "transition-colors"]
791
+ item: ["text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-[state=open]:text-gray-900 dark:data-[state=open]:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50 data-[state=open]:before:bg-gray-50 dark:data-[state=open]:before:bg-gray-800/50", options.theme?.transitions && "transition-colors before:transition-colors"],
792
+ itemLeadingIcon: ["text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.theme?.transitions && "transition-colors"]
793
793
  }
794
794
  },
795
795
  size: {
@@ -883,7 +883,7 @@ const formField = {
883
883
  const input = (options) => ({
884
884
  slots: {
885
885
  root: "relative inline-flex items-center",
886
- base: ["w-full rounded-md border-0 focus:outline-none disabled:cursor-not-allowed disabled:opacity-75", options.transitions && "transition-colors"],
886
+ base: ["w-full rounded-md border-0 focus:outline-none disabled:cursor-not-allowed disabled:opacity-75", options.theme?.transitions && "transition-colors"],
887
887
  leading: "absolute inset-y-0 start-0 flex items-center",
888
888
  leadingIcon: "shrink-0 text-gray-400 dark:text-gray-500",
889
889
  leadingAvatar: "shrink-0",
@@ -1036,6 +1036,8 @@ const input = (options) => ({
1036
1036
  const inputMenu = (options) => {
1037
1037
  return defuFn({
1038
1038
  slots: {
1039
+ base: () => ["rounded-md", options.theme?.transitions && "transition-colors"],
1040
+ trailing: "absolute inset-y-0 end-0 flex items-center disabled:cursor-not-allowed disabled:opacity-75",
1039
1041
  arrow: "fill-gray-200 dark:fill-gray-800",
1040
1042
  content: "max-h-60 w-[--radix-popper-anchor-width] bg-white dark:bg-gray-900 shadow-lg rounded-md ring ring-gray-200 dark:ring-gray-800 overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in]",
1041
1043
  viewport: "divide-y divide-gray-200 dark:divide-gray-800 scroll-py-1",
@@ -1043,8 +1045,8 @@ const inputMenu = (options) => {
1043
1045
  empty: "py-2 text-center text-sm text-gray-500 dark:text-gray-400",
1044
1046
  label: "font-semibold text-gray-900 dark:text-white",
1045
1047
  separator: "-mx-1 my-1 h-px bg-gray-200 dark:bg-gray-800",
1046
- item: ["group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50", options.transitions && "transition-colors before:transition-colors"],
1047
- itemLeadingIcon: ["shrink-0 text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200", options.transitions && "transition-colors"],
1048
+ item: ["group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50", options.theme?.transitions && "transition-colors before:transition-colors"],
1049
+ itemLeadingIcon: ["shrink-0 text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200", options.theme?.transitions && "transition-colors"],
1048
1050
  itemLeadingAvatar: "shrink-0",
1049
1051
  itemLeadingAvatarSize: "",
1050
1052
  itemLeadingChip: "shrink-0",
@@ -1054,14 +1056,9 @@ const inputMenu = (options) => {
1054
1056
  itemLabel: "truncate",
1055
1057
  tagsItem: "px-1.5 py-0.5 rounded font-medium inline-flex items-center gap-0.5 ring ring-inset ring-gray-300 dark:ring-gray-700 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200 data-disabled:cursor-not-allowed data-disabled:opacity-75",
1056
1058
  tagsItemText: "truncate",
1057
- tagsItemDelete: ["inline-flex items-center rounded-sm text-gray-400 dark:text-gray-500 hover:text-gray-700 hover:bg-gray-200 dark:hover:text-gray-200 dark:hover:bg-gray-700/50 disabled:pointer-events-none", options.transitions && "transition-colors"],
1059
+ tagsItemDelete: ["inline-flex items-center rounded-sm text-gray-400 dark:text-gray-500 hover:text-gray-700 hover:bg-gray-200 dark:hover:text-gray-200 dark:hover:bg-gray-700/50 disabled:pointer-events-none", options.theme?.transitions && "transition-colors"],
1058
1060
  tagsItemDeleteIcon: "",
1059
1061
  tagsInput: "border-0 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none disabled:cursor-not-allowed disabled:opacity-75"
1060
- }
1061
- }, {
1062
- slots: {
1063
- base: () => ["rounded-md", options.transitions && "transition-colors"],
1064
- trailing: "absolute inset-y-0 end-0 flex items-center disabled:cursor-not-allowed disabled:opacity-75"
1065
1062
  },
1066
1063
  variants: {
1067
1064
  multiple: {
@@ -1170,7 +1167,7 @@ const link = (options) => ({
1170
1167
  variants: {
1171
1168
  active: {
1172
1169
  true: "text-primary-500 dark:text-primary-400",
1173
- false: ["text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200", options.transitions && "transition-colors"]
1170
+ false: ["text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200", options.theme?.transitions && "transition-colors"]
1174
1171
  },
1175
1172
  disabled: {
1176
1173
  true: "cursor-not-allowed opacity-75"
@@ -1277,8 +1274,8 @@ const navigationMenu = (options) => ({
1277
1274
  false: {
1278
1275
  link: "text-gray-500 dark:text-gray-400",
1279
1276
  linkLeadingIcon: "text-gray-400 dark:text-gray-500",
1280
- childLink: ["hover:bg-gray-50 dark:hover:bg-gray-800/50 text-gray-700 dark:text-gray-200 hover:text-gray-900 dark:hover:text-white", options.transitions && "transition-colors"],
1281
- childLinkIcon: ["text-gray-400 dark:text-gray-500 group-hover:text-gray-700 dark:group-hover:text-gray-200", options.transitions && "transition-colors"]
1277
+ childLink: ["hover:bg-gray-50 dark:hover:bg-gray-800/50 text-gray-700 dark:text-gray-200 hover:text-gray-900 dark:hover:text-white", options.theme?.transitions && "transition-colors"],
1278
+ childLinkIcon: ["text-gray-400 dark:text-gray-500 group-hover:text-gray-700 dark:group-hover:text-gray-200", options.theme?.transitions && "transition-colors"]
1282
1279
  }
1283
1280
  },
1284
1281
  disabled: {
@@ -1309,8 +1306,8 @@ const navigationMenu = (options) => ({
1309
1306
  active: false,
1310
1307
  variant: "pill",
1311
1308
  class: {
1312
- link: ["hover:text-gray-900 dark:hover:text-white hover:before:bg-gray-50 dark:hover:before:bg-gray-800/50 data-[state=open]:text-gray-900 dark:data-[state=open]:text-white data-[state=open]:before:bg-gray-50 dark:data-[state=open]:before:bg-gray-800/50", options.transitions && "transition-colors before:transition-colors"],
1313
- linkLeadingIcon: ["group-hover:text-gray-700 dark:group-hover:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.transitions && "transition-colors"]
1309
+ link: ["hover:text-gray-900 dark:hover:text-white hover:before:bg-gray-50 dark:hover:before:bg-gray-800/50 data-[state=open]:text-gray-900 dark:data-[state=open]:text-white data-[state=open]:before:bg-gray-50 dark:data-[state=open]:before:bg-gray-800/50", options.theme?.transitions && "transition-colors before:transition-colors"],
1310
+ linkLeadingIcon: ["group-hover:text-gray-700 dark:group-hover:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.theme?.transitions && "transition-colors"]
1314
1311
  }
1315
1312
  }, ...options.colors.map((color) => ({
1316
1313
  color,
@@ -1340,15 +1337,15 @@ const navigationMenu = (options) => ({
1340
1337
  active: true,
1341
1338
  highlight: true,
1342
1339
  class: {
1343
- link: ["hover:before:bg-gray-50 dark:hover:before:bg-gray-800/50", options.transitions && "before:transition-colors"]
1340
+ link: ["hover:before:bg-gray-50 dark:hover:before:bg-gray-800/50", options.theme?.transitions && "before:transition-colors"]
1344
1341
  }
1345
1342
  }, {
1346
1343
  disabled: false,
1347
1344
  active: false,
1348
1345
  variant: "link",
1349
1346
  class: {
1350
- link: ["hover:text-gray-900 dark:hover:text-white data-[state=open]:text-gray-900 dark:data-[state=open]:text-white", options.transitions && "transition-colors"],
1351
- linkLeadingIcon: ["group-hover:text-gray-700 dark:group-hover:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.transitions && "transition-colors"]
1347
+ link: ["hover:text-gray-900 dark:hover:text-white data-[state=open]:text-gray-900 dark:data-[state=open]:text-white", options.theme?.transitions && "transition-colors"],
1348
+ linkLeadingIcon: ["group-hover:text-gray-700 dark:group-hover:text-gray-200 group-data-[state=open]:text-gray-700 dark:group-data-[state=open]:text-gray-200", options.theme?.transitions && "transition-colors"]
1352
1349
  }
1353
1350
  }, ...options.colors.map((color) => ({
1354
1351
  color,
@@ -1714,6 +1711,9 @@ const radioGroup = (options) => ({
1714
1711
  const select = (options) => {
1715
1712
  return defuFn({
1716
1713
  slots: {
1714
+ root: () => void 0,
1715
+ base: () => ["relative group rounded-md inline-flex items-center focus:outline-none disabled:cursor-not-allowed disabled:opacity-75", options.theme?.transitions && "transition-colors"],
1716
+ value: "truncate group-data-placeholder:text-current/50",
1717
1717
  arrow: "fill-gray-200 dark:fill-gray-800",
1718
1718
  content: "max-h-60 w-[--radix-popper-anchor-width] bg-white dark:bg-gray-900 shadow-lg rounded-md ring ring-gray-200 dark:ring-gray-800 overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in]",
1719
1719
  viewport: "divide-y divide-gray-200 dark:divide-gray-800 scroll-py-1",
@@ -1721,8 +1721,8 @@ const select = (options) => {
1721
1721
  empty: "py-2 text-center text-sm text-gray-500 dark:text-gray-400",
1722
1722
  label: "font-semibold text-gray-900 dark:text-white",
1723
1723
  separator: "-mx-1 my-1 h-px bg-gray-200 dark:bg-gray-800",
1724
- item: ["group relative w-full flex items-center select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50", options.transitions && "transition-colors before:transition-colors"],
1725
- itemLeadingIcon: ["shrink-0 text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200", options.transitions && "transition-colors"],
1724
+ item: ["group relative w-full flex items-center select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-gray-700 dark:text-gray-200 data-highlighted:text-gray-900 dark:data-highlighted:text-white data-highlighted:before:bg-gray-50 dark:data-highlighted:before:bg-gray-800/50", options.theme?.transitions && "transition-colors before:transition-colors"],
1725
+ itemLeadingIcon: ["shrink-0 text-gray-400 dark:text-gray-500 group-data-highlighted:text-gray-700 dark:group-data-highlighted:text-gray-200", options.theme?.transitions && "transition-colors"],
1726
1726
  itemLeadingAvatar: "shrink-0",
1727
1727
  itemLeadingAvatarSize: "",
1728
1728
  itemLeadingChip: "shrink-0",
@@ -1732,6 +1732,7 @@ const select = (options) => {
1732
1732
  itemLabel: "truncate"
1733
1733
  },
1734
1734
  variants: {
1735
+ ...buttonGroupVariant,
1735
1736
  size: {
1736
1737
  xs: {
1737
1738
  label: "p-1 text-[10px]/3 gap-1",
@@ -1780,14 +1781,6 @@ const select = (options) => {
1780
1781
  }
1781
1782
  }
1782
1783
  }
1783
- }, {
1784
- slots: {
1785
- base: () => ["relative group rounded-md inline-flex items-center focus:outline-none disabled:cursor-not-allowed disabled:opacity-75", options.transitions && "transition-colors"],
1786
- value: "truncate group-data-placeholder:text-current/50"
1787
- },
1788
- variants: {
1789
- ...buttonGroupVariant
1790
- }
1791
1784
  }, input(options));
1792
1785
  };
1793
1786
 
@@ -2098,10 +2091,10 @@ const slider = (options) => ({
2098
2091
  const _switch = (options) => ({
2099
2092
  slots: {
2100
2093
  root: "relative flex items-start",
2101
- base: ["inline-flex items-center shrink-0 rounded-full border-2 border-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-900 data-[state=unchecked]:bg-gray-200 dark:data-[state=unchecked]:bg-gray-700", options.transitions && "transition-colors duration-200"],
2094
+ base: ["inline-flex items-center shrink-0 rounded-full border-2 border-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-900 data-[state=unchecked]:bg-gray-200 dark:data-[state=unchecked]:bg-gray-700", options.theme?.transitions && "transition-colors duration-200"],
2102
2095
  container: "flex items-center",
2103
2096
  thumb: "group pointer-events-none block rounded-full bg-white dark:bg-gray-900 shadow-lg ring-0 transition-transform duration-200 data-[state=unchecked]:translate-x-0 flex items-center justify-center",
2104
- icon: ["absolute shrink-0 group-data-[state=unchecked]:text-gray-400 dark:group-data-[state=unchecked]:text-gray-500 opacity-0 size-10/12", options.transitions && "transition-[color,opacity] duration-200"],
2097
+ icon: ["absolute shrink-0 group-data-[state=unchecked]:text-gray-400 dark:group-data-[state=unchecked]:text-gray-500 opacity-0 size-10/12", options.theme?.transitions && "transition-[color,opacity] duration-200"],
2105
2098
  wrapper: "ms-2",
2106
2099
  label: "block font-medium text-gray-700 dark:text-gray-200",
2107
2100
  description: "text-gray-500 dark:text-gray-400"
@@ -2188,7 +2181,7 @@ const tabs = (options) => ({
2188
2181
  root: "flex items-center gap-2",
2189
2182
  list: "relative flex p-1 group",
2190
2183
  indicator: "absolute transition-[translate,width] duration-200",
2191
- trigger: ["relative inline-flex items-center shrink-0 data-[state=inactive]:text-gray-500 dark:data-[state=inactive]:text-gray-400 hover:data-[state=inactive]:text-gray-700 dark:hover:data-[state=inactive]:text-gray-200 font-medium rounded-md disabled:cursor-not-allowed disabled:opacity-75 focus:outline-none", options.transitions && "transition-colors"],
2184
+ trigger: ["relative inline-flex items-center shrink-0 data-[state=inactive]:text-gray-500 dark:data-[state=inactive]:text-gray-400 hover:data-[state=inactive]:text-gray-700 dark:hover:data-[state=inactive]:text-gray-200 font-medium rounded-md disabled:cursor-not-allowed disabled:opacity-75 focus:outline-none", options.theme?.transitions && "transition-colors"],
2192
2185
  content: "focus:outline-none w-full",
2193
2186
  leadingIcon: "shrink-0",
2194
2187
  leadingAvatar: "shrink-0",
@@ -2558,7 +2551,10 @@ const module = defineNuxtModule({
2558
2551
  defaults: {
2559
2552
  prefix: "U",
2560
2553
  colors: void 0,
2561
- transitions: true
2554
+ fonts: true,
2555
+ theme: {
2556
+ transitions: true
2557
+ }
2562
2558
  },
2563
2559
  async setup(options, nuxt) {
2564
2560
  const { resolve } = createResolver(import.meta.url);
@@ -2581,7 +2577,18 @@ const module = defineNuxtModule({
2581
2577
  } else {
2582
2578
  nuxt.options.postcss.plugins["@tailwindcss/postcss"] = {};
2583
2579
  }
2584
- await installModule("@nuxt/icon", { cssLayer: "components" });
2580
+ if (options.fonts) {
2581
+ if (!hasNuxtModule("@nuxt/fonts")) {
2582
+ await installModule("@nuxt/fonts", { experimental: { processCSSVariables: true } });
2583
+ } else {
2584
+ nuxt.options.fonts = defu(nuxt.options.fonts, { experimental: { processCSSVariables: true } });
2585
+ }
2586
+ }
2587
+ if (!hasNuxtModule("@nuxt/icon")) {
2588
+ await installModule("@nuxt/icon", { cssLayer: "components" });
2589
+ } else {
2590
+ nuxt.options.icon = defu(nuxt.options.icon, { cssLayer: "components" });
2591
+ }
2585
2592
  addPlugin({
2586
2593
  src: resolve("./runtime/plugins/colors")
2587
2594
  });
@@ -6,6 +6,7 @@ import theme from '#build/ui/button'
6
6
  import type { LinkProps } from './Link.vue'
7
7
  import type { UseComponentIconsProps } from '../composables/useComponentIcons'
8
8
  import type { PartialString } from '../types/utils'
9
+ import { formLoadingInjectionKey } from '../composables/useFormField'
9
10
 
10
11
  const appConfig = _appConfig as AppConfig & { ui: { button: Partial<typeof theme> } }
11
12
 
@@ -22,6 +23,9 @@ export interface ButtonProps extends UseComponentIconsProps, Omit<LinkProps, 'ra
22
23
  square?: boolean
23
24
  /** Render the button full width. */
24
25
  block?: boolean
26
+ /** Set loading state automatically based on the `@click` promise state */
27
+ loadingAuto?: boolean
28
+ onClick?: ((event: MouseEvent) => void | Promise<void>) | Array<((event: MouseEvent) => void | Promise<void>)>
25
29
  class?: any
26
30
  ui?: PartialString<typeof button.slots>
27
31
  }
@@ -34,7 +38,7 @@ export interface ButtonSlots {
34
38
  </script>
35
39
 
36
40
  <script setup lang="ts">
37
- import { computed } from 'vue'
41
+ import { type Ref, computed, ref, inject } from 'vue'
38
42
  import { useForwardProps } from 'radix-vue'
39
43
  import { useComponentIcons } from '../composables/useComponentIcons'
40
44
  import { useButtonGroup } from '../composables/useButtonGroup'
@@ -48,13 +52,33 @@ const slots = defineSlots<ButtonSlots>()
48
52
  const linkProps = useForwardProps(pickLinkProps(props))
49
53
 
50
54
  const { orientation, size: buttonSize } = useButtonGroup<ButtonProps>(props)
51
- const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)
55
+
56
+ const loadingAutoState = ref(false)
57
+ const formLoading = inject<Ref<boolean> | undefined>(formLoadingInjectionKey, undefined)
58
+
59
+ async function onClickWrapper(event: MouseEvent) {
60
+ loadingAutoState.value = true
61
+ const callbacks = Array.isArray(props.onClick) ? props.onClick : [props.onClick]
62
+ try {
63
+ await Promise.all(callbacks.map(fn => fn?.(event)))
64
+ } finally {
65
+ loadingAutoState.value = false
66
+ }
67
+ }
68
+
69
+ const isLoading = computed(() => {
70
+ return props.loading || (props.loadingAuto && (loadingAutoState.value || (formLoading?.value && props.type === 'submit')))
71
+ })
72
+
73
+ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(
74
+ computed(() => ({ ...props, loading: isLoading.value }))
75
+ )
52
76
 
53
77
  const ui = computed(() => button({
54
78
  color: props.color,
55
79
  variant: props.variant,
56
80
  size: buttonSize.value,
57
- loading: props.loading,
81
+ loading: isLoading.value,
58
82
  block: props.block,
59
83
  square: props.square || (!slots.default && !props.label),
60
84
  leading: isLeading.value,
@@ -64,7 +88,14 @@ const ui = computed(() => button({
64
88
  </script>
65
89
 
66
90
  <template>
67
- <ULink :type="type" :disabled="disabled || loading" :class="ui.base({ class: props.class })" v-bind="linkProps" raw>
91
+ <ULink
92
+ :type="type"
93
+ :disabled="disabled || isLoading"
94
+ :class="ui.base({ class: [props.class, props.ui?.base] })"
95
+ v-bind="linkProps"
96
+ raw
97
+ @click="onClickWrapper"
98
+ >
68
99
  <slot name="leading">
69
100
  <UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
70
101
  </slot>
@@ -180,7 +180,7 @@ const groups = computed(() => {
180
180
  }
181
181
 
182
182
  acc[item.group] ||= []
183
- acc[item.group].push({ ...item, matches })
183
+ acc[item.group]?.push({ ...item, matches })
184
184
 
185
185
  return acc
186
186
  }, {} as Record<string, (T & { matches?: FuseResult<T>['matches'] })[]>)
@@ -13,11 +13,12 @@ export interface FormProps<T extends object> {
13
13
  id?: string | number
14
14
  schema?: FormSchema<T>
15
15
  state: Partial<T>
16
- validate?: (state: Partial<T>) => Promise<FormError[]>
16
+ validate?: (state: Partial<T>) => Promise<FormError[]> | FormError[]
17
17
  validateOn?: FormInputEvents[]
18
18
  disabled?: boolean
19
19
  validateOnInputDelay?: number
20
20
  class?: any
21
+ onSubmit?: ((event: FormSubmitEvent<T>) => void | Promise<void>) | (() => void | Promise<void>)
21
22
  }
22
23
 
23
24
  export interface FormEmits<T extends object> {
@@ -31,9 +32,9 @@ export interface FormSlots {
31
32
  </script>
32
33
 
33
34
  <script lang="ts" setup generic="T extends object">
34
- import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId } from 'vue'
35
+ import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly } from 'vue'
35
36
  import { useEventBus } from '@vueuse/core'
36
- import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey } from '../composables/useFormField'
37
+ import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey } from '../composables/useFormField'
37
38
  import { getYupErrors, isYupSchema, getValibotError, isValibotSchema, getZodErrors, isZodSchema, getJoiErrors, isJoiSchema } from '../utils/form'
38
39
  import { FormValidationException } from '../types/form'
39
40
 
@@ -53,6 +54,7 @@ const parentBus = inject(
53
54
  formBusInjectionKey,
54
55
  undefined
55
56
  )
57
+
56
58
  provide(formBusInjectionKey, bus)
57
59
 
58
60
  const nestedForms = ref<Map<string | number, { validate: () => any }>>(new Map())
@@ -86,11 +88,6 @@ onUnmounted(() => {
86
88
  }
87
89
  })
88
90
 
89
- provide(formOptionsInjectionKey, computed(() => ({
90
- disabled: props.disabled,
91
- validateOnInputDelay: props.validateOnInputDelay
92
- })))
93
-
94
91
  const errors = ref<FormErrorWithId[]>([])
95
92
  provide('form-errors', errors)
96
93
 
@@ -147,7 +144,8 @@ async function _validate(opts: { name?: string | string[], silent?: boolean, nes
147
144
  errors.value = await getErrors()
148
145
  }
149
146
 
150
- const childErrors = nestedValidatePromises ? await Promise.all(nestedValidatePromises) : []
147
+ const childErrors = (await Promise.all(nestedValidatePromises)).filter(val => val)
148
+
151
149
  if (errors.value.length + childErrors.length > 0) {
152
150
  if (opts.silent) return false
153
151
  throw new FormValidationException(formId, errors.value, childErrors)
@@ -156,13 +154,18 @@ async function _validate(opts: { name?: string | string[], silent?: boolean, nes
156
154
  return props.state as T
157
155
  }
158
156
 
159
- async function onSubmit(payload: Event) {
157
+ const loading = ref(false)
158
+ provide(formLoadingInjectionKey, readonly(loading))
159
+
160
+ async function onSubmitWrapper(payload: Event) {
161
+ loading.value = true
162
+
160
163
  const event = payload as FormSubmitEvent<any>
161
164
 
162
165
  try {
163
166
  await _validate({ nested: true })
164
167
  event.data = props.state
165
- emits('submit', event)
168
+ await props.onSubmit?.(event)
166
169
  } catch (error) {
167
170
  if (!(error instanceof FormValidationException)) {
168
171
  throw error
@@ -173,11 +176,19 @@ async function onSubmit(payload: Event) {
173
176
  errors: error.errors,
174
177
  childrens: error.childrens
175
178
  }
176
-
177
179
  emits('error', errorEvent)
178
180
  }
181
+
182
+ loading.value = false
179
183
  }
180
184
 
185
+ const disabled = computed(() => props.disabled || loading.value)
186
+
187
+ provide(formOptionsInjectionKey, computed(() => ({
188
+ disabled: disabled.value,
189
+ validateOnInputDelay: props.validateOnInputDelay
190
+ })))
191
+
181
192
  defineExpose<Form<T>>({
182
193
  validate: _validate,
183
194
  errors,
@@ -193,7 +204,7 @@ defineExpose<Form<T>>({
193
204
  },
194
205
 
195
206
  async submit() {
196
- await onSubmit(new Event('submit'))
207
+ await onSubmitWrapper(new Event('submit'))
197
208
  },
198
209
 
199
210
  getErrors(name?: string) {
@@ -211,7 +222,7 @@ defineExpose<Form<T>>({
211
222
  }
212
223
  },
213
224
 
214
- disabled: computed(() => props.disabled)
225
+ disabled
215
226
  })
216
227
  </script>
217
228
 
@@ -220,7 +231,7 @@ defineExpose<Form<T>>({
220
231
  :is="parentBus ? 'div' : 'form'"
221
232
  :id="formId"
222
233
  :class="form({ class: props.class })"
223
- @submit.prevent="onSubmit"
234
+ @submit.prevent="onSubmitWrapper"
224
235
  >
225
236
  <slot />
226
237
  </component>
@@ -3,7 +3,7 @@ export interface LinkBaseProps {
3
3
  as?: string
4
4
  type?: string
5
5
  disabled?: boolean
6
- click?: (e: MouseEvent) => void
6
+ onClick?: (e: MouseEvent) => void | Promise<void>
7
7
  href?: string
8
8
  navigate?: (e: MouseEvent) => void
9
9
  rel?: string
@@ -20,15 +20,15 @@ const props = withDefaults(defineProps<LinkBaseProps>(), {
20
20
  type: 'button'
21
21
  })
22
22
 
23
- function onClick(e: MouseEvent) {
23
+ function onClickWrapper(e: MouseEvent) {
24
24
  if (props.disabled) {
25
25
  e.stopPropagation()
26
26
  e.preventDefault()
27
27
  return
28
28
  }
29
29
 
30
- if (props.click) {
31
- props.click(e)
30
+ if (props.onClick) {
31
+ props.onClick(e)
32
32
  }
33
33
 
34
34
  if (props.href && props.navigate && !props.isExternal) {
@@ -43,7 +43,8 @@ function onClick(e: MouseEvent) {
43
43
  'as': 'a',
44
44
  'href': disabled ? undefined : href,
45
45
  'aria-disabled': disabled ? 'true' : undefined,
46
- 'role': disabled ? 'link' : undefined
46
+ 'role': disabled ? 'link' : undefined,
47
+ 'tabindex': disabled ? -1 : undefined
47
48
  } : as === 'button' ? {
48
49
  as,
49
50
  type,
@@ -53,7 +54,7 @@ function onClick(e: MouseEvent) {
53
54
  }"
54
55
  :rel="rel"
55
56
  :target="target"
56
- @click="onClick"
57
+ @click="onClickWrapper"
57
58
  >
58
59
  <slot />
59
60
  </Primitive>
@@ -161,7 +161,7 @@ function onUpdateOpen(value: boolean) {
161
161
  @update:model-value="onUpdate"
162
162
  @update:open="onUpdateOpen"
163
163
  >
164
- <SelectTrigger :class="ui.base({ class: props.class })">
164
+ <SelectTrigger :class="ui.base({ class: [props.class, props.ui?.base] })">
165
165
  <span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
166
166
  <slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
167
167
  <UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
@@ -219,7 +219,7 @@ function onUpdateOpen(value: boolean) {
219
219
  @update:open="onUpdateOpen"
220
220
  >
221
221
  <ComboboxAnchor as-child>
222
- <ComboboxTrigger :class="ui.base({ class: props.class })" tabindex="0">
222
+ <ComboboxTrigger :class="ui.base({ class: [props.class, props.ui?.base] })" tabindex="0">
223
223
  <span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
224
224
  <slot name="leading" :model-value="(modelValue as T)" :open="open" :ui="ui">
225
225
  <UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
@@ -115,7 +115,7 @@ function getOffset(index: number) {
115
115
 
116
116
  <ToastViewport
117
117
  :data-expanded="expanded"
118
- :class="ui.viewport({ class: props.class })"
118
+ :class="ui.viewport({ class: [props.class, props.ui?.viewport] })"
119
119
  :style="{
120
120
  '--scale-factor': '0.05',
121
121
  '--translate-factor': position?.startsWith('top') ? '1px' : '-1px',
@@ -18,6 +18,7 @@ export declare const formBusInjectionKey: InjectionKey<UseEventBusReturn<FormEve
18
18
  export declare const formFieldInjectionKey: InjectionKey<ComputedRef<FormFieldInjectedOptions<FormFieldProps>>>;
19
19
  export declare const inputIdInjectionKey: InjectionKey<Ref<string | undefined>>;
20
20
  export declare const formInputsInjectionKey: InjectionKey<Ref<Record<string, string>>>;
21
+ export declare const formLoadingInjectionKey: InjectionKey<Readonly<Ref<boolean>>>;
21
22
  export declare function useFormField<T>(props?: Props<T>, opts?: {
22
23
  bind?: boolean;
23
24
  }): {
@@ -5,6 +5,7 @@ export const formBusInjectionKey = Symbol("nuxt-ui.form-events");
5
5
  export const formFieldInjectionKey = Symbol("nuxt-ui.form-field");
6
6
  export const inputIdInjectionKey = Symbol("nuxt-ui.input-id");
7
7
  export const formInputsInjectionKey = Symbol("nuxt-ui.form-inputs");
8
+ export const formLoadingInjectionKey = Symbol("nuxt-ui.form-loading");
8
9
  export function useFormField(props, opts) {
9
10
  const formOptions = inject(formOptionsInjectionKey, void 0);
10
11
  const formBus = inject(formBusInjectionKey, void 0);
@@ -6,7 +6,7 @@ export interface Toast extends Omit<ToastProps, 'defaultOpen'> {
6
6
  export declare function useToast(): {
7
7
  toasts: import("vue").Ref<Toast[], Toast[]>;
8
8
  add: (toast: Partial<Toast>) => Toast;
9
- update: (id: string | number, toast: Partial<Toast>) => void;
9
+ update: (id: string | number, toast: Omit<Partial<Toast>, "id">) => void;
10
10
  remove: (id: string | number) => void;
11
11
  clear: () => void;
12
12
  };
@@ -1,5 +1,5 @@
1
1
  export declare function pick<Data extends object, Keys extends keyof Data>(data: Data, keys: Keys[]): Pick<Data, Keys>;
2
2
  export declare function omit<Data extends object, Keys extends keyof Data>(data: Data, keys: Keys[]): Omit<Data, Keys>;
3
- export declare function get(object: Record<string, any>, path: (string | number)[] | string, defaultValue?: any): any;
3
+ export declare function get(object: Record<string, any> | undefined, path: (string | number)[] | string, defaultValue?: any): any;
4
4
  export declare function set(object: Record<string, any>, path: (string | number)[] | string, value: any): void;
5
5
  export declare function looseToNumber(val: any): any;
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@nuxt/ui",
3
- "version": "3.0.0-alpha.1",
3
+ "description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
4
+ "version": "3.0.0-alpha.2",
4
5
  "packageManager": "pnpm@9.10.0",
5
6
  "repository": {
6
7
  "type": "git",
@@ -44,36 +45,37 @@
44
45
  "release": "release-it --preRelease=alpha --npm.tag=next"
45
46
  },
46
47
  "dependencies": {
48
+ "@nuxt/fonts": "^0.8.0",
47
49
  "@nuxt/icon": "^1.5.1",
48
- "@nuxt/kit": "^3.13.1",
49
- "@nuxt/schema": "^3.13.1",
50
- "@nuxtjs/color-mode": "^3.4.4",
51
- "@tailwindcss/postcss": "4.0.0-alpha.23",
52
- "@tailwindcss/vite": "4.0.0-alpha.23",
53
- "@vueuse/core": "^11.0.3",
54
- "@vueuse/integrations": "^11.0.3",
50
+ "@nuxt/kit": "^3.13.2",
51
+ "@nuxt/schema": "^3.13.2",
52
+ "@nuxtjs/color-mode": "^3.5.1",
53
+ "@tailwindcss/postcss": "4.0.0-alpha.24",
54
+ "@tailwindcss/vite": "4.0.0-alpha.24",
55
+ "@vueuse/core": "^11.1.0",
56
+ "@vueuse/integrations": "^11.1.0",
55
57
  "defu": "^6.1.4",
56
58
  "fuse.js": "^7.0.0",
57
- "ohash": "^1.1.3",
59
+ "ohash": "^1.1.4",
58
60
  "radix-vue": "^1.9.5",
59
61
  "scule": "^1.3.0",
60
62
  "tailwind-variants": "^0.2.1",
61
- "tailwindcss": "4.0.0-alpha.23",
63
+ "tailwindcss": "4.0.0-alpha.24",
62
64
  "vaul-vue": "^0.2.0"
63
65
  },
64
66
  "devDependencies": {
65
67
  "@nuxt/eslint-config": "^0.5.7",
66
68
  "@nuxt/module-builder": "^0.8.4",
67
69
  "@nuxt/test-utils": "^3.14.2",
68
- "@release-it/conventional-changelog": "^8.0.1",
70
+ "@release-it/conventional-changelog": "^8.0.2",
69
71
  "@vue/test-utils": "^2.4.6",
70
72
  "eslint": "^9.10.0",
71
- "happy-dom": "^15.7.3",
73
+ "happy-dom": "^15.7.4",
72
74
  "joi": "^17.13.3",
73
- "nuxt": "^3.13.1",
75
+ "nuxt": "^3.13.2",
74
76
  "release-it": "^17.6.0",
75
- "valibot": "^0.41.0",
76
- "vitest": "^2.0.5",
77
+ "valibot": "^0.42.0",
78
+ "vitest": "^2.1.1",
77
79
  "vitest-environment-nuxt": "^1.0.1",
78
80
  "vue-tsc": "^2.1.6",
79
81
  "yup": "^1.4.0",