@mihcm/ui 0.14.1 → 0.15.1

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 (300) hide show
  1. package/dist/CheckboxGrid.native.d.ts.map +1 -1
  2. package/dist/CheckboxGrid.native.js +2 -1
  3. package/dist/CheckboxGrid.native.js.map +1 -1
  4. package/dist/Combobox.native.d.ts.map +1 -1
  5. package/dist/Combobox.native.js +2 -1
  6. package/dist/Combobox.native.js.map +1 -1
  7. package/dist/DataTable/column-filter.d.ts +8 -0
  8. package/dist/DataTable/column-filter.d.ts.map +1 -0
  9. package/dist/DataTable/column-filter.js +67 -0
  10. package/dist/DataTable/column-filter.js.map +1 -0
  11. package/dist/DataTable/column-header.d.ts +16 -0
  12. package/dist/DataTable/column-header.d.ts.map +1 -0
  13. package/dist/DataTable/column-header.js +11 -0
  14. package/dist/DataTable/column-header.js.map +1 -0
  15. package/dist/DataTable/column-visibility.d.ts +7 -0
  16. package/dist/DataTable/column-visibility.d.ts.map +1 -0
  17. package/dist/DataTable/column-visibility.js +35 -0
  18. package/dist/DataTable/column-visibility.js.map +1 -0
  19. package/dist/DataTable/index.d.ts +5 -0
  20. package/dist/DataTable/index.d.ts.map +1 -0
  21. package/dist/DataTable/index.js +5 -0
  22. package/dist/DataTable/index.js.map +1 -0
  23. package/dist/DataTable/pinning.d.ts +13 -0
  24. package/dist/DataTable/pinning.d.ts.map +1 -0
  25. package/dist/DataTable/pinning.js +29 -0
  26. package/dist/DataTable/pinning.js.map +1 -0
  27. package/dist/DataTable.d.ts +3 -7
  28. package/dist/DataTable.d.ts.map +1 -1
  29. package/dist/DataTable.js +7 -126
  30. package/dist/DataTable.js.map +1 -1
  31. package/dist/Dialog.native.d.ts +3 -1
  32. package/dist/Dialog.native.d.ts.map +1 -1
  33. package/dist/Dialog.native.js +2 -2
  34. package/dist/Dialog.native.js.map +1 -1
  35. package/dist/Form/building-blocks.d.ts +26 -0
  36. package/dist/Form/building-blocks.d.ts.map +1 -0
  37. package/dist/Form/building-blocks.js +29 -0
  38. package/dist/Form/building-blocks.js.map +1 -0
  39. package/dist/Form/fields-choice.d.ts +72 -0
  40. package/dist/Form/fields-choice.d.ts.map +1 -0
  41. package/dist/Form/fields-choice.js +69 -0
  42. package/dist/Form/fields-choice.js.map +1 -0
  43. package/dist/Form/fields-complex.d.ts +28 -0
  44. package/dist/Form/fields-complex.d.ts.map +1 -0
  45. package/dist/Form/fields-complex.js +38 -0
  46. package/dist/Form/fields-complex.js.map +1 -0
  47. package/dist/Form/fields-date.d.ts +46 -0
  48. package/dist/Form/fields-date.d.ts.map +1 -0
  49. package/dist/Form/fields-date.js +41 -0
  50. package/dist/Form/fields-date.js.map +1 -0
  51. package/dist/Form/fields-text.d.ts +47 -0
  52. package/dist/Form/fields-text.d.ts.map +1 -0
  53. package/dist/Form/fields-text.js +46 -0
  54. package/dist/Form/fields-text.js.map +1 -0
  55. package/dist/Form/fields-toggle.d.ts +24 -0
  56. package/dist/Form/fields-toggle.d.ts.map +1 -0
  57. package/dist/Form/fields-toggle.js +32 -0
  58. package/dist/Form/fields-toggle.js.map +1 -0
  59. package/dist/Form/helpers.d.ts +66 -0
  60. package/dist/Form/helpers.d.ts.map +1 -0
  61. package/dist/Form/helpers.js +44 -0
  62. package/dist/Form/helpers.js.map +1 -0
  63. package/dist/Form/types.d.ts +25 -0
  64. package/dist/Form/types.d.ts.map +1 -0
  65. package/dist/Form/types.js +8 -0
  66. package/dist/Form/types.js.map +1 -0
  67. package/dist/Form.d.ts +24 -298
  68. package/dist/Form.d.ts.map +1 -1
  69. package/dist/Form.js +30 -246
  70. package/dist/Form.js.map +1 -1
  71. package/dist/IconSidebar.d.ts +6 -46
  72. package/dist/IconSidebar.d.ts.map +1 -1
  73. package/dist/IconSidebar.js +6 -116
  74. package/dist/IconSidebar.js.map +1 -1
  75. package/dist/MainSidebar/back-button.d.ts +14 -0
  76. package/dist/MainSidebar/back-button.d.ts.map +1 -0
  77. package/dist/MainSidebar/back-button.js +14 -0
  78. package/dist/MainSidebar/back-button.js.map +1 -0
  79. package/dist/MainSidebar/breadcrumb.d.ts +10 -0
  80. package/dist/MainSidebar/breadcrumb.d.ts.map +1 -0
  81. package/dist/MainSidebar/breadcrumb.js +24 -0
  82. package/dist/MainSidebar/breadcrumb.js.map +1 -0
  83. package/dist/MainSidebar/columns.d.ts +3 -0
  84. package/dist/MainSidebar/columns.d.ts.map +1 -0
  85. package/dist/MainSidebar/columns.js +198 -0
  86. package/dist/MainSidebar/columns.js.map +1 -0
  87. package/dist/MainSidebar/command.d.ts +3 -0
  88. package/dist/MainSidebar/command.d.ts.map +1 -0
  89. package/dist/MainSidebar/command.js +193 -0
  90. package/dist/MainSidebar/command.js.map +1 -0
  91. package/dist/MainSidebar/drilldown.d.ts +3 -0
  92. package/dist/MainSidebar/drilldown.d.ts.map +1 -0
  93. package/dist/MainSidebar/drilldown.js +154 -0
  94. package/dist/MainSidebar/drilldown.js.map +1 -0
  95. package/dist/MainSidebar/expanded.d.ts +7 -0
  96. package/dist/MainSidebar/expanded.d.ts.map +1 -0
  97. package/dist/MainSidebar/expanded.js +102 -0
  98. package/dist/MainSidebar/expanded.js.map +1 -0
  99. package/dist/MainSidebar/floating.d.ts +3 -0
  100. package/dist/MainSidebar/floating.d.ts.map +1 -0
  101. package/dist/MainSidebar/floating.js +116 -0
  102. package/dist/MainSidebar/floating.js.map +1 -0
  103. package/dist/MainSidebar/helpers.d.ts +50 -0
  104. package/dist/MainSidebar/helpers.d.ts.map +1 -0
  105. package/dist/MainSidebar/helpers.js +150 -0
  106. package/dist/MainSidebar/helpers.js.map +1 -0
  107. package/dist/MainSidebar/hover.d.ts +3 -0
  108. package/dist/MainSidebar/hover.d.ts.map +1 -0
  109. package/dist/MainSidebar/hover.js +177 -0
  110. package/dist/MainSidebar/hover.js.map +1 -0
  111. package/dist/MainSidebar/index.d.ts +6 -0
  112. package/dist/MainSidebar/index.d.ts.map +1 -0
  113. package/dist/MainSidebar/index.js +108 -0
  114. package/dist/MainSidebar/index.js.map +1 -0
  115. package/dist/MainSidebar/mobile.d.ts +29 -0
  116. package/dist/MainSidebar/mobile.d.ts.map +1 -0
  117. package/dist/MainSidebar/mobile.js +38 -0
  118. package/dist/MainSidebar/mobile.js.map +1 -0
  119. package/dist/MainSidebar/motion.d.ts +23 -0
  120. package/dist/MainSidebar/motion.d.ts.map +1 -0
  121. package/dist/MainSidebar/motion.js +40 -0
  122. package/dist/MainSidebar/motion.js.map +1 -0
  123. package/dist/MainSidebar/rail.d.ts +24 -0
  124. package/dist/MainSidebar/rail.d.ts.map +1 -0
  125. package/dist/MainSidebar/rail.js +29 -0
  126. package/dist/MainSidebar/rail.js.map +1 -0
  127. package/dist/MainSidebar/search.d.ts +19 -0
  128. package/dist/MainSidebar/search.d.ts.map +1 -0
  129. package/dist/MainSidebar/search.js +33 -0
  130. package/dist/MainSidebar/search.js.map +1 -0
  131. package/dist/MainSidebar/types.d.ts +161 -0
  132. package/dist/MainSidebar/types.d.ts.map +1 -0
  133. package/dist/MainSidebar/types.js +2 -0
  134. package/dist/MainSidebar/types.js.map +1 -0
  135. package/dist/MainSidebar.d.ts +6 -1
  136. package/dist/MainSidebar.d.ts.map +1 -1
  137. package/dist/MainSidebar.js +6 -1
  138. package/dist/MainSidebar.js.map +1 -1
  139. package/dist/NavigationMenu.js +1 -1
  140. package/dist/NavigationMenu.js.map +1 -1
  141. package/dist/RichTextEditor/theme.d.ts +44 -0
  142. package/dist/RichTextEditor/theme.d.ts.map +1 -0
  143. package/dist/RichTextEditor/theme.js +41 -0
  144. package/dist/RichTextEditor/theme.js.map +1 -0
  145. package/dist/RichTextEditor/toolbar-icons.d.ts +21 -0
  146. package/dist/RichTextEditor/toolbar-icons.d.ts.map +1 -0
  147. package/dist/RichTextEditor/toolbar-icons.js +21 -0
  148. package/dist/RichTextEditor/toolbar-icons.js.map +1 -0
  149. package/dist/RichTextEditor/toolbar.d.ts +5 -0
  150. package/dist/RichTextEditor/toolbar.d.ts.map +1 -0
  151. package/dist/RichTextEditor/toolbar.js +116 -0
  152. package/dist/RichTextEditor/toolbar.js.map +1 -0
  153. package/dist/RichTextEditor.d.ts +16 -9
  154. package/dist/RichTextEditor.d.ts.map +1 -1
  155. package/dist/RichTextEditor.js +18 -164
  156. package/dist/RichTextEditor.js.map +1 -1
  157. package/dist/Select/content.d.ts +9 -0
  158. package/dist/Select/content.d.ts.map +1 -0
  159. package/dist/Select/content.js +80 -0
  160. package/dist/Select/content.js.map +1 -0
  161. package/dist/Select/context.d.ts +27 -0
  162. package/dist/Select/context.d.ts.map +1 -0
  163. package/dist/Select/context.js +35 -0
  164. package/dist/Select/context.js.map +1 -0
  165. package/dist/Select/item.d.ts +13 -0
  166. package/dist/Select/item.d.ts.map +1 -0
  167. package/dist/Select/item.js +39 -0
  168. package/dist/Select/item.js.map +1 -0
  169. package/dist/Select/parts.d.ts +14 -0
  170. package/dist/Select/parts.d.ts.map +1 -0
  171. package/dist/Select/parts.js +17 -0
  172. package/dist/Select/parts.js.map +1 -0
  173. package/dist/Select/react-select.d.ts +25 -0
  174. package/dist/Select/react-select.d.ts.map +1 -0
  175. package/dist/Select/react-select.js +66 -0
  176. package/dist/Select/react-select.js.map +1 -0
  177. package/dist/Select/root.d.ts +15 -0
  178. package/dist/Select/root.d.ts.map +1 -0
  179. package/dist/Select/root.js +41 -0
  180. package/dist/Select/root.js.map +1 -0
  181. package/dist/Select/trigger.d.ts +15 -0
  182. package/dist/Select/trigger.d.ts.map +1 -0
  183. package/dist/Select/trigger.js +61 -0
  184. package/dist/Select/trigger.js.map +1 -0
  185. package/dist/Select.d.ts +14 -62
  186. package/dist/Select.d.ts.map +1 -1
  187. package/dist/Select.js +14 -293
  188. package/dist/Select.js.map +1 -1
  189. package/dist/Sidebar/context.d.ts +28 -0
  190. package/dist/Sidebar/context.d.ts.map +1 -0
  191. package/dist/Sidebar/context.js +37 -0
  192. package/dist/Sidebar/context.js.map +1 -0
  193. package/dist/Sidebar/group.d.ts +13 -0
  194. package/dist/Sidebar/group.d.ts.map +1 -0
  195. package/dist/Sidebar/group.js +20 -0
  196. package/dist/Sidebar/group.js.map +1 -0
  197. package/dist/Sidebar/icons.d.ts +7 -0
  198. package/dist/Sidebar/icons.d.ts.map +1 -0
  199. package/dist/Sidebar/icons.js +12 -0
  200. package/dist/Sidebar/icons.js.map +1 -0
  201. package/dist/Sidebar/layout.d.ts +9 -0
  202. package/dist/Sidebar/layout.d.ts.map +1 -0
  203. package/dist/Sidebar/layout.js +21 -0
  204. package/dist/Sidebar/layout.js.map +1 -0
  205. package/dist/Sidebar/menu.d.ts +29 -0
  206. package/dist/Sidebar/menu.d.ts.map +1 -0
  207. package/dist/Sidebar/menu.js +55 -0
  208. package/dist/Sidebar/menu.js.map +1 -0
  209. package/dist/Sidebar/provider.d.ts +33 -0
  210. package/dist/Sidebar/provider.d.ts.map +1 -0
  211. package/dist/Sidebar/provider.js +110 -0
  212. package/dist/Sidebar/provider.js.map +1 -0
  213. package/dist/Sidebar/sidebar.d.ts +17 -0
  214. package/dist/Sidebar/sidebar.d.ts.map +1 -0
  215. package/dist/Sidebar/sidebar.js +51 -0
  216. package/dist/Sidebar/sidebar.js.map +1 -0
  217. package/dist/Sidebar/submenu.d.ts +13 -0
  218. package/dist/Sidebar/submenu.d.ts.map +1 -0
  219. package/dist/Sidebar/submenu.js +17 -0
  220. package/dist/Sidebar/submenu.js.map +1 -0
  221. package/dist/Sidebar/trigger.d.ts +9 -0
  222. package/dist/Sidebar/trigger.d.ts.map +1 -0
  223. package/dist/Sidebar/trigger.js +33 -0
  224. package/dist/Sidebar/trigger.js.map +1 -0
  225. package/dist/Sidebar.d.ts +14 -104
  226. package/dist/Sidebar.d.ts.map +1 -1
  227. package/dist/Sidebar.js +14 -300
  228. package/dist/Sidebar.js.map +1 -1
  229. package/dist/StatCard.d.ts +67 -9
  230. package/dist/StatCard.d.ts.map +1 -1
  231. package/dist/StatCard.js +111 -9
  232. package/dist/StatCard.js.map +1 -1
  233. package/dist/TransferList.native.d.ts.map +1 -1
  234. package/dist/TransferList.native.js +2 -1
  235. package/dist/TransferList.native.js.map +1 -1
  236. package/package.json +2 -2
  237. package/src/CheckboxGrid.native.tsx +2 -1
  238. package/src/Combobox.native.tsx +2 -1
  239. package/src/DataTable/column-filter.tsx +134 -0
  240. package/src/DataTable/column-header.tsx +67 -0
  241. package/src/DataTable/column-visibility.tsx +87 -0
  242. package/src/DataTable/index.ts +4 -0
  243. package/src/DataTable/pinning.ts +40 -0
  244. package/src/DataTable.tsx +14 -297
  245. package/src/Dialog.native.tsx +4 -2
  246. package/src/Form/building-blocks.tsx +97 -0
  247. package/src/Form/fields-choice.tsx +312 -0
  248. package/src/Form/fields-complex.tsx +195 -0
  249. package/src/Form/fields-date.tsx +195 -0
  250. package/src/Form/fields-text.tsx +218 -0
  251. package/src/Form/fields-toggle.tsx +123 -0
  252. package/src/Form/helpers.tsx +189 -0
  253. package/src/Form/types.ts +26 -0
  254. package/src/Form.tsx +91 -1308
  255. package/src/IconSidebar.tsx +20 -442
  256. package/src/MainSidebar/back-button.tsx +58 -0
  257. package/src/MainSidebar/breadcrumb.tsx +53 -0
  258. package/src/MainSidebar/columns.tsx +350 -0
  259. package/src/MainSidebar/command.tsx +404 -0
  260. package/src/MainSidebar/drilldown.tsx +373 -0
  261. package/src/MainSidebar/expanded.tsx +414 -0
  262. package/src/MainSidebar/floating.tsx +268 -0
  263. package/src/MainSidebar/helpers.ts +166 -0
  264. package/src/MainSidebar/hover.tsx +334 -0
  265. package/src/MainSidebar/index.tsx +191 -0
  266. package/src/MainSidebar/mobile.tsx +117 -0
  267. package/src/MainSidebar/motion.ts +64 -0
  268. package/src/MainSidebar/rail.tsx +137 -0
  269. package/src/MainSidebar/search.tsx +99 -0
  270. package/src/MainSidebar/types.ts +208 -0
  271. package/src/MainSidebar.tsx +15 -4
  272. package/src/NavigationMenu.tsx +1 -1
  273. package/src/RichTextEditor/theme.ts +43 -0
  274. package/src/RichTextEditor/toolbar-icons.tsx +40 -0
  275. package/src/RichTextEditor/toolbar.tsx +271 -0
  276. package/src/RichTextEditor.tsx +23 -371
  277. package/src/Select/content.tsx +111 -0
  278. package/src/Select/context.tsx +66 -0
  279. package/src/Select/item.tsx +97 -0
  280. package/src/Select/parts.tsx +43 -0
  281. package/src/Select/react-select.tsx +216 -0
  282. package/src/Select/root.tsx +75 -0
  283. package/src/Select/trigger.tsx +122 -0
  284. package/src/Select.tsx +34 -692
  285. package/src/Sidebar/context.tsx +72 -0
  286. package/src/Sidebar/group.tsx +69 -0
  287. package/src/Sidebar/icons.tsx +42 -0
  288. package/src/Sidebar/layout.tsx +64 -0
  289. package/src/Sidebar/menu.tsx +171 -0
  290. package/src/Sidebar/provider.tsx +224 -0
  291. package/src/Sidebar/sidebar.tsx +178 -0
  292. package/src/Sidebar/submenu.tsx +58 -0
  293. package/src/Sidebar/trigger.tsx +104 -0
  294. package/src/Sidebar.tsx +44 -927
  295. package/src/StatCard.tsx +365 -20
  296. package/src/TransferList.native.tsx +2 -1
  297. package/dist/TiptapEditor.d.ts +0 -24
  298. package/dist/TiptapEditor.d.ts.map +0 -1
  299. package/dist/TiptapEditor.js +0 -84
  300. package/dist/TiptapEditor.js.map +0 -1
