@djangocfg/ui-core 2.1.260 → 2.1.261

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +27 -12
  2. package/package.json +4 -4
  3. package/src/components/{avatar.story.tsx → data/avatar/avatar.story.tsx} +1 -1
  4. package/src/components/{avatar.tsx → data/avatar/index.tsx} +1 -1
  5. package/src/components/{badge.story.tsx → data/badge/badge.story.tsx} +1 -1
  6. package/src/components/{badge.tsx → data/badge/index.tsx} +1 -1
  7. package/src/components/{calendar.story.tsx → data/calendar/calendar.story.tsx} +2 -1
  8. package/src/components/{calendar → data/calendar}/calendar.tsx +2 -2
  9. package/src/components/{calendar → data/calendar}/date-picker.tsx +3 -3
  10. package/src/components/{carousel.story.tsx → data/carousel/carousel.story.tsx} +2 -2
  11. package/src/components/{carousel.tsx → data/carousel/index.tsx} +2 -2
  12. package/src/components/{chart.tsx → data/chart/index.tsx} +1 -1
  13. package/src/components/{progress.tsx → data/progress/index.tsx} +1 -1
  14. package/src/components/{progress.story.tsx → data/progress/progress.story.tsx} +1 -1
  15. package/src/components/{table.tsx → data/table/index.tsx} +1 -1
  16. package/src/components/{table.story.tsx → data/table/table.story.tsx} +2 -2
  17. package/src/components/{toggle.tsx → data/toggle/index.tsx} +1 -1
  18. package/src/components/{toggle.story.tsx → data/toggle/toggle.story.tsx} +1 -1
  19. package/src/components/{toggle-group.tsx → data/toggle-group/index.tsx} +2 -2
  20. package/src/components/{toggle-group.story.tsx → data/toggle-group/toggle-group.story.tsx} +1 -1
  21. package/src/components/{alert.story.tsx → feedback/alert/alert.story.tsx} +1 -1
  22. package/src/components/{alert.tsx → feedback/alert/index.tsx} +1 -1
  23. package/src/components/{empty.story.tsx → feedback/empty/empty.story.tsx} +2 -2
  24. package/src/components/{empty.tsx → feedback/empty/index.tsx} +1 -1
  25. package/src/components/{preloader.tsx → feedback/preloader/index.tsx} +1 -1
  26. package/src/components/{preloader.story.tsx → feedback/preloader/preloader.story.tsx} +1 -1
  27. package/src/components/{sonner.tsx → feedback/sonner/index.tsx} +1 -1
  28. package/src/components/{spinner.tsx → feedback/spinner/index.tsx} +1 -1
  29. package/src/components/{spinner.story.tsx → feedback/spinner/spinner.story.tsx} +1 -1
  30. package/src/components/{button.story.tsx → forms/button/button.story.tsx} +1 -1
  31. package/src/components/{button.tsx → forms/button/index.tsx} +1 -1
  32. package/src/components/{button-download.story.tsx → forms/button-download/button-download.story.tsx} +1 -1
  33. package/src/components/{button-download.tsx → forms/button-download/index.tsx} +3 -3
  34. package/src/components/{button-group.story.tsx → forms/button-group/button-group.story.tsx} +2 -2
  35. package/src/components/{button-group.tsx → forms/button-group/index.tsx} +2 -2
  36. package/src/components/{checkbox.story.tsx → forms/checkbox/checkbox.story.tsx} +2 -2
  37. package/src/components/{checkbox.tsx → forms/checkbox/index.tsx} +1 -1
  38. package/src/components/{field.tsx → forms/field/index.tsx} +3 -3
  39. package/src/components/{form.tsx → forms/form/index.tsx} +2 -2
  40. package/src/components/{input.tsx → forms/input/index.tsx} +2 -2
  41. package/src/components/{input.story.tsx → forms/input/input.story.tsx} +2 -2
  42. package/src/components/{input-group.tsx → forms/input-group/index.tsx} +4 -4
  43. package/src/components/{input-group.story.tsx → forms/input-group/input-group.story.tsx} +2 -2
  44. package/src/components/{input-otp.tsx → forms/input-otp/index.tsx} +1 -1
  45. package/src/components/{input-otp.story.tsx → forms/input-otp/input-otp.story.tsx} +1 -1
  46. package/src/components/{label.tsx → forms/label/index.tsx} +1 -1
  47. package/src/components/{label.story.tsx → forms/label/label.story.tsx} +3 -3
  48. package/src/components/{otp → forms/otp}/index.tsx +2 -2
  49. package/src/components/{phone-input.tsx → forms/phone-input/index.tsx} +4 -4
  50. package/src/components/{radio-group.tsx → forms/radio-group/index.tsx} +1 -1
  51. package/src/components/{radio-group.story.tsx → forms/radio-group/radio-group.story.tsx} +2 -2
  52. package/src/components/{slider.tsx → forms/slider/index.tsx} +2 -2
  53. package/src/components/{slider.story.tsx → forms/slider/slider.story.tsx} +2 -2
  54. package/src/components/{switch.tsx → forms/switch/index.tsx} +1 -1
  55. package/src/components/{switch.story.tsx → forms/switch/switch.story.tsx} +2 -2
  56. package/src/components/{textarea.tsx → forms/textarea/index.tsx} +2 -2
  57. package/src/components/{textarea.story.tsx → forms/textarea/textarea.story.tsx} +2 -2
  58. package/src/components/index.ts +110 -100
  59. package/src/components/{aspect-ratio.story.tsx → layout/aspect-ratio/aspect-ratio.story.tsx} +1 -1
  60. package/src/components/{card.story.tsx → layout/card/card.story.tsx} +4 -4
  61. package/src/components/{card.tsx → layout/card/index.tsx} +1 -1
  62. package/src/components/{resizable.tsx → layout/resizable/index.tsx} +1 -1
  63. package/src/components/{resizable.story.tsx → layout/resizable/resizable.story.tsx} +1 -1
  64. package/src/components/{scroll-area.tsx → layout/scroll-area/index.tsx} +1 -1
  65. package/src/components/{scroll-area.story.tsx → layout/scroll-area/scroll-area.story.tsx} +2 -2
  66. package/src/components/{section.tsx → layout/section/index.tsx} +1 -1
  67. package/src/components/{separator.tsx → layout/separator/index.tsx} +1 -1
  68. package/src/components/{separator.story.tsx → layout/separator/separator.story.tsx} +1 -1
  69. package/src/components/{skeleton.tsx → layout/skeleton/index.tsx} +1 -1
  70. package/src/components/{skeleton.story.tsx → layout/skeleton/skeleton.story.tsx} +1 -1
  71. package/src/components/{sticky.tsx → layout/sticky/index.tsx} +1 -1
  72. package/src/components/{accordion.story.tsx → navigation/accordion/accordion.story.tsx} +1 -1
  73. package/src/components/{accordion.tsx → navigation/accordion/index.tsx} +2 -2
  74. package/src/components/{collapsible.story.tsx → navigation/collapsible/collapsible.story.tsx} +2 -2
  75. package/src/components/{command.story.tsx → navigation/command/command.story.tsx} +2 -2
  76. package/src/components/{command.tsx → navigation/command/index.tsx} +2 -2
  77. package/src/components/{context-menu.story.tsx → navigation/context-menu/context-menu.story.tsx} +1 -1
  78. package/src/components/{context-menu.tsx → navigation/context-menu/index.tsx} +1 -1
  79. package/src/components/{dropdown-menu.story.tsx → navigation/dropdown-menu/dropdown-menu.story.tsx} +2 -2
  80. package/src/components/{dropdown-menu.tsx → navigation/dropdown-menu/index.tsx} +1 -1
  81. package/src/components/{menubar.tsx → navigation/menubar/index.tsx} +1 -1
  82. package/src/components/{menubar.story.tsx → navigation/menubar/menubar.story.tsx} +1 -1
  83. package/src/components/{navigation-menu.tsx → navigation/navigation-menu/index.tsx} +1 -1
  84. package/src/components/{navigation-menu.story.tsx → navigation/navigation-menu/navigation-menu.story.tsx} +2 -2
  85. package/src/components/{tabs.tsx → navigation/tabs/index.tsx} +6 -6
  86. package/src/components/{tabs.story.tsx → navigation/tabs/tabs.story.tsx} +5 -5
  87. package/src/components/{alert-dialog.story.tsx → overlay/alert-dialog/alert-dialog.story.tsx} +2 -2
  88. package/src/components/{alert-dialog.tsx → overlay/alert-dialog/index.tsx} +2 -2
  89. package/src/components/{dialog.story.tsx → overlay/dialog/dialog.story.tsx} +4 -4
  90. package/src/components/{dialog.tsx → overlay/dialog/index.tsx} +1 -1
  91. package/src/components/{drawer.story.tsx → overlay/drawer/drawer.story.tsx} +4 -4
  92. package/src/components/{drawer.tsx → overlay/drawer/index.tsx} +1 -1
  93. package/src/components/{hover-card.story.tsx → overlay/hover-card/hover-card.story.tsx} +3 -3
  94. package/src/components/{hover-card.tsx → overlay/hover-card/index.tsx} +1 -1
  95. package/src/components/{popover.tsx → overlay/popover/index.tsx} +1 -1
  96. package/src/components/{popover.story.tsx → overlay/popover/popover.story.tsx} +4 -4
  97. package/src/components/{responsive-sheet.tsx → overlay/responsive-sheet/index.tsx} +3 -3
  98. package/src/components/{responsive-sheet.story.tsx → overlay/responsive-sheet/responsive-sheet.story.tsx} +4 -4
  99. package/src/components/{sheet.tsx → overlay/sheet/index.tsx} +1 -1
  100. package/src/components/{sheet.story.tsx → overlay/sheet/sheet.story.tsx} +4 -4
  101. package/src/components/{tooltip.tsx → overlay/tooltip/index.tsx} +1 -1
  102. package/src/components/{tooltip.story.tsx → overlay/tooltip/tooltip.story.tsx} +2 -2
  103. package/src/components/select/README.md +272 -0
  104. package/src/components/{combobox.story.tsx → select/combobox.story.tsx} +2 -2
  105. package/src/components/{combobox.tsx → select/combobox.tsx} +50 -8
  106. package/src/components/{country-select.story.tsx → select/country-select.story.tsx} +1 -1
  107. package/src/components/{country-select.tsx → select/country-select.tsx} +8 -8
  108. package/src/components/{multi-select-pro → select}/helpers.tsx +2 -2
  109. package/src/components/select/index.ts +59 -0
  110. package/src/components/{language-select.story.tsx → select/language-select.story.tsx} +1 -1
  111. package/src/components/{language-select.tsx → select/language-select.tsx} +8 -8
  112. package/src/components/{multi-select-pro/async.tsx → select/multi-select-pro-async.tsx} +5 -5
  113. package/src/components/{multi-select-pro/index.tsx → select/multi-select-pro.tsx} +5 -5
  114. package/src/components/{multi-select.story.tsx → select/multi-select.story.tsx} +1 -1
  115. package/src/components/{multi-select.tsx → select/multi-select.tsx} +6 -6
  116. package/src/components/{select.story.tsx → select/select.story.tsx} +2 -2
  117. package/src/components/{select.tsx → select/select.tsx} +25 -7
  118. package/src/components/select/types.ts +57 -0
  119. package/src/components/{copy.story.tsx → specialized/copy/copy.story.tsx} +1 -1
  120. package/src/components/{copy.tsx → specialized/copy/index.tsx} +2 -2
  121. package/src/components/{image-with-fallback.story.tsx → specialized/image-with-fallback/image-with-fallback.story.tsx} +1 -1
  122. package/src/components/{image-with-fallback.tsx → specialized/image-with-fallback/index.tsx} +2 -2
  123. package/src/components/{item.tsx → specialized/item/index.tsx} +2 -2
  124. package/src/components/{kbd.tsx → specialized/kbd/index.tsx} +1 -1
  125. package/src/components/{kbd.story.tsx → specialized/kbd/kbd.story.tsx} +1 -1
  126. package/src/components/{token-icon.tsx → specialized/token-icon/index.tsx} +1 -1
  127. package/src/lib/dialog-service/dialog-service.story.tsx +1 -1
  128. package/src/lib/dialog-service/dialogs/AlertDialogUI.tsx +1 -1
  129. package/src/lib/dialog-service/dialogs/ConfirmDialogUI.tsx +2 -2
  130. package/src/lib/dialog-service/dialogs/PromptDialogUI.tsx +3 -3
  131. package/src/stories/index.ts +8 -8
  132. /package/src/components/{calendar → data/calendar}/index.ts +0 -0
  133. /package/src/components/{otp → forms/otp}/types.ts +0 -0
  134. /package/src/components/{otp → forms/otp}/use-otp-input.ts +0 -0
  135. /package/src/components/{aspect-ratio.tsx → layout/aspect-ratio/index.tsx} +0 -0
  136. /package/src/components/{collapsible.tsx → navigation/collapsible/index.tsx} +0 -0
  137. /package/src/components/{tooltip-provider-safe.tsx → overlay/tooltip/tooltip-provider-safe.tsx} +0 -0
  138. /package/src/components/{portal.tsx → specialized/portal/index.tsx} +0 -0
