@redis-ui/components 42.7.0 → 43.0.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 (197) hide show
  1. package/dist/AutoCompleteSelect/AutoCompleteSelect.cjs +7 -1
  2. package/dist/AutoCompleteSelect/AutoCompleteSelect.js +7 -1
  3. package/dist/AutoCompleteSelect/hooks/useAutoCompleteSelect.cjs +7 -1
  4. package/dist/AutoCompleteSelect/hooks/useAutoCompleteSelect.d.ts +8 -1
  5. package/dist/AutoCompleteSelect/hooks/useAutoCompleteSelect.js +7 -1
  6. package/dist/BoxSelectionGroup/components/Item/components/BoxStateIndicator/BoxStateIndicator.cjs +8 -4
  7. package/dist/BoxSelectionGroup/components/Item/components/BoxStateIndicator/BoxStateIndicator.js +8 -4
  8. package/dist/BoxSelectionGroup/components/Item/components/Compose/Compose.style.cjs +18 -4
  9. package/dist/BoxSelectionGroup/components/Item/components/Compose/Compose.style.js +18 -4
  10. package/dist/BoxSelectionGroup/hooks/useBoxSelectionGroup.cjs +3 -1
  11. package/dist/BoxSelectionGroup/hooks/useBoxSelectionGroup.js +3 -1
  12. package/dist/Breadcrumbs/Breadcrumbs.cjs +51 -0
  13. package/dist/Breadcrumbs/Breadcrumbs.d.ts +10 -0
  14. package/dist/Breadcrumbs/Breadcrumbs.js +51 -0
  15. package/dist/Breadcrumbs/Breadcrumbs.types.d.ts +17 -0
  16. package/dist/Breadcrumbs/components/Compose/Compose.cjs +14 -0
  17. package/dist/Breadcrumbs/components/Compose/Compose.d.ts +3 -0
  18. package/dist/Breadcrumbs/components/Compose/Compose.js +14 -0
  19. package/dist/Breadcrumbs/components/Compose/Compose.style.cjs +10 -0
  20. package/dist/Breadcrumbs/components/Compose/Compose.style.d.ts +1 -0
  21. package/dist/Breadcrumbs/components/Compose/Compose.style.js +8 -0
  22. package/dist/Breadcrumbs/components/Compose/Compose.types.d.ts +5 -0
  23. package/dist/Breadcrumbs/components/Current/Current.cjs +13 -0
  24. package/dist/Breadcrumbs/components/Current/Current.d.ts +3 -0
  25. package/dist/Breadcrumbs/components/Current/Current.js +13 -0
  26. package/dist/Breadcrumbs/components/Current/Current.style.cjs +11 -0
  27. package/dist/Breadcrumbs/components/Current/Current.style.d.ts +1 -0
  28. package/dist/Breadcrumbs/components/Current/Current.style.js +9 -0
  29. package/dist/Breadcrumbs/components/Current/Current.types.d.ts +4 -0
  30. package/dist/Breadcrumbs/components/Item/Item.cjs +12 -0
  31. package/dist/Breadcrumbs/components/Item/Item.d.ts +3 -0
  32. package/dist/Breadcrumbs/components/Item/Item.js +12 -0
  33. package/dist/Breadcrumbs/components/Item/Item.style.cjs +11 -0
  34. package/dist/Breadcrumbs/components/Item/Item.style.d.ts +1 -0
  35. package/dist/Breadcrumbs/components/Item/Item.style.js +9 -0
  36. package/dist/Breadcrumbs/components/Item/Item.types.d.ts +2 -0
  37. package/dist/Breadcrumbs/components/Link/Link.cjs +52 -0
  38. package/dist/Breadcrumbs/components/Link/Link.d.ts +3 -0
  39. package/dist/Breadcrumbs/components/Link/Link.js +52 -0
  40. package/dist/Breadcrumbs/components/Link/Link.style.cjs +13 -0
  41. package/dist/Breadcrumbs/components/Link/Link.style.d.ts +1 -0
  42. package/dist/Breadcrumbs/components/Link/Link.style.js +11 -0
  43. package/dist/Breadcrumbs/components/Link/Link.types.d.ts +5 -0
  44. package/dist/Breadcrumbs/components/List/List.cjs +12 -0
  45. package/dist/Breadcrumbs/components/List/List.d.ts +3 -0
  46. package/dist/Breadcrumbs/components/List/List.js +12 -0
  47. package/dist/Breadcrumbs/components/List/List.style.cjs +11 -0
  48. package/dist/Breadcrumbs/components/List/List.style.d.ts +1 -0
  49. package/dist/Breadcrumbs/components/List/List.style.js +9 -0
  50. package/dist/Breadcrumbs/components/List/List.types.d.ts +2 -0
  51. package/dist/Breadcrumbs/components/Separator/Separator.cjs +13 -0
  52. package/dist/Breadcrumbs/components/Separator/Separator.d.ts +3 -0
  53. package/dist/Breadcrumbs/components/Separator/Separator.js +13 -0
  54. package/dist/Breadcrumbs/components/Separator/Separator.style.cjs +11 -0
  55. package/dist/Breadcrumbs/components/Separator/Separator.style.d.ts +1 -0
  56. package/dist/Breadcrumbs/components/Separator/Separator.style.js +9 -0
  57. package/dist/Breadcrumbs/components/Separator/Separator.types.d.ts +4 -0
  58. package/dist/Breadcrumbs/index.d.ts +5 -0
  59. package/dist/Button/Button.style.cjs +4 -1
  60. package/dist/Button/Button.style.js +4 -1
  61. package/dist/Button/Button.style.utils.cjs +16 -1
  62. package/dist/Button/Button.style.utils.js +16 -1
  63. package/dist/Button/Button.types.cjs +1 -1
  64. package/dist/Button/Button.types.d.ts +1 -1
  65. package/dist/Button/Button.types.js +1 -1
  66. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.cjs +59 -0
  67. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.d.ts +4 -0
  68. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.js +57 -0
  69. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.cjs +40 -0
  70. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.d.ts +8 -0
  71. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.js +38 -0
  72. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.types.d.ts +5 -0
  73. package/dist/Button/TextButton/TextButton.style.cjs +4 -1
  74. package/dist/Button/TextButton/TextButton.style.js +4 -1
  75. package/dist/Button/TextButton/TextButton.types.cjs +1 -1
  76. package/dist/Button/TextButton/TextButton.types.d.ts +1 -1
  77. package/dist/Button/TextButton/TextButton.types.js +1 -1
  78. package/dist/Button/index.d.ts +2 -0
  79. package/dist/Checkbox/components/Label/Label.style.cjs +15 -3
  80. package/dist/Checkbox/components/Label/Label.style.js +15 -3
  81. package/dist/Chip/components/CloseButton/CloseButton.cjs +3 -1
  82. package/dist/Chip/components/CloseButton/CloseButton.js +3 -1
  83. package/dist/Chip/components/Compose/Compose.style.cjs +4 -1
  84. package/dist/Chip/components/Compose/Compose.style.js +4 -1
  85. package/dist/Drawer/components/Description/Description.cjs +3 -1
  86. package/dist/Drawer/components/Description/Description.js +3 -1
  87. package/dist/Helpers/contexts/Popper/PopperCollisionBoundaryManager.cjs +3 -1
  88. package/dist/Helpers/contexts/Popper/PopperCollisionBoundaryManager.js +3 -1
  89. package/dist/Helpers/contexts/PrimitiveContextState.cjs +28 -16
  90. package/dist/Helpers/contexts/PrimitiveContextState.js +28 -16
  91. package/dist/Helpers/contexts/SharedId.context.cjs +9 -5
  92. package/dist/Helpers/contexts/SharedId.context.js +9 -5
  93. package/dist/Helpers/css.utils.cjs +18 -4
  94. package/dist/Helpers/css.utils.d.ts +15 -3
  95. package/dist/Helpers/css.utils.js +18 -4
  96. package/dist/Helpers/hooks/useScrollable.cjs +3 -1
  97. package/dist/Helpers/hooks/useScrollable.js +3 -1
  98. package/dist/Helpers/react.utils.cjs +6 -2
  99. package/dist/Helpers/react.utils.js +6 -2
  100. package/dist/Inputs/QuantityCounter/components/InputGroup/components/ValueLabel/ValueLabel.cjs +9 -5
  101. package/dist/Inputs/QuantityCounter/components/InputGroup/components/ValueLabel/ValueLabel.js +9 -5
  102. package/dist/Inputs/components/Compose/Compose.style.cjs +29 -6
  103. package/dist/Inputs/components/Compose/Compose.style.js +29 -6
  104. package/dist/Inputs/hooks/numericInput/numericInput.utils.cjs +12 -4
  105. package/dist/Inputs/hooks/numericInput/numericInput.utils.js +12 -4
  106. package/dist/Inputs/hooks/numericInput/useNumericInput.cjs +15 -3
  107. package/dist/Inputs/hooks/numericInput/useNumericInput.js +15 -3
  108. package/dist/Loader/Loader.cjs +1 -0
  109. package/dist/Loader/Loader.js +1 -0
  110. package/dist/Menu/components/Content/components/Item/Components/Compose/Compose.style.cjs +19 -4
  111. package/dist/Menu/components/Content/components/Item/Components/Compose/Compose.style.js +19 -4
  112. package/dist/Menu/components/Content/components/Label/components/Compose/Compose.style.cjs +4 -1
  113. package/dist/Menu/components/Content/components/Label/components/Compose/Compose.style.js +4 -1
  114. package/dist/Modal/components/Content/components/Compose/Compose.cjs +3 -1
  115. package/dist/Modal/components/Content/components/Compose/Compose.js +3 -1
  116. package/dist/Modal/components/Content/components/Description/Description.cjs +3 -1
  117. package/dist/Modal/components/Content/components/Description/Description.js +3 -1
  118. package/dist/MultiSelect/components/Compose/hooks/useMultiSelectContextApi.cjs +3 -1
  119. package/dist/MultiSelect/components/Compose/hooks/useMultiSelectContextApi.js +3 -1
  120. package/dist/MultiSelect/components/Trigger/components/MultiValue/MultiValue.cjs +3 -1
  121. package/dist/MultiSelect/components/Trigger/components/MultiValue/MultiValue.js +3 -1
  122. package/dist/Overflow/Overflow.cjs +3 -1
  123. package/dist/Overflow/Overflow.js +3 -1
  124. package/dist/Overflow/Overflow.utils.cjs +15 -6
  125. package/dist/Overflow/Overflow.utils.js +15 -6
  126. package/dist/Overflow/components/OverflowContainer/OverflowContainer.cjs +3 -1
  127. package/dist/Overflow/components/OverflowContainer/OverflowContainer.js +3 -1
  128. package/dist/Pagination/components/PageSizeSelect.cjs +3 -1
  129. package/dist/Pagination/components/PageSizeSelect.js +3 -1
  130. package/dist/Popover/components/Content/Content.cjs +3 -1
  131. package/dist/Popover/components/Content/Content.js +3 -1
  132. package/dist/Popover/components/Content/components/Footer/Footer.cjs +3 -1
  133. package/dist/Popover/components/Content/components/Footer/Footer.js +3 -1
  134. package/dist/RadioGroup/components/Item/components/Label/Label.style.cjs +15 -3
  135. package/dist/RadioGroup/components/Item/components/Label/Label.style.js +15 -3
  136. package/dist/ScreenReaderAnnounce/ScreenReaderAnnounce.cjs +3 -1
  137. package/dist/ScreenReaderAnnounce/ScreenReaderAnnounce.js +3 -1
  138. package/dist/Section/components/Header/components/CollapseButton/CollapseButton.cjs +3 -1
  139. package/dist/Section/components/Header/components/CollapseButton/CollapseButton.js +3 -1
  140. package/dist/Select/components/Content/components/Option/components/Compose/Compose.style.cjs +16 -4
  141. package/dist/Select/components/Content/components/Option/components/Compose/Compose.style.js +16 -4
  142. package/dist/Select/components/Content/components/OptionList/OptionList.cjs +6 -4
  143. package/dist/Select/components/Content/components/OptionList/OptionList.js +6 -4
  144. package/dist/Select/components/Content/components/OptionList/Virtual.cjs +9 -5
  145. package/dist/Select/components/Content/components/OptionList/Virtual.js +9 -5
  146. package/dist/Select/components/Context/hooks/useSearch.cjs +3 -1
  147. package/dist/Select/components/Context/hooks/useSearch.js +3 -1
  148. package/dist/Select/components/Trigger/components/Compose/Compose.style.cjs +33 -7
  149. package/dist/Select/components/Trigger/components/Compose/Compose.style.js +33 -7
  150. package/dist/SideBar/components/Item/Item.style.cjs +14 -3
  151. package/dist/SideBar/components/Item/Item.style.js +14 -3
  152. package/dist/Skeleton/components/Circle/Circle.cjs +1 -1
  153. package/dist/Skeleton/components/Circle/Circle.js +1 -1
  154. package/dist/Skeleton/components/Square/Square.cjs +1 -1
  155. package/dist/Skeleton/components/Square/Square.js +1 -1
  156. package/dist/Slider/components/Label/Compose/Compose.cjs +3 -1
  157. package/dist/Slider/components/Label/Compose/Compose.js +3 -1
  158. package/dist/Slider/components/Mark/Compose/Compose.cjs +3 -1
  159. package/dist/Slider/components/Mark/Compose/Compose.js +3 -1
  160. package/dist/Slider/hooks/useOffset.cjs +3 -1
  161. package/dist/Slider/hooks/useOffset.js +3 -1
  162. package/dist/Stepper/components/Step/components/Compose/Compose.cjs +3 -1
  163. package/dist/Stepper/components/Step/components/Compose/Compose.js +3 -1
  164. package/dist/Stepper/hooks/useStepperInteractive.cjs +12 -4
  165. package/dist/Stepper/hooks/useStepperInteractive.js +12 -4
  166. package/dist/Switch/components/Switcher/Switcher.cjs +3 -1
  167. package/dist/Switch/components/Switcher/Switcher.js +3 -1
  168. package/dist/Switch/components/Switcher/Switcher.style.cjs +31 -8
  169. package/dist/Switch/components/Switcher/Switcher.style.js +31 -8
  170. package/dist/Tabs/components/TabBar/components/Trigger/components/Marker/Marker.style.cjs +24 -5
  171. package/dist/Tabs/components/TabBar/components/Trigger/components/Marker/Marker.style.js +24 -5
  172. package/dist/Tabs/components/TabBar/components/Trigger/components/Tab/Tab.style.cjs +24 -5
  173. package/dist/Tabs/components/TabBar/components/Trigger/components/Tab/Tab.style.js +24 -5
  174. package/dist/ThemeModeSwitch/useThemeModeSwitch.cjs +6 -2
  175. package/dist/ThemeModeSwitch/useThemeModeSwitch.js +6 -2
  176. package/dist/Toast/core/content.helper.cjs +8 -4
  177. package/dist/Toast/core/content.helper.js +8 -4
  178. package/dist/Tooltip/components/Content/Content.cjs +3 -1
  179. package/dist/Tooltip/components/Content/Content.js +3 -1
  180. package/dist/TreeView/TreeView.cjs +3 -1
  181. package/dist/TreeView/TreeView.js +3 -1
  182. package/dist/TreeView/components/TreeItem/components/Compose/Compose.cjs +6 -4
  183. package/dist/TreeView/components/TreeItem/components/Compose/Compose.js +6 -4
  184. package/dist/Typography/Typography.types.cjs +4 -0
  185. package/dist/Typography/Typography.types.d.ts +2 -1
  186. package/dist/Typography/Typography.types.js +4 -0
  187. package/dist/index.cjs +6 -0
  188. package/dist/index.d.ts +1 -0
  189. package/dist/index.js +110 -104
  190. package/package.json +10 -9
  191. package/skills/redis-ui-components/SKILL.md +128 -0
  192. package/skills/redis-ui-components/references/Button.md +169 -0
  193. package/skills/redis-ui-components/references/FlexDivider.md +152 -0
  194. package/skills/redis-ui-components/references/FlexGroup.md +149 -0
  195. package/skills/redis-ui-components/references/FlexItem.md +58 -0
  196. package/skills/redis-ui-components/references/FlexSplit.md +37 -0
  197. package/skills/redis-ui-components/references/Select.md +517 -0