package/src/Select.tsx CHANGED
@@ -3,9 +3,10 @@
3
3
  /**
4
4
  * Select (web variant — React DOM).
5
5
  *
6
- * Custom composable select dropdown. No native `<select>` or external deps.
6
+ * Composable select dropdown built on top of native focus management no
7
+ * external listbox engine, no native `<select>`. Plus a `react-select`-backed
8
+ * family for searchable / async / multi / creatable cases.
7
9
  *
8
- * Usage:
9
10
  * <Select value={val} onValueChange={setVal}>
10
11
  * <SelectTrigger placeholder="Pick a fruit" />
11
12
  * <SelectContent>
@@ -14,697 +15,38 @@
14
15
  * </SelectContent>
15
16
  * </Select>
16
17
  *
17
- * Controlled-only: pass `value` / `onValueChange`.
18
- * Keyboard: ArrowDown/Up to navigate, Enter to select, Escape to close.
19
- * WCAG 2.1 AA: role="listbox", role="option", aria-expanded, aria-selected.
18
+ * Controlled-only: pass `value` / `onValueChange`. Keyboard: ArrowDown/Up to
19
+ * navigate, Enter to select, Escape to close. WCAG 2.1 AA: role="listbox",
20
+ * role="option", aria-expanded, aria-selected.
21
+ *
22
+ * Public barrel — implementation split across `./Select/*` per CLAUDE.md §6.
20
23
  *
21
24
  * Wiki: docs/components/Select.md
22
25
  */
