@redis-ui/components 42.8.0 → 43.2.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 (228) 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/Button/Button.style.cjs +4 -1
  13. package/dist/Button/Button.style.js +4 -1
  14. package/dist/Button/Button.style.utils.cjs +16 -1
  15. package/dist/Button/Button.style.utils.js +16 -1
  16. package/dist/Button/Button.types.cjs +1 -1
  17. package/dist/Button/Button.types.d.ts +1 -1
  18. package/dist/Button/Button.types.js +1 -1
  19. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.cjs +59 -0
  20. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.d.ts +4 -0
  21. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.js +57 -0
  22. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.cjs +40 -0
  23. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.d.ts +8 -0
  24. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.js +38 -0
  25. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.types.d.ts +5 -0
  26. package/dist/Button/TextButton/TextButton.style.cjs +4 -1
  27. package/dist/Button/TextButton/TextButton.style.js +4 -1
  28. package/dist/Button/TextButton/TextButton.types.cjs +1 -1
  29. package/dist/Button/TextButton/TextButton.types.d.ts +1 -1
  30. package/dist/Button/TextButton/TextButton.types.js +1 -1
  31. package/dist/Button/index.d.ts +2 -0
  32. package/dist/Checkbox/components/Label/Label.style.cjs +15 -3
  33. package/dist/Checkbox/components/Label/Label.style.js +15 -3
  34. package/dist/Chip/components/CloseButton/CloseButton.cjs +3 -1
  35. package/dist/Chip/components/CloseButton/CloseButton.js +3 -1
  36. package/dist/Chip/components/Compose/Compose.style.cjs +4 -1
  37. package/dist/Chip/components/Compose/Compose.style.js +4 -1
  38. package/dist/Drawer/components/Description/Description.cjs +3 -1
  39. package/dist/Drawer/components/Description/Description.js +3 -1
  40. package/dist/Helpers/contexts/Popper/PopperCollisionBoundaryManager.cjs +3 -1
  41. package/dist/Helpers/contexts/Popper/PopperCollisionBoundaryManager.js +3 -1
  42. package/dist/Helpers/contexts/PrimitiveContextState.cjs +28 -16
  43. package/dist/Helpers/contexts/PrimitiveContextState.js +28 -16
  44. package/dist/Helpers/contexts/SharedId.context.cjs +9 -5
  45. package/dist/Helpers/contexts/SharedId.context.js +9 -5
  46. package/dist/Helpers/css.utils.cjs +18 -4
  47. package/dist/Helpers/css.utils.d.ts +15 -3
  48. package/dist/Helpers/css.utils.js +18 -4
  49. package/dist/Helpers/hooks/useScrollable.cjs +3 -1
  50. package/dist/Helpers/hooks/useScrollable.js +3 -1
  51. package/dist/Helpers/react.utils.cjs +6 -2
  52. package/dist/Helpers/react.utils.js +6 -2
  53. package/dist/HighlightedIcon/HighlightedIcon.cjs +26 -0
  54. package/dist/HighlightedIcon/HighlightedIcon.d.ts +3 -0
  55. package/dist/HighlightedIcon/HighlightedIcon.js +26 -0
  56. package/dist/HighlightedIcon/HighlightedIcon.style.cjs +49 -0
  57. package/dist/HighlightedIcon/HighlightedIcon.style.d.ts +5 -0
  58. package/dist/HighlightedIcon/HighlightedIcon.style.js +47 -0
  59. package/dist/HighlightedIcon/HighlightedIcon.types.d.ts +8 -0
  60. package/dist/HighlightedIcon/index.d.ts +3 -0
  61. package/dist/Inputs/QuantityCounter/components/InputGroup/components/ValueLabel/ValueLabel.cjs +9 -5
  62. package/dist/Inputs/QuantityCounter/components/InputGroup/components/ValueLabel/ValueLabel.js +9 -5
  63. package/dist/Inputs/components/Compose/Compose.style.cjs +29 -6
  64. package/dist/Inputs/components/Compose/Compose.style.js +29 -6
  65. package/dist/Inputs/hooks/numericInput/numericInput.utils.cjs +12 -4
  66. package/dist/Inputs/hooks/numericInput/numericInput.utils.js +12 -4
  67. package/dist/Inputs/hooks/numericInput/useNumericInput.cjs +15 -3
  68. package/dist/Inputs/hooks/numericInput/useNumericInput.js +15 -3
  69. package/dist/Loader/Loader.cjs +1 -0
  70. package/dist/Loader/Loader.js +1 -0
  71. package/dist/Menu/components/Content/components/Item/Components/Compose/Compose.style.cjs +19 -4
  72. package/dist/Menu/components/Content/components/Item/Components/Compose/Compose.style.js +19 -4
  73. package/dist/Menu/components/Content/components/Label/components/Compose/Compose.style.cjs +4 -1
  74. package/dist/Menu/components/Content/components/Label/components/Compose/Compose.style.js +4 -1
  75. package/dist/Modal/components/Content/components/Compose/Compose.cjs +3 -1
  76. package/dist/Modal/components/Content/components/Compose/Compose.js +3 -1
  77. package/dist/Modal/components/Content/components/Description/Description.cjs +3 -1
  78. package/dist/Modal/components/Content/components/Description/Description.js +3 -1
  79. package/dist/MultiSelect/components/Compose/hooks/useMultiSelectContextApi.cjs +3 -1
  80. package/dist/MultiSelect/components/Compose/hooks/useMultiSelectContextApi.js +3 -1
  81. package/dist/MultiSelect/components/Trigger/components/MultiValue/MultiValue.cjs +3 -1
  82. package/dist/MultiSelect/components/Trigger/components/MultiValue/MultiValue.js +3 -1
  83. package/dist/Overflow/Overflow.cjs +3 -1
  84. package/dist/Overflow/Overflow.js +3 -1
  85. package/dist/Overflow/Overflow.utils.cjs +15 -6
  86. package/dist/Overflow/Overflow.utils.js +15 -6
  87. package/dist/Overflow/components/OverflowContainer/OverflowContainer.cjs +3 -1
  88. package/dist/Overflow/components/OverflowContainer/OverflowContainer.js +3 -1
  89. package/dist/Pagination/components/PageSizeSelect.cjs +3 -1
  90. package/dist/Pagination/components/PageSizeSelect.js +3 -1
  91. package/dist/Popover/components/Content/Content.cjs +3 -1
  92. package/dist/Popover/components/Content/Content.js +3 -1
  93. package/dist/Popover/components/Content/components/Footer/Footer.cjs +3 -1
  94. package/dist/Popover/components/Content/components/Footer/Footer.js +3 -1
  95. package/dist/RadioGroup/components/Item/components/Label/Label.style.cjs +15 -3
  96. package/dist/RadioGroup/components/Item/components/Label/Label.style.js +15 -3
  97. package/dist/ScreenReaderAnnounce/ScreenReaderAnnounce.cjs +3 -1
  98. package/dist/ScreenReaderAnnounce/ScreenReaderAnnounce.js +3 -1
  99. package/dist/Section/components/Header/components/CollapseButton/CollapseButton.cjs +3 -1
  100. package/dist/Section/components/Header/components/CollapseButton/CollapseButton.js +3 -1
  101. package/dist/Select/components/Content/components/Option/components/Compose/Compose.style.cjs +16 -4
  102. package/dist/Select/components/Content/components/Option/components/Compose/Compose.style.js +16 -4
  103. package/dist/Select/components/Content/components/OptionList/OptionList.cjs +6 -4
  104. package/dist/Select/components/Content/components/OptionList/OptionList.js +6 -4
  105. package/dist/Select/components/Content/components/OptionList/Virtual.cjs +9 -5
  106. package/dist/Select/components/Content/components/OptionList/Virtual.js +9 -5
  107. package/dist/Select/components/Context/hooks/useSearch.cjs +3 -1
  108. package/dist/Select/components/Context/hooks/useSearch.js +3 -1
  109. package/dist/Select/components/Trigger/components/Compose/Compose.style.cjs +33 -7
  110. package/dist/Select/components/Trigger/components/Compose/Compose.style.js +33 -7
  111. package/dist/SideBar/components/Item/Item.style.cjs +14 -3
  112. package/dist/SideBar/components/Item/Item.style.js +14 -3
  113. package/dist/Skeleton/components/Circle/Circle.cjs +1 -1
  114. package/dist/Skeleton/components/Circle/Circle.js +1 -1
  115. package/dist/Skeleton/components/Square/Square.cjs +1 -1
  116. package/dist/Skeleton/components/Square/Square.js +1 -1
  117. package/dist/Slider/components/Label/Compose/Compose.cjs +3 -1
  118. package/dist/Slider/components/Label/Compose/Compose.js +3 -1
  119. package/dist/Slider/components/Mark/Compose/Compose.cjs +3 -1
  120. package/dist/Slider/components/Mark/Compose/Compose.js +3 -1
  121. package/dist/Slider/hooks/useOffset.cjs +3 -1
  122. package/dist/Slider/hooks/useOffset.js +3 -1
  123. package/dist/Stepper/Stepper.cjs +14 -5
  124. package/dist/Stepper/Stepper.d.ts +2 -0
  125. package/dist/Stepper/Stepper.js +14 -5
  126. package/dist/Stepper/Stepper.utils.cjs +12 -0
  127. package/dist/Stepper/Stepper.utils.d.ts +2 -0
  128. package/dist/Stepper/Stepper.utils.js +12 -0
  129. package/dist/Stepper/components/Compose/Compose.d.ts +1 -0
  130. package/dist/Stepper/components/Step/Step.cjs +2 -0
  131. package/dist/Stepper/components/Step/Step.d.ts +1 -0
  132. package/dist/Stepper/components/Step/Step.js +2 -0
  133. package/dist/Stepper/components/Step/components/Compose/Compose.cjs +5 -10
  134. package/dist/Stepper/components/Step/components/Compose/Compose.js +5 -10
  135. package/dist/Stepper/components/Step/components/Separator/Separator.cjs +15 -0
  136. package/dist/Stepper/components/Step/components/Separator/Separator.d.ts +3 -0
  137. package/dist/Stepper/components/Step/components/Separator/Separator.js +15 -0
  138. package/dist/Stepper/components/Step/components/Separator/Separator.style.cjs +24 -0
  139. package/dist/Stepper/components/Step/components/Separator/Separator.style.d.ts +1 -0
  140. package/dist/Stepper/components/Step/components/Separator/Separator.style.js +22 -0
  141. package/dist/Stepper/components/Step/components/Separator/Separator.types.d.ts +5 -0
  142. package/dist/Stepper/hooks/useStepperInteractive.cjs +12 -4
  143. package/dist/Stepper/hooks/useStepperInteractive.js +12 -4
  144. package/dist/Switch/components/Switcher/Switcher.cjs +3 -1
  145. package/dist/Switch/components/Switcher/Switcher.js +3 -1
  146. package/dist/Switch/components/Switcher/Switcher.style.cjs +31 -8
  147. package/dist/Switch/components/Switcher/Switcher.style.js +31 -8
  148. package/dist/Tabs/components/TabBar/components/Trigger/components/Marker/Marker.style.cjs +24 -5
  149. package/dist/Tabs/components/TabBar/components/Trigger/components/Marker/Marker.style.js +24 -5
  150. package/dist/Tabs/components/TabBar/components/Trigger/components/Tab/Tab.style.cjs +24 -5
  151. package/dist/Tabs/components/TabBar/components/Trigger/components/Tab/Tab.style.js +24 -5
  152. package/dist/ThemeModeSwitch/useThemeModeSwitch.cjs +6 -2
  153. package/dist/ThemeModeSwitch/useThemeModeSwitch.js +6 -2
  154. package/dist/Toast/core/content.helper.cjs +8 -4
  155. package/dist/Toast/core/content.helper.js +8 -4
  156. package/dist/Tooltip/components/Content/Content.cjs +3 -1
  157. package/dist/Tooltip/components/Content/Content.js +3 -1
  158. package/dist/TreeView/TreeView.cjs +3 -1
  159. package/dist/TreeView/TreeView.js +3 -1
  160. package/dist/TreeView/components/TreeItem/components/Compose/Compose.cjs +6 -4
  161. package/dist/TreeView/components/TreeItem/components/Compose/Compose.js +6 -4
  162. package/dist/Typography/Typography.types.cjs +4 -0
  163. package/dist/Typography/Typography.types.d.ts +2 -1
  164. package/dist/Typography/Typography.types.js +4 -0
  165. package/dist/index.cjs +8 -0
  166. package/dist/index.d.ts +1 -0
  167. package/dist/index.js +98 -90
  168. package/package.json +10 -9
  169. package/skills/redis-ui-components/SKILL.md +126 -0
  170. package/skills/redis-ui-components/references/ActionIconButton.md +96 -0
  171. package/skills/redis-ui-components/references/AppBar.md +161 -0
  172. package/skills/redis-ui-components/references/AppSelectionMenu.md +184 -0
  173. package/skills/redis-ui-components/references/AutoCompleteSelect.md +193 -0
  174. package/skills/redis-ui-components/references/Badge.md +77 -0
  175. package/skills/redis-ui-components/references/Banner.md +563 -0
  176. package/skills/redis-ui-components/references/BoxSelectionGroup.md +487 -0
  177. package/skills/redis-ui-components/references/Breadcrumbs.md +214 -0
  178. package/skills/redis-ui-components/references/Button.md +169 -0
  179. package/skills/redis-ui-components/references/ButtonGroup.md +126 -0
  180. package/skills/redis-ui-components/references/Card.md +56 -0
  181. package/skills/redis-ui-components/references/Checkbox.md +171 -0
  182. package/skills/redis-ui-components/references/Chip.md +154 -0
  183. package/skills/redis-ui-components/references/ChipList.md +307 -0
  184. package/skills/redis-ui-components/references/CopyToClipboardButton.md +47 -0
  185. package/skills/redis-ui-components/references/CountryFlag.md +57 -0
  186. package/skills/redis-ui-components/references/Drawer.md +298 -0
  187. package/skills/redis-ui-components/references/Filters.md +162 -0
  188. package/skills/redis-ui-components/references/FlexDivider.md +152 -0
  189. package/skills/redis-ui-components/references/FlexGroup.md +149 -0
  190. package/skills/redis-ui-components/references/FlexItem.md +58 -0
  191. package/skills/redis-ui-components/references/FlexSplit.md +37 -0
  192. package/skills/redis-ui-components/references/FormField.md +678 -0
  193. package/skills/redis-ui-components/references/IconButton.md +63 -0
  194. package/skills/redis-ui-components/references/Input.md +295 -0
  195. package/skills/redis-ui-components/references/KeyValueList.md +501 -0
  196. package/skills/redis-ui-components/references/Label.md +238 -0
  197. package/skills/redis-ui-components/references/Link.md +402 -0
  198. package/skills/redis-ui-components/references/Loader.md +100 -0
  199. package/skills/redis-ui-components/references/Menu.md +988 -0
  200. package/skills/redis-ui-components/references/MidBar.md +358 -0
  201. package/skills/redis-ui-components/references/Modal.md +525 -0
  202. package/skills/redis-ui-components/references/MoreInfoIcon.md +119 -0
  203. package/skills/redis-ui-components/references/MultiSelect.md +558 -0
  204. package/skills/redis-ui-components/references/NumericInput.md +322 -0
  205. package/skills/redis-ui-components/references/Overflow.md +127 -0
  206. package/skills/redis-ui-components/references/Pagination.md +151 -0
  207. package/skills/redis-ui-components/references/PasswordInput.md +262 -0
  208. package/skills/redis-ui-components/references/Popover.md +868 -0
  209. package/skills/redis-ui-components/references/ProfileIcon.md +65 -0
  210. package/skills/redis-ui-components/references/ProgressBar.md +103 -0
  211. package/skills/redis-ui-components/references/QuantityCounter.md +555 -0
  212. package/skills/redis-ui-components/references/RadioGroup.md +265 -0
  213. package/skills/redis-ui-components/references/ScreenReaderAnnounce.md +147 -0
  214. package/skills/redis-ui-components/references/SearchBar.md +242 -0
  215. package/skills/redis-ui-components/references/SearchInput.md +213 -0
  216. package/skills/redis-ui-components/references/Section.md +349 -0
  217. package/skills/redis-ui-components/references/Select.md +517 -0
  218. package/skills/redis-ui-components/references/SideBar.md +468 -0
  219. package/skills/redis-ui-components/references/Slider.md +398 -0
  220. package/skills/redis-ui-components/references/Stepper.md +288 -0
  221. package/skills/redis-ui-components/references/Switch.md +193 -0
  222. package/skills/redis-ui-components/references/Tabs.md +383 -0
  223. package/skills/redis-ui-components/references/TextArea.md +139 -0
  224. package/skills/redis-ui-components/references/TextButton.md +217 -0
  225. package/skills/redis-ui-components/references/Toast.md +399 -0
  226. package/skills/redis-ui-components/references/ToggleButton.md +163 -0
  227. package/skills/redis-ui-components/references/Tooltip.md +636 -0
  228. package/skills/redis-ui-components/references/Typography.md +323 -0
