@nuxt/ui 3.0.0-alpha.1 → 3.0.0-alpha.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.
package/dist/module.d.mts CHANGED
@@ -8,15 +8,22 @@ interface ModuleOptions {
8
8
  */
9
9
  prefix?: string;
10
10
  /**
11
- * Colors to generate classes for (based on TailwindCSS colors)
12
- * @defaultValue ['red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose']
13
- */
14
- colors?: string[];
15
- /**
16
- * Disable color transitions
11
+ * Enable or disable `@nuxt/fonts` module
17
12
  * @defaultValue true
18
13
  */
19
- transitions?: boolean;
14
+ fonts?: boolean;
15
+ theme?: {
16
+ /**
17
+ * Colors to generate classes for (defaults to TailwindCSS colors)
18
+ * @defaultValue ['red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose']
19
+ */
20
+ colors?: string[];
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
@@ -8,15 +8,22 @@ interface ModuleOptions {
8
8
  */
9
9
  prefix?: string;
10
10
  /**
11
- * Colors to generate classes for (based on TailwindCSS colors)
12
- * @defaultValue ['red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose']
13
- */
14
- colors?: string[];
15
- /**
16
- * Disable color transitions
11
+ * Enable or disable `@nuxt/fonts` module
17
12
  * @defaultValue true
18
13
  */
19
- transitions?: boolean;
14
+ fonts?: boolean;
15
+ theme?: {
16
+ /**
17
+ * Colors to generate classes for (defaults to TailwindCSS colors)
18
+ * @defaultValue ['red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose']
19
+ */
20
+ colors?: string[];
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.3",
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
 
@@ -38,7 +38,7 @@ const alert = (options) => ({
38
38
  },
39
39
  variants: {
40
40
  color: {
41
- ...Object.fromEntries(options.colors.map((color) => [color, ""])),
41
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, ""])),
42
42
  gray: ""
43
43
  },
44
44
  variant: {
@@ -58,25 +58,25 @@ const alert = (options) => ({
58
58
  }
59
59
  }
60
60
  },
61
- compoundVariants: [...options.colors.map((color) => ({
61
+ compoundVariants: [...(options.theme.colors || []).map((color) => ({
62
62
  color,
63
63
  variant: "solid",
64
64
  class: {
65
65
  root: `bg-${color}-500 dark:bg-${color}-400 text-white dark:text-gray-900`
66
66
  }
67
- })), ...options.colors.map((color) => ({
67
+ })), ...(options.theme.colors || []).map((color) => ({
68
68
  color,
69
69
  variant: "outline",
70
70
  class: {
71
71
  root: `text-${color}-500 dark:text-${color}-400 ring ring-inset ring-${color}-500/25 dark:ring-${color}-400/25`
72
72
  }
73
- })), ...options.colors.map((color) => ({
73
+ })), ...(options.theme.colors || []).map((color) => ({
74
74
  color,
75
75
  variant: "soft",
76
76
  class: {
77
77
  root: `bg-${color}-500/10 dark:bg-${color}-400/10 text-${color}-500 dark:text-${color}-400`
78
78
  }
79
- })), ...options.colors.map((color) => ({
79
+ })), ...(options.theme.colors || []).map((color) => ({
80
80
  color,
81
81
  variant: "subtle",
82
82
  class: {
@@ -201,7 +201,7 @@ const badge = (options) => ({
201
201
  base: "rounded-md font-medium inline-flex items-center",
202
202
  variants: {
203
203
  color: {
204
- ...Object.fromEntries(options.colors.map((color) => [color, ""])),
204
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, ""])),
205
205
  gray: ""
206
206
  },
207
207
  variant: {
@@ -216,19 +216,19 @@ const badge = (options) => ({
216
216
  lg: "text-sm px-2 py-1"
217
217
  }
218
218
  },
219
- compoundVariants: [...options.colors.map((color) => ({
219
+ compoundVariants: [...(options.theme.colors || []).map((color) => ({
220
220
  color,
221
221
  variant: "solid",
222
222
  class: `bg-${color}-500 dark:bg-${color}-400 text-white dark:text-gray-900`
223
- })), ...options.colors.map((color) => ({
223
+ })), ...(options.theme.colors || []).map((color) => ({
224
224
  color,
225
225
  variant: "outline",
226
226
  class: `text-${color}-500 dark:text-${color}-400 ring ring-inset ring-${color}-500/50 dark:ring-${color}-400/50`
227
- })), ...options.colors.map((color) => ({
227
+ })), ...(options.theme.colors || []).map((color) => ({
228
228
  color,
229
229
  variant: "soft",
230
230
  class: `bg-${color}-500/10 dark:bg-${color}-400/10 text-${color}-500 dark:text-${color}-400`
231
- })), ...options.colors.map((color) => ({
231
+ })), ...(options.theme.colors || []).map((color) => ({
232
232
  color,
233
233
  variant: "subtle",
234
234
  class: `bg-${color}-500/10 dark:bg-${color}-400/10 text-${color}-500 dark:text-${color}-400 ring ring-inset ring-${color}-500/25 dark:ring-${color}-400/25`
@@ -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",
@@ -343,7 +343,7 @@ const button = (options) => ({
343
343
  variants: {
344
344
  ...buttonGroupVariant,
345
345
  color: {
346
- ...Object.fromEntries(options.colors.map((color) => [color, ""])),
346
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, ""])),
347
347
  gray: ""
348
348
  },
349
349
  variant: {
@@ -400,54 +400,54 @@ const button = (options) => ({
400
400
  true: ""
401
401
  }
402
402
  },
403
- compoundVariants: [...options.colors.map((color) => ({
403
+ compoundVariants: [...(options.theme.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`
407
- })), ...options.colors.map((color) => ({
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
+ })), ...(options.theme.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`
411
- })), ...options.colors.map((color) => ({
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
+ })), ...(options.theme.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`
415
- })), ...options.colors.map((color) => ({
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
+ })), ...(options.theme.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`
419
- })), ...options.colors.map((color) => ({
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
+ })), ...(options.theme.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`
423
- })), ...options.colors.map((color) => ({
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
+ })), ...(options.theme.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,
@@ -510,7 +510,7 @@ const checkbox = (options) => ({
510
510
  },
511
511
  variants: {
512
512
  color: {
513
- ...Object.fromEntries(options.colors.map((color) => [color, `focus-visible:outline-${color}-500 dark:focus-visible:outline-${color}-400`])),
513
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, `focus-visible:outline-${color}-500 dark:focus-visible:outline-${color}-400`])),
514
514
  gray: "focus-visible:outline-gray-900 dark:focus-visible:outline-white"
515
515
  },
516
516
  size: {
@@ -556,7 +556,7 @@ const checkbox = (options) => ({
556
556
  true: ""
557
557
  }
558
558
  },
559
- compoundVariants: [...options.colors.map((color) => ({
559
+ compoundVariants: [...(options.theme.colors || []).map((color) => ({
560
560
  color,
561
561
  checked: true,
562
562
  class: `ring-2 ring-${color}-500 dark:ring-${color}-400 bg-${color}-500 dark:bg-${color}-400`
@@ -578,7 +578,7 @@ const chip = (options) => ({
578
578
  },
579
579
  variants: {
580
580
  color: {
581
- ...Object.fromEntries(options.colors.map((color) => [color, `bg-${color}-500 dark:bg-${color}-400`])),
581
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, `bg-${color}-500 dark:bg-${color}-400`])),
582
582
  gray: "bg-gray-500 dark:bg-gray-400"
583
583
  },
584
584
  size: {
@@ -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",
@@ -937,7 +937,7 @@ const input = (options) => ({
937
937
  none: "text-gray-900 dark:text-white"
938
938
  },
939
939
  color: {
940
- ...Object.fromEntries(options.colors.map((color) => [color, ""])),
940
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, ""])),
941
941
  gray: ""
942
942
  },
943
943
  leading: {
@@ -956,11 +956,11 @@ const input = (options) => ({
956
956
  file: "file:mr-1.5 file:font-medium file:text-gray-500 dark:file:text-gray-400 file:outline-none"
957
957
  }
958
958
  },
959
- compoundVariants: [...options.colors.map((color) => ({
959
+ compoundVariants: [...(options.theme.colors || []).map((color) => ({
960
960
  color,
961
961
  variant: ["outline", "subtle"],
962
962
  class: `focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`
963
- })), ...options.colors.map((color) => ({
963
+ })), ...(options.theme.colors || []).map((color) => ({
964
964
  color,
965
965
  highlight: true,
966
966
  class: `ring ring-inset ring-${color}-500 dark:ring-${color}-400`
@@ -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: {
@@ -1131,7 +1128,7 @@ const inputMenu = (options) => {
1131
1128
  }
1132
1129
  }
1133
1130
  },
1134
- compoundVariants: [...options.colors.map((color) => ({
1131
+ compoundVariants: [...(options.theme.colors || []).map((color) => ({
1135
1132
  color,
1136
1133
  multiple: true,
1137
1134
  variant: ["outline", "subtle"],
@@ -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"
@@ -1240,7 +1237,7 @@ const navigationMenu = (options) => ({
1240
1237
  },
1241
1238
  variants: {
1242
1239
  color: {
1243
- ...Object.fromEntries(options.colors.map((color) => [color, {
1240
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, {
1244
1241
  link: `focus-visible:before:ring-${color}-500 dark:focus-visible:before:ring-${color}-400`,
1245
1242
  childLink: `focus-visible:outline-${color}-500 dark:focus-visible:outline-${color}-400`
1246
1243
  }])),
@@ -1250,7 +1247,7 @@ const navigationMenu = (options) => ({
1250
1247
  }
1251
1248
  },
1252
1249
  highlightColor: {
1253
- ...Object.fromEntries(options.colors.map((color) => [color, ""])),
1250
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, ""])),
1254
1251
  gray: ""
1255
1252
  },
1256
1253
  variant: {
@@ -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,10 +1306,10 @@ 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
- }, ...options.colors.map((color) => ({
1312
+ }, ...(options.theme.colors || []).map((color) => ({
1316
1313
  color,
1317
1314
  variant: "pill",
1318
1315
  active: true,
@@ -1340,17 +1337,17 @@ 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
- }, ...options.colors.map((color) => ({
1350
+ }, ...(options.theme.colors || []).map((color) => ({
1354
1351
  color,
1355
1352
  variant: "link",
1356
1353
  active: true,
@@ -1366,7 +1363,7 @@ const navigationMenu = (options) => ({
1366
1363
  link: "text-gray-900 dark:text-white",
1367
1364
  linkLeadingIcon: "text-gray-900 dark:text-white"
1368
1365
  }
1369
- }, ...options.colors.map((highlightColor) => ({
1366
+ }, ...(options.theme.colors || []).map((highlightColor) => ({
1370
1367
  highlightColor,
1371
1368
  highlight: true,
1372
1369
  active: true,
@@ -1421,7 +1418,7 @@ const progress = (options) => ({
1421
1418
  "elastic": ""
1422
1419
  },
1423
1420
  color: {
1424
- ...Object.fromEntries(options.colors.map((color) => [color, {
1421
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, {
1425
1422
  indicator: `bg-${color}-500 dark:bg-${color}-400`,
1426
1423
  steps: `text-${color}-500 dark:text-${color}-400`
1427
1424
  }])),
@@ -1633,7 +1630,7 @@ const radioGroup = (options) => ({
1633
1630
  },
1634
1631
  variants: {
1635
1632
  color: {
1636
- ...Object.fromEntries(options.colors.map((color) => [color, {
1633
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, {
1637
1634
  base: `focus-visible:outline-${color}-500 dark:focus-visible:outline-${color}-400`,
1638
1635
  indicator: `bg-${color}-500 dark:bg-${color}-400`
1639
1636
  }])),
@@ -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
 
@@ -1832,7 +1825,7 @@ const separator = (options) => ({
1832
1825
  },
1833
1826
  variants: {
1834
1827
  color: {
1835
- ...Object.fromEntries(options.colors.map((color) => [color, { border: `border-${color}-500 dark:border-${color}-400` }])),
1828
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, { border: `border-${color}-500 dark:border-${color}-400` }])),
1836
1829
  gray: { border: "border-gray-200 dark:border-gray-800" }
1837
1830
  },
1838
1831
  orientation: {
@@ -1986,7 +1979,7 @@ const slider = (options) => ({
1986
1979
  },
1987
1980
  variants: {
1988
1981
  color: {
1989
- ...Object.fromEntries(options.colors.map((color) => [color, {
1982
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, {
1990
1983
  range: `bg-${color}-500 dark:bg-${color}-400`,
1991
1984
  thumb: `ring-${color}-500 dark:ring-${color}-400 focus-visible:outline-${color}-500/50 dark:focus-visible:outline-${color}-400/50`
1992
1985
  }])),
@@ -2098,17 +2091,17 @@ 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"
2108
2101
  },
2109
2102
  variants: {
2110
2103
  color: {
2111
- ...Object.fromEntries(options.colors.map((color) => [color, {
2104
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, {
2112
2105
  base: `data-[state=checked]:bg-${color}-500 dark:data-[state=checked]:bg-${color}-400 focus-visible:ring-${color}-500 dark:focus-visible:ring-${color}-400`,
2113
2106
  icon: `group-data-[state=checked]:text-${color}-500 dark:group-data-[state=checked]:text-${color}-400`
2114
2107
  }])),
@@ -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",
@@ -2197,7 +2190,7 @@ const tabs = (options) => ({
2197
2190
  },
2198
2191
  variants: {
2199
2192
  color: {
2200
- ...Object.fromEntries(options.colors.map((color) => [color, ""])),
2193
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, ""])),
2201
2194
  gray: ""
2202
2195
  },
2203
2196
  variant: {
@@ -2278,7 +2271,7 @@ const tabs = (options) => ({
2278
2271
  list: "border-l",
2279
2272
  indicator: "-left-px w-px"
2280
2273
  }
2281
- }, ...options.colors.map((color) => ({
2274
+ }, ...(options.theme.colors || []).map((color) => ({
2282
2275
  color,
2283
2276
  variant: "pill",
2284
2277
  class: {
@@ -2292,7 +2285,7 @@ const tabs = (options) => ({
2292
2285
  indicator: "bg-gray-900 dark:bg-white",
2293
2286
  trigger: "data-[state=active]:text-white dark:data-[state=active]:text-gray-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900 dark:focus-visible:outline-white"
2294
2287
  }
2295
- }, ...options.colors.map((color) => ({
2288
+ }, ...(options.theme.colors || []).map((color) => ({
2296
2289
  color,
2297
2290
  variant: "link",
2298
2291
  class: {
@@ -2333,7 +2326,7 @@ const toast = (options) => ({
2333
2326
  },
2334
2327
  variants: {
2335
2328
  color: {
2336
- ...Object.fromEntries(options.colors.map((color) => [color, {
2329
+ ...Object.fromEntries((options.theme.colors || []).map((color) => [color, {
2337
2330
  icon: `text-${color}-500 dark:text-${color}-400`,
2338
2331
  progress: `bg-${color}-500 dark:bg-${color}-400`
2339
2332
  }])),
@@ -2557,12 +2550,16 @@ const module = defineNuxtModule({
2557
2550
  },
2558
2551
  defaults: {
2559
2552
  prefix: "U",
2560
- colors: void 0,
2561
- transitions: true
2553
+ fonts: true,
2554
+ theme: {
2555
+ colors: void 0,
2556
+ transitions: true
2557
+ }
2562
2558
  },
2563
2559
  async setup(options, nuxt) {
2564
2560
  const { resolve } = createResolver(import.meta.url);
2565
- options.colors = options.colors?.length ? [.../* @__PURE__ */ new Set(["primary", "error", ...options.colors])] : ["primary", "error", "red", "orange", "amber", "yellow", "lime", "green", "emerald", "teal", "cyan", "sky", "blue", "indigo", "violet", "purple", "fuchsia", "pink", "rose"];
2561
+ options.theme = options.theme || {};
2562
+ options.theme.colors = options.theme.colors?.length ? [.../* @__PURE__ */ new Set(["primary", "error", ...options.theme.colors])] : ["primary", "error", "red", "orange", "amber", "yellow", "lime", "green", "emerald", "teal", "cyan", "sky", "blue", "indigo", "violet", "purple", "fuchsia", "pink", "rose"];
2566
2563
  nuxt.options.ui = options;
2567
2564
  nuxt.options.alias["#ui"] = resolve("./runtime");
2568
2565
  nuxt.options.appConfig.ui = defu(nuxt.options.appConfig.ui || {}, {
@@ -2581,7 +2578,18 @@ const module = defineNuxtModule({
2581
2578
  } else {
2582
2579
  nuxt.options.postcss.plugins["@tailwindcss/postcss"] = {};
2583
2580
  }
2584
- await installModule("@nuxt/icon", { cssLayer: "components" });
2581
+ if (options.fonts) {
2582
+ if (!hasNuxtModule("@nuxt/fonts")) {
2583
+ await installModule("@nuxt/fonts", { experimental: { processCSSVariables: true } });
2584
+ } else {
2585
+ nuxt.options.fonts = defu(nuxt.options.fonts, { experimental: { processCSSVariables: true } });
2586
+ }
2587
+ }
2588
+ if (!hasNuxtModule("@nuxt/icon")) {
2589
+ await installModule("@nuxt/icon", { cssLayer: "components" });
2590
+ } else {
2591
+ nuxt.options.icon = defu(nuxt.options.icon, { cssLayer: "components" });
2592
+ }
2585
2593
  addPlugin({
2586
2594
  src: resolve("./runtime/plugins/colors")
2587
2595
  });
@@ -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.3",
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",