23
- import {
24
- forwardRef,
25
- Children,
26
- createContext,
27
- isValidElement,
28
- useContext,
29
- useCallback,
30
- useEffect,
31
- useRef,
32
- useState,
33
- type HTMLAttributes,
34
- type ReactNode,
35
- } from 'react';
36
- import { cva, type VariantProps } from 'class-variance-authority';
37
- import ReactSelectBase, {
38
- type ClassNamesConfig,
39
- type GroupBase,
40
- type Props as BaseReactSelectProps,
41
- type SelectComponentsConfig,
42
- } from 'react-select';
43
- import ReactAsyncSelectBase, { type AsyncProps } from 'react-select/async';
44
- import ReactCreatableSelectBase, { type CreatableProps } from 'react-select/creatable';
45
- import ReactAsyncCreatableSelectBase, {
46
- type AsyncCreatableProps,
47
- } from 'react-select/async-creatable';
48
- import makeAnimated from 'react-select/animated';
49
- import { cn } from './internal/cn.js';
50
-
51
- interface ReactSelectDefaultableProps<
52
- Option,
53
- IsMulti extends boolean,
54
- Group extends GroupBase<Option>,
55
- > {
56
- className?: string | undefined;
57
- classNamePrefix?: string | null | undefined;
58
- classNames?: ClassNamesConfig<Option, IsMulti, Group> | undefined;
59
- unstyled?: boolean | undefined;
60
- }
61
-
62
- export interface DefaultReactSelectOption {
63
- value: string;
64
- label: string;
65
- isDisabled?: boolean;
66
- }
67
-
68
- export type ReactSelectProps<
69
- Option = DefaultReactSelectOption,
70
- IsMulti extends boolean = false,
71
- Group extends GroupBase<Option> = GroupBase<Option>,
72
- > = BaseReactSelectProps<Option, IsMulti, Group>;
73
-
74
- export type ReactAsyncSelectProps<
75
- Option = DefaultReactSelectOption,
76
- IsMulti extends boolean = false,
77
- Group extends GroupBase<Option> = GroupBase<Option>,
78
- > = AsyncProps<Option, IsMulti, Group>;
79
-
80
- export type ReactCreatableSelectProps<
81
- Option = DefaultReactSelectOption,
82
- IsMulti extends boolean = false,
83
- Group extends GroupBase<Option> = GroupBase<Option>,
84
- > = CreatableProps<Option, IsMulti, Group>;
85
-
86
- export type ReactAsyncCreatableSelectProps<
87
- Option = DefaultReactSelectOption,
88
- IsMulti extends boolean = false,
89
- Group extends GroupBase<Option> = GroupBase<Option>,
90
- > = AsyncCreatableProps<Option, IsMulti, Group>;
91
-
92
- export function getReactSelectAnimatedComponents<
93
- Option = DefaultReactSelectOption,
94
- IsMulti extends boolean = false,
95
- Group extends GroupBase<Option> = GroupBase<Option>,
96
- >(): SelectComponentsConfig<Option, IsMulti, Group> {
97
- return makeAnimated() as unknown as SelectComponentsConfig<Option, IsMulti, Group>;
98
- }
99
-
100
- export const reactSelectAnimatedComponents: SelectComponentsConfig<
101
- DefaultReactSelectOption,
102
- false,
103
- GroupBase<DefaultReactSelectOption>
104
- > =
105
- getReactSelectAnimatedComponents<DefaultReactSelectOption>();
106
-
107
- const reactSelectClassNames = {
108
- clearIndicator: ({ isFocused }) => cn(
109
- 'rounded-md p-1 text-muted-foreground transition-colors',
110
- 'hover:bg-muted hover:text-foreground',
111
- isFocused && 'text-foreground',
112
- ),
113
- control: ({ isDisabled, isFocused }) => cn(
114
- 'min-h-10 rounded-lg border bg-card px-2.5 text-body-sm shadow-mi-input transition-colors',
115
- 'hover:border-primary/60',
116
- isFocused ? 'border-primary ring-2 ring-ring/20' : 'border-border',
117
- isDisabled && 'cursor-not-allowed bg-muted opacity-50',
118
- ),
119
- dropdownIndicator: ({ isFocused }) => cn(
120
- 'rounded-md p-1 text-muted-foreground transition-colors',
121
- 'hover:bg-muted hover:text-foreground',
122
- isFocused && 'text-foreground',
123
- ),
124
- group: () => 'py-1',
125
- groupHeading: () => 'px-2 py-1 text-xs font-semibold text-muted-foreground',
126
- indicatorsContainer: () => 'gap-1',
127
- indicatorSeparator: () => 'mx-1 my-2 w-px self-stretch bg-border',
128
- input: () => 'text-foreground',
129
- loadingIndicator: () => 'text-muted-foreground',
130
- loadingMessage: () => 'px-3 py-6 text-center text-body-sm text-muted-foreground',
131
- menu: () => 'z-50 mt-1 overflow-hidden rounded-lg border border-border bg-card text-card-foreground shadow-mi-input',
132
- menuList: () => 'max-h-72 overflow-y-auto p-1',
133
- multiValue: () => 'm-0.5 inline-flex items-center gap-1 rounded-md bg-muted text-foreground',
134
- multiValueLabel: () => 'px-2 py-0.5 text-xs font-medium',
135
- multiValueRemove: () => cn(
136
- 'rounded-r-md px-1 text-muted-foreground transition-colors',
137
- 'hover:bg-destructive hover:text-destructive-foreground',
138
- ),
139
- noOptionsMessage: () => 'px-3 py-6 text-center text-body-sm text-muted-foreground',
140
- option: ({ isDisabled, isFocused, isSelected }) => cn(
141
- 'cursor-pointer rounded-md px-2 py-1.5 text-body-sm outline-none transition-colors',
142
- isFocused && 'bg-muted',
143
- isSelected && 'bg-primary text-primary-foreground',
144
- isDisabled && 'pointer-events-none cursor-not-allowed opacity-50',
145
- ),
146
- placeholder: () => 'text-muted-foreground',
147
- singleValue: () => 'text-foreground',
148
- valueContainer: () => 'gap-1 py-1.5',
149
- } satisfies ClassNamesConfig<unknown, boolean, GroupBase<unknown>>;
150
-
151
- function withReactSelectDefaults<
152
- Option,
153
- IsMulti extends boolean,
154
- Group extends GroupBase<Option>,
155
- Props extends ReactSelectDefaultableProps<Option, IsMulti, Group>,
156
- >(props: Props): Props {
157
- const {
158
- className,
159
- classNamePrefix = 'mihcm-select',
160
- classNames,
161
- unstyled = true,
162
- ...rest
163
- } = props;
164
- const defaultClassNames = reactSelectClassNames as unknown as ClassNamesConfig<
165
- Option,
166
- IsMulti,
167
- Group
168
- >;
169
-
170
- return {
171
- ...rest,
172
- className: cn('w-full min-w-0', className),
173
- classNamePrefix,
174
- classNames: {
175
- ...defaultClassNames,
176
- ...classNames,
177
- },
178
- unstyled,
179
- } as Props;
180
- }
181
-
182
- /* ── React Select powered exports ──────────────────────────────────── */
183
-
184
- export function ReactSelect<
185
- Option = DefaultReactSelectOption,
186
- IsMulti extends boolean = false,
187
- Group extends GroupBase<Option> = GroupBase<Option>,
188
- >(props: ReactSelectProps<Option, IsMulti, Group>) {
189
- return (
190
- <ReactSelectBase
191
- {...withReactSelectDefaults<Option, IsMulti, Group, ReactSelectProps<Option, IsMulti, Group>>(
192
- props,
193
- )}
194
- />
195
- );
196
- }
197
-
198
- export function ReactAsyncSelect<
199
- Option = DefaultReactSelectOption,
200
- IsMulti extends boolean = false,
201
- Group extends GroupBase<Option> = GroupBase<Option>,
202
- >(props: ReactAsyncSelectProps<Option, IsMulti, Group>) {
203
- return (
204
- <ReactAsyncSelectBase
205
- {...withReactSelectDefaults<
206
- Option,
207
- IsMulti,
208
- Group,
209
- ReactAsyncSelectProps<Option, IsMulti, Group>
210
- >(props)}
211
- />
212
- );
213
- }
214
-
215
- export function ReactCreatableSelect<
216
- Option = DefaultReactSelectOption,
217
- IsMulti extends boolean = false,
218
- Group extends GroupBase<Option> = GroupBase<Option>,
219
- >(props: ReactCreatableSelectProps<Option, IsMulti, Group>) {
220
- return (
221
- <ReactCreatableSelectBase
222
- {...withReactSelectDefaults<
223
- Option,
224
- IsMulti,
225
- Group,
226
- ReactCreatableSelectProps<Option, IsMulti, Group>
227
- >(props)}
228
- />
229
- );
230
- }
231
-
232
- export function ReactAsyncCreatableSelect<
233
- Option = DefaultReactSelectOption,
234
- IsMulti extends boolean = false,
235
- Group extends GroupBase<Option> = GroupBase<Option>,
236
- >(props: ReactAsyncCreatableSelectProps<Option, IsMulti, Group>) {
237
- return (
238
- <ReactAsyncCreatableSelectBase
239
- {...withReactSelectDefaults<
240
- Option,
241
- IsMulti,
242
- Group,
243
- ReactAsyncCreatableSelectProps<Option, IsMulti, Group>
244
- >(props)}
245
- />
246
- );
247
- }
248
-
249
- /* ── Context ───────────────────────────────────────────────────────── */
250
-
251
- interface SelectContextValue {
252
- value: string | undefined;
253
- onValueChange: (value: string) => void;
254
- open: boolean;
255
- setOpen: (open: boolean) => void;
256
- disabled: boolean;
257
- triggerRef: React.RefObject<HTMLButtonElement | null>;
258
- setTriggerRef: (el: HTMLButtonElement | null) => void;
259
- /** Label text of the currently selected item (set by SelectItem). */
260
- selectedLabel: { value: string; label: string } | undefined;
261
- setSelectedLabel: (selected: { value: string; label: string } | undefined) => void;
262
- getLabelForValue: (value: string | undefined) => string | undefined;
263
- }
264
-
265
- const SelectContext = createContext<SelectContextValue | null>(null);
266
-
267
- function useSelectContext() {
268
- const ctx = useContext(SelectContext);
269
- if (!ctx) throw new Error('Select sub-components must be used within <Select>.');
270
- return ctx;
271
- }
272
-
273
- function getTextLabel(children: ReactNode): string | undefined {
274
- if (typeof children === 'string' || typeof children === 'number') {
275
- return String(children);
276
- }
277
-
278
- return undefined;
279
- }
280
-
281
- function findSelectItemLabel(children: ReactNode, value: string | undefined): string | undefined {
282
- if (!value) return undefined;
283
-
284
- let match: string | undefined;
285
-
286
- Children.forEach(children, (child) => {
287
- if (match || !isValidElement(child)) return;
288
-
289
- const props = child.props as {
290
- value?: unknown;
291
- children?: ReactNode;
292
- };
293
-
294
- if (props.value === value) {
295
- match = getTextLabel(props.children);
296
- return;
297
- }
298
-
299
- match = findSelectItemLabel(props.children, value);
300
- });
301
-
302
- return match;
303
- }
304
-
305
- /* ── Root ───────────────────────────────────────────────────────────── */
306
-
307
- export interface SelectProps {
308
- value?: string | undefined;
309
- onValueChange?: ((value: string) => void) | undefined;
310
- open?: boolean | undefined;
311
- onOpenChange?: ((open: boolean) => void) | undefined;
312
- disabled?: boolean | undefined;
313
- children: ReactNode;
314
- }
315
-
316
- export function Select({
317
- value,
318
- onValueChange,
319
- open: controlledOpen,
320
- onOpenChange,
321
- disabled,
322
- children,
323
- }: SelectProps) {
324
- const [internalOpen, setInternalOpen] = useState(false);
325
- const open = controlledOpen ?? internalOpen;
326
- const setOpen = useCallback(
327
- (next: boolean) => {
328
- if (disabled && next) return;
329
- onOpenChange?.(next);
330
- setInternalOpen(next);
331
- },
332
- [disabled, onOpenChange],
333
- );
334
-
335
- const triggerRef = useRef<HTMLButtonElement | null>(null);
336
- const setTriggerRef = useCallback((el: HTMLButtonElement | null) => {
337
- triggerRef.current = el;
338
- }, []);
339
- const [selectedLabel, setSelectedLabel] = useState<{ value: string; label: string } | undefined>();
340
-
341
- const handleValueChange = useCallback(
342
- (v: string) => {
343
- onValueChange?.(v);
344
- setOpen(false);
345
- },
346
- [onValueChange, setOpen],
347
- );
348
-
349
- const getLabelForValue = useCallback(
350
- (nextValue: string | undefined) => findSelectItemLabel(children, nextValue),
351
- [children],
352
- );
353
-
354
- return (
355
- <SelectContext.Provider
356
- value={{
357
- value,
358
- onValueChange: handleValueChange,
359
- open,
360
- setOpen,
361
- disabled: !!disabled,
362
- triggerRef,
363
- setTriggerRef,
364
- selectedLabel,
365
- setSelectedLabel,
366
- getLabelForValue,
367
- }}
368
- >
369
- <div className="relative inline-block">{children}</div>
370
- </SelectContext.Provider>
371
- );
372
- }
373
-
374
- /* ── Trigger ───────────────────────────────────────────────────────── */
375
-
376
- export const selectTriggerVariants = cva(
377
- 'inline-flex w-full items-center justify-between gap-2 rounded-lg border bg-card text-foreground shadow-mi-input ' +
378
- 'transition-colors duration-150 ' +
379
- 'focus-visible:outline-none focus-visible:border-primary ' +
380
- 'disabled:pointer-events-none disabled:opacity-50 ' +
381
- 'select-none whitespace-nowrap',
382
- {
383
- variants: {
384
- variant: {
385
- default: 'border-border',
386
- destructive:
387
- 'border-destructive text-destructive focus-visible:border-destructive',
388
- },
389
- size: {
390
- sm: 'h-9 px-3 text-body-sm',
391
- md: 'h-10 px-3.5 text-body-sm',
392
- lg: 'h-12 px-4 text-body-sm',
393
- },
394
- },
395
- defaultVariants: {
396
- variant: 'default',
397
- size: 'md',
398
- },
399
- },
400
- );
401
-
402
- export interface SelectTriggerProps
403
- extends Omit<HTMLAttributes<HTMLButtonElement>, 'children'>,
404
- VariantProps<typeof selectTriggerVariants> {
405
- placeholder?: string | undefined;
406
- disabled?: boolean | undefined;
407
- }
408
-
409
- export const SelectTrigger = forwardRef<HTMLButtonElement, SelectTriggerProps>(
410
- function SelectTrigger({ className, variant, size, placeholder, disabled, id, ...props }, ref) {
411
- const ctx = useSelectContext();
412
- const isDisabled = disabled ?? ctx.disabled;
413
- const listboxId = id ? `${id}-listbox` : undefined;
414
-
415
- const handleClick = useCallback(() => {
416
- ctx.setOpen(!ctx.open);
417
- }, [ctx]);
418
-
419
- const handleKeyDown = useCallback(
420
- (e: React.KeyboardEvent) => {
421
- if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Enter' || e.key === ' ') {
422
- e.preventDefault();
423
- if (!ctx.open) ctx.setOpen(true);
424
- }
425
- },
426
- [ctx],
427
- );
428
-
429
- // Merge refs
430
- const setRef = useCallback(
431
- (el: HTMLButtonElement | null) => {
432
- ctx.setTriggerRef(el);
433
- if (typeof ref === 'function') ref(el);
434
- else if (ref) (ref as React.MutableRefObject<HTMLButtonElement | null>).current = el;
435
- },
436
- [ctx, ref],
437
- );
438
-
439
- const selectedLabel = ctx.selectedLabel;
440
- const hasValue = ctx.value !== undefined && ctx.value !== '';
441
- const displayText =
442
- hasValue && selectedLabel && selectedLabel.value === ctx.value
443
- ? selectedLabel.label
444
- : hasValue
445
- ? ctx.getLabelForValue(ctx.value) ?? ctx.value
446
- : undefined;
447
-
448
- return (
449
- <button
450
- ref={setRef}
451
- type="button"
452
- id={id}
453
- role="combobox"
454
- aria-expanded={ctx.open}
455
- aria-haspopup="listbox"
456
- aria-controls={ctx.open ? listboxId : undefined}
457
- disabled={isDisabled}
458
- onClick={handleClick}
459
- onKeyDown={handleKeyDown}
460
- className={cn(selectTriggerVariants({ variant, size }), className)}
461
- {...props}
462
- >
463
- <span className={cn('truncate', !displayText && 'text-muted-foreground')}>
464
- {displayText ?? placeholder ?? 'Select…'}
465
- </span>
466
- {/* Chevron-down icon */}
467
- <svg
468
- aria-hidden
469
- viewBox="0 0 16 16"
470
- fill="none"
471
- stroke="currentColor"
472
- strokeWidth={2}
473
- className={cn(
474
- 'h-4 w-4 shrink-0 opacity-50 transition-transform duration-200',
475
- ctx.open && 'rotate-180',
476
- )}
477
- >
478
- <path strokeLinecap="round" strokeLinejoin="round" d="M4 6l4 4 4-4" />
479
- </svg>
480
- </button>
481
- );
482
- },
483
- );
484
-
485
- /* ── Content ───────────────────────────────────────────────────────── */
486
-
487
- export interface SelectContentProps extends HTMLAttributes<HTMLDivElement> {}
488
-
489
- export const SelectContent = forwardRef<HTMLDivElement, SelectContentProps>(
490
- function SelectContent({ className, children, ...props }, ref) {
491
- const ctx = useSelectContext();
492
- const contentRef = useRef<HTMLDivElement | null>(null);
493
- const focusedIndexRef = useRef(-1);
494
-
495
- // Close on click outside
496
- useEffect(() => {
497
- if (!ctx.open) return;
498
- function handleClickOutside(e: MouseEvent) {
499
- const target = e.target as Node;
500
- if (
501
- contentRef.current &&
502
- !contentRef.current.contains(target) &&
503
- ctx.triggerRef.current &&
504
- !ctx.triggerRef.current.contains(target)
505
- ) {
506
- ctx.setOpen(false);
507
- }
508
- }
509
- document.addEventListener('mousedown', handleClickOutside);
510
- return () => document.removeEventListener('mousedown', handleClickOutside);
511
- }, [ctx]);
512
-
513
- // Keyboard navigation within the list
514
- useEffect(() => {
515
- if (!ctx.open) return;
516
- function handleKeyDown(e: KeyboardEvent) {
517
- const options = contentRef.current?.querySelectorAll<HTMLElement>('[role="option"]');
518
- if (!options?.length) return;
519
-
520
- if (e.key === 'Escape') {
521
- e.preventDefault();
522
- ctx.setOpen(false);
523
- ctx.triggerRef.current?.focus();
524
- return;
525
- }
526
-
527
- if (e.key === 'ArrowDown') {
528
- e.preventDefault();
529
- focusedIndexRef.current = Math.min(focusedIndexRef.current + 1, options.length - 1);
530
- options[focusedIndexRef.current]?.focus();
531
- } else if (e.key === 'ArrowUp') {
532
- e.preventDefault();
533
- focusedIndexRef.current = Math.max(focusedIndexRef.current - 1, 0);
534
- options[focusedIndexRef.current]?.focus();
535
- }
536
- }
537
- document.addEventListener('keydown', handleKeyDown);
538
- return () => document.removeEventListener('keydown', handleKeyDown);
539
- }, [ctx]);
540
-
541
- // Focus first option (or selected) on open
542
- useEffect(() => {
543
- if (!ctx.open || !contentRef.current) return;
544
- focusedIndexRef.current = -1;
545
- const selected = contentRef.current.querySelector<HTMLElement>('[aria-selected="true"]');
546
- if (selected) {
547
- selected.focus();
548
- } else {
549
- const first = contentRef.current.querySelector<HTMLElement>('[role="option"]');
550
- first?.focus();
551
- }
552
- }, [ctx.open]);
553
-
554
- // Merge refs
555
- const setRef = useCallback(
556
- (el: HTMLDivElement | null) => {
557
- contentRef.current = el;
558
- if (typeof ref === 'function') ref(el);
559
- else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = el;
560
- },
561
- [ref],
562
- );
563
-
564
- if (!ctx.open) return null;
565
-
566
- return (
567
- <div
568
- ref={setRef}
569
- id={ctx.triggerRef.current?.id ? `${ctx.triggerRef.current.id}-listbox` : undefined}
570
- role="listbox"
571
- aria-labelledby={ctx.triggerRef.current?.id || undefined}
572
- className={cn(
573
- 'absolute left-0 top-full z-50 mt-1 w-full min-w-[8rem] overflow-hidden rounded-lg',
574
- 'border border-border bg-card text-card-foreground shadow-mi-input',
575
- 'animate-dropdown-in',
576
- className,
577
- )}
578
- {...props}
579
- >
580
- <div className="max-h-60 overflow-y-auto p-1">{children}</div>
581
- </div>
582
- );
583
- },
584
- );
585
-
586
- /* ── Item ──────────────────────────────────────────────────────────── */
587
-
588
- export interface SelectItemProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onClick'> {
589
- value: string;
590
- disabled?: boolean;
591
- children: ReactNode;
592
- }
593
-
594
- export const SelectItem = forwardRef<HTMLDivElement, SelectItemProps>(
595
- function SelectItem({ className, value, disabled, children, ...props }, ref) {
596
- const ctx = useSelectContext();
597
- const { onValueChange, selectedLabel, setSelectedLabel, triggerRef } = ctx;
598
- const isSelected = ctx.value === value;
599
-
600
- // Register label of selected item
601
- useEffect(() => {
602
- if (
603
- isSelected &&
604
- typeof children === 'string' &&
605
- (selectedLabel?.value !== value || selectedLabel.label !== children)
606
- ) {
607
- setSelectedLabel({ value, label: children });
608
- }
609
- }, [isSelected, children, selectedLabel?.label, selectedLabel?.value, setSelectedLabel, value]);
610
-
611
- const handleSelect = useCallback(() => {
612
- if (disabled) return;
613
- if (typeof children === 'string') {
614
- setSelectedLabel({ value, label: children });
615
- }
616
- onValueChange(value);
617
- triggerRef.current?.focus();
618
- }, [children, disabled, onValueChange, setSelectedLabel, triggerRef, value]);
619
-
620
- const handleKeyDown = useCallback(
621
- (e: React.KeyboardEvent) => {
622
- if (e.key === 'Enter' || e.key === ' ') {
623
- e.preventDefault();
624
- handleSelect();
625
- }
626
- },
627
- [handleSelect],
628
- );
629
-
630
- return (
631
- <div
632
- ref={ref}
633
- role="option"
634
- aria-selected={isSelected}
635
- aria-disabled={disabled || undefined}
636
- tabIndex={disabled ? undefined : -1}
637
- onClick={handleSelect}
638
- onKeyDown={handleKeyDown}
639
- className={cn(
640
- 'relative flex cursor-pointer items-center rounded-md px-2 py-1.5 text-body-sm outline-none',
641
- 'transition-colors duration-150',
642
- 'hover:bg-muted focus:bg-muted',
643
- isSelected && 'font-medium',
644
- disabled && 'pointer-events-none opacity-50',
645
- className,
646
- )}
647
- {...props}
648
- >
649
- {/* Check icon */}
650
- <span className="mr-2 inline-flex h-4 w-4 shrink-0 items-center justify-center">
651
- {isSelected && (
652
- <svg
653
- aria-hidden
654
- viewBox="0 0 16 16"
655
- fill="none"
656
- stroke="currentColor"
657
- strokeWidth={2}
658
- className="h-4 w-4"
659
- >
660
- <path strokeLinecap="round" strokeLinejoin="round" d="M3 8l3 3 7-7" />
661
- </svg>
662
- )}
663
- </span>
664
- <span className="truncate">{children}</span>
665
- </div>
666
- );
667
- },
668
- );
669
-
670
- /* ── Group ─────────────────────────────────────────────────────────── */
671
-
672
- export interface SelectGroupProps extends HTMLAttributes<HTMLDivElement> {}
673
-
674
- export const SelectGroup = forwardRef<HTMLDivElement, SelectGroupProps>(
675
- function SelectGroup({ className, ...props }, ref) {
676
- return <div ref={ref} role="group" className={cn('py-1', className)} {...props} />;
677
- },
678
- );
679
-
680
- /* ── Label ─────────────────────────────────────────────────────────── */
681
-
682
- export interface SelectLabelProps extends HTMLAttributes<HTMLDivElement> {}
683
-
684
- export const SelectLabel = forwardRef<HTMLDivElement, SelectLabelProps>(
685
- function SelectLabel({ className, ...props }, ref) {
686
- return (
687
- <div
688
- ref={ref}
689
- className={cn('px-2 py-1.5 text-xs font-semibold text-muted-foreground', className)}
690
- {...props}
691
- />
692
- );
693
- },
694
- );
695
-
696
- /* ── Separator ─────────────────────────────────────────────────────── */
697
-
698
- export interface SelectSeparatorProps extends HTMLAttributes<HTMLHRElement> {}
699
26
 
