@a13y/react 0.1.0
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/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/components/index.d.ts +374 -0
- package/dist/components/index.js +849 -0
- package/dist/components/index.js.map +1 -0
- package/dist/hooks/index.d.ts +725 -0
- package/dist/hooks/index.js +648 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +1875 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/index.d.ts +539 -0
- package/dist/patterns/index.js +1170 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/use-accessible-button-B0syf-Az.d.ts +83 -0
- package/package.json +101 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Diego Aneli and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/DiegoAneli/a13y/main/assets/logo.svg" alt="A13Y Logo" width="150" />
|
|
3
|
+
|
|
4
|
+
<h1>@a13y/react</h1>
|
|
5
|
+
|
|
6
|
+
<p><strong>Type-safe React hooks for accessibility with compile-time guarantees</strong></p>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<br />
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Type-Safe**: Restrictive TypeScript signatures prevent misuse
|
|
14
|
+
- **Props Enforcement**: Required props enforced at compile-time
|
|
15
|
+
- **Automatic ARIA**: Correct ARIA attributes applied automatically
|
|
16
|
+
- **Keyboard Support**: Enter, Space, Arrow keys handled correctly
|
|
17
|
+
- **Focus Management**: Focus trap, restoration, roving tabindex
|
|
18
|
+
- **Dev Validation**: Runtime warnings in development (via @a13y/devtools)
|
|
19
|
+
- **Zero Overhead**: All dev code stripped in production
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @a13y/react @a13y/core
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Optional devtools for development warnings:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install -D @a13y/devtools
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Hooks
|
|
34
|
+
|
|
35
|
+
### useAccessibleButton
|
|
36
|
+
|
|
37
|
+
Creates accessible buttons with keyboard support.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { useAccessibleButton } from '@a13y/react';
|
|
41
|
+
|
|
42
|
+
function DeleteButton() {
|
|
43
|
+
const { buttonProps } = useAccessibleButton({
|
|
44
|
+
label: 'Delete item', // Required for icon-only buttons
|
|
45
|
+
onPress: (event) => {
|
|
46
|
+
console.log(event.type); // 'mouse' | 'keyboard'
|
|
47
|
+
console.log(event.key); // 'Enter' | ' ' | undefined
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return <button {...buttonProps}>🗑️</button>;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Props:**
|
|
56
|
+
- `label?: string` - Accessible label (required for icon-only buttons)
|
|
57
|
+
- `onPress: (event: PressEvent) => void` - Called on click or Enter/Space
|
|
58
|
+
- `isDisabled?: boolean` - Whether button is disabled
|
|
59
|
+
- `role?: 'button' | 'link'` - ARIA role (default: 'button')
|
|
60
|
+
- `elementType?: 'button' | 'a'` - HTML element type (default: 'button')
|
|
61
|
+
|
|
62
|
+
### useAccessibleDialog
|
|
63
|
+
|
|
64
|
+
Creates accessible modals/dialogs with focus trap.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useAccessibleDialog } from '@a13y/react';
|
|
68
|
+
|
|
69
|
+
function ConfirmDialog({ isOpen, onClose }) {
|
|
70
|
+
const { dialogProps, titleProps, descriptionProps, backdropProps } =
|
|
71
|
+
useAccessibleDialog({
|
|
72
|
+
isOpen,
|
|
73
|
+
onClose,
|
|
74
|
+
title: 'Confirm Action', // ✅ Required
|
|
75
|
+
description: 'This action cannot be undone',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!isOpen) return null;
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<>
|
|
82
|
+
{backdropProps && <div className="backdrop" {...backdropProps} />}
|
|
83
|
+
<div className="dialog" {...dialogProps}>
|
|
84
|
+
<h2 {...titleProps}>Confirm Action</h2>
|
|
85
|
+
<p {...descriptionProps}>This action cannot be undone</p>
|
|
86
|
+
<button onClick={onClose}>Cancel</button>
|
|
87
|
+
</div>
|
|
88
|
+
</>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Props:**
|
|
94
|
+
- `isOpen: boolean` - Whether dialog is open
|
|
95
|
+
- `onClose: () => void` - Called when dialog should close
|
|
96
|
+
- `title: string` - Dialog title (REQUIRED for accessibility)
|
|
97
|
+
- `description?: string` - Dialog description
|
|
98
|
+
- `role?: 'dialog' | 'alertdialog'` - ARIA role (default: 'dialog')
|
|
99
|
+
- `isModal?: boolean` - Whether dialog is modal/blocking (default: true)
|
|
100
|
+
- `closeOnBackdropClick?: boolean` - Close on backdrop click (default: true)
|
|
101
|
+
|
|
102
|
+
### useFocusTrap
|
|
103
|
+
|
|
104
|
+
Creates a focus trap for modals and popups.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import { useFocusTrap } from '@a13y/react';
|
|
108
|
+
|
|
109
|
+
function Modal({ isOpen, onClose }) {
|
|
110
|
+
const { trapRef } = useFocusTrap({
|
|
111
|
+
isActive: isOpen,
|
|
112
|
+
onEscape: onClose,
|
|
113
|
+
restoreFocus: true, // Restore focus on close
|
|
114
|
+
autoFocus: true, // Auto-focus first element
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!isOpen) return null;
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div ref={trapRef} className="modal">
|
|
121
|
+
<h2>Modal Title</h2>
|
|
122
|
+
<button onClick={onClose}>Close</button>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Props:**
|
|
129
|
+
- `isActive: boolean` - Whether focus trap is active
|
|
130
|
+
- `onEscape?: () => void` - Called when Escape key is pressed
|
|
131
|
+
- `restoreFocus?: boolean` - Restore focus on deactivation (default: true)
|
|
132
|
+
- `autoFocus?: boolean` - Auto-focus first element (default: true)
|
|
133
|
+
|
|
134
|
+
### useKeyboardNavigation
|
|
135
|
+
|
|
136
|
+
Implements roving tabindex keyboard navigation.
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { useKeyboardNavigation } from '@a13y/react';
|
|
140
|
+
|
|
141
|
+
function Toolbar() {
|
|
142
|
+
const { containerProps, getItemProps, currentIndex } =
|
|
143
|
+
useKeyboardNavigation({
|
|
144
|
+
orientation: 'horizontal', // Arrow Left/Right
|
|
145
|
+
loop: true, // Wrap around at edges
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const tools = ['Cut', 'Copy', 'Paste', 'Undo', 'Redo'];
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div className="toolbar" {...containerProps}>
|
|
152
|
+
{tools.map((tool, index) => (
|
|
153
|
+
<button
|
|
154
|
+
key={tool}
|
|
155
|
+
{...getItemProps(index)}
|
|
156
|
+
className={index === currentIndex ? 'focused' : ''}
|
|
157
|
+
>
|
|
158
|
+
{tool}
|
|
159
|
+
</button>
|
|
160
|
+
))}
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Props:**
|
|
167
|
+
- `orientation: 'horizontal' | 'vertical' | 'both'` - Navigation direction
|
|
168
|
+
- `loop?: boolean` - Whether to loop at boundaries (default: false)
|
|
169
|
+
- `onNavigate?: (index: number) => void` - Called when navigation occurs
|
|
170
|
+
- `defaultIndex?: number` - Initial focused index (default: 0)
|
|
171
|
+
- `currentIndex?: number` - Controlled current index
|
|
172
|
+
|
|
173
|
+
## Type Safety
|
|
174
|
+
|
|
175
|
+
### Forbidden Props
|
|
176
|
+
|
|
177
|
+
The hooks prevent misuse by forbidding certain props:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
const { buttonProps } = useAccessibleButton({ onPress: () => {} });
|
|
181
|
+
|
|
182
|
+
// ❌ TypeScript Error: These props are managed by the hook
|
|
183
|
+
<button {...buttonProps} onClick={() => {}} />
|
|
184
|
+
<button {...buttonProps} onKeyDown={() => {}} />
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Required Props
|
|
188
|
+
|
|
189
|
+
Required props are enforced at compile-time:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// ❌ TypeScript Error: 'title' is required
|
|
193
|
+
useAccessibleDialog({
|
|
194
|
+
isOpen: true,
|
|
195
|
+
onClose: () => {},
|
|
196
|
+
// title: missing!
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Development Warnings
|
|
201
|
+
|
|
202
|
+
When `@a13y/devtools` is installed, you get runtime warnings in development:
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
// ⚠️ Console warning: Element is missing an accessible name
|
|
206
|
+
<button {...buttonProps}></button>
|
|
207
|
+
|
|
208
|
+
// ⚠️ Console warning: Focus trap has no focusable elements
|
|
209
|
+
<div ref={trapRef}></div>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
All warnings include:
|
|
213
|
+
- Clear description of the issue
|
|
214
|
+
- WCAG 2.2 criterion reference
|
|
215
|
+
- Multiple fix suggestions with code examples
|
|
216
|
+
|
|
217
|
+
## Production Build
|
|
218
|
+
|
|
219
|
+
Zero overhead in production:
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
// Development build
|
|
223
|
+
useAccessibleButton({ onPress: () => {} });
|
|
224
|
+
// ✅ Includes validation code from @a13y/devtools
|
|
225
|
+
|
|
226
|
+
// Production build (NODE_ENV=production)
|
|
227
|
+
useAccessibleButton({ onPress: () => {} });
|
|
228
|
+
// ✅ All validation code removed via dead code elimination
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Examples
|
|
232
|
+
|
|
233
|
+
See [EXAMPLES.md](./EXAMPLES.md) for complete usage examples.
|
|
234
|
+
|
|
235
|
+
## Author
|
|
236
|
+
|
|
237
|
+
Created and maintained by **Diego Aneli** ([@DiegoAneli](https://github.com/DiegoAneli))
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT © Diego Aneli and contributors
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { P as PressEvent } from '../use-accessible-button-B0syf-Az.js';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Button variants
|
|
7
|
+
*/
|
|
8
|
+
type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'ghost';
|
|
9
|
+
/**
|
|
10
|
+
* Props for AccessibleButton
|
|
11
|
+
*/
|
|
12
|
+
interface AccessibleButtonProps {
|
|
13
|
+
/**
|
|
14
|
+
* Button content
|
|
15
|
+
* If content is not text (e.g., icon only), label is REQUIRED
|
|
16
|
+
*/
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* Accessible label
|
|
20
|
+
* REQUIRED if children is not text (e.g., icon-only button)
|
|
21
|
+
*/
|
|
22
|
+
label?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Click handler
|
|
25
|
+
*/
|
|
26
|
+
onPress: (event: PressEvent) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Whether button is disabled
|
|
29
|
+
*/
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Visual variant (does not affect accessibility)
|
|
33
|
+
*/
|
|
34
|
+
variant?: ButtonVariant;
|
|
35
|
+
/**
|
|
36
|
+
* Custom className
|
|
37
|
+
*/
|
|
38
|
+
className?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Button type
|
|
41
|
+
*/
|
|
42
|
+
type?: 'button' | 'submit' | 'reset';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Accessible Button Component
|
|
46
|
+
*
|
|
47
|
+
* Features:
|
|
48
|
+
* - Automatic keyboard support (Enter, Space)
|
|
49
|
+
* - Required accessible name (compile-time + runtime)
|
|
50
|
+
* - Disabled state handling
|
|
51
|
+
* - Development-time validation
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* // Text button (label optional)
|
|
56
|
+
* <AccessibleButton onPress={() => console.log('Clicked')}>
|
|
57
|
+
* Save
|
|
58
|
+
* </AccessibleButton>
|
|
59
|
+
*
|
|
60
|
+
* // Icon button (label REQUIRED)
|
|
61
|
+
* <AccessibleButton
|
|
62
|
+
* label="Delete item"
|
|
63
|
+
* onPress={() => console.log('Deleted')}
|
|
64
|
+
* >
|
|
65
|
+
* 🗑️
|
|
66
|
+
* </AccessibleButton>
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare const AccessibleButton: (props: AccessibleButtonProps) => react_jsx_runtime.JSX.Element;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Props for AccessibleDialog
|
|
73
|
+
*/
|
|
74
|
+
interface AccessibleDialogProps {
|
|
75
|
+
/**
|
|
76
|
+
* Whether dialog is open
|
|
77
|
+
*/
|
|
78
|
+
isOpen: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Called when dialog should close
|
|
81
|
+
*/
|
|
82
|
+
onClose: () => void;
|
|
83
|
+
/**
|
|
84
|
+
* Dialog title - REQUIRED for accessibility
|
|
85
|
+
* This will be announced to screen readers
|
|
86
|
+
*/
|
|
87
|
+
title: string;
|
|
88
|
+
/**
|
|
89
|
+
* Dialog content
|
|
90
|
+
*/
|
|
91
|
+
children: ReactNode;
|
|
92
|
+
/**
|
|
93
|
+
* Optional description
|
|
94
|
+
* Provides additional context to screen readers
|
|
95
|
+
*/
|
|
96
|
+
description?: string;
|
|
97
|
+
/**
|
|
98
|
+
* ARIA role
|
|
99
|
+
*/
|
|
100
|
+
role?: 'dialog' | 'alertdialog';
|
|
101
|
+
/**
|
|
102
|
+
* Whether to show close button
|
|
103
|
+
*/
|
|
104
|
+
showCloseButton?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Custom className for dialog container
|
|
107
|
+
*/
|
|
108
|
+
className?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Custom className for backdrop
|
|
111
|
+
*/
|
|
112
|
+
backdropClassName?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Accessible Dialog Component
|
|
116
|
+
*
|
|
117
|
+
* Features:
|
|
118
|
+
* - Focus trap with Tab/Shift+Tab cycling
|
|
119
|
+
* - Escape key to close
|
|
120
|
+
* - Focus restoration on close
|
|
121
|
+
* - Click outside to close
|
|
122
|
+
* - Required title for screen readers
|
|
123
|
+
* - Body scroll lock when open
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```tsx
|
|
127
|
+
* <AccessibleDialog
|
|
128
|
+
* isOpen={isOpen}
|
|
129
|
+
* onClose={() => setIsOpen(false)}
|
|
130
|
+
* title="Confirm Action"
|
|
131
|
+
* description="This action cannot be undone"
|
|
132
|
+
* >
|
|
133
|
+
* <p>Are you sure you want to delete this item?</p>
|
|
134
|
+
* <button onClick={handleConfirm}>Confirm</button>
|
|
135
|
+
* <button onClick={() => setIsOpen(false)}>Cancel</button>
|
|
136
|
+
* </AccessibleDialog>
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
declare const AccessibleDialog: (props: AccessibleDialogProps) => react_jsx_runtime.JSX.Element | null;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Menu item definition
|
|
143
|
+
*/
|
|
144
|
+
interface MenuItem {
|
|
145
|
+
/**
|
|
146
|
+
* Unique identifier
|
|
147
|
+
*/
|
|
148
|
+
id: string;
|
|
149
|
+
/**
|
|
150
|
+
* Item label
|
|
151
|
+
*/
|
|
152
|
+
label: string;
|
|
153
|
+
/**
|
|
154
|
+
* Click handler
|
|
155
|
+
*/
|
|
156
|
+
onPress: () => void;
|
|
157
|
+
/**
|
|
158
|
+
* Whether item is disabled
|
|
159
|
+
*/
|
|
160
|
+
disabled?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Optional icon
|
|
163
|
+
*/
|
|
164
|
+
icon?: ReactNode;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Props for AccessibleMenu
|
|
168
|
+
*/
|
|
169
|
+
interface AccessibleMenuProps {
|
|
170
|
+
/**
|
|
171
|
+
* Menu trigger button label
|
|
172
|
+
*/
|
|
173
|
+
label: string;
|
|
174
|
+
/**
|
|
175
|
+
* Trigger button content
|
|
176
|
+
*/
|
|
177
|
+
trigger: ReactNode;
|
|
178
|
+
/**
|
|
179
|
+
* Menu items
|
|
180
|
+
*/
|
|
181
|
+
items: MenuItem[];
|
|
182
|
+
/**
|
|
183
|
+
* Custom className for trigger button
|
|
184
|
+
*/
|
|
185
|
+
className?: string;
|
|
186
|
+
/**
|
|
187
|
+
* Custom className for menu container
|
|
188
|
+
*/
|
|
189
|
+
menuClassName?: string;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Accessible Menu Component
|
|
193
|
+
*
|
|
194
|
+
* Dropdown menu with full keyboard navigation:
|
|
195
|
+
* - Arrow Up/Down to navigate items
|
|
196
|
+
* - Enter/Space to select
|
|
197
|
+
* - Escape to close
|
|
198
|
+
* - Focus trap when open
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```tsx
|
|
202
|
+
* <AccessibleMenu
|
|
203
|
+
* label="Open actions menu"
|
|
204
|
+
* trigger="Actions ▼"
|
|
205
|
+
* items={[
|
|
206
|
+
* { id: 'edit', label: 'Edit', onPress: () => console.log('Edit') },
|
|
207
|
+
* { id: 'delete', label: 'Delete', onPress: () => console.log('Delete'), disabled: true },
|
|
208
|
+
* { id: 'share', label: 'Share', onPress: () => console.log('Share') },
|
|
209
|
+
* ]}
|
|
210
|
+
* />
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
declare const AccessibleMenu: (props: AccessibleMenuProps) => react_jsx_runtime.JSX.Element;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Props for AccessibleModal
|
|
217
|
+
*/
|
|
218
|
+
interface AccessibleModalProps {
|
|
219
|
+
/**
|
|
220
|
+
* Whether modal is open
|
|
221
|
+
*/
|
|
222
|
+
isOpen: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Called when modal should close
|
|
225
|
+
*/
|
|
226
|
+
onClose: () => void;
|
|
227
|
+
/**
|
|
228
|
+
* Modal title - REQUIRED
|
|
229
|
+
*/
|
|
230
|
+
title: string;
|
|
231
|
+
/**
|
|
232
|
+
* Modal body content
|
|
233
|
+
*/
|
|
234
|
+
children: ReactNode;
|
|
235
|
+
/**
|
|
236
|
+
* Footer content (typically action buttons)
|
|
237
|
+
*/
|
|
238
|
+
footer?: ReactNode;
|
|
239
|
+
/**
|
|
240
|
+
* Modal size
|
|
241
|
+
*/
|
|
242
|
+
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
243
|
+
/**
|
|
244
|
+
* Whether modal can be closed by clicking outside
|
|
245
|
+
*/
|
|
246
|
+
closeOnBackdropClick?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Custom className for modal container
|
|
249
|
+
*/
|
|
250
|
+
className?: string;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Accessible Modal Component
|
|
254
|
+
*
|
|
255
|
+
* Full-featured modal with header, body, and footer sections.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```tsx
|
|
259
|
+
* <AccessibleModal
|
|
260
|
+
* isOpen={isOpen}
|
|
261
|
+
* onClose={() => setIsOpen(false)}
|
|
262
|
+
* title="Edit Profile"
|
|
263
|
+
* size="md"
|
|
264
|
+
* footer={
|
|
265
|
+
* <>
|
|
266
|
+
* <AccessibleButton onPress={() => setIsOpen(false)}>
|
|
267
|
+
* Cancel
|
|
268
|
+
* </AccessibleButton>
|
|
269
|
+
* <AccessibleButton onPress={handleSave} variant="primary">
|
|
270
|
+
* Save Changes
|
|
271
|
+
* </AccessibleButton>
|
|
272
|
+
* </>
|
|
273
|
+
* }
|
|
274
|
+
* >
|
|
275
|
+
* <form>
|
|
276
|
+
* <input type="text" placeholder="Name" />
|
|
277
|
+
* <input type="email" placeholder="Email" />
|
|
278
|
+
* </form>
|
|
279
|
+
* </AccessibleModal>
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
declare const AccessibleModal: (props: AccessibleModalProps) => react_jsx_runtime.JSX.Element | null;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Tab definition
|
|
286
|
+
*/
|
|
287
|
+
interface Tab {
|
|
288
|
+
/**
|
|
289
|
+
* Unique identifier
|
|
290
|
+
*/
|
|
291
|
+
id: string;
|
|
292
|
+
/**
|
|
293
|
+
* Tab label - REQUIRED for accessibility
|
|
294
|
+
*/
|
|
295
|
+
label: string;
|
|
296
|
+
/**
|
|
297
|
+
* Tab panel content
|
|
298
|
+
*/
|
|
299
|
+
content: ReactNode;
|
|
300
|
+
/**
|
|
301
|
+
* Whether tab is disabled
|
|
302
|
+
*/
|
|
303
|
+
disabled?: boolean;
|
|
304
|
+
/**
|
|
305
|
+
* Optional icon
|
|
306
|
+
*/
|
|
307
|
+
icon?: ReactNode;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Props for AccessibleTabs
|
|
311
|
+
*/
|
|
312
|
+
interface AccessibleTabsProps {
|
|
313
|
+
/**
|
|
314
|
+
* Tabs configuration - REQUIRED
|
|
315
|
+
* Must have at least one tab
|
|
316
|
+
*/
|
|
317
|
+
tabs: [Tab, ...Tab[]];
|
|
318
|
+
/**
|
|
319
|
+
* Initially selected tab index
|
|
320
|
+
*/
|
|
321
|
+
defaultTab?: number;
|
|
322
|
+
/**
|
|
323
|
+
* Controlled selected tab index
|
|
324
|
+
*/
|
|
325
|
+
selectedTab?: number;
|
|
326
|
+
/**
|
|
327
|
+
* Called when tab changes
|
|
328
|
+
*/
|
|
329
|
+
onTabChange?: (index: number) => void;
|
|
330
|
+
/**
|
|
331
|
+
* Custom className for tabs container
|
|
332
|
+
*/
|
|
333
|
+
className?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Custom className for panel
|
|
336
|
+
*/
|
|
337
|
+
panelClassName?: string;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Accessible Tabs Component
|
|
341
|
+
*
|
|
342
|
+
* Tab interface following WAI-ARIA Tabs pattern:
|
|
343
|
+
* - Arrow Left/Right to navigate tabs
|
|
344
|
+
* - Home/End to jump to first/last
|
|
345
|
+
* - Automatic panel switching
|
|
346
|
+
* - Proper ARIA attributes
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```tsx
|
|
350
|
+
* <AccessibleTabs
|
|
351
|
+
* tabs={[
|
|
352
|
+
* {
|
|
353
|
+
* id: 'account',
|
|
354
|
+
* label: 'Account',
|
|
355
|
+
* content: <div>Account settings...</div>,
|
|
356
|
+
* },
|
|
357
|
+
* {
|
|
358
|
+
* id: 'security',
|
|
359
|
+
* label: 'Security',
|
|
360
|
+
* content: <div>Security settings...</div>,
|
|
361
|
+
* },
|
|
362
|
+
* {
|
|
363
|
+
* id: 'billing',
|
|
364
|
+
* label: 'Billing',
|
|
365
|
+
* content: <div>Billing information...</div>,
|
|
366
|
+
* disabled: true,
|
|
367
|
+
* },
|
|
368
|
+
* ]}
|
|
369
|
+
* />
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
372
|
+
declare const AccessibleTabs: (props: AccessibleTabsProps) => react_jsx_runtime.JSX.Element;
|
|
373
|
+
|
|
374
|
+
export { AccessibleButton, AccessibleDialog, AccessibleMenu, AccessibleModal, AccessibleTabs, type AccessibleButtonProps as ButtonComponentProps, type ButtonVariant, type AccessibleDialogProps as DialogComponentProps, type AccessibleMenuProps as MenuComponentProps, type MenuItem, type AccessibleModalProps as ModalComponentProps, type Tab, type AccessibleTabsProps as TabsComponentProps };
|