@neynar/ui 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/components/ui/accordion.d.ts +1 -25
  2. package/dist/components/ui/accordion.d.ts.map +1 -1
  3. package/dist/components/ui/alert-dialog.d.ts +240 -46
  4. package/dist/components/ui/alert-dialog.d.ts.map +1 -1
  5. package/dist/components/ui/alert.d.ts +73 -11
  6. package/dist/components/ui/alert.d.ts.map +1 -1
  7. package/dist/components/ui/aspect-ratio.d.ts +44 -10
  8. package/dist/components/ui/aspect-ratio.d.ts.map +1 -1
  9. package/dist/components/ui/avatar.d.ts +117 -33
  10. package/dist/components/ui/avatar.d.ts.map +1 -1
  11. package/dist/components/ui/badge.d.ts +50 -71
  12. package/dist/components/ui/badge.d.ts.map +1 -1
  13. package/dist/components/ui/breadcrumb.d.ts +231 -49
  14. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  15. package/dist/components/ui/button.d.ts +189 -71
  16. package/dist/components/ui/button.d.ts.map +1 -1
  17. package/dist/components/ui/calendar.d.ts +197 -40
  18. package/dist/components/ui/calendar.d.ts.map +1 -1
  19. package/dist/components/ui/card.d.ts +7 -22
  20. package/dist/components/ui/card.d.ts.map +1 -1
  21. package/dist/components/ui/carousel.d.ts +369 -99
  22. package/dist/components/ui/carousel.d.ts.map +1 -1
  23. package/dist/components/ui/chart.d.ts.map +1 -1
  24. package/dist/components/ui/checkbox.d.ts +110 -38
  25. package/dist/components/ui/checkbox.d.ts.map +1 -1
  26. package/dist/components/ui/collapsible.d.ts +246 -61
  27. package/dist/components/ui/collapsible.d.ts.map +1 -1
  28. package/dist/components/ui/combobox.d.ts +207 -159
  29. package/dist/components/ui/combobox.d.ts.map +1 -1
  30. package/dist/components/ui/command.d.ts +336 -67
  31. package/dist/components/ui/command.d.ts.map +1 -1
  32. package/dist/components/ui/container.d.ts +159 -64
  33. package/dist/components/ui/container.d.ts.map +1 -1
  34. package/dist/components/ui/context-menu.d.ts +321 -39
  35. package/dist/components/ui/context-menu.d.ts.map +1 -1
  36. package/dist/components/ui/date-picker.d.ts +113 -86
  37. package/dist/components/ui/date-picker.d.ts.map +1 -1
  38. package/dist/components/ui/dialog.d.ts +106 -25
  39. package/dist/components/ui/dialog.d.ts.map +1 -1
  40. package/dist/components/ui/drawer.d.ts +388 -59
  41. package/dist/components/ui/drawer.d.ts.map +1 -1
  42. package/dist/components/ui/dropdown-menu.d.ts +521 -74
  43. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  44. package/dist/components/ui/empty-state.d.ts +148 -76
  45. package/dist/components/ui/empty-state.d.ts.map +1 -1
  46. package/dist/components/ui/hover-card.d.ts +253 -34
  47. package/dist/components/ui/hover-card.d.ts.map +1 -1
  48. package/dist/components/ui/input.d.ts +143 -44
  49. package/dist/components/ui/input.d.ts.map +1 -1
  50. package/dist/components/ui/label.d.ts +0 -8
  51. package/dist/components/ui/label.d.ts.map +1 -1
  52. package/dist/components/ui/menubar.d.ts +288 -46
  53. package/dist/components/ui/menubar.d.ts.map +1 -1
  54. package/dist/components/ui/navigation-menu.d.ts +444 -127
  55. package/dist/components/ui/navigation-menu.d.ts.map +1 -1
  56. package/dist/components/ui/pagination.d.ts +342 -66
  57. package/dist/components/ui/pagination.d.ts.map +1 -1
  58. package/dist/components/ui/popover.d.ts +0 -8
  59. package/dist/components/ui/popover.d.ts.map +1 -1
  60. package/dist/components/ui/progress.d.ts +88 -30
  61. package/dist/components/ui/progress.d.ts.map +1 -1
  62. package/dist/components/ui/radio-group.d.ts +189 -45
  63. package/dist/components/ui/radio-group.d.ts.map +1 -1
  64. package/dist/components/ui/resizable.d.ts +178 -62
  65. package/dist/components/ui/resizable.d.ts.map +1 -1
  66. package/dist/components/ui/scroll-area.d.ts +180 -21
  67. package/dist/components/ui/scroll-area.d.ts.map +1 -1
  68. package/dist/components/ui/select.d.ts +382 -60
  69. package/dist/components/ui/select.d.ts.map +1 -1
  70. package/dist/components/ui/separator.d.ts +52 -39
  71. package/dist/components/ui/separator.d.ts.map +1 -1
  72. package/dist/components/ui/sheet.d.ts +144 -27
  73. package/dist/components/ui/sheet.d.ts.map +1 -1
  74. package/dist/components/ui/sidebar.d.ts +81 -31
  75. package/dist/components/ui/sidebar.d.ts.map +1 -1
  76. package/dist/components/ui/skeleton.d.ts +94 -32
  77. package/dist/components/ui/skeleton.d.ts.map +1 -1
  78. package/dist/components/ui/slider.d.ts +37 -31
  79. package/dist/components/ui/slider.d.ts.map +1 -1
  80. package/dist/components/ui/sonner.d.ts +280 -46
  81. package/dist/components/ui/sonner.d.ts.map +1 -1
  82. package/dist/components/ui/stack.d.ts +289 -148
  83. package/dist/components/ui/stack.d.ts.map +1 -1
  84. package/dist/components/ui/stories/aspect-ratio.stories.d.ts +1 -2
  85. package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -1
  86. package/dist/components/ui/stories/container.stories.d.ts +2 -3
  87. package/dist/components/ui/stories/container.stories.d.ts.map +1 -1
  88. package/dist/components/ui/stories/empty-state.stories.d.ts +2 -2
  89. package/dist/components/ui/stories/scroll-area.stories.d.ts +1 -2
  90. package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -1
  91. package/dist/components/ui/stories/stack.stories.d.ts +1 -1
  92. package/dist/components/ui/stories/text-field.stories.d.ts +7 -1
  93. package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -1
  94. package/dist/components/ui/switch.d.ts +44 -38
  95. package/dist/components/ui/switch.d.ts.map +1 -1
  96. package/dist/components/ui/table.d.ts +33 -0
  97. package/dist/components/ui/table.d.ts.map +1 -1
  98. package/dist/components/ui/tabs.d.ts +4 -22
  99. package/dist/components/ui/tabs.d.ts.map +1 -1
  100. package/dist/components/ui/text-field.d.ts +170 -84
  101. package/dist/components/ui/text-field.d.ts.map +1 -1
  102. package/dist/components/ui/textarea.d.ts +106 -29
  103. package/dist/components/ui/textarea.d.ts.map +1 -1
  104. package/dist/components/ui/theme-toggle.d.ts +190 -65
  105. package/dist/components/ui/theme-toggle.d.ts.map +1 -1
  106. package/dist/components/ui/theme.d.ts +107 -23
  107. package/dist/components/ui/theme.d.ts.map +1 -1
  108. package/dist/components/ui/toggle-group.d.ts +143 -67
  109. package/dist/components/ui/toggle-group.d.ts.map +1 -1
  110. package/dist/components/ui/toggle.d.ts +118 -30
  111. package/dist/components/ui/toggle.d.ts.map +1 -1
  112. package/dist/components/ui/tooltip.d.ts +152 -28
  113. package/dist/components/ui/tooltip.d.ts.map +1 -1
  114. package/dist/components/ui/typography.d.ts +452 -134
  115. package/dist/components/ui/typography.d.ts.map +1 -1
  116. package/dist/index.js +9388 -8281
  117. package/dist/index.js.map +1 -1
  118. package/dist/tsconfig.tsbuildinfo +1 -1
  119. package/llms.txt +173 -3
  120. package/package.json +5 -2
  121. package/src/components/ui/accordion.tsx +112 -27
  122. package/src/components/ui/alert-dialog.tsx +401 -46
  123. package/src/components/ui/alert.tsx +114 -11
  124. package/src/components/ui/aspect-ratio.tsx +69 -14
  125. package/src/components/ui/avatar.tsx +179 -33
  126. package/src/components/ui/badge.tsx +74 -75
  127. package/src/components/ui/breadcrumb.tsx +335 -50
  128. package/src/components/ui/button.tsx +198 -90
  129. package/src/components/ui/calendar.tsx +867 -43
  130. package/src/components/ui/card.tsx +140 -33
  131. package/src/components/ui/carousel.tsx +529 -98
  132. package/src/components/ui/chart.tsx +222 -1
  133. package/src/components/ui/checkbox.tsx +176 -38
  134. package/src/components/ui/collapsible.tsx +321 -67
  135. package/src/components/ui/combobox.tsx +284 -83
  136. package/src/components/ui/command.tsx +527 -67
  137. package/src/components/ui/container.tsx +217 -65
  138. package/src/components/ui/context-menu.tsx +716 -51
  139. package/src/components/ui/date-picker.tsx +228 -38
  140. package/src/components/ui/dialog.tsx +270 -33
  141. package/src/components/ui/drawer.tsx +546 -67
  142. package/src/components/ui/dropdown-menu.tsx +657 -74
  143. package/src/components/ui/empty-state.tsx +241 -82
  144. package/src/components/ui/hover-card.tsx +328 -39
  145. package/src/components/ui/input.tsx +207 -44
  146. package/src/components/ui/label.tsx +98 -8
  147. package/src/components/ui/menubar.tsx +587 -54
  148. package/src/components/ui/navigation-menu.tsx +557 -128
  149. package/src/components/ui/pagination.tsx +561 -79
  150. package/src/components/ui/popover.tsx +119 -8
  151. package/src/components/ui/progress.tsx +131 -29
  152. package/src/components/ui/radio-group.tsx +260 -51
  153. package/src/components/ui/resizable.tsx +289 -63
  154. package/src/components/ui/scroll-area.tsx +377 -66
  155. package/src/components/ui/select.tsx +545 -60
  156. package/src/components/ui/separator.tsx +146 -40
  157. package/src/components/ui/sheet.tsx +348 -31
  158. package/src/components/ui/sidebar.tsx +471 -29
  159. package/src/components/ui/skeleton.tsx +114 -32
  160. package/src/components/ui/slider.tsx +77 -31
  161. package/src/components/ui/sonner.tsx +574 -46
  162. package/src/components/ui/stack.tsx +423 -101
  163. package/src/components/ui/switch.tsx +78 -39
  164. package/src/components/ui/table.tsx +170 -4
  165. package/src/components/ui/tabs.tsx +108 -22
  166. package/src/components/ui/text-field.tsx +226 -81
  167. package/src/components/ui/textarea.tsx +180 -29
  168. package/src/components/ui/theme-toggle.tsx +313 -65
  169. package/src/components/ui/theme.tsx +117 -23
  170. package/src/components/ui/toggle-group.tsx +280 -69
  171. package/src/components/ui/toggle.tsx +124 -35
  172. package/src/components/ui/tooltip.tsx +239 -29
  173. package/src/components/ui/typography.tsx +1115 -165
