@ceed/ads 1.23.2 → 1.23.4
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/components/data-display/Badge.md +71 -39
- package/dist/components/data-display/InfoSign.md +74 -98
- package/dist/components/data-display/Typography.md +310 -61
- package/dist/components/feedback/CircularProgress.md +257 -0
- package/dist/components/feedback/Dialog.md +8 -4
- package/dist/components/feedback/Modal.md +7 -3
- package/dist/components/feedback/Skeleton.md +280 -0
- package/dist/components/feedback/llms.txt +2 -0
- package/dist/components/inputs/ButtonGroup.md +115 -106
- package/dist/components/inputs/Calendar.md +98 -459
- package/dist/components/inputs/CurrencyInput.md +181 -8
- package/dist/components/inputs/DatePicker.md +108 -436
- package/dist/components/inputs/DateRangePicker.md +130 -496
- package/dist/components/inputs/FilterMenu.md +169 -19
- package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
- package/dist/components/inputs/FormControl.md +368 -0
- package/dist/components/inputs/IconButton.md +137 -88
- package/dist/components/inputs/MonthPicker.md +95 -427
- package/dist/components/inputs/MonthRangePicker.md +89 -471
- package/dist/components/inputs/PercentageInput.md +183 -19
- package/dist/components/inputs/RadioButton.md +163 -35
- package/dist/components/inputs/RadioList.md +241 -0
- package/dist/components/inputs/RadioTileGroup.md +146 -62
- package/dist/components/inputs/Select.md +219 -328
- package/dist/components/inputs/Slider.md +334 -0
- package/dist/components/inputs/Switch.md +136 -376
- package/dist/components/inputs/Textarea.md +209 -11
- package/dist/components/inputs/Uploader/Uploader.md +145 -66
- package/dist/components/inputs/llms.txt +3 -0
- package/dist/components/navigation/Breadcrumbs.md +80 -322
- package/dist/components/navigation/Dropdown.md +92 -221
- package/dist/components/navigation/IconMenuButton.md +40 -502
- package/dist/components/navigation/InsetDrawer.md +68 -738
- package/dist/components/navigation/Link.md +39 -298
- package/dist/components/navigation/Menu.md +92 -285
- package/dist/components/navigation/MenuButton.md +55 -448
- package/dist/components/navigation/Pagination.md +47 -338
- package/dist/components/navigation/ProfileMenu.md +45 -268
- package/dist/components/navigation/Stepper.md +160 -28
- package/dist/components/navigation/Tabs.md +57 -316
- package/dist/components/surfaces/Sheet.md +150 -333
- package/dist/guides/ThemeProvider.md +116 -0
- package/dist/guides/llms.txt +9 -0
- package/dist/llms.txt +8 -0
- package/package.json +1 -1
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
FilterMenu
|
|
5
|
+
FilterMenu is a comprehensive filtering component that supports multiple filter types within a single dropdown panel. It enables users to apply, combine, and reset various filters -- including checkboxes, radio buttons, date ranges, currency inputs, percentage inputs, and autocomplete fields -- through a consistent, organized interface.
|
|
6
|
+
|
|
7
|
+
FilterMenu is ideal for data-heavy admin interfaces such as tables, lists, and dashboards where users need to narrow down results based on multiple criteria. It supports both controlled and uncontrolled state management, allowing flexible integration with different state architectures.
|
|
6
8
|
|
|
7
9
|
```tsx
|
|
8
10
|
<FilterMenu {...args} defaultValues={values} onChange={newValues => {
|
|
@@ -57,11 +59,11 @@ function MyComponent() {
|
|
|
57
59
|
|
|
58
60
|
## Filter Types
|
|
59
61
|
|
|
60
|
-
FilterMenu
|
|
62
|
+
FilterMenu supports the following filter types. Each type is configured through the `filters` array prop.
|
|
61
63
|
|
|
62
64
|
### Checkbox Group
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
Multi-select filter with checkboxes. The selected values are stored as an array.
|
|
65
67
|
|
|
66
68
|
```tsx
|
|
67
69
|
{
|
|
@@ -77,7 +79,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
77
79
|
|
|
78
80
|
### Filterable Checkbox Group
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
A searchable checkbox group for long option lists. Includes a text input to filter visible options.
|
|
81
83
|
|
|
82
84
|
```tsx
|
|
83
85
|
{
|
|
@@ -87,7 +89,6 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
87
89
|
options: [
|
|
88
90
|
{ label: 'Electronics', value: 'electronics' },
|
|
89
91
|
{ label: 'Clothing', value: 'clothing' },
|
|
90
|
-
{ label: 'Food', value: 'food' },
|
|
91
92
|
{ label: 'Books', value: 'books' },
|
|
92
93
|
],
|
|
93
94
|
placeholder: 'Search categories...',
|
|
@@ -97,7 +98,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
97
98
|
|
|
98
99
|
### Radio Group
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
Single-select filter with radio buttons. The selected value is stored as a single string.
|
|
101
102
|
|
|
102
103
|
```tsx
|
|
103
104
|
{
|
|
@@ -114,7 +115,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
114
115
|
|
|
115
116
|
### Date Range
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+
A date range picker filter. The value is stored as a two-element array of date strings.
|
|
118
119
|
|
|
119
120
|
```tsx
|
|
120
121
|
{
|
|
@@ -129,7 +130,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
129
130
|
|
|
130
131
|
### Currency Input
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
A single currency value input field.
|
|
133
134
|
|
|
134
135
|
```tsx
|
|
135
136
|
{
|
|
@@ -143,7 +144,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
143
144
|
|
|
144
145
|
### Currency Range
|
|
145
146
|
|
|
146
|
-
|
|
147
|
+
A currency range filter with min and max inputs.
|
|
147
148
|
|
|
148
149
|
```tsx
|
|
149
150
|
{
|
|
@@ -157,7 +158,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
157
158
|
|
|
158
159
|
### Percentage Input
|
|
159
160
|
|
|
160
|
-
|
|
161
|
+
A single percentage value input field.
|
|
161
162
|
|
|
162
163
|
```tsx
|
|
163
164
|
{
|
|
@@ -172,7 +173,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
172
173
|
|
|
173
174
|
### Percentage Range
|
|
174
175
|
|
|
175
|
-
|
|
176
|
+
A percentage range filter with min and max inputs.
|
|
176
177
|
|
|
177
178
|
```tsx
|
|
178
179
|
{
|
|
@@ -186,7 +187,7 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
186
187
|
|
|
187
188
|
### Autocomplete
|
|
188
189
|
|
|
189
|
-
|
|
190
|
+
A searchable single-select filter with autocomplete support.
|
|
190
191
|
|
|
191
192
|
```tsx
|
|
192
193
|
{
|
|
@@ -202,6 +203,8 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
202
203
|
|
|
203
204
|
### Controlled Mode
|
|
204
205
|
|
|
206
|
+
In controlled mode, you manage the filter state externally using `values` (or `defaultValues` with an `onChange` handler).
|
|
207
|
+
|
|
205
208
|
```tsx
|
|
206
209
|
<FilterMenu {...args} defaultValues={values} onChange={newValues => {
|
|
207
210
|
setValues(newValues);
|
|
@@ -211,20 +214,167 @@ FilterMenu는 다음과 같은 필터 타입을 지원합니다:
|
|
|
211
214
|
|
|
212
215
|
### Uncontrolled Mode
|
|
213
216
|
|
|
217
|
+
In uncontrolled mode, FilterMenu manages its own internal state. This is useful when you only need the final filter values on submission.
|
|
218
|
+
|
|
214
219
|
```tsx
|
|
215
220
|
<FilterMenu />
|
|
216
221
|
```
|
|
217
222
|
|
|
223
|
+
## Common Use Cases
|
|
224
|
+
|
|
225
|
+
### Table Filters
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
function DataTable() {
|
|
229
|
+
const [filters, setFilters] = useState({});
|
|
230
|
+
const { data } = useQuery(['items', filters], () => fetchItems(filters));
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<Box>
|
|
234
|
+
<FilterMenu
|
|
235
|
+
filters={[
|
|
236
|
+
{
|
|
237
|
+
id: 'status',
|
|
238
|
+
type: 'checkbox-group',
|
|
239
|
+
label: 'Status',
|
|
240
|
+
options: [
|
|
241
|
+
{ label: 'Active', value: 'active' },
|
|
242
|
+
{ label: 'Pending', value: 'pending' },
|
|
243
|
+
{ label: 'Archived', value: 'archived' },
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
id: 'dateRange',
|
|
248
|
+
type: 'date-range',
|
|
249
|
+
label: 'Created Date',
|
|
250
|
+
displayFormat: 'MM/DD/YYYY',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: 'amount',
|
|
254
|
+
type: 'currency-range',
|
|
255
|
+
label: 'Amount',
|
|
256
|
+
currency: 'USD',
|
|
257
|
+
},
|
|
258
|
+
]}
|
|
259
|
+
defaultValues={filters}
|
|
260
|
+
onChange={setFilters}
|
|
261
|
+
useReset
|
|
262
|
+
/>
|
|
263
|
+
<Table data={data} />
|
|
264
|
+
</Box>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Dashboard Filters
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
function DashboardFilters({ onFilterChange }) {
|
|
273
|
+
return (
|
|
274
|
+
<FilterMenu
|
|
275
|
+
filters={[
|
|
276
|
+
{
|
|
277
|
+
id: 'region',
|
|
278
|
+
type: 'filterable-checkbox-group',
|
|
279
|
+
label: 'Region',
|
|
280
|
+
options: regions.map((r) => ({ label: r.name, value: r.id })),
|
|
281
|
+
placeholder: 'Search regions...',
|
|
282
|
+
maxHeight: 200,
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: 'period',
|
|
286
|
+
type: 'radio-group',
|
|
287
|
+
label: 'Time Period',
|
|
288
|
+
options: [
|
|
289
|
+
{ label: 'Last 7 days', value: '7d' },
|
|
290
|
+
{ label: 'Last 30 days', value: '30d' },
|
|
291
|
+
{ label: 'Last 90 days', value: '90d' },
|
|
292
|
+
{ label: 'Custom', value: 'custom' },
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
]}
|
|
296
|
+
onChange={onFilterChange}
|
|
297
|
+
useReset
|
|
298
|
+
/>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Invoice Filters
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
function InvoiceFilters({ onFilterChange }) {
|
|
307
|
+
return (
|
|
308
|
+
<FilterMenu
|
|
309
|
+
filters={[
|
|
310
|
+
{
|
|
311
|
+
id: 'status',
|
|
312
|
+
type: 'checkbox-group',
|
|
313
|
+
label: 'Invoice Status',
|
|
314
|
+
options: [
|
|
315
|
+
{ label: 'Paid', value: 'paid' },
|
|
316
|
+
{ label: 'Pending', value: 'pending' },
|
|
317
|
+
{ label: 'Overdue', value: 'overdue' },
|
|
318
|
+
],
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: 'amount',
|
|
322
|
+
type: 'currency-range',
|
|
323
|
+
label: 'Amount Range',
|
|
324
|
+
currency: 'USD',
|
|
325
|
+
useMinorUnit: true,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: 'date',
|
|
329
|
+
type: 'date-range',
|
|
330
|
+
label: 'Invoice Date',
|
|
331
|
+
displayFormat: 'MM/DD/YYYY',
|
|
332
|
+
},
|
|
333
|
+
]}
|
|
334
|
+
onChange={onFilterChange}
|
|
335
|
+
useReset
|
|
336
|
+
/>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
218
341
|
## Best Practices
|
|
219
342
|
|
|
220
|
-
1.
|
|
343
|
+
1. **Use unique filter IDs**: Each filter's `id` must be unique since it serves as the key for state management.
|
|
344
|
+
|
|
345
|
+
```tsx
|
|
346
|
+
// ✅ Good: Unique IDs
|
|
347
|
+
filters={[
|
|
348
|
+
{ id: 'status', type: 'checkbox-group', ... },
|
|
349
|
+
{ id: 'priority', type: 'radio-group', ... },
|
|
350
|
+
]}
|
|
351
|
+
|
|
352
|
+
// ❌ Bad: Duplicate IDs cause state conflicts
|
|
353
|
+
filters={[
|
|
354
|
+
{ id: 'filter1', type: 'checkbox-group', ... },
|
|
355
|
+
{ id: 'filter1', type: 'radio-group', ... },
|
|
356
|
+
]}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
2. **Choose the right reset strategy**: Use `useReset` when the FilterMenu contains multiple filters that users may want to clear all at once. Use `useClear` for single-filter scenarios.
|
|
360
|
+
|
|
361
|
+
3. **Provide descriptive labels**: Each filter should have a clear `label` that tells users what they are filtering. Avoid generic names like "Filter 1".
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
// ✅ Good: Descriptive labels
|
|
365
|
+
{ id: 'invoiceStatus', type: 'checkbox-group', label: 'Invoice Status', ... }
|
|
366
|
+
|
|
367
|
+
// ❌ Bad: Vague labels
|
|
368
|
+
{ id: 'filter1', type: 'checkbox-group', label: 'Options', ... }
|
|
369
|
+
```
|
|
221
370
|
|
|
222
|
-
|
|
371
|
+
4. **Use filterable checkbox groups for long lists**: When an option list exceeds 8-10 items, switch from `checkbox-group` to `filterable-checkbox-group` so users can search rather than scroll.
|
|
223
372
|
|
|
224
|
-
|
|
225
|
-
- `useReset`: 여러 필터가 있을 때 모든 필터를 초기화
|
|
226
|
-
- `useClear`: 단일 필터만 있을 때 해당 필터를 초기화
|
|
373
|
+
5. **Prefer controlled mode for complex state**: When filter values need to be synced with URL parameters, API requests, or other UI elements, use the controlled pattern with `values` and `onChange`.
|
|
227
374
|
|
|
228
|
-
|
|
375
|
+
## Accessibility
|
|
229
376
|
|
|
230
|
-
|
|
377
|
+
- Each filter section is labeled with its `label` prop, providing clear context for screen readers.
|
|
378
|
+
- Checkbox and radio groups follow standard form control patterns with proper labeling.
|
|
379
|
+
- The reset button is keyboard-accessible and clearly labeled, allowing users to quickly clear all filters.
|
|
380
|
+
- Use the `placeholder` prop on filterable checkbox groups and autocomplete filters to provide instructional text for assistive technology users.
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
FilterableCheckboxGroup
|
|
5
|
+
FilterableCheckboxGroup is a multi-select component that combines a search input with a scrollable list of checkboxes. It is designed for scenarios where users need to select multiple items from a potentially large dataset. The built-in search filter narrows down visible options in real time, and virtual scrolling ensures smooth performance even with hundreds of items.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Key capabilities include a "Select all" toggle for bulk selection, automatic sorting (selected items first, then alphabetical), customizable list height, and built-in form integration via `label`, `helperText`, and `required` props. The component accepts options as either simple strings or `{ value, label }` objects.
|
|
8
|
+
|
|
9
|
+
> **Form 구성 시 내장 prop 사용을 권장합니다**
|
|
8
10
|
>
|
|
9
11
|
> 이 컴포넌트는 `label`, `helperText` 등의 Form 요소를 자체적으로 지원합니다.
|
|
10
12
|
> Form을 구성할 때 Typography로 별도의 label이나 helperText를 만드는 대신, 컴포넌트의 내장 prop을 사용하세요.
|
|
@@ -55,11 +57,9 @@ function MyComponent() {
|
|
|
55
57
|
}
|
|
56
58
|
```
|
|
57
59
|
|
|
58
|
-
##
|
|
59
|
-
|
|
60
|
-
### Sizes
|
|
60
|
+
## Sizes
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
Three sizes are available: `sm`, `md`, and `lg`. The size affects the search input, checkboxes, and overall spacing.
|
|
63
63
|
|
|
64
64
|
```tsx
|
|
65
65
|
<Stack spacing={3}>
|
|
@@ -69,9 +69,11 @@ function MyComponent() {
|
|
|
69
69
|
</Stack>
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
## Label and Helper Text
|
|
73
|
+
|
|
72
74
|
### With Label
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
Use the `label` prop to describe the purpose of the checkbox group.
|
|
75
77
|
|
|
76
78
|
```tsx
|
|
77
79
|
<FilterableCheckboxGroup
|
|
@@ -83,7 +85,7 @@ function MyComponent() {
|
|
|
83
85
|
|
|
84
86
|
### With Helper Text
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
Add a `helperText` prop to provide additional guidance below the component.
|
|
87
89
|
|
|
88
90
|
```tsx
|
|
89
91
|
<FilterableCheckboxGroup
|
|
@@ -96,7 +98,7 @@ function MyComponent() {
|
|
|
96
98
|
|
|
97
99
|
### Required Field
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
Set `required` to append a required indicator to the label.
|
|
100
102
|
|
|
101
103
|
```tsx
|
|
102
104
|
<FilterableCheckboxGroup
|
|
@@ -108,9 +110,9 @@ function MyComponent() {
|
|
|
108
110
|
/>
|
|
109
111
|
```
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
## Custom Max Height
|
|
112
114
|
|
|
113
|
-
|
|
115
|
+
Control the visible height of the options list with the `maxHeight` prop (default: 300px). A smaller height is useful when screen space is limited.
|
|
114
116
|
|
|
115
117
|
```tsx
|
|
116
118
|
<Stack spacing={3}>
|
|
@@ -119,9 +121,9 @@ function MyComponent() {
|
|
|
119
121
|
</Stack>
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
## Long List with Virtual Scrolling
|
|
123
125
|
|
|
124
|
-
|
|
126
|
+
When the options list is large, the component uses virtual scrolling to render only the visible items. This keeps the UI performant regardless of the total number of options.
|
|
125
127
|
|
|
126
128
|
```tsx
|
|
127
129
|
<FilterableCheckboxGroup
|
|
@@ -134,9 +136,9 @@ function MyComponent() {
|
|
|
134
136
|
/>
|
|
135
137
|
```
|
|
136
138
|
|
|
137
|
-
|
|
139
|
+
## Empty State
|
|
138
140
|
|
|
139
|
-
|
|
141
|
+
When no options are provided, the component displays an empty state. This is useful for dynamically loaded option lists that may start empty.
|
|
140
142
|
|
|
141
143
|
```tsx
|
|
142
144
|
<FilterableCheckboxGroup
|
|
@@ -146,9 +148,9 @@ function MyComponent() {
|
|
|
146
148
|
/>
|
|
147
149
|
```
|
|
148
150
|
|
|
149
|
-
|
|
151
|
+
## Controlled Mode
|
|
150
152
|
|
|
151
|
-
|
|
153
|
+
Pass `value` and `onChange` to manage the selection state externally. This is the recommended approach when the component is part of a form or when the selected values need to be used by other parts of the UI.
|
|
152
154
|
|
|
153
155
|
```tsx
|
|
154
156
|
<Stack spacing={2}>
|
|
@@ -160,9 +162,9 @@ function MyComponent() {
|
|
|
160
162
|
</Stack>
|
|
161
163
|
```
|
|
162
164
|
|
|
163
|
-
|
|
165
|
+
## Sorting Behavior
|
|
164
166
|
|
|
165
|
-
|
|
167
|
+
The component automatically sorts options on initial render: selected items appear first, followed by unselected items in alphabetical order. When new options are added dynamically, they are inserted in the correct sorted position.
|
|
166
168
|
|
|
167
169
|
```tsx
|
|
168
170
|
<Stack spacing={2}>
|
|
@@ -196,13 +198,13 @@ function MyComponent() {
|
|
|
196
198
|
</Stack>
|
|
197
199
|
```
|
|
198
200
|
|
|
199
|
-
|
|
201
|
+
## Disabled State
|
|
200
202
|
|
|
201
|
-
|
|
203
|
+
The component supports both full and partial disabling.
|
|
202
204
|
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
- **"Select all"
|
|
205
|
+
- **Full disable**: Set `disabled` on the component to disable the search input, "Select all" toggle, and all checkboxes.
|
|
206
|
+
- **Partial disable**: Set `disabled: true` on individual option objects to disable specific items while keeping the rest interactive.
|
|
207
|
+
- **"Select all" behavior**: Disabled options are excluded from the "Select all" toggle. Their selected state is preserved regardless of bulk actions.
|
|
206
208
|
|
|
207
209
|
```tsx
|
|
208
210
|
<Stack spacing={3}>
|
|
@@ -221,3 +223,96 @@ function MyComponent() {
|
|
|
221
223
|
</Stack>
|
|
222
224
|
</Stack>
|
|
223
225
|
```
|
|
226
|
+
|
|
227
|
+
## Common Use Cases
|
|
228
|
+
|
|
229
|
+
### Filter Panel
|
|
230
|
+
|
|
231
|
+
Use FilterableCheckboxGroup in a sidebar or panel to let users filter a data table or list by multiple criteria.
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
import { FilterableCheckboxGroup } from '@ceed/ads';
|
|
235
|
+
|
|
236
|
+
function FilterPanel({ categories, onFilterChange }) {
|
|
237
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
238
|
+
|
|
239
|
+
const handleChange = (values: string[]) => {
|
|
240
|
+
setSelected(values);
|
|
241
|
+
onFilterChange(values);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
<FilterableCheckboxGroup
|
|
246
|
+
label="Categories"
|
|
247
|
+
placeholder="Search categories..."
|
|
248
|
+
options={categories}
|
|
249
|
+
value={selected}
|
|
250
|
+
onChange={handleChange}
|
|
251
|
+
maxHeight={200}
|
|
252
|
+
/>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### User Role Assignment
|
|
258
|
+
|
|
259
|
+
Assign multiple roles to a user from a searchable list.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
<FilterableCheckboxGroup
|
|
263
|
+
label="Assign Roles"
|
|
264
|
+
placeholder="Search roles..."
|
|
265
|
+
helperText="Select all roles that apply to this user"
|
|
266
|
+
options={[
|
|
267
|
+
{ value: 'admin', label: 'Administrator' },
|
|
268
|
+
{ value: 'editor', label: 'Editor' },
|
|
269
|
+
{ value: 'viewer', label: 'Viewer' },
|
|
270
|
+
{ value: 'moderator', label: 'Moderator' },
|
|
271
|
+
{ value: 'billing', label: 'Billing Manager' },
|
|
272
|
+
]}
|
|
273
|
+
required
|
|
274
|
+
value={selectedRoles}
|
|
275
|
+
onChange={setSelectedRoles}
|
|
276
|
+
/>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Region / Country Selection
|
|
280
|
+
|
|
281
|
+
When dealing with a large set of options like countries, the search filter and virtual scrolling work together for fast selection.
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
<FilterableCheckboxGroup
|
|
285
|
+
label="Service Regions"
|
|
286
|
+
placeholder="Search countries..."
|
|
287
|
+
options={allCountries.map((c) => ({ value: c.code, label: c.name }))}
|
|
288
|
+
value={selectedCountries}
|
|
289
|
+
onChange={setSelectedCountries}
|
|
290
|
+
/>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Best Practices
|
|
294
|
+
|
|
295
|
+
1. **Provide a meaningful placeholder.** The search input placeholder should hint at the type of content being filtered (e.g., "Search countries..." instead of a generic "Search...").
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
// ✅ Specific and helpful
|
|
299
|
+
<FilterableCheckboxGroup placeholder="Search countries..." />
|
|
300
|
+
|
|
301
|
+
// ❌ Too generic
|
|
302
|
+
<FilterableCheckboxGroup placeholder="Type here..." />
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
2. **Use `maxHeight` to fit the layout.** In tight spaces like sidebars or modals, set a smaller `maxHeight` to prevent the component from dominating the layout.
|
|
306
|
+
|
|
307
|
+
3. **Prefer controlled mode for form integration.** Always pass `value` and `onChange` when the selected values participate in form submission or affect other UI state.
|
|
308
|
+
|
|
309
|
+
4. **Leverage individual `disabled` for permissions.** When some options should be visible but not selectable (e.g., due to user permissions), disable them individually rather than hiding them. This communicates availability without surprising users.
|
|
310
|
+
|
|
311
|
+
5. **Keep option labels concise.** Long labels will be truncated with an ellipsis. If detailed descriptions are needed, consider using a tooltip or a separate detail view.
|
|
312
|
+
|
|
313
|
+
## Accessibility
|
|
314
|
+
|
|
315
|
+
- The search input is labeled by the component's `label` prop, ensuring screen readers announce its purpose.
|
|
316
|
+
- Each checkbox option uses a native `<input type="checkbox">` with an associated `<label>`, enabling click-on-label and proper screen reader announcements.
|
|
317
|
+
- The "Select all" toggle clearly communicates its tri-state behavior (all, none, indeterminate) to assistive technologies.
|
|
318
|
+
- Keyboard navigation is fully supported: Tab to move between the search input and the checkbox list, Space to toggle individual checkboxes, and standard arrow keys to navigate within the list.
|