@@ -0,0 +1,501 @@
1
+ # KeyValueList
2
+
3
+ A table for editing key-value pairs inline. It supports row deletion, custom key/value renderers, scrolling, and a companion add-row button.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import {
9
+ KeyValueList,
10
+ KeyValuePair,
11
+ RowInitializers,
12
+ UseKeyValueListReturn,
13
+ useKeyValueList
14
+ } from '@redislabsdev/redis-ui-components';
15
+ ```
16
+
17
+ > Also exported: `KeyValueList.AddButton` and `KeyValueListAddButtonProps`.
18
+
19
+ ## Props
20
+
21
+ | Prop | Type | Default | Description |
22
+ |------|------|---------|-------------|
23
+ | data | `KeyValuePair<TKey, TValue>[]` | - | Rows rendered by the table; each row needs a unique `id` |
24
+ | emptyStateMessage | `string` | `'There are no tags associated with this database'` | Empty-state copy shown when `data` is empty |
25
+ | onDelete | `(row: KeyValuePair<TKey, TValue>) => void` | - | Called when a row delete action is triggered |
26
+ | onKeyChange | `(row: KeyValuePair<TKey, TValue>, newKey: TKey) => void` | - | Called when the key field changes for a row |
27
+ | onValueChange | `(row: KeyValuePair<TKey, TValue>, newValue: TValue) => void` | - | Called when the value field changes for a row |
28
+ | renderKey | `(row: KeyValuePair<TKey, TValue>) => React.ReactNode` | - | Custom renderer for the key column |
29
+ | renderValue | `(row: KeyValuePair<TKey, TValue>) => React.ReactNode` | - | Custom renderer for the value column |
30
+ | maxHeight | `string` | - | Max height applied to the scroll container |
31
+ | keyPlaceholder | `string` | `'Enter key'` | Placeholder shown by the default key input |
32
+ | valuePlaceholder | `string` | `'Enter value'` | Placeholder shown by the default value input |
33
+
34
+ `KeyValueList` also extends `React.HTMLAttributes<HTMLDivElement>`.
35
+
36
+ ## Sub-components
37
+
38
+ - `KeyValueList.AddButton` - pre-styled add-row button with optional tooltip support.
39
+
40
+ ### KeyValueList.AddButton Props
41
+
42
+ | Prop | Type | Default | Description |
43
+ |------|------|---------|-------------|
44
+ | children | `React.ReactNode` | `'Add additional tag'` | Button label |
45
+ | tooltip | `React.ReactNode` | - | Optional tooltip content shown on hover |
46
+
47
+ `KeyValueList.AddButton` also extends `React.ButtonHTMLAttributes<HTMLButtonElement>` and forwards its ref to the underlying button.
48
+
49
+ ## Related Types
50
+
51
+ ### KeyValuePair
52
+
53
+ | Field | Type | Default | Description |
54
+ |------|------|---------|-------------|
55
+ | key | `TKey` | - | Row key value |
56
+ | value | `TValue` | - | Row value |
57
+ | id | `string` | - | Stable row identifier used as the React key |
58
+
59
+ ### RowInitializers
60
+
61
+ | Field | Type | Default | Description |
62
+ |------|------|---------|-------------|
63
+ | initializeKey | `() => TKey` | - | Creates the initial key for a new row |
64
+ | initializeValue | `() => TValue` | - | Creates the initial value for a new row |
65
+
66
+ ### UseKeyValueListReturn
67
+
68
+ | Field | Type | Default | Description |
69
+ |------|------|---------|-------------|
70
+ | data | `KeyValuePair<TKey, TValue>[]` | - | Current rows |
71
+ | handleAdd | `() => void` | - | Adds a new row using the initializers |
72
+ | handleDelete | `(row: KeyValuePair<TKey, TValue>) => void` | - | Removes a row |
73
+ | handleKeyChange | `(row: KeyValuePair<TKey, TValue>, newKey: TKey) => void` | - | Updates a row key |
74
+ | handleValueChange | `(row: KeyValuePair<TKey, TValue>, newValue: TValue) => void` | - | Updates a row value |
75
+ | setData | `React.Dispatch<React.SetStateAction<KeyValuePair<TKey, TValue>[]>>` | - | Direct state setter for the row array |
76
+
77
+ ### useKeyValueList
78
+
79
+ A convenience hook for managing `KeyValueList` row state.
80
+
81
+ | Parameter | Type | Default | Description |
82
+ |------|------|---------|-------------|
83
+ | initialData | `KeyValuePair<TKey, TValue>[]` | - | Initial rows seeded into the hook |
84
+ | initializers | `RowInitializers<TKey, TValue>` | - | Functions used when `handleAdd` creates a new row |
85
+
86
+ The hook returns a `UseKeyValueListReturn<TKey, TValue>` object with `data`, `handleAdd`, `handleDelete`, `handleKeyChange`, `handleValueChange`, and `setData`.
87
+
88
+ ## Examples
89
+
90
+ ### Basic Usage
91
+
92
+ > Interactive playground for KeyValueList component. Use the controls below to experiment with different props and configurations.
93
+
94
+ ```tsx
95
+ import { useRef } from 'react';
96
+ import { KeyValueList, KeyValuePair } from '@redislabsdev/redis-ui-components';
97
+ import { useArgState } from '../../helpers/useArgState';
98
+ import { sampleData } from './KeyValueList.data';
99
+
100
+ export function Render(args) {
101
+ const nextIdRef = useRef(sampleData.length);
102
+
103
+ const [data, handleDelete, setData] = useArgState({
104
+ arg: args.data as KeyValuePair<string, string>[],
105
+ event: args.onDelete,
106
+ getNewState: (items, [row]) => items.filter((item) => item.id !== row.id)
107
+ });
108
+
109
+ const handleKeyChange = (row: KeyValuePair<string, string>, newKey: string) => {
110
+ setData((prevData) =>
111
+ prevData.map((item) => (item.id === row.id ? { ...item, key: newKey } : item))
112
+ );
113
+ args.onKeyChange?.(row, newKey);
114
+ };
115
+
116
+ const handleValueChange = (row: KeyValuePair<string, string>, newValue: string) => {
117
+ setData((prevData) =>
118
+ prevData.map((item) => (item.id === row.id ? { ...item, value: newValue } : item))
119
+ );
120
+ args.onValueChange?.(row, newValue);
121
+ };
122
+
123
+ const handleAdd = () => {
124
+ const newRow: KeyValuePair<string, string> = {
125
+ id: `row-${nextIdRef.current}`,
126
+ key: '',
127
+ value: ''
128
+ };
129
+ nextIdRef.current += 1;
130
+ setData((prevData) => [...prevData, newRow]);
131
+ };
132
+
133
+ return (
134
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
135
+ <KeyValueList<string, string>
136
+ maxHeight={args.maxHeight}
137
+ emptyStateMessage={args.emptyStateMessage}
138
+ data={data}
139
+ onKeyChange={handleKeyChange}
140
+ onValueChange={handleValueChange}
141
+ onDelete={handleDelete}
142
+ />
143
+ <KeyValueList.AddButton onClick={handleAdd} />
144
+ </div>
145
+ );
146
+ }
147
+ ```
148
+
149
+ ### SimpleInput
150
+
151
+ > Basic example showing KeyValueList with simple text inputs for both keys and values. This is the most common use case with default rendering.
152
+
153
+ ```tsx
154
+ import { KeyValueList, useKeyValueList } from '@redislabsdev/redis-ui-components';
155
+ import { sampleData } from './KeyValueList.data';
156
+
157
+ export function Render() {
158
+ const { data, handleAdd, handleDelete, handleKeyChange, handleValueChange } = useKeyValueList(
159
+ sampleData,
160
+ {
161
+ initializeKey: () => '',
162
+ initializeValue: () => ''
163
+ }
164
+ );
165
+
166
+ return (
167
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
168
+ <KeyValueList
169
+ data={data}
170
+ onKeyChange={handleKeyChange}
171
+ onValueChange={handleValueChange}
172
+ onDelete={handleDelete}
173
+ />
174
+ <KeyValueList.AddButton onClick={handleAdd} />
175
+ </div>
176
+ );
177
+ }
178
+ ```
179
+
180
+ ### EmptyState
181
+
182
+ > Demonstrates the default empty state when no data is present. The component displays a default message prompting users to add their first row.
183
+
184
+ ```tsx
185
+ import { KeyValueList, useKeyValueList } from '@redislabsdev/redis-ui-components';
186
+ import { emptyData } from './KeyValueList.data';
187
+
188
+ export function Render() {
189
+ const { data, handleAdd, handleDelete } = useKeyValueList(emptyData, {
190
+ initializeKey: () => '',
191
+ initializeValue: () => ''
192
+ });
193
+
194
+ return (
195
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
196
+ <KeyValueList data={data} onDelete={handleDelete} />
197
+ <KeyValueList.AddButton onClick={handleAdd} />
198
+ </div>
199
+ );
200
+ }
201
+ ```
202
+
203
+ ### CustomEmptyState
204
+
205
+ > Shows how to customize the empty state message using the `emptyStateMessage` prop. You can also customize the AddButton text to match your use case.
206
+
207
+ ```tsx
208
+ import { KeyValueList, useKeyValueList } from '@redislabsdev/redis-ui-components';
209
+ import { emptyData } from './KeyValueList.data';
210
+
211
+ export function Render() {
212
+ const { data, handleAdd, handleDelete } = useKeyValueList(emptyData, {
213
+ initializeKey: () => '',
214
+ initializeValue: () => ''
215
+ });
216
+
217
+ return (
218
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
219
+ <KeyValueList
220
+ data={data}
221
+ emptyStateMessage="🏷️ No labels found. Start by adding your first label!"
222
+ onDelete={handleDelete}
223
+ />
224
+ <KeyValueList.AddButton onClick={handleAdd}>Add new label</KeyValueList.AddButton>
225
+ </div>
226
+ );
227
+ }
228
+ ```
229
+
230
+ ### WithDropdown
231
+
232
+ > Demonstrates using a dropdown (Select) for keys with predefined options. Use the `renderKey` prop to provide custom rendering for the key column.
233
+
234
+ ```tsx
235
+ import { KeyValueList, KeyValuePair, Select, useKeyValueList } from '@redislabsdev/redis-ui-components';
236
+ import { keyOptions, sampleData } from './KeyValueList.data';
237
+
238
+ const renderKeyWithDropdown = (
239
+ row: KeyValuePair<string, string>,
240
+ handleKeyChange: (row: KeyValuePair<string, string>, newKey: string) => void
241
+ ) => (
242
+ <Select
243
+ options={keyOptions}
244
+ value={row.key}
245
+ onChange={(newKey) => handleKeyChange(row, newKey)}
246
+ placeholder="Select key"
247
+ />
248
+ );
249
+
250
+ export function Render() {
251
+ const { data, handleAdd, handleDelete, handleKeyChange, handleValueChange } = useKeyValueList(
252
+ sampleData,
253
+ {
254
+ initializeKey: () => '',
255
+ initializeValue: () => ''
256
+ }
257
+ );
258
+
259
+ return (
260
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
261
+ <KeyValueList
262
+ data={data}
263
+ renderKey={(row) => renderKeyWithDropdown(row, handleKeyChange)}
264
+ onValueChange={handleValueChange}
265
+ onDelete={handleDelete}
266
+ />
267
+ <KeyValueList.AddButton onClick={handleAdd} />
268
+ </div>
269
+ );
270
+ }
271
+ ```
272
+
273
+ ### WithSuggestions
274
+
275
+ > Shows how to use AutoCompleteSelect for values with suggestions. Users can select from predefined options or enter custom values. Use the `renderValue` prop for custom value rendering.
276
+
277
+ ```tsx
278
+ import { AutoCompleteSelect, KeyValueList, KeyValuePair, useKeyValueList } from '@redislabsdev/redis-ui-components';
279
+ import { suggestionOptions, sampleData } from './KeyValueList.data';
280
+
281
+ const renderValueWithSuggestions = (
282
+ row: KeyValuePair<string, string>,
283
+ handleValueChange: (row: KeyValuePair<string, string>, newValue: string) => void
284
+ ) => (
285
+ <AutoCompleteSelect
286
+ options={suggestionOptions}
287
+ value={row.value}
288
+ onChange={(newValue) => handleValueChange(row, newValue)}
289
+ placeholder="Select or type value"
290
+ manualOptionText="Use custom value"
291
+ optionsLabel="Suggestions"
292
+ />
293
+ );
294
+
295
+ export function Render() {
296
+ const { data, handleAdd, handleDelete, handleKeyChange, handleValueChange } = useKeyValueList(
297
+ sampleData,
298
+ {
299
+ initializeKey: () => '',
300
+ initializeValue: () => ''
301
+ }
302
+ );
303
+
304
+ return (
305
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
306
+ <KeyValueList
307
+ data={data}
308
+ onKeyChange={handleKeyChange}
309
+ renderValue={(row) => renderValueWithSuggestions(row, handleValueChange)}
310
+ onDelete={handleDelete}
311
+ />
312
+ <KeyValueList.AddButton onClick={handleAdd} />
313
+ </div>
314
+ );
315
+ }
316
+ ```
317
+
318
+ ### WithMaxHeightAndMaxRows
319
+
320
+ > Demonstrates using `maxHeight` prop to control table scrolling and implementing a maximum row limit. The AddButton shows a tooltip when the maximum is reached using the `disabled` and `tooltip` props.
321
+
322
+ ```tsx
323
+ import { KeyValueList, useKeyValueList } from '@redislabsdev/redis-ui-components';
324
+ import { largeData } from './KeyValueList.data';
325
+
326
+ export function Render() {
327
+ const maxRows = 10;
328
+ const { data, handleAdd, handleDelete, handleKeyChange, handleValueChange } = useKeyValueList(
329
+ largeData.slice(0, 8),
330
+ {
331
+ initializeKey: () => '',
332
+ initializeValue: () => ''
333
+ }
334
+ );
335
+
336
+ const isMaxReached = data.length >= maxRows;
337
+
338
+ return (
339
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
340
+ <KeyValueList
341
+ data={data}
342
+ maxHeight="200px"
343
+ onKeyChange={handleKeyChange}
344
+ onValueChange={handleValueChange}
345
+ onDelete={handleDelete}
346
+ />
347
+ <KeyValueList.AddButton
348
+ onClick={handleAdd}
349
+ disabled={isMaxReached}
350
+ tooltip={isMaxReached ? 'Maximum of 10 rows reached' : undefined}
351
+ />
352
+ </div>
353
+ );
354
+ }
355
+ ```
356
+
357
+ ### WithKeyValidation
358
+
359
+ > Example showing how to implement validation for keys using the `renderKey` prop with custom Input components. This demonstrates required field validation, format validation, and uniqueness checks.
360
+
361
+ ```tsx
362
+ import { useState } from 'react';
363
+ import { Input, KeyValueList, KeyValuePair, useKeyValueList } from '@redislabsdev/redis-ui-components';
364
+ import { sampleData } from './KeyValueList.data';
365
+
366
+ const renderKeyWithValidation = (
367
+ row: KeyValuePair<string, string>,
368
+ options: {
369
+ touchedFields: Set<string>;
370
+ validateKey: (key: string) => string | undefined;
371
+ handleKeyChange: (row: KeyValuePair<string, string>, newKey: string) => void;
372
+ handleFieldTouch: (rowId: string) => void;
373
+ }
374
+ ) => {
375
+ const { touchedFields, validateKey, handleKeyChange, handleFieldTouch } = options;
376
+ const isTouched = touchedFields.has(row.id);
377
+ const errorMessage = isTouched ? validateKey(row.key) : undefined;
378
+
379
+ return (
380
+ <Input
381
+ value={row.key}
382
+ onChange={(newKey) => handleKeyChange(row, newKey)}
383
+ onBlur={() => handleFieldTouch(row.id)}
384
+ placeholder="Enter key"
385
+ error={errorMessage}
386
+ />
387
+ );
388
+ };
389
+
390
+ export function Render() {
391
+ const [touchedFields, setTouchedFields] = useState<Set<string>>(new Set());
392
+ const { data, handleAdd, handleDelete, handleKeyChange, handleValueChange } = useKeyValueList(
393
+ sampleData,
394
+ {
395
+ initializeKey: () => '',
396
+ initializeValue: () => ''
397
+ }
398
+ );
399
+
400
+ const validateKey = (key: string): string | undefined => {
401
+ if (!key || key.trim() === '') {
402
+ return 'Key is required';
403
+ }
404
+
405
+ if (key.includes(' ')) {
406
+ return 'Key cannot contain spaces';
407
+ }
408
+
409
+ const duplicateCount = data.filter((item) => item.key === key).length;
410
+
411
+ if (duplicateCount > 1) {
412
+ return 'Key must be unique';
413
+ }
414
+
415
+ return undefined;
416
+ };
417
+
418
+ const handleFieldTouch = (rowId: string) => {
419
+ setTouchedFields((prev) => new Set(prev).add(rowId));
420
+ };
421
+
422
+ return (
423
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
424
+ <KeyValueList
425
+ data={data}
426
+ renderKey={(row) =>
427
+ renderKeyWithValidation(row, {
428
+ touchedFields,
429
+ validateKey,
430
+ handleKeyChange,
431
+ handleFieldTouch
432
+ })
433
+ }
434
+ onValueChange={handleValueChange}
435
+ onDelete={handleDelete}
436
+ />
437
+ <KeyValueList.AddButton onClick={handleAdd} />
438
+ </div>
439
+ );
440
+ }
441
+ ```
442
+
443
+ ### WithCustomAddButton
444
+
445
+ > Shows how to implement a completely custom add button instead of using `KeyValueList.AddButton`. You can use any button component and add custom UI elements like row counters, multiple buttons, or custom styling.
446
+
447
+ ```tsx
448
+ import { Button, KeyValueList, Tooltip, useKeyValueList } from '@redislabsdev/redis-ui-components';
449
+ import { PlusIcon } from '@redislabsdev/redis-ui-icons';
450
+ import { sampleData } from './KeyValueList.data';
451
+
452
+ export function Render() {
453
+ const maxRows = 5;
454
+ const { data, handleAdd, handleDelete, handleKeyChange, handleValueChange } = useKeyValueList(
455
+ sampleData,
456
+ {
457
+ initializeKey: () => '',
458
+ initializeValue: () => ''
459
+ }
460
+ );
461
+
462
+ const isMaxReached = data.length >= maxRows;
463
+
464
+ return (
465
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1.6rem' }}>
466
+ <KeyValueList
467
+ data={data}
468
+ onKeyChange={handleKeyChange}
469
+ onValueChange={handleValueChange}
470
+ onDelete={handleDelete}
471
+ />
472
+
473
+ <div style={{ display: 'flex', gap: '1.2rem', alignItems: 'center' }}>
474
+ <Tooltip content={isMaxReached ? `Maximum of ${maxRows} rows reached` : undefined}>
475
+ <Button size="medium" variant="primary" onClick={handleAdd} disabled={isMaxReached}>
476
+ <Button.Icon icon={PlusIcon} />
477
+ Add Custom Row
478
+ </Button>
479
+ </Tooltip>
480
+ <span style={{ fontSize: '1.4rem', color: '#666' }}>
481
+ {data.length} / {maxRows} rows
482
+ </span>
483
+ </div>
484
+ </div>
485
+ );
486
+ }
487
+ ```
488
+
489
+ ## Notes
490
+
491
+ - `Playground` is an interactive playground for experimenting with different props and configurations.
492
+ - `SimpleInput` is the default editing flow with plain `Input` fields.
493
+ - `EmptyState` shows the default empty-state copy when no rows exist.
494
+ - `CustomEmptyState` shows how to override the empty-state message and the add-button label.
495
+ - `WithDropdown` uses `renderKey` to swap the key cell for `Select`.
496
+ - `WithSuggestions` uses `renderValue` to swap the value cell for `AutoCompleteSelect`.
497
+ - `WithMaxHeightAndMaxRows` demonstrates `maxHeight` plus a disabled add button with tooltip when the maximum row count is reached.
498
+ - `WithKeyValidation` shows required, format, and uniqueness validation via `renderKey`.
499
+ - `WithCustomAddButton` shows how to replace `KeyValueList.AddButton` with fully custom button UI.
500
+ - `KeyValueList.AddButton` supports optional tooltip content and forwards refs to the underlying button.
501
+ - The default empty-state message is `There are no tags associated with this database`.