@@ -9,8 +9,8 @@ import {
9
9
  AlertDialogDescription,
10
10
  AlertDialogAction,
11
11
  AlertDialogCancel,
12
- } from './alert-dialog';
13
- import { Button } from './button';
12
+ } from '.';
13
+ import { Button } from '../../forms/button';
14
14
 
15
15
  export default defineStory({
16
16
  title: 'Core/Alert Dialog',
@@ -4,8 +4,8 @@ import * as React from 'react';
4
4
 
5
5
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
6
6
 
7
- import { cn } from '../lib/utils';
8
- import { buttonVariants } from './button';
7
+ import { cn } from '../../../lib/utils';
8
+ import { buttonVariants } from '../../forms/button';
9
9
 
10
10
  const AlertDialog = AlertDialogPrimitive.Root
11
11
 
@@ -8,10 +8,10 @@ import {
8
8
  DialogTitle,
9
9
  DialogDescription,
10
10
  DialogClose,
11
- } from './dialog';
12
- import { Button } from './button';
13
- import { Input } from './input';
14
- import { Label } from './label';
11
+ } from '.';
12
+ import { Button } from '../../forms/button';
13
+ import { Input } from '../../forms/input';
14
+ import { Label } from '../../forms/label';
15
15
 
16
16
  export default defineStory({
17
17
  title: 'Core/Dialog',
@@ -5,7 +5,7 @@ import * as React from 'react';
5
5
  import * as DialogPrimitive from '@radix-ui/react-dialog';
6
6
  import { Cross2Icon } from '@radix-ui/react-icons';
7
7
 
8
- import { cn } from '../lib/utils';
8
+ import { cn } from '../../../lib/utils';
9
9
 
10
10
  const Dialog = DialogPrimitive.Root
11
11
 
@@ -8,10 +8,10 @@ import {
8
8
  DrawerTitle,
9
9
  DrawerDescription,
10
10
  DrawerClose,
11
- } from './drawer';
12
- import { Button } from './button';
13
- import { Input } from './input';
14
- import { Label } from './label';
11
+ } from '.';
12
+ import { Button } from '../../forms/button';
13
+ import { Input } from '../../forms/input';
14
+ import { Label } from '../../forms/label';
15
15
 
16
16
  export default defineStory({
17
17
  title: 'Core/Drawer',
@@ -3,7 +3,7 @@
3
3
  import * as React from 'react';
4
4
  import { Drawer as DrawerPrimitive } from 'vaul';
5
5
 
6
- import { cn } from '../lib/utils';
6
+ import { cn } from '../../../lib/utils';
7
7
 
8
8
  const Drawer = ({
9
9
  shouldScaleBackground = true,
@@ -1,7 +1,7 @@
1
1
  import { defineStory } from '@djangocfg/playground';
2
- import { HoverCard, HoverCardContent, HoverCardTrigger } from './hover-card';
3
- import { Avatar, AvatarFallback, AvatarImage } from './avatar';
4
- import { Button } from './button';
2
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from '.';
3
+ import { Avatar, AvatarFallback, AvatarImage } from '../../data/avatar';
4
+ import { Button } from '../../forms/button';
5
5
  import { CalendarDays } from 'lucide-react';
6
6
 
7
7
  export default defineStory({
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
 
5
5
  import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
6
6
 
7
- import { cn } from '../lib/utils';
7
+ import { cn } from '../../../lib/utils';
8
8
 
9
9
  const HoverCard = HoverCardPrimitive.Root
10
10
 
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
 
5
5
  import * as PopoverPrimitive from '@radix-ui/react-popover';
6
6
 
7
- import { cn } from '../lib/utils';
7
+ import { cn } from '../../../lib/utils';
8
8
 
9
9
  const Popover = PopoverPrimitive.Root
10
10
 
@@ -1,8 +1,8 @@
1
1
  import { defineStory, useSelect } from '@djangocfg/playground';
2
- import { Popover, PopoverContent, PopoverTrigger } from './popover';
3
- import { Button } from './button';
4
- import { Input } from './input';
5
- import { Label } from './label';
2
+ import { Popover, PopoverContent, PopoverTrigger } from '.';
3
+ import { Button } from '../../forms/button';
4
+ import { Input } from '../../forms/input';
5
+ import { Label } from '../../forms/label';
6
6
 
7
7
  export default defineStory({
8
8
  title: 'Core/Popover',
@@ -9,7 +9,7 @@
9
9
 
10
10
  import * as React from 'react';
11
11
 
12
- import { useIsMobile } from '../hooks/useMobile';
12
+ import { useIsMobile } from '../../../hooks/useMobile';
13
13
 
14
14
  import {
15
15
  Dialog,
@@ -18,7 +18,7 @@ import {
18
18
  DialogFooter,
19
19
  DialogHeader,
20
20
  DialogTitle,
21
- } from './dialog';
21
+ } from '../../overlay/dialog';
22
22
 
23
23
  import {
24
24
  Drawer,
@@ -27,7 +27,7 @@ import {
27
27
  DrawerFooter,
28
28
  DrawerHeader,
29
29
  DrawerTitle,
30
- } from './drawer';
30
+ } from '../../overlay/drawer';
31
31
 
32
32
  // ─────────────────────────────────────────────────────────────────────────────
33
33
  // Context
@@ -7,10 +7,10 @@ import {
7
7
  ResponsiveSheetTitle,
8
8
  ResponsiveSheetDescription,
9
9
  ResponsiveSheetFooter,
10
- } from './responsive-sheet';
11
- import { Button } from './button';
12
- import { Input } from './input';
13
- import { Label } from './label';
10
+ } from '.';
11
+ import { Button } from '../../forms/button';
12
+ import { Input } from '../../forms/input';
13
+ import { Label } from '../../forms/label';
14
14
 
15
15
  export default defineStory({
16
16
  title: 'Core/ResponsiveSheet',
@@ -6,7 +6,7 @@ import * as React from 'react';
6
6
  import * as SheetPrimitive from '@radix-ui/react-dialog';
7
7
  import { Cross2Icon } from '@radix-ui/react-icons';
8
8
 
9
- import { cn } from '../lib/utils';
9
+ import { cn } from '../../../lib/utils';
10
10
 
11
11
  const Sheet = SheetPrimitive.Root
12
12
 
@@ -8,10 +8,10 @@ import {
8
8
  SheetTitle,
9
9
  SheetDescription,
10
10
  SheetClose,
11
- } from './sheet';
12
- import { Button } from './button';
13
- import { Input } from './input';
14
- import { Label } from './label';
11
+ } from '.';
12
+ import { Button } from '../../forms/button';
13
+ import { Input } from '../../forms/input';
14
+ import { Label } from '../../forms/label';
15
15
 
16
16
  export default defineStory({
17
17
  title: 'Core/Sheet',
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
 
5
5
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
6
6
 
7
- import { cn } from '../lib/utils';
7
+ import { cn } from '../../../lib/utils';
8
8
 
9
9
  const TooltipProvider = TooltipPrimitive.Provider
10
10
 
@@ -1,6 +1,6 @@
1
1
  import { defineStory, useSelect } from '@djangocfg/playground';
2
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './tooltip';
3
- import { Button } from './button';
2
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '.';
3
+ import { Button } from '../../forms/button';
4
4
  import { Plus, Settings, HelpCircle } from 'lucide-react';
5
5
 
6
6
  export default defineStory({
@@ -0,0 +1,272 @@
1
+ # Select Components
2
+
3
+ Unified collection of all select-based components with consistent API supporting **icons** and **badges**.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ components/select/
9
+ ├── index.ts # Re-exports everything
10
+ ├── select.tsx # Radix UI primitives (enhanced)
11
+ ├── combobox.tsx # Searchable single-select
12
+ ├── multi-select.tsx # Simple multi-select
13
+ ├── multi-select-pro/ # Advanced multi-select
14
+ │ ├── index.tsx # MultiSelectPro
15
+ │ ├── async.tsx # Async version
16
+ │ └── helpers.tsx # Option builders
17
+ └── types.ts # Shared types
18
+ ```
19
+
20
+ ## Components
21
+
22
+ ### 1. Select (Radix Primitives)
23
+
24
+ Low-level primitives with icon and badge support.
25
+
26
+ ```tsx
27
+ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@djangocfg/ui-core';
28
+
29
+ // With icon in trigger
30
+ <Select>
31
+ <SelectTrigger icon={MailIcon}>
32
+ <SelectValue placeholder="Select email" />
33
+ </SelectTrigger>
34
+ <SelectContent>
35
+ <SelectItem value="work" icon={BriefcaseIcon} badge="Work">
36
+ john@company.com
37
+ </SelectItem>
38
+ <SelectItem value="personal" icon={HomeIcon}>
39
+ john@gmail.com
40
+ </SelectItem>
41
+ </SelectContent>
42
+ </Select>
43
+ ```
44
+
45
+ ### 2. Combobox
46
+
47
+ Searchable single-select with icon and badge support.
48
+
49
+ ```tsx
50
+ import { Combobox } from '@djangocfg/ui-core';
51
+
52
+ // Basic usage
53
+ <Combobox
54
+ options={[
55
+ {
56
+ value: 'react',
57
+ label: 'React',
58
+ icon: ReactIcon,
59
+ badge: 'Popular',
60
+ style: { badgeColor: '#3b82f6' }
61
+ },
62
+ {
63
+ value: 'vue',
64
+ label: 'Vue',
65
+ icon: VueIcon,
66
+ badge: 'New',
67
+ style: { gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }
68
+ },
69
+ ]}
70
+ value={selected}
71
+ onValueChange={setSelected}
72
+ />
73
+
74
+ // With custom render
75
+ <Combobox
76
+ options={frameworks}
77
+ renderValue={(option) => (
78
+ <div className="flex items-center gap-2">
79
+ {option?.icon && <option.icon className="h-4 w-4" />}
80
+ <span>{option?.label}</span>
81
+ {option?.badge && <Badge>{option.badge}</Badge>}
82
+ </div>
83
+ )}
84
+ />
85
+ ```
86
+
87
+ ### 3. MultiSelectPro
88
+
89
+ Advanced multi-select with badges, icons, animations.
90
+
91
+ ```tsx
92
+ import { MultiSelectPro } from '@djangocfg/ui-core';
93
+
94
+ <MultiSelectPro
95
+ options={[
96
+ {
97
+ label: 'JavaScript',
98
+ value: 'js',
99
+ icon: JsIcon,
100
+ style: { badgeColor: '#f7df1e', iconColor: '#000' }
101
+ },
102
+ {
103
+ label: 'TypeScript',
104
+ value: 'ts',
105
+ icon: TsIcon,
106
+ badge: 'Recommended',
107
+ style: { badgeColor: '#3178c6' }
108
+ },
109
+ {
110
+ label: 'Python',
111
+ value: 'py',
112
+ icon: PythonIcon,
113
+ description: 'Great for ML/AI'
114
+ },
115
+ ]}
116
+ onValueChange={setSelected}
117
+ maxCount={3}
118
+ variant="default"
119
+ />
120
+
121
+ // With groups
122
+ <MultiSelectPro
123
+ options={[
124
+ {
125
+ heading: 'Frontend',
126
+ options: [
127
+ { label: 'React', value: 'react', icon: ReactIcon },
128
+ { label: 'Vue', value: 'vue', icon: VueIcon },
129
+ ]
130
+ },
131
+ {
132
+ heading: 'Backend',
133
+ options: [
134
+ { label: 'Node.js', value: 'node', icon: NodeIcon },
135
+ { label: 'Django', value: 'django', icon: DjangoIcon },
136
+ ]
137
+ }
138
+ ]}
139
+ />
140
+ ```
141
+
142
+ ### 4. MultiSelectProAsync
143
+
144
+ Async version with debounced search.
145
+
146
+ ```tsx
147
+ import { MultiSelectProAsync } from '@djangocfg/ui-core';
148
+
149
+ <MultiSelectProAsync
150
+ options={loadedOptions}
151
+ searchValue={search}
152
+ onSearchChange={(value) => {
153
+ setSearch(value);
154
+ debouncedSearch(value); // Your async search
155
+ }}
156
+ isLoading={isLoading}
157
+ onValueChange={setSelected}
158
+ />
159
+ ```
160
+
161
+ ### 5. Option Builders
162
+
163
+ Helper utilities for creating options from data.
164
+
165
+ ```tsx
166
+ import { createOption, createOptions } from '@djangocfg/ui-core';
167
+
168
+ // Single option builder
169
+ const buildUserOption = createOption({
170
+ getValue: (user) => user.id,
171
+ getLabel: (user) => user.name,
172
+ getDescription: (user) => user.email,
173
+ getIcon: (user) => user.avatar ? AvatarIcon : UserIcon,
174
+ getStyle: (user) => user.isPremium
175
+ ? { gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' }
176
+ : undefined,
177
+ });
178
+
179
+ const option = buildUserOption(user);
180
+
181
+ // Batch create options
182
+ const options = createOptions(users, {
183
+ getValue: (u) => u.id,
184
+ getLabel: (u) => u.name,
185
+ getDescription: (u) => u.role,
186
+ isDisabled: (u) => !u.isActive,
187
+ });
188
+ ```
189
+
190
+ ## Option API
191
+
192
+ All components share the same option interface:
193
+
194
+ ```typescript
195
+ interface BaseSelectOption {
196
+ value: string;
197
+ label: string;
198
+ description?: string;
199
+ icon?: React.ComponentType<{ className?: string }>;
200
+ badge?: string | React.ReactNode;
201
+ disabled?: boolean;
202
+ style?: {
203
+ badgeColor?: string;
204
+ iconColor?: string;
205
+ gradient?: string;
206
+ };
207
+ }
208
+ ```
209
+
210
+ ### Examples
211
+
212
+ ```tsx
213
+ // Minimal
214
+ { value: 'a', label: 'Option A' }
215
+
216
+ // With icon
217
+ { value: 'b', label: 'Option B', icon: MailIcon }
218
+
219
+ // With badge
220
+ { value: 'c', label: 'Option C', badge: 'New' }
221
+
222
+ // With description
223
+ { value: 'd', label: 'Option D', description: 'Extra info here' }
224
+
225
+ // Full featured
226
+ {
227
+ value: 'e',
228
+ label: 'Premium Option',
229
+ icon: StarIcon,
230
+ badge: '⭐ Premium',
231
+ description: 'Includes all features',
232
+ style: {
233
+ gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
234
+ iconColor: '#fff'
235
+ }
236
+ }
237
+
238
+ // Disabled
239
+ { value: 'f', label: 'Disabled', disabled: true }
240
+ ```
241
+
242
+ ## Migration
243
+
244
+ ### Old imports (still work for backwards compatibility)
245
+
246
+ ```tsx
247
+ import { Combobox, Select, MultiSelectPro } from '@djangocfg/ui-core';
248
+ ```
249
+
250
+ ### New imports (recommended)
251
+
252
+ ```tsx
253
+ import {
254
+ Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
255
+ Combobox,
256
+ MultiSelectPro,
257
+ MultiSelectProAsync,
258
+ createOption,
259
+ createOptions,
260
+ } from '@djangocfg/ui-core';
261
+
262
+ // Or deep import
263
+ import { Combobox } from '@djangocfg/ui-core/components/select';
264
+ ```
265
+
266
+ ## What's New
267
+
268
+ ✅ **Icon support** — all components can display icons in options and triggers
269
+ ✅ **Badge support** — display badges in triggers and dropdown items
270
+ ✅ **Custom styling** — gradient badges, custom colors via `style` prop
271
+ ✅ **Unified API** — consistent option interface across all components
272
+ ✅ **Organized structure** — all select components in one place
@@ -1,7 +1,7 @@
1
1
  import { useState } from 'react';
2
2
  import { defineStory, useBoolean } from '@djangocfg/playground';
3
- import { Combobox, type ComboboxOption } from './combobox';
4
- import { Label } from './label';
3
+ import { Combobox, type ComboboxOption } from '.';
4
+ import { Label } from '../forms/label';
5
5
 
6
6
  export default defineStory({
7
7
  title: 'Core/Combobox',
@@ -4,19 +4,27 @@ import { Check, ChevronsUpDown } from 'lucide-react';
4
4
  import * as React from 'react';
5
5
 
6
6
  import { useAppT } from '@djangocfg/i18n';
7
- import { useStoredValue, type StorageType, type UseStoredValueOptions } from '../hooks/useStoredValue';
8
- import { cn } from '../lib/utils';
9
- import { Button } from './button';
7
+ import { useStoredValue, type StorageType, type UseStoredValueOptions } from '../../hooks/useStoredValue';
8
+ import { cn } from '../../lib/utils';
9
+ import { Badge } from '../data/badge';
10
+ import { Button } from '../forms/button';
10
11
  import {
11
- Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList
12
- } from './command';
13
- import { Popover, PopoverContent, PopoverTrigger } from './popover';
12
+ Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList
13
+ } from '../navigation/command';
14
+ import { Popover, PopoverContent, PopoverTrigger } from '../overlay/popover';
14
15
 
15
16
  export interface ComboboxOption {
16
17
  value: string
17
18
  label: string
18
19
  description?: string
20
+ icon?: React.ComponentType<{ className?: string }>
21
+ badge?: string | React.ReactNode
19
22
  disabled?: boolean
23
+ style?: {
24
+ badgeColor?: string
25
+ iconColor?: string
26
+ gradient?: string
27
+ }
20
28
  }
21
29
 
22
30
  export interface ComboboxProps {
@@ -194,6 +202,32 @@ export function Combobox({
194
202
  [value, storageKey, setStoredValue, controlledValue, onValueChange],
195
203
  );
196
204
 
205
+ // Render badge for selected option in trigger
206
+ const renderSelectedBadge = (option: ComboboxOption) => {
207
+ const { style, icon: Icon, badge } = option;
208
+ const badgeStyle: React.CSSProperties = {};
209
+
210
+ if (style?.gradient) {
211
+ badgeStyle.background = style.gradient;
212
+ badgeStyle.color = style.iconColor || "white";
213
+ } else if (style?.badgeColor) {
214
+ badgeStyle.backgroundColor = style.badgeColor;
215
+ badgeStyle.color = style.iconColor || "white";
216
+ }
217
+
218
+ return (
219
+ <div className="flex items-center gap-2">
220
+ {Icon && <Icon className="h-4 w-4 shrink-0" />}
221
+ <span className="truncate">{option.label}</span>
222
+ {badge && (
223
+ <Badge variant="secondary" className="text-xs" style={Object.keys(badgeStyle).length > 0 ? badgeStyle : undefined}>
224
+ {badge}
225
+ </Badge>
226
+ )}
227
+ </div>
228
+ );
229
+ };
230
+
197
231
  return (
198
232
  <Popover
199
233
  open={open}
@@ -219,7 +253,7 @@ export function Combobox({
219
253
  {renderValue && selectedOption
220
254
  ? renderValue(selectedOption)
221
255
  : selectedOption
222
- ? selectedOption.label
256
+ ? renderSelectedBadge(selectedOption)
223
257
  : resolvedPlaceholder}
224
258
  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
225
259
  </Button>
@@ -266,11 +300,19 @@ export function Combobox({
266
300
  value === option.value ? "opacity-100" : "opacity-0"
267
301
  )}
268
302
  />
303
+ {option.icon && <option.icon className="mr-2 h-4 w-4 shrink-0" />}
269
304
  {renderOption ? (
270
305
  renderOption(option)
271
306
  ) : (
272
307
  <div className="flex flex-col flex-1 min-w-0">
273
- <span className="truncate">{option.label}</span>
308
+ <div className="flex items-center gap-2 truncate">
309
+ <span className="truncate">{option.label}</span>
310
+ {option.badge && (
311
+ <Badge variant="outline" className="text-xs shrink-0">
312
+ {option.badge}
313
+ </Badge>
314
+ )}
315
+ </div>
274
316
  {option.description && (
275
317
  <span className="text-xs text-muted-foreground truncate">
276
318
  {option.description}
@@ -1,7 +1,7 @@
1
1
  import { useState } from 'react';
2
2
  import { defineStory } from '@djangocfg/playground';
3
3
  import { CountrySelect, type TCountryCode } from './country-select';
4
- import { Label } from './label';
4
+ import { Label } from '../forms/label';
5
5
 
6
6
  export default defineStory({
7
7
  title: 'Core/CountrySelect',
@@ -4,16 +4,16 @@ import { Check, ChevronsUpDown, Search, X } from 'lucide-react';
4
4
  import * as React from 'react';
5
5
  import { countries, getEmojiFlag, type TCountryCode } from 'countries-list';
6
6
 
7
- import { cn } from '../lib/utils';
8
- import { Badge } from './badge';
9
- import { Button } from './button';
10
- import { Checkbox } from './checkbox';
7
+ import { cn } from '../../lib/utils';
8
+ import { Badge } from '../data/badge';
9
+ import { Button } from '../forms/button';
10
+ import { Checkbox } from '../forms/checkbox';
11
11
  import {
12
12
  Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList
13
- } from './command';
14
- import { Input } from './input';
15
- import { Popover, PopoverContent, PopoverTrigger } from './popover';
16
- import { ScrollArea } from './scroll-area';
13
+ } from '../navigation/command';
14
+ import { Input } from '../forms/input';
15
+ import { Popover, PopoverContent, PopoverTrigger } from '../overlay/popover';
16
+ import { ScrollArea } from '../layout/scroll-area';
17
17
 
18
18
  export interface CountryOption {
19
19
  code: TCountryCode;
@@ -2,8 +2,8 @@
2
2
  * Helper utilities for MultiSelectPro components
3
3
  */
4
4
 
5
- import type { MultiSelectProOption } from './index'
6
- import type { MultiSelectProAsyncOption } from './async'
5
+ import type { MultiSelectProOption } from './multi-select-pro'
6
+ import type { MultiSelectProAsyncOption } from './multi-select-pro-async'
7
7
 
8
8
  // ==================== TYPES ====================
9
9