@compa11y/react 0.1.0 → 0.1.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.
- package/README.md +487 -5
- package/dist/index.cjs +3169 -157
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +760 -3
- package/dist/index.d.ts +760 -3
- package/dist/index.js +3139 -161
- package/dist/index.js.map +1 -1
- package/package.json +44 -3
package/README.md
CHANGED
|
@@ -75,11 +75,7 @@ function SettingsTabs() {
|
|
|
75
75
|
### Toast
|
|
76
76
|
|
|
77
77
|
```tsx
|
|
78
|
-
import {
|
|
79
|
-
ToastProvider,
|
|
80
|
-
ToastViewport,
|
|
81
|
-
useToastHelpers,
|
|
82
|
-
} from '@compa11y/react';
|
|
78
|
+
import { ToastProvider, ToastViewport, useToastHelpers } from '@compa11y/react';
|
|
83
79
|
|
|
84
80
|
function App() {
|
|
85
81
|
return (
|
|
@@ -125,6 +121,430 @@ function CountrySelect() {
|
|
|
125
121
|
}
|
|
126
122
|
```
|
|
127
123
|
|
|
124
|
+
### Select
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { Select } from '@compa11y/react';
|
|
128
|
+
|
|
129
|
+
const fruits = [
|
|
130
|
+
{ value: 'apple', label: 'Apple' },
|
|
131
|
+
{ value: 'banana', label: 'Banana' },
|
|
132
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
133
|
+
{ value: 'dragonfruit', label: 'Dragon Fruit', disabled: true },
|
|
134
|
+
{ value: 'elderberry', label: 'Elderberry' },
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
function FruitPicker() {
|
|
138
|
+
const [value, setValue] = useState(null);
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<Select
|
|
142
|
+
options={fruits}
|
|
143
|
+
value={value}
|
|
144
|
+
onValueChange={setValue}
|
|
145
|
+
aria-label="Choose a fruit"
|
|
146
|
+
>
|
|
147
|
+
<Select.Trigger placeholder="Pick a fruit..." />
|
|
148
|
+
<Select.Listbox />
|
|
149
|
+
</Select>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Keyboard Navigation:**
|
|
155
|
+
|
|
156
|
+
| Key | Action |
|
|
157
|
+
| ----------------- | ----------------------------------------- |
|
|
158
|
+
| `Enter` / `Space` | Open listbox or select highlighted option |
|
|
159
|
+
| `ArrowDown` | Open listbox / move highlight down |
|
|
160
|
+
| `ArrowUp` | Open listbox / move highlight up |
|
|
161
|
+
| `Home` / `End` | Jump to first / last option |
|
|
162
|
+
| `Escape` | Close listbox |
|
|
163
|
+
| `Tab` | Close listbox and move focus |
|
|
164
|
+
| Type characters | Jump to matching option (type-ahead) |
|
|
165
|
+
|
|
166
|
+
**Props:**
|
|
167
|
+
|
|
168
|
+
| Prop | Type | Default | Description |
|
|
169
|
+
| ----------------- | --------------------------------- | ----------------------- | ---------------------------- |
|
|
170
|
+
| `options` | `SelectOption[]` | — | List of options |
|
|
171
|
+
| `value` | `string \| null` | — | Controlled selected value |
|
|
172
|
+
| `defaultValue` | `string` | — | Default value (uncontrolled) |
|
|
173
|
+
| `onValueChange` | `(value: string \| null) => void` | — | Change handler |
|
|
174
|
+
| `placeholder` | `string` | `'Select an option...'` | Trigger placeholder text |
|
|
175
|
+
| `disabled` | `boolean` | `false` | Disable the select |
|
|
176
|
+
| `aria-label` | `string` | — | Accessible label |
|
|
177
|
+
| `aria-labelledby` | `string` | — | ID of labelling element |
|
|
178
|
+
|
|
179
|
+
### Switch
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
import { Switch } from '@compa11y/react';
|
|
183
|
+
|
|
184
|
+
function NotificationSettings() {
|
|
185
|
+
const [enabled, setEnabled] = useState(false);
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<Switch checked={enabled} onCheckedChange={setEnabled}>
|
|
189
|
+
Enable notifications
|
|
190
|
+
</Switch>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Customization:**
|
|
196
|
+
|
|
197
|
+
```css
|
|
198
|
+
.my-switch {
|
|
199
|
+
--compa11y-switch-bg: #d1d5db;
|
|
200
|
+
--compa11y-switch-checked-bg: #10b981;
|
|
201
|
+
--compa11y-switch-thumb-bg: white;
|
|
202
|
+
--compa11y-switch-width: 3rem;
|
|
203
|
+
--compa11y-switch-height: 1.75rem;
|
|
204
|
+
--compa11y-focus-color: #10b981;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Listbox
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
import { Listbox } from '@compa11y/react';
|
|
212
|
+
|
|
213
|
+
// Single select (selection follows focus)
|
|
214
|
+
function FruitPicker() {
|
|
215
|
+
const [fruit, setFruit] = useState('apple');
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<Listbox value={fruit} onValueChange={setFruit} aria-label="Favorite fruit">
|
|
219
|
+
<Listbox.Group label="Citrus">
|
|
220
|
+
<Listbox.Option value="orange">Orange</Listbox.Option>
|
|
221
|
+
<Listbox.Option value="lemon">Lemon</Listbox.Option>
|
|
222
|
+
<Listbox.Option value="grapefruit">Grapefruit</Listbox.Option>
|
|
223
|
+
</Listbox.Group>
|
|
224
|
+
<Listbox.Option value="apple">Apple</Listbox.Option>
|
|
225
|
+
<Listbox.Option value="banana" disabled>
|
|
226
|
+
Banana (sold out)
|
|
227
|
+
</Listbox.Option>
|
|
228
|
+
</Listbox>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Multi select (focus independent of selection)
|
|
233
|
+
function ToppingsPicker() {
|
|
234
|
+
const [toppings, setToppings] = useState(['cheese']);
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<Listbox
|
|
238
|
+
multiple
|
|
239
|
+
value={toppings}
|
|
240
|
+
onValueChange={setToppings}
|
|
241
|
+
aria-label="Pizza toppings"
|
|
242
|
+
>
|
|
243
|
+
<Listbox.Option value="cheese">Cheese</Listbox.Option>
|
|
244
|
+
<Listbox.Option value="pepperoni">Pepperoni</Listbox.Option>
|
|
245
|
+
<Listbox.Option value="mushrooms">Mushrooms</Listbox.Option>
|
|
246
|
+
<Listbox.Option value="olives">Olives</Listbox.Option>
|
|
247
|
+
</Listbox>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Props (Listbox):**
|
|
253
|
+
|
|
254
|
+
| Prop | Type | Default | Description |
|
|
255
|
+
| ----------------- | ------------------------------------- | ------------ | ----------------------------------------------------- |
|
|
256
|
+
| `value` | `string \| string[]` | — | Controlled value (string for single, array for multi) |
|
|
257
|
+
| `defaultValue` | `string \| string[]` | — | Default value (uncontrolled) |
|
|
258
|
+
| `onValueChange` | `(value: string \| string[]) => void` | — | Change handler |
|
|
259
|
+
| `multiple` | `boolean` | `false` | Enable multi-select mode |
|
|
260
|
+
| `disabled` | `boolean` | `false` | Disable all options |
|
|
261
|
+
| `discoverable` | `boolean` | `true` | Keep disabled listbox in tab order |
|
|
262
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Layout orientation |
|
|
263
|
+
| `unstyled` | `boolean` | `false` | Remove default styles |
|
|
264
|
+
| `aria-label` | `string` | — | Accessible label |
|
|
265
|
+
| `aria-labelledby` | `string` | — | ID of labelling element |
|
|
266
|
+
|
|
267
|
+
**Props (Listbox.Option):**
|
|
268
|
+
|
|
269
|
+
| Prop | Type | Default | Description |
|
|
270
|
+
| -------------- | --------- | ------- | ------------------------------------------ |
|
|
271
|
+
| `value` | `string` | — | Value for this option (required) |
|
|
272
|
+
| `disabled` | `boolean` | `false` | Disable this option |
|
|
273
|
+
| `discoverable` | `boolean` | `true` | Keep disabled option discoverable |
|
|
274
|
+
| `unstyled` | `boolean` | — | Remove default styles (inherits from root) |
|
|
275
|
+
| `aria-label` | `string` | — | Accessible label override |
|
|
276
|
+
|
|
277
|
+
**Props (Listbox.Group):**
|
|
278
|
+
|
|
279
|
+
| Prop | Type | Default | Description |
|
|
280
|
+
| ---------- | --------- | ------- | ------------------------------------------ |
|
|
281
|
+
| `label` | `string` | — | Group label (required, visible) |
|
|
282
|
+
| `disabled` | `boolean` | `false` | Disable all options in group |
|
|
283
|
+
| `unstyled` | `boolean` | — | Remove default styles (inherits from root) |
|
|
284
|
+
|
|
285
|
+
**Keyboard Navigation:**
|
|
286
|
+
|
|
287
|
+
| Key | Single Select | Multi Select |
|
|
288
|
+
| ----------------------- | ---------------------------- | -------------------------- |
|
|
289
|
+
| `ArrowDown` / `ArrowUp` | Move focus and select | Move focus only |
|
|
290
|
+
| `Home` / `End` | First/last option and select | Move focus only |
|
|
291
|
+
| `Space` | — | Toggle focused option |
|
|
292
|
+
| `Shift+Arrow` | — | Move focus and toggle |
|
|
293
|
+
| `Ctrl+Shift+Home/End` | — | Select range to first/last |
|
|
294
|
+
| `Ctrl+A` | — | Toggle select all |
|
|
295
|
+
| Type characters | Jump to match and select | Jump to match |
|
|
296
|
+
|
|
297
|
+
**Customization:**
|
|
298
|
+
|
|
299
|
+
```css
|
|
300
|
+
[data-compa11y-listbox] {
|
|
301
|
+
--compa11y-listbox-bg: white;
|
|
302
|
+
--compa11y-listbox-border: 1px solid #ccc;
|
|
303
|
+
--compa11y-listbox-radius: 6px;
|
|
304
|
+
--compa11y-listbox-max-height: 300px;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
[data-compa11y-listbox-option] {
|
|
308
|
+
--compa11y-option-hover-bg: #f5f5f5;
|
|
309
|
+
--compa11y-option-focused-bg: #e6f0ff;
|
|
310
|
+
--compa11y-option-selected-bg: #e6f0ff;
|
|
311
|
+
--compa11y-option-selected-color: #10b981;
|
|
312
|
+
--compa11y-option-check-color: #10b981;
|
|
313
|
+
--compa11y-option-disabled-color: #999;
|
|
314
|
+
--compa11y-focus-color: #10b981;
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Input
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { Input } from '@compa11y/react';
|
|
322
|
+
|
|
323
|
+
function ContactForm() {
|
|
324
|
+
const [name, setName] = useState('');
|
|
325
|
+
const [nameError, setNameError] = useState('');
|
|
326
|
+
|
|
327
|
+
const validate = () => {
|
|
328
|
+
if (!name.trim()) setNameError('Name is required');
|
|
329
|
+
else setNameError('');
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<Input
|
|
334
|
+
label="Full Name"
|
|
335
|
+
hint="Enter your first and last name"
|
|
336
|
+
error={nameError || undefined}
|
|
337
|
+
required
|
|
338
|
+
placeholder="John Doe"
|
|
339
|
+
value={name}
|
|
340
|
+
onValueChange={setName}
|
|
341
|
+
onBlur={validate}
|
|
342
|
+
/>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Compound mode for custom layouts
|
|
347
|
+
function CustomInput() {
|
|
348
|
+
const [value, setValue] = useState('');
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<Input value={value} onValueChange={setValue}>
|
|
352
|
+
<Input.Label>Email</Input.Label>
|
|
353
|
+
<Input.Field type="email" placeholder="you@example.com" />
|
|
354
|
+
<Input.Hint>We'll never share your email</Input.Hint>
|
|
355
|
+
<Input.Error>{/* error message here */}</Input.Error>
|
|
356
|
+
</Input>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Props:**
|
|
362
|
+
|
|
363
|
+
| Prop | Type | Default | Description |
|
|
364
|
+
| ----------------- | ------------------------- | -------- | ------------------------------------------------------------ |
|
|
365
|
+
| `label` | `ReactNode` | — | Visible label text |
|
|
366
|
+
| `hint` | `ReactNode` | — | Hint/description text |
|
|
367
|
+
| `error` | `ReactNode` | — | Error message (enables `aria-invalid`) |
|
|
368
|
+
| `value` | `string` | — | Controlled value |
|
|
369
|
+
| `defaultValue` | `string` | `''` | Default value (uncontrolled) |
|
|
370
|
+
| `onValueChange` | `(value: string) => void` | — | Change handler |
|
|
371
|
+
| `type` | `string` | `'text'` | Input type (text, email, password, number, tel, url, search) |
|
|
372
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
373
|
+
| `required` | `boolean` | `false` | Required field |
|
|
374
|
+
| `disabled` | `boolean` | `false` | Disable the input |
|
|
375
|
+
| `readOnly` | `boolean` | `false` | Read-only input |
|
|
376
|
+
| `unstyled` | `boolean` | `false` | Remove default styles |
|
|
377
|
+
| `aria-label` | `string` | — | Accessible label (when no visible label) |
|
|
378
|
+
| `aria-labelledby` | `string` | — | ID of labelling element |
|
|
379
|
+
|
|
380
|
+
**Customization:**
|
|
381
|
+
|
|
382
|
+
```css
|
|
383
|
+
.my-input {
|
|
384
|
+
--compa11y-input-border: 1px solid #ccc;
|
|
385
|
+
--compa11y-input-border-focus: #10b981;
|
|
386
|
+
--compa11y-input-border-error: #ef4444;
|
|
387
|
+
--compa11y-input-radius: 8px;
|
|
388
|
+
--compa11y-input-label-weight: 600;
|
|
389
|
+
--compa11y-input-error-color: #ef4444;
|
|
390
|
+
--compa11y-input-hint-color: #666;
|
|
391
|
+
--compa11y-focus-color: #10b981;
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Button
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
import { Button } from '@compa11y/react';
|
|
399
|
+
|
|
400
|
+
function Actions() {
|
|
401
|
+
return (
|
|
402
|
+
<div style={{ display: 'flex', gap: '0.5rem' }}>
|
|
403
|
+
<Button variant="primary" onClick={handleSave}>
|
|
404
|
+
Save
|
|
405
|
+
</Button>
|
|
406
|
+
<Button variant="outline" onClick={handleCancel}>
|
|
407
|
+
Cancel
|
|
408
|
+
</Button>
|
|
409
|
+
<Button variant="danger" onClick={handleDelete}>
|
|
410
|
+
Delete
|
|
411
|
+
</Button>
|
|
412
|
+
</div>
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Loading state
|
|
417
|
+
function SaveButton() {
|
|
418
|
+
const [loading, setLoading] = useState(false);
|
|
419
|
+
|
|
420
|
+
const handleSave = async () => {
|
|
421
|
+
setLoading(true);
|
|
422
|
+
await saveData();
|
|
423
|
+
setLoading(false);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
return (
|
|
427
|
+
<Button variant="primary" loading={loading} onClick={handleSave}>
|
|
428
|
+
{loading ? 'Saving...' : 'Save Changes'}
|
|
429
|
+
</Button>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Disabled but discoverable (stays in tab order)
|
|
434
|
+
<Button variant="primary" disabled discoverable>
|
|
435
|
+
Unavailable
|
|
436
|
+
</Button>;
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Props:**
|
|
440
|
+
|
|
441
|
+
| Prop | Type | Default | Description |
|
|
442
|
+
| -------------- | -------------------------------------------------------------- | ------------- | ------------------------------------------------------ |
|
|
443
|
+
| `variant` | `'primary' \| 'secondary' \| 'danger' \| 'outline' \| 'ghost'` | `'secondary'` | Visual variant |
|
|
444
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
445
|
+
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | HTML button type |
|
|
446
|
+
| `disabled` | `boolean` | `false` | Disable the button |
|
|
447
|
+
| `discoverable` | `boolean` | `false` | Keep disabled button in tab order with `aria-disabled` |
|
|
448
|
+
| `loading` | `boolean` | `false` | Loading state (shows spinner, sets `aria-busy`) |
|
|
449
|
+
| `unstyled` | `boolean` | `false` | Remove default styles |
|
|
450
|
+
| `aria-label` | `string` | — | Accessible label |
|
|
451
|
+
|
|
452
|
+
**Customization:**
|
|
453
|
+
|
|
454
|
+
```css
|
|
455
|
+
[data-compa11y-button] {
|
|
456
|
+
--compa11y-button-radius: 8px;
|
|
457
|
+
--compa11y-button-font-weight: 600;
|
|
458
|
+
--compa11y-button-primary-bg: #10b981;
|
|
459
|
+
--compa11y-button-primary-color: white;
|
|
460
|
+
--compa11y-button-danger-bg: #ef4444;
|
|
461
|
+
--compa11y-button-danger-color: white;
|
|
462
|
+
--compa11y-button-disabled-opacity: 0.5;
|
|
463
|
+
--compa11y-focus-color: #10b981;
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Textarea
|
|
468
|
+
|
|
469
|
+
```tsx
|
|
470
|
+
import { Textarea } from '@compa11y/react';
|
|
471
|
+
|
|
472
|
+
function FeedbackForm() {
|
|
473
|
+
const [desc, setDesc] = useState('');
|
|
474
|
+
const [descError, setDescError] = useState('');
|
|
475
|
+
|
|
476
|
+
const validate = () => {
|
|
477
|
+
if (!desc.trim()) setDescError('Description is required');
|
|
478
|
+
else if (desc.trim().length < 10)
|
|
479
|
+
setDescError('Must be at least 10 characters');
|
|
480
|
+
else setDescError('');
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
return (
|
|
484
|
+
<Textarea
|
|
485
|
+
label="Description"
|
|
486
|
+
hint="Provide at least 10 characters"
|
|
487
|
+
error={descError || undefined}
|
|
488
|
+
required
|
|
489
|
+
rows={4}
|
|
490
|
+
placeholder="Enter a description..."
|
|
491
|
+
value={desc}
|
|
492
|
+
onValueChange={setDesc}
|
|
493
|
+
onBlur={validate}
|
|
494
|
+
/>
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Compound mode for custom layouts
|
|
499
|
+
function CustomTextarea() {
|
|
500
|
+
const [value, setValue] = useState('');
|
|
501
|
+
|
|
502
|
+
return (
|
|
503
|
+
<Textarea value={value} onValueChange={setValue}>
|
|
504
|
+
<Textarea.Label>Bio</Textarea.Label>
|
|
505
|
+
<Textarea.Field rows={5} placeholder="Tell us about yourself..." />
|
|
506
|
+
<Textarea.Hint>Markdown is supported</Textarea.Hint>
|
|
507
|
+
<Textarea.Error>{/* error message here */}</Textarea.Error>
|
|
508
|
+
</Textarea>
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**Props:**
|
|
514
|
+
|
|
515
|
+
| Prop | Type | Default | Description |
|
|
516
|
+
| ----------------- | ------------------------- | ------------ | -------------------------------------------------- |
|
|
517
|
+
| `label` | `ReactNode` | — | Visible label text |
|
|
518
|
+
| `hint` | `ReactNode` | — | Hint/description text |
|
|
519
|
+
| `error` | `ReactNode` | — | Error message (enables `aria-invalid`) |
|
|
520
|
+
| `value` | `string` | — | Controlled value |
|
|
521
|
+
| `defaultValue` | `string` | `''` | Default value (uncontrolled) |
|
|
522
|
+
| `onValueChange` | `(value: string) => void` | — | Change handler |
|
|
523
|
+
| `rows` | `number` | `3` | Number of visible text rows |
|
|
524
|
+
| `resize` | `string` | `'vertical'` | Resize behavior (none, both, horizontal, vertical) |
|
|
525
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
526
|
+
| `required` | `boolean` | `false` | Required field |
|
|
527
|
+
| `disabled` | `boolean` | `false` | Disable the textarea |
|
|
528
|
+
| `readOnly` | `boolean` | `false` | Read-only textarea |
|
|
529
|
+
| `unstyled` | `boolean` | `false` | Remove default styles |
|
|
530
|
+
| `aria-label` | `string` | — | Accessible label (when no visible label) |
|
|
531
|
+
| `aria-labelledby` | `string` | — | ID of labelling element |
|
|
532
|
+
|
|
533
|
+
**Customization:**
|
|
534
|
+
|
|
535
|
+
```css
|
|
536
|
+
.my-textarea {
|
|
537
|
+
--compa11y-textarea-border: 1px solid #ccc;
|
|
538
|
+
--compa11y-textarea-border-focus: #10b981;
|
|
539
|
+
--compa11y-textarea-border-error: #ef4444;
|
|
540
|
+
--compa11y-textarea-radius: 8px;
|
|
541
|
+
--compa11y-textarea-label-weight: 600;
|
|
542
|
+
--compa11y-textarea-error-color: #ef4444;
|
|
543
|
+
--compa11y-textarea-hint-color: #666;
|
|
544
|
+
--compa11y-focus-color: #10b981;
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
128
548
|
## Hooks
|
|
129
549
|
|
|
130
550
|
### useFocusTrap
|
|
@@ -245,6 +665,68 @@ All components are unstyled. Use `data-*` attributes for state-based styling:
|
|
|
245
665
|
[data-compa11y-combobox-option][data-highlighted='true'] {
|
|
246
666
|
background: #f0f0f0;
|
|
247
667
|
}
|
|
668
|
+
|
|
669
|
+
/* Listbox */
|
|
670
|
+
[data-compa11y-listbox] {
|
|
671
|
+
border: 1px solid #e0e0e0;
|
|
672
|
+
border-radius: 6px;
|
|
673
|
+
max-height: 300px;
|
|
674
|
+
overflow-y: auto;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
[data-compa11y-listbox-option][data-focused='true'] {
|
|
678
|
+
background: #e6f0ff;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
[data-compa11y-listbox-option][data-selected='true'] {
|
|
682
|
+
background: #e6f0ff;
|
|
683
|
+
font-weight: 600;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/* Select */
|
|
687
|
+
[data-compa11y-select] {
|
|
688
|
+
position: relative;
|
|
689
|
+
width: 300px;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
[data-compa11y-select-trigger] {
|
|
693
|
+
width: 100%;
|
|
694
|
+
display: flex;
|
|
695
|
+
align-items: center;
|
|
696
|
+
justify-content: space-between;
|
|
697
|
+
padding: 0.5rem 2rem 0.5rem 0.75rem;
|
|
698
|
+
border: 1px solid #ccc;
|
|
699
|
+
border-radius: 4px;
|
|
700
|
+
background: white;
|
|
701
|
+
cursor: pointer;
|
|
702
|
+
text-align: left;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
[data-compa11y-select-listbox] {
|
|
706
|
+
position: absolute;
|
|
707
|
+
top: 100%;
|
|
708
|
+
left: 0;
|
|
709
|
+
right: 0;
|
|
710
|
+
margin-top: 4px;
|
|
711
|
+
background: white;
|
|
712
|
+
border: 1px solid #e0e0e0;
|
|
713
|
+
border-radius: 4px;
|
|
714
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
715
|
+
max-height: 200px;
|
|
716
|
+
overflow-y: auto;
|
|
717
|
+
z-index: 1000;
|
|
718
|
+
list-style: none;
|
|
719
|
+
padding: 0;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
[data-compa11y-select-option][data-highlighted='true'] {
|
|
723
|
+
background: #f0f0f0;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
[data-compa11y-select-option][data-selected='true'] {
|
|
727
|
+
background: #e6f0ff;
|
|
728
|
+
font-weight: 600;
|
|
729
|
+
}
|
|
248
730
|
```
|
|
249
731
|
|
|
250
732
|
## License
|