@redis-ui/components 43.0.2 → 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.
- package/dist/HighlightedIcon/HighlightedIcon.cjs +26 -0
- package/dist/HighlightedIcon/HighlightedIcon.d.ts +3 -0
- package/dist/HighlightedIcon/HighlightedIcon.js +26 -0
- package/dist/HighlightedIcon/HighlightedIcon.style.cjs +49 -0
- package/dist/HighlightedIcon/HighlightedIcon.style.d.ts +5 -0
- package/dist/HighlightedIcon/HighlightedIcon.style.js +47 -0
- package/dist/HighlightedIcon/HighlightedIcon.types.d.ts +8 -0
- package/dist/HighlightedIcon/index.d.ts +3 -0
- package/dist/Stepper/Stepper.cjs +14 -5
- package/dist/Stepper/Stepper.d.ts +2 -0
- package/dist/Stepper/Stepper.js +14 -5
- package/dist/Stepper/Stepper.utils.cjs +12 -0
- package/dist/Stepper/Stepper.utils.d.ts +2 -0
- package/dist/Stepper/Stepper.utils.js +12 -0
- package/dist/Stepper/components/Compose/Compose.d.ts +1 -0
- package/dist/Stepper/components/Step/Step.cjs +2 -0
- package/dist/Stepper/components/Step/Step.d.ts +1 -0
- package/dist/Stepper/components/Step/Step.js +2 -0
- package/dist/Stepper/components/Step/components/Compose/Compose.cjs +2 -9
- package/dist/Stepper/components/Step/components/Compose/Compose.js +2 -9
- package/dist/Stepper/components/Step/components/Separator/Separator.cjs +15 -0
- package/dist/Stepper/components/Step/components/Separator/Separator.d.ts +3 -0
- package/dist/Stepper/components/Step/components/Separator/Separator.js +15 -0
- package/dist/Stepper/components/Step/components/Separator/Separator.style.cjs +24 -0
- package/dist/Stepper/components/Step/components/Separator/Separator.style.d.ts +1 -0
- package/dist/Stepper/components/Step/components/Separator/Separator.style.js +22 -0
- package/dist/Stepper/components/Step/components/Separator/Separator.types.d.ts +5 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +74 -70
- package/package.json +2 -2
- package/skills/redis-ui-components/SKILL.md +0 -2
- package/skills/redis-ui-components/references/ActionIconButton.md +96 -0
- package/skills/redis-ui-components/references/AppBar.md +161 -0
- package/skills/redis-ui-components/references/AppSelectionMenu.md +184 -0
- package/skills/redis-ui-components/references/AutoCompleteSelect.md +193 -0
- package/skills/redis-ui-components/references/Badge.md +77 -0
- package/skills/redis-ui-components/references/Banner.md +563 -0
- package/skills/redis-ui-components/references/BoxSelectionGroup.md +487 -0
- package/skills/redis-ui-components/references/Breadcrumbs.md +214 -0
- package/skills/redis-ui-components/references/ButtonGroup.md +126 -0
- package/skills/redis-ui-components/references/Card.md +56 -0
- package/skills/redis-ui-components/references/Checkbox.md +171 -0
- package/skills/redis-ui-components/references/Chip.md +154 -0
- package/skills/redis-ui-components/references/ChipList.md +307 -0
- package/skills/redis-ui-components/references/CopyToClipboardButton.md +47 -0
- package/skills/redis-ui-components/references/CountryFlag.md +57 -0
- package/skills/redis-ui-components/references/Drawer.md +298 -0
- package/skills/redis-ui-components/references/Filters.md +162 -0
- package/skills/redis-ui-components/references/FormField.md +678 -0
- package/skills/redis-ui-components/references/IconButton.md +63 -0
- package/skills/redis-ui-components/references/Input.md +295 -0
- package/skills/redis-ui-components/references/KeyValueList.md +501 -0
- package/skills/redis-ui-components/references/Label.md +238 -0
- package/skills/redis-ui-components/references/Link.md +402 -0
- package/skills/redis-ui-components/references/Loader.md +100 -0
- package/skills/redis-ui-components/references/Menu.md +988 -0
- package/skills/redis-ui-components/references/MidBar.md +358 -0
- package/skills/redis-ui-components/references/Modal.md +525 -0
- package/skills/redis-ui-components/references/MoreInfoIcon.md +119 -0
- package/skills/redis-ui-components/references/MultiSelect.md +558 -0
- package/skills/redis-ui-components/references/NumericInput.md +322 -0
- package/skills/redis-ui-components/references/Overflow.md +127 -0
- package/skills/redis-ui-components/references/Pagination.md +151 -0
- package/skills/redis-ui-components/references/PasswordInput.md +262 -0
- package/skills/redis-ui-components/references/Popover.md +868 -0
- package/skills/redis-ui-components/references/ProfileIcon.md +65 -0
- package/skills/redis-ui-components/references/ProgressBar.md +103 -0
- package/skills/redis-ui-components/references/QuantityCounter.md +555 -0
- package/skills/redis-ui-components/references/RadioGroup.md +265 -0
- package/skills/redis-ui-components/references/ScreenReaderAnnounce.md +147 -0
- package/skills/redis-ui-components/references/SearchBar.md +242 -0
- package/skills/redis-ui-components/references/SearchInput.md +213 -0
- package/skills/redis-ui-components/references/Section.md +349 -0
- package/skills/redis-ui-components/references/SideBar.md +468 -0
- package/skills/redis-ui-components/references/Slider.md +398 -0
- package/skills/redis-ui-components/references/Stepper.md +288 -0
- package/skills/redis-ui-components/references/Switch.md +193 -0
- package/skills/redis-ui-components/references/Tabs.md +383 -0
- package/skills/redis-ui-components/references/TextArea.md +139 -0
- package/skills/redis-ui-components/references/TextButton.md +217 -0
- package/skills/redis-ui-components/references/Toast.md +399 -0
- package/skills/redis-ui-components/references/ToggleButton.md +163 -0
- package/skills/redis-ui-components/references/Tooltip.md +636 -0
- 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`.
|