@@ -1,3 +1,5 @@
1
+ import * as React from "react";
2
+ import { Popover } from "@/components/ui/popover";
1
3
  /**
2
4
  * Option structure for combobox items
3
5
  *
@@ -28,111 +30,30 @@ export type ComboboxOption = {
28
30
  */
29
31
  disabled?: boolean;
30
32
  };
31
- /**
32
- * Properties for the Combobox component
33
- *
34
- * Comprehensive configuration options for customizing combobox behavior,
35
- * appearance, and interaction patterns.
36
- *
37
- * @since 1.0.0
38
- */
39
- export type ComboboxProps = {
40
- /**
41
- * Array of options to display in the combobox dropdown
42
- *
43
- * Each option should have a unique value and descriptive label.
44
- * Options can be disabled to prevent selection while remaining visible.
45
- */
46
- options: ComboboxOption[];
47
- /**
48
- * Currently selected value from the options array
49
- *
50
- * Should match the value property of one of the provided options.
51
- * Use with onValueChange for controlled component behavior.
52
- */
53
- value?: string;
54
- /**
55
- * Callback fired when the selected value changes
56
- *
57
- * Receives the new selected value as a string. If the same option
58
- * is clicked again, an empty string is passed to allow deselection.
59
- *
60
- * @param value - The newly selected option value or empty string for deselection
61
- */
62
- onValueChange?: (value: string) => void;
63
- /**
64
- * Placeholder text displayed when no option is selected
65
- *
66
- * Should be descriptive and help users understand what they're selecting.
67
- *
68
- * @default "Select option..."
69
- */
70
- placeholder?: string;
71
- /**
72
- * Text displayed when search query returns no matching options
73
- *
74
- * Customize this message to match your application's tone and context.
75
- *
76
- * @default "No option found."
77
- */
78
- emptyText?: string;
79
- /**
80
- * Placeholder text for the search input field
81
- *
82
- * Should guide users on how to search effectively within your option set.
83
- *
84
- * @default "Search options..."
85
- */
86
- searchPlaceholder?: string;
87
- /**
88
- * Additional CSS classes for the root container element
89
- *
90
- * Use for custom spacing, positioning, or layout adjustments.
91
- */
92
- className?: string;
93
- /**
94
- * Whether the entire combobox is disabled
95
- *
96
- * When disabled, the trigger button cannot be clicked and the
97
- * dropdown cannot be opened. Use individual option.disabled for
98
- * granular control.
99
- *
100
- * @default false
101
- */
102
- disabled?: boolean;
103
- /**
104
- * Additional CSS classes for the trigger button
105
- *
106
- * Commonly used to control width (e.g., "w-[300px]"), styling variants,
107
- * or responsive behavior. For best UX, consider matching popoverClassName width.
108
- *
109
- * @example "w-full sm:w-[280px] border-primary/50"
110
- */
111
- buttonClassName?: string;
112
- /**
113
- * Additional CSS classes for the popover dropdown content
114
- *
115
- * Should typically match buttonClassName width for consistent alignment.
116
- * Use to control positioning, width, and styling of the dropdown.
117
- *
118
- * @example "w-full sm:w-[280px] border-primary/50"
119
- */
120
- popoverClassName?: string;
121
- };
122
33
  /**
123
34
  * Searchable dropdown selection component with typeahead functionality
124
35
  *
125
36
  * A versatile combobox that combines a button trigger with a searchable dropdown list.
126
37
  * Ideal for selecting from moderate to large lists of options where search functionality
127
- * improves user experience. Built on top of shadcn/ui Command and Popover primitives.
38
+ * improves user experience. Built on Radix UI Popover primitives for accessibility and
39
+ * CMDK for powerful command menu functionality with real-time filtering.
128
40
  *
129
- * Use this component when:
130
- * - You have 10+ options that would benefit from filtering
131
- * - Users need to quickly find specific options
132
- * - You want to provide a better UX than a basic select dropdown
133
- * - You need real-time search/filtering capabilities
41
+ * **Technical Architecture:**
42
+ * - **Popover Container**: Radix UI Popover.Root provides modal/non-modal behavior, focus management, and positioning
43
+ * - **Trigger Button**: Uses Button component with proper ARIA attributes and visual states
44
+ * - **Command Menu**: CMDK provides keyboard navigation, filtering, and accessibility features
45
+ * - **State Management**: Controlled/uncontrolled modes with proper React patterns
134
46
  *
135
- * For fewer options or simpler selection, consider using the Select component instead.
47
+ * **Use Cases:**
48
+ * - Selecting from 10+ options that benefit from real-time filtering
49
+ * - User interfaces requiring quick option discovery through search
50
+ * - Forms needing better UX than basic select dropdowns
51
+ * - Applications with dynamic or large option sets
52
+ *
53
+ * **When Not to Use:**
54
+ * - Simple selection from few options (use Select component instead)
55
+ * - Multi-select scenarios (use Checkbox group or specialized multi-select)
56
+ * - Tree or hierarchical data (use TreeSelect or nested menus)
136
57
  *
137
58
  * @component
138
59
  * @example
@@ -141,9 +62,9 @@ export type ComboboxProps = {
141
62
  * const [framework, setFramework] = useState("")
142
63
  *
143
64
  * const frameworks = [
144
- * { value: "next", label: "Next.js" },
65
+ * { value: "nextjs", label: "Next.js" },
145
66
  * { value: "remix", label: "Remix" },
146
- * { value: "svelte", label: "SvelteKit" },
67
+ * { value: "sveltekit", label: "SvelteKit" },
147
68
  * { value: "nuxt", label: "Nuxt.js" },
148
69
  * ]
149
70
  *
@@ -154,11 +75,12 @@ export type ComboboxProps = {
154
75
  * placeholder="Select framework..."
155
76
  * searchPlaceholder="Search frameworks..."
156
77
  * buttonClassName="w-[300px]"
78
+ * popoverClassName="w-[300px]"
157
79
  * />
158
80
  * ```
159
81
  *
160
82
  * @example
161
- * Combobox with disabled options and custom styling
83
+ * Advanced combobox with disabled options and custom styling
162
84
  * ```tsx
163
85
  * const statusOptions = [
164
86
  * { value: "active", label: "Active" },
@@ -170,101 +92,227 @@ export type ComboboxProps = {
170
92
  * <Combobox
171
93
  * options={statusOptions}
172
94
  * value={status}
173
- * onValueChange={setStatus}
95
+ * onValueChange={(value) => {
96
+ * setStatus(value)
97
+ * // Track selection analytics
98
+ * analytics.track('status_selected', { value })
99
+ * }}
174
100
  * placeholder="Select status..."
175
- * emptyText="No status found."
101
+ * emptyText="No matching status found."
102
+ * searchPlaceholder="Filter statuses..."
176
103
  * buttonClassName="w-[250px] border-primary/50"
177
104
  * popoverClassName="w-[250px]"
105
+ * disabled={isLoading}
178
106
  * />
179
107
  * ```
180
108
  *
181
109
  * @example
182
- * Form integration with validation and error states
110
+ * Form integration with validation and error handling
183
111
  * ```tsx
184
112
  * import { Label } from "@/components/ui/label"
113
+ * import { useFormContext } from "react-hook-form"
185
114
  *
186
- * <form onSubmit={handleSubmit}>
187
- * <div className="space-y-2">
188
- * <Label htmlFor="country">Country</Label>
189
- * <Combobox
190
- * options={countries}
191
- * value={formData.country}
192
- * onValueChange={(value) =>
193
- * setFormData(prev => ({ ...prev, country: value }))
194
- * }
195
- * placeholder="Choose a country..."
196
- * searchPlaceholder="Type to search countries..."
197
- * emptyText="Country not found."
198
- * buttonClassName="w-full"
199
- * disabled={isSubmitting}
200
- * />
201
- * {errors.country && (
202
- * <p className="text-sm text-destructive">{errors.country}</p>
203
- * )}
204
- * </div>
205
- * </form>
115
+ * function CountryField() {
116
+ * const { register, setValue, watch, formState: { errors } } = useFormContext()
117
+ * const selectedCountry = watch("country")
118
+ *
119
+ * return (
120
+ * <div className="space-y-2">
121
+ * <Label htmlFor="country" className={errors.country ? "text-destructive" : ""}>
122
+ * Country {errors.country && "*"}
123
+ * </Label>
124
+ * <Combobox
125
+ * options={countries}
126
+ * value={selectedCountry}
127
+ * onValueChange={(value) => setValue("country", value, { shouldValidate: true })}
128
+ * placeholder="Choose your country..."
129
+ * searchPlaceholder="Type to search countries..."
130
+ * emptyText="Country not found. Try a different search."
131
+ * buttonClassName={cn(
132
+ * "w-full",
133
+ * errors.country && "border-destructive focus-visible:ring-destructive"
134
+ * )}
135
+ * popoverClassName="w-full"
136
+ * disabled={isSubmitting}
137
+ * />
138
+ * {errors.country && (
139
+ * <p className="text-sm text-destructive" role="alert">
140
+ * {errors.country.message}
141
+ * </p>
142
+ * )}
143
+ * </div>
144
+ * )
145
+ * }
206
146
  * ```
207
147
  *
208
148
  * @example
209
- * Responsive width with mobile optimization
149
+ * Responsive design with mobile optimization
210
150
  * ```tsx
211
151
  * <Combobox
212
- * options={userOptions}
213
- * value={selectedUser}
214
- * onValueChange={setSelectedUser}
215
- * placeholder="Select team member..."
216
- * searchPlaceholder="Search users..."
217
- * buttonClassName="w-full sm:w-[280px]"
218
- * popoverClassName="w-full sm:w-[280px]"
152
+ * options={teamMembers}
153
+ * value={assignedTo}
154
+ * onValueChange={setAssignedTo}
155
+ * placeholder="Assign to team member..."
156
+ * searchPlaceholder="Search team members..."
157
+ * emptyText="No team members found."
158
+ * buttonClassName="w-full sm:w-[280px] md:w-[320px]"
159
+ * popoverClassName="w-full sm:w-[280px] md:w-[320px]"
160
+ * // Mobile: full width, Desktop: fixed width for consistent layout
219
161
  * />
220
162
  * ```
221
163
  *
164
+ * @example
165
+ * Async data loading with loading states
166
+ * ```tsx
167
+ * function AsyncCombobox() {
168
+ * const [options, setOptions] = useState([])
169
+ * const [loading, setLoading] = useState(false)
170
+ * const [searchTerm, setSearchTerm] = useState("")
171
+ *
172
+ * // Debounced search effect
173
+ * useEffect(() => {
174
+ * if (!searchTerm) return
175
+ *
176
+ * const timeoutId = setTimeout(async () => {
177
+ * setLoading(true)
178
+ * try {
179
+ * const results = await searchAPI(searchTerm)
180
+ * setOptions(results)
181
+ * } finally {
182
+ * setLoading(false)
183
+ * }
184
+ * }, 300)
185
+ *
186
+ * return () => clearTimeout(timeoutId)
187
+ * }, [searchTerm])
188
+ *
189
+ * return (
190
+ * <Combobox
191
+ * options={options}
192
+ * value={selectedValue}
193
+ * onValueChange={setSelectedValue}
194
+ * placeholder={loading ? "Searching..." : "Search items..."}
195
+ * emptyText={loading ? "Loading..." : "No results found."}
196
+ * disabled={loading}
197
+ * />
198
+ * )
199
+ * }
200
+ * ```
201
+ *
222
202
  * @accessibility
223
203
  *
224
- * **ARIA Implementation:**
225
- * - Uses `role="combobox"` on trigger button with proper `aria-expanded` state
226
- * - Implements `aria-controls` to reference the popup when visible
227
- * - Uses `aria-activedescendant` for focus management within the dropdown
228
- * - Provides `aria-haspopup="listbox"` to indicate popup type
204
+ * **ARIA Implementation (WCAG 2.1 Level AA Compliant):**
205
+ * - **Combobox Role**: Trigger button uses `role="combobox"` with proper `aria-expanded` state
206
+ * - **Popup Association**: `aria-controls` links trigger to popup when visible
207
+ * - **Active Descendant**: `aria-activedescendant` manages focus within dropdown
208
+ * - **Popup Type**: `aria-haspopup="listbox"` indicates the nature of the popup
209
+ * - **Selection State**: `aria-selected` attributes on options indicate current selection
210
+ * - **Disabled State**: Proper `aria-disabled` attributes for unavailable options
229
211
  *
230
- * **Keyboard Navigation (W3C ARIA 1.2 compliant):**
231
- * - **Tab**: Moves focus to/from combobox in page tab order
232
- * - **Down Arrow**: Opens dropdown and moves to first option, or navigates to next option
212
+ * **Keyboard Navigation (W3C ARIA 1.2 Combobox Pattern):**
213
+ * - **Tab**: Moves focus to/from combobox in natural tab order
214
+ * - **Space/Enter**: Opens/closes dropdown, selects focused option
215
+ * - **Down Arrow**: Opens dropdown (if closed) or moves to next option
233
216
  * - **Up Arrow**: Moves to previous option (when dropdown is open)
234
- * - **Enter**: Selects the focused option and closes dropdown
235
- * - **Escape**: Closes dropdown and returns focus to trigger
236
- * - **Home/End**: Moves to first/last option in list
217
+ * - **Home**: Moves to first option in list
218
+ * - **End**: Moves to last option in list
219
+ * - **Escape**: Closes dropdown and returns focus to trigger button
237
220
  * - **Type-ahead**: Real-time filtering as user types in search input
221
+ * - **Character Keys**: When dropdown is closed, opens and starts filtering
238
222
  *
239
223
  * **Screen Reader Support:**
240
- * - Announces current selection state and option count
241
- * - Provides clear labels for empty states and loading states
242
- * - Announces selection changes and dropdown open/close states
243
- * - Disabled options are properly announced and skipped during navigation
224
+ * - **Selection Announcements**: Current selection state announced on focus
225
+ * - **Option Count**: Number of available options announced when dropdown opens
226
+ * - **Filter Results**: Live announcements of filtered results count
227
+ * - **State Changes**: Open/close state changes announced appropriately
228
+ * - **Empty State**: Clear messaging when no options match search
229
+ * - **Disabled Feedback**: Disabled options announced and properly skipped
244
230
  *
245
231
  * **Focus Management:**
246
- * - DOM focus remains on combobox trigger for screen reader compatibility
247
- * - Visual focus moves through options using `aria-activedescendant`
248
- * - Search input automatically receives focus when dropdown opens
249
- * - Focus returns to trigger when dropdown closes via Escape or selection
232
+ * - **Programmatic Focus**: DOM focus remains on combobox trigger for screen reader compatibility
233
+ * - **Visual Focus**: Options highlighted using `aria-activedescendant` pattern
234
+ * - **Auto Focus**: Search input automatically receives focus when dropdown opens
235
+ * - **Focus Return**: Focus returns to trigger when dropdown closes via Escape or selection
236
+ * - **Focus Trap**: Focus contained within popover when modal behavior is desired
250
237
  *
251
238
  * **Visual Accessibility:**
252
- * - Maintains sufficient color contrast for all states
253
- * - Provides hover and focus indicators for all interactive elements
254
- * - Disabled options are visually distinct and non-interactive
255
- * - Clear visual feedback for selected state with check icon
239
+ * - **Color Contrast**: All states meet WCAG AA contrast requirements (4.5:1)
240
+ * - **Focus Indicators**: Clear visual focus indicators for all interactive elements
241
+ * - **Hover States**: Distinct hover states for better interaction feedback
242
+ * - **Disabled State**: Visually distinct disabled options with reduced opacity
243
+ * - **Selection Indicator**: Check icon provides clear visual selection feedback
244
+ * - **High Contrast Mode**: Supports Windows High Contrast Mode
245
+ *
246
+ * **Touch and Mobile Accessibility:**
247
+ * - **Touch Targets**: Minimum 44px touch target size for mobile interactions
248
+ * - **Scroll Behavior**: Proper scroll support for long option lists
249
+ * - **Responsive Design**: Adapts to different screen sizes and orientations
250
+ * - **Mobile Navigation**: Touch-optimized selection and scrolling
256
251
  *
257
252
  * @performance
258
- * - Efficient option lookup with single find() operation
259
- * - Minimal re-renders through proper state management
260
- * - Supports large option lists with built-in virtualization via cmdk
253
+ *
254
+ * **Optimization Strategies:**
255
+ * - **Efficient Filtering**: Single-pass option filtering with memoized results
256
+ * - **Minimal Re-renders**: Optimized state management prevents unnecessary renders
257
+ * - **Virtual Scrolling**: Built-in support for large datasets via CMDK virtualization
258
+ * - **Debounced Search**: Search input changes debounced to prevent excessive API calls
259
+ * - **Lazy Loading**: Options can be loaded asynchronously as needed
260
+ *
261
+ * **Memory Management:**
262
+ * - **Event Cleanup**: Proper cleanup of event listeners and timers
263
+ * - **Reference Management**: No memory leaks through proper ref handling
264
+ * - **Option Caching**: Previously loaded options cached for better performance
265
+ *
266
+ * @technical
267
+ *
268
+ * **Component Composition:**
269
+ * ```
270
+ * Combobox
271
+ * ├── Popover (Radix UI)
272
+ * │ ├── PopoverTrigger
273
+ * │ │ └── Button (outline variant)
274
+ * │ └── PopoverContent
275
+ * │ └── Command (CMDK)
276
+ * │ ├── CommandInput (search)
277
+ * │ └── CommandList
278
+ * │ ├── CommandEmpty
279
+ * │ └── CommandGroup
280
+ * │ └── CommandItem(s)
281
+ * ```
282
+ *
283
+ * **State Flow:**
284
+ * 1. User clicks trigger → Popover opens → Command input focuses
285
+ * 2. User types → CMDK filters options → Results update
286
+ * 3. User navigates → aria-activedescendant updates → Visual focus moves
287
+ * 4. User selects → onValueChange fires → Popover closes → Focus returns
288
+ *
289
+ * **Event Handling:**
290
+ * - Popover manages open/close state and positioning
291
+ * - CMDK handles keyboard navigation and filtering
292
+ * - Button handles trigger interactions and ARIA states
293
+ * - Custom logic manages selection and deselection behavior
261
294
  *
262
295
  * @see {@link https://ui.shadcn.com/docs/components/combobox} shadcn/ui Combobox documentation
263
296
  * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/combobox/} W3C ARIA Combobox Pattern
297
+ * @see {@link https://www.radix-ui.com/primitives/docs/components/popover} Radix UI Popover API
298
+ * @see {@link https://cmdk.paco.me/} CMDK Command Menu documentation
264
299
  * @see {@link Select} For simpler dropdowns without search functionality
265
300
  * @see {@link Command} The underlying command menu component
266
301
  * @see {@link Popover} The popover container component
302
+ * @see {@link Button} The trigger button component
267
303
  * @since 1.0.0
268
304
  */