@@ -0,0 +1,517 @@
1
+ # Select
2
+
3
+ A single-select dropdown component built on Radix UI primitives. Supports searchable options, virtualized lists, custom value rendering, validation states, and full composition via sub-components for trigger, content, and option customization.
4
+
5
+ ## Import
6
+ ```tsx
7
+ import { Select } from '@redislabsdev/redis-ui-components';
8
+ ```
9
+
10
+ ## Props
11
+ | Prop | Type | Default | Description |
12
+ |------|------|---------|-------------|
13
+ | options | `TOption[]` (extends `SelectOption`) | *required* | Array of selectable options |
14
+ | disabled | `boolean` | `false` | Whether the select is disabled |
15
+ | defaultOpen | `boolean` | - | Uncontrolled initial open state |
16
+ | open | `boolean` | - | Controlled open state |
17
+ | onOpenChange | `(open: boolean) => void` | - | Called when open state changes |
18
+ | defaultValue | `TValue` | - | Uncontrolled initial selected value |
19
+ | value | `TValue` | - | Controlled selected value |
20
+ | onChange | `(value: TValue) => void` | - | Called when selection changes |
21
+ | customCompare | `SelectCompareHandler<TOption>` | - | Custom search comparison handler. Receives `(option, searchValue)` and returns boolean |
22
+ | error | `string \| ReactElement` | - | Error message or element. Enables error state; overrides valid status |
23
+ | valid | `boolean` | - | Enables valid status indicator |
24
+ | placeholder | `ReactNode` | `'Select...'` | Placeholder text when no value is selected |
25
+ | valueRender | `SelectValueRender<TOption>` | - | Custom render function for both trigger and option values. Receives `{ option, isSelected, isOptionValue }` |
26
+ | searchable | `boolean` | - | Enables search input in the dropdown content |
27
+ | placement | `'top' \| 'bottom' \| 'left' \| 'right'` | - | Dropdown placement relative to trigger |
28
+ | maxVisibleItems | `number` | - | Maximum number of visible items before scrolling |
29
+ | virtualized | `boolean` | - | Enables virtualized rendering for long lists |
30
+ | contentWidth | `string` | - | Custom width for the dropdown content |
31
+ | allowReset | `boolean` | - | Shows a reset button to clear the selected value |
32
+ | loading | `boolean` | - | Shows a loading indicator on the trigger |
33
+ | id | `string` | - | Custom id for the select trigger (must start with a letter) |
34
+
35
+ The component also extends Radix UI `SelectTriggerProps` (excluding `children`, `placeholder`, `asChild`, `onChange`).
36
+
37
+ ### SelectOption Type
38
+ | Field | Type | Description |
39
+ |-------|------|-------------|
40
+ | value | `string` | *required* - Unique option value |
41
+ | label | `string` | Display label |
42
+ | icon | `IconType \| ComponentType` | Optional icon component |
43
+ | disabled | `boolean` | Whether the option is disabled |
44
+ | hidden | `boolean` | Whether the option is hidden |
45
+
46
+ ## Sub-components
47
+
48
+ - **`Select.Compose`** - Context provider that wraps trigger and content. Accepts state/option props.
49
+ - **`Select.Trigger`** - Default trigger button with combobox styling.
50
+ - **`Select.Trigger.Compose`** - Composable trigger wrapper. Accepts `customContainer` prop for custom trigger UI.
51
+ - **`Select.Trigger.Value`** - Displays the selected value or placeholder text.
52
+ - **`Select.Trigger.Arrow`** - Dropdown arrow indicator. Accepts optional `icon` prop.
53
+ - **`Select.Trigger.ResetButton`** - Button to clear the current selection.
54
+ - **`Select.Trigger.StatusIndicator`** - Shows valid/error status indicator.
55
+ - **`Select.Trigger.LoadingIndicator`** - Shows loading spinner. Accepts `loading` prop.
56
+ - **`Select.Content`** - Default dropdown content with options list and optional search.
57
+ - **`Select.Content.Compose`** - Composable content wrapper for custom content layouts.
58
+ - **`Select.Content.Search`** - Search input for filtering options.
59
+ - **`Select.Content.OptionList`** - Renders the list of options. Accepts `style` for custom sizing.
60
+ - **`Select.Content.Footer`** - Footer area inside the dropdown content.
61
+ - **`Select.Option`** - Default option component.
62
+ - **`Select.Option.Compose`** - Composable option wrapper (must be root element in custom option components).
63
+ - **`Select.Option.Indicator`** - Selection check indicator. Accepts children to customize the icon.
64
+ - **`Select.Option.Content`** - Content area within an option.
65
+
66
+ ### Select.Content Props
67
+ | Prop | Type | Default | Description |
68
+ |------|------|---------|-------------|
69
+ | searchable | `boolean` | - | Enables the search input |
70
+ | optionValueRender | `SelectValueRender<TOption>` | - | Custom render for option values only |
71
+ | optionComponent | `SelectOptionComponent<TOption>` | - | Custom component to render each option |
72
+ | maxVisibleItems | `number` | - | Maximum visible items before scrolling |
73
+ | virtualized | `boolean` | - | Enables virtualized rendering |
74
+ | placement | `'top' \| 'bottom' \| 'left' \| 'right'` | - | Dropdown placement |
75
+ | contentWidth | `string` | - | Custom dropdown width |
76
+
77
+ ### Select.Trigger Props
78
+ | Prop | Type | Default | Description |
79
+ |------|------|---------|-------------|
80
+ | placeholder | `ReactNode` | - | Placeholder text |
81
+ | valueRender | `SelectValueRender<TOption>` | - | Custom render for the trigger value |
82
+ | allowReset | `boolean` | - | Shows reset button |
83
+ | loading | `boolean` | - | Shows loading indicator |
84
+ | id | `string` | - | Custom id for the trigger element |
85
+
86
+ ### Select.Trigger.Compose Props
87
+ | Prop | Type | Default | Description |
88
+ |------|------|---------|-------------|
89
+ | customContainer | `boolean` | - | When true, allows using a custom container element instead of the default combobox button |
90
+ | id | `string` | - | Custom id |
91
+
92
+ ## Examples
93
+
94
+ ### Playground
95
+ ```tsx
96
+ import { Select } from '@redislabsdev/redis-ui-components';
97
+
98
+ <Select
99
+ options={options}
100
+ searchable
101
+ onChange={(value) => console.log(value)}
102
+ onOpenChange={(open) => console.log(open)}
103
+ />
104
+ ```
105
+
106
+ ### WithLabel
107
+ > Component doesn't have internal label or any other external decoration elements.
108
+ > For these purposes, there is a wrapper element `FormField`.
109
+ > If custom id specified for select, `FormField` inherits it,
110
+ > otherwise label will be auto connected to the select with generated id.
111
+ > Note: custom id must start with a letter to work correctly.
112
+ ```tsx
113
+ import { Select, FormField } from '@redislabsdev/redis-ui-components';
114
+
115
+ <FormField label="FormField Label with custom id" additionalText="Additional text">
116
+ <Select
117
+ options={options}
118
+ placeholder="Select placeholder"
119
+ id="custom-id"
120
+ onChange={(value) => console.log(value)}
121
+ onOpenChange={(open) => console.log(open)}
122
+ />
123
+ </FormField>
124
+ ```
125
+
126
+ ### Status
127
+ > Adding `valid` prop enables valid status.
128
+ > Adding some text to the `error` prop of `Select` enables error state. Hover error indicator to see specified text in tooltip.
129
+ > Note: error status overrides valid status.
130
+ ```tsx
131
+ import { Select } from '@redislabsdev/redis-ui-components';
132
+
133
+ <>
134
+ Valid status
135
+ <Select options={options} valid onChange={(value) => console.log(value)} />
136
+ Error status
137
+ <Select options={options} error="Error message" onChange={(value) => console.log(value)} />
138
+ </>
139
+ ```
140
+
141
+ ### ResetButton
142
+ > Single Select allows user to clean selected value. Set `allowReset` prop to show Reset button.
143
+ ```tsx
144
+ import { Select } from '@redislabsdev/redis-ui-components';
145
+
146
+ <Select
147
+ options={options}
148
+ allowReset
149
+ defaultValue="orange"
150
+ onChange={(value) => console.log(value)}
151
+ />
152
+ ```
153
+
154
+ ### Loading
155
+ > Adding `loading` prop enables loading indicator. It can be used together with other indicators and states.
156
+ ```tsx
157
+ import { Select } from '@redislabsdev/redis-ui-components';
158
+
159
+ <>
160
+ Loading indicator
161
+ <Select options={options} loading onChange={(value) => console.log(value)} />
162
+ With other elements
163
+ <Select
164
+ options={options}
165
+ defaultValue="banana"
166
+ valid
167
+ allowReset
168
+ loading
169
+ onChange={(value) => console.log(value)}
170
+ />
171
+ </>
172
+ ```
173
+
174
+ ### Disabled
175
+ ```tsx
176
+ import { Select } from '@redislabsdev/redis-ui-components';
177
+
178
+ <>
179
+ Default
180
+ <Select options={options} disabled />
181
+ With selected item
182
+ <Select options={options} disabled value="orange" />
183
+ With error message
184
+ <Select
185
+ options={options}
186
+ disabled
187
+ value="banana"
188
+ error="Error message"
189
+ allowReset
190
+ loading
191
+ />
192
+ </>
193
+ ```
194
+
195
+ ### ValueRender
196
+ > Value rendering can be customized by specifying `valueRender` prop.
197
+ > It can be customized for both option and trigger.
198
+ > Event handler receives current `option`, `isSelected` flag and `isOptionValue` flag if rendering option in dropdown list.
199
+ > Note: if valueRender handler returns `undefined` or `null`, then default rendering will be applied.
200
+ ```tsx
201
+ import { Select, SelectValueRender } from '@redislabsdev/redis-ui-components';
202
+
203
+ const customValueRender: SelectValueRender = ({ option, isSelected, isOptionValue }) => {
204
+ const color = !isOptionValue ? 'green' : (isSelected && 'blueviolet') || 'orange';
205
+ const stateLabel = isOptionValue ? `${isSelected ? 'Selected Option' : 'Option'}` : 'Value';
206
+
207
+ return (
208
+ <div>
209
+ <span style={{ fontSize: '0.7em', color }}>{stateLabel}: </span>
210
+ {option.label}
211
+ </div>
212
+ );
213
+ };
214
+
215
+ <Select
216
+ options={options}
217
+ defaultValue="orange"
218
+ valueRender={customValueRender}
219
+ onChange={(value) => console.log(value)}
220
+ />
221
+ ```
222
+
223
+ ### CustomSearch
224
+ > If there is additional info for an option, then it is possible to search by that info as well.
225
+ > Set the comparison handler to the `customCompare` prop to enable custom search.
226
+ > The handler receives an option and a search string in lowercase.
227
+ > The handler should return true if the search string is found in the option search fields.
228
+ > Note: if a custom search should include a default search by label, then label needs to be added to the custom search implementation, since custom search completely replaces the default search.
229
+ ```tsx
230
+ import { Select, SelectCompareHandler, SelectOption, SelectValueRender } from '@redislabsdev/redis-ui-components';
231
+
232
+ const customCompare: SelectCompareHandler<SelectOption> = (option, searchValue) => {
233
+ const fieldsForSearch = [option.label, option.state as string];
234
+ return fieldsForSearch.some((field) => field?.toLowerCase().includes(searchValue));
235
+ };
236
+
237
+ const valueRender: SelectValueRender = ({ option }) => {
238
+ return (
239
+ <>
240
+ <span>{option.label}</span>
241
+ &nbsp;
242
+ <span style={{ fontSize: '0.8em' }}>{`(${option.state})`}</span>
243
+ </>
244
+ );
245
+ };
246
+
247
+ <Select
248
+ options={usStates}
249
+ searchable
250
+ customCompare={customCompare}
251
+ valueRender={valueRender}
252
+ onChange={(value) => console.log(value)}
253
+ />
254
+ ```
255
+
256
+ ### VirtualList
257
+ > List of options can be virtualized by adding `virtualized` prop. It allows to have very long list of items without performance drop.
258
+ ```tsx
259
+ import { Select, FormField } from '@redislabsdev/redis-ui-components';
260
+
261
+ <FormField label="Countries">
262
+ <Select
263
+ virtualized
264
+ searchable
265
+ options={countryOptions}
266
+ allowReset
267
+ defaultValue="ua"
268
+ maxVisibleItems={6}
269
+ onChange={(value) => console.log(value)}
270
+ />
271
+ </FormField>
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Content Composition
277
+
278
+ ### Content Playground
279
+ ```tsx
280
+ import { Select } from '@redislabsdev/redis-ui-components';
281
+
282
+ <Select.Compose options={options} onChange={(value) => console.log(value)}>
283
+ <Select.Trigger />
284
+ <Select.Content />
285
+ </Select.Compose>
286
+ ```
287
+
288
+ ### OptionValueRender
289
+ > Value rendering can be customized separately for option and trigger values.
290
+ > Option value rendering can be customized by specifying `optionValueRender` prop of `Select.Content`.
291
+ > Event handler receives current `option`, `isSelected` flag and truthy `isOptionValue` flag for rendering option value.
292
+ ```tsx
293
+ import { Select } from '@redislabsdev/redis-ui-components';
294
+
295
+ <Select.Compose
296
+ options={options}
297
+ defaultValue="orange"
298
+ onChange={(value) => console.log(value)}
299
+ >
300
+ <Select.Trigger />
301
+ <Select.Content
302
+ optionValueRender={({ option, isSelected }) => {
303
+ return (
304
+ <div>
305
+ <span
306
+ style={{
307
+ fontSize: '0.7em',
308
+ color: (isSelected && 'blueviolet') || 'orange'
309
+ }}
310
+ >
311
+ {isSelected ? 'Selected Option' : 'Option'}:
312
+ </span>{' '}
313
+ {option.label}
314
+ </div>
315
+ );
316
+ }}
317
+ />
318
+ </Select.Compose>
319
+ ```
320
+
321
+ ### OptionComponent
322
+ > Prop `optionComponent` (unlike `optionValueRender`) allows rendering the entire option, including the selection indicator.
323
+ > If Option Component is not specified, `Select` renders options using default `Select.Option`.
324
+ > Custom `optionComponent` can be used together with custom `optionValueRender`.
325
+ > Option component receives default or custom rendered value as `content` prop.
326
+ > Note: custom option component must use `Select.Option.Compose` as root element to work correctly.
327
+ ```tsx
328
+ import { Select, SelectOptionComponent } from '@redislabsdev/redis-ui-components';
329
+
330
+ const CustomOption: SelectOptionComponent = ({ option, content, ...restProps }) => (
331
+ <Select.Option.Compose option={option} {...restProps}>
332
+ <Select.Option.Indicator />
333
+ <Select.Option.Content>{content}</Select.Option.Content>
334
+ </Select.Option.Compose>
335
+ );
336
+
337
+ <Select.Compose
338
+ options={options}
339
+ defaultValue="orange"
340
+ onChange={(value) => console.log(value)}
341
+ >
342
+ <Select.Trigger />
343
+ <Select.Content optionComponent={CustomOption} />
344
+ </Select.Compose>
345
+ ```
346
+
347
+ ### CustomCheckIndicator
348
+ > Shows how, using composition, to replace the icon of the check indicator.
349
+ ```tsx
350
+ import { Select, SelectOptionComponent } from '@redislabsdev/redis-ui-components';
351
+ import { PocIcon } from '@redislabsdev/redis-ui-icons';
352
+
353
+ const CustomOption: SelectOptionComponent = ({ option, content, ...restProps }) => (
354
+ <Select.Option.Compose option={option} {...restProps}>
355
+ <Select.Option.Content>{content}</Select.Option.Content>
356
+ <Select.Option.Indicator>
357
+ <PocIcon color="danger500" size="XL" />
358
+ </Select.Option.Indicator>
359
+ </Select.Option.Compose>
360
+ );
361
+
362
+ <Select.Compose
363
+ options={options}
364
+ defaultValue="orange"
365
+ onChange={(value) => console.log(value)}
366
+ >
367
+ <Select.Trigger />
368
+ <Select.Content optionComponent={CustomOption} />
369
+ </Select.Compose>
370
+ ```
371
+
372
+ ### ContentComposition
373
+ > Composition example includes all parts of `Select.Content` and shows usage of static elements.
374
+ ```tsx
375
+ import { Select } from '@redislabsdev/redis-ui-components';
376
+
377
+ <Select.Compose
378
+ options={options}
379
+ onChange={(value) => console.log(value)}
380
+ >
381
+ <Select.Trigger />
382
+ <Select.Content.Compose>
383
+ <div style={{ textAlign: 'center' }}>Top static element</div>
384
+ <Select.Content.Search />
385
+ <div style={{ textAlign: 'center' }}>Middle static element</div>
386
+ <Select.Content.OptionList style={{ maxHeight: 100 }} />
387
+ <div style={{ textAlign: 'center' }}>Bottom static element</div>
388
+ <Select.Content.Footer>
389
+ <div style={{ textAlign: 'center' }}>Custom element in Footer</div>
390
+ </Select.Content.Footer>
391
+ </Select.Content.Compose>
392
+ </Select.Compose>
393
+ ```
394
+
395
+ ### ContentListComposition
396
+ > By adding extra list container, some static elements can be scrolled along with other options.
397
+ ```tsx
398
+ import { Select } from '@redislabsdev/redis-ui-components';
399
+
400
+ <Select.Compose
401
+ options={options}
402
+ onChange={(value) => console.log(value)}
403
+ >
404
+ <Select.Trigger />
405
+ <Select.Content.Compose>
406
+ <Select.Content.Search />
407
+ <div style={{ overflowY: 'auto', maxHeight: 200 }}>
408
+ <div style={{ textAlign: 'center' }}>Top scrollable element</div>
409
+ <Select.Content.OptionList />
410
+ <div style={{ textAlign: 'center' }}>Bottom scrollable element</div>
411
+ </div>
412
+ </Select.Content.Compose>
413
+ </Select.Compose>
414
+ ```
415
+
416
+ ---
417
+
418
+ ## Trigger Composition
419
+
420
+ ### Trigger Playground
421
+ ```tsx
422
+ import { Select } from '@redislabsdev/redis-ui-components';
423
+
424
+ <Select.Compose options={options} onChange={(value) => console.log(value)}>
425
+ <Select.Trigger placeholder="Select fruit..." allowReset={false} />
426
+ <Select.Content />
427
+ </Select.Compose>
428
+ ```
429
+
430
+ ### Trigger ValueRender
431
+ > Value rendering can be customized separately for option and trigger values.
432
+ > Trigger value rendering can be customized by specifying `valueRender` prop of `Select.Trigger`.
433
+ > Event handler receives current `option` prop.
434
+ ```tsx
435
+ import { Select } from '@redislabsdev/redis-ui-components';
436
+
437
+ const valueRender = ({ option }) => {
438
+ return (
439
+ <div>
440
+ <span style={{ fontSize: '0.7em', color: 'green' }}> Option: </span> {option.label}
441
+ </div>
442
+ );
443
+ };
444
+
445
+ <Select.Compose
446
+ options={options}
447
+ defaultValue="orange"
448
+ onChange={(value) => console.log(value)}
449
+ >
450
+ <Select.Trigger valueRender={valueRender} />
451
+ <Select.Content />
452
+ </Select.Compose>
453
+ ```
454
+
455
+ ### CustomContainer
456
+ > By default, `Select.Trigger` wraps children with combobox-styled button container.
457
+ > It is possible to use custom container by defining the `customContainer` prop.
458
+ > Note: custom container may have its own style and behavior and therefore can have name conflicts with attributes added by `Select.Trigger`. In this case custom container can be wrapped in a `span` or `div`, which will take over all attributes from the trigger.
459
+ ```tsx
460
+ import { useState } from 'react';
461
+ import { Select, ToggleButton } from '@redislabsdev/redis-ui-components';
462
+
463
+ const [open, setOpen] = useState(false);
464
+
465
+ <Select.Compose
466
+ options={options}
467
+ defaultValue="orange"
468
+ open={open}
469
+ onOpenChange={setOpen}
470
+ onChange={(value) => console.log(value)}
471
+ >
472
+ <Select.Trigger.Compose customContainer>
473
+ <span>
474
+ <ToggleButton pressed={open}>
475
+ <Select.Trigger.Value />
476
+ <Select.Trigger.Arrow />
477
+ </ToggleButton>
478
+ </span>
479
+ </Select.Trigger.Compose>
480
+ <Select.Content />
481
+ </Select.Compose>
482
+ ```
483
+
484
+ ### TriggerComposition
485
+ > Default composition example includes all parts of `Trigger`.
486
+ ```tsx
487
+ import { Select } from '@redislabsdev/redis-ui-components';
488
+
489
+ <Select.Compose
490
+ options={options}
491
+ defaultValue="orange"
492
+ error="error message"
493
+ onChange={(value) => console.log(value)}
494
+ >
495
+ <Select.Trigger.Compose>
496
+ <Select.Trigger.Value placeholder="Placeholder" />
497
+ <Select.Trigger.ResetButton />
498
+ <Select.Trigger.StatusIndicator />
499
+ <Select.Trigger.LoadingIndicator loading />
500
+ <Select.Trigger.Arrow />
501
+ </Select.Trigger.Compose>
502
+
503
+ <Select.Content />
504
+ </Select.Compose>
505
+ ```
506
+
507
+ ## Notes
508
+
509
+ - The `Select` top-level component is a convenience wrapper that internally uses `Select.Compose`, `Select.Trigger`, and `Select.Content`.
510
+ - For full customization, use the compose pattern: `Select.Compose` > `Select.Trigger` / `Select.Content`.
511
+ - Custom id must start with a letter to work correctly with `FormField` label association.
512
+ - Error status overrides valid status when both are set.
513
+ - If `valueRender` returns `undefined` or `null`, default rendering is applied.
514
+ - Custom search via `customCompare` completely replaces the default search -- include label matching in your handler if needed.
515
+ - Custom option components must use `Select.Option.Compose` as the root element.
516
+ - Custom trigger containers may have name conflicts with attributes added by `Select.Trigger`; wrap in a `span` or `div` to avoid this.
517
+ - `useSelectContext` hook is exported and can be used inside custom option components to access select state.