700
- export const SelectSeparator = forwardRef<HTMLHRElement, SelectSeparatorProps>(
701
- function SelectSeparator({ className, ...props }, ref) {
702
- return (
703
- <hr
704
- ref={ref}
705
- className={cn('-mx-1 my-1 border-t border-border', className)}
706
- {...props}
707
- />
708
- );
709
- },
710
- );
27
+ export {
28
+ getReactSelectAnimatedComponents,
29
+ reactSelectAnimatedComponents,
30
+ ReactAsyncCreatableSelect,
31
+ ReactAsyncSelect,
32
+ ReactCreatableSelect,
33
+ ReactSelect,
34
+ type DefaultReactSelectOption,
35
+ type ReactAsyncCreatableSelectProps,
36
+ type ReactAsyncSelectProps,
37
+ type ReactCreatableSelectProps,
38
+ type ReactSelectProps,
39
+ } from './Select/react-select.js';
40
+
41
+ export { Select, type SelectProps } from './Select/root.js';
42
+ export { SelectTrigger, selectTriggerVariants, type SelectTriggerProps } from './Select/trigger.js';
43
+ export { SelectContent, type SelectContentProps } from './Select/content.js';
44
+ export { SelectItem, type SelectItemProps } from './Select/item.js';
45
+ export {
46
+ SelectGroup,
47
+ SelectLabel,
48
+ SelectSeparator,
49
+ type SelectGroupProps,
50
+ type SelectLabelProps,
51
+ type SelectSeparatorProps,
52
+ } from './Select/parts.js';