269
- export declare function Combobox({ options, value, onValueChange, placeholder, emptyText, searchPlaceholder, className, disabled, buttonClassName, popoverClassName, }: ComboboxProps): import("react/jsx-runtime").JSX.Element;
305
+ declare function Combobox({ options, value, onValueChange, placeholder, emptyText, searchPlaceholder, className, disabled, buttonClassName, popoverClassName, ...popoverProps }: {
306
+ options: ComboboxOption[];
307
+ value?: string;
308
+ onValueChange?: (value: string) => void;
309
+ placeholder?: string;
310
+ emptyText?: string;
311
+ searchPlaceholder?: string;
312
+ className?: string;
313
+ disabled?: boolean;
314
+ buttonClassName?: string;
315
+ popoverClassName?: string;
316
+ } & Omit<React.ComponentProps<typeof Popover>, "children">): import("react/jsx-runtime").JSX.Element;
317
+ export { Combobox };
270
318
  //# sourceMappingURL=combobox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/ui/combobox.tsx"],"names":[],"mappings":"AAqBA;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;OAKG;IACH,OAAO,EAAE,cAAc,EAAE,CAAC;IAE1B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkJG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,KAAK,EACL,aAAa,EACb,WAAgC,EAChC,SAA8B,EAC9B,iBAAuC,EACvC,SAAS,EACT,QAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,EAAE,aAAa,2CA2Df"}
1
+ {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/ui/combobox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAa/B,OAAO,EACL,OAAO,EAGR,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAiKF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+QG;AACH,iBAAS,QAAQ,CAAC,EAChB,OAAO,EACP,KAAK,EACL,aAAa,EACb,WAAgC,EAChC,SAA8B,EAC9B,iBAAuC,EACvC,SAAS,EACT,QAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,GAAG,YAAY,EAChB,EAAE;IACD,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,OAAO,CAAC,EAAE,UAAU,CAAC,2CA+DzD;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}