@a11ypros/a11y-ui-components 1.0.1 → 1.0.3
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 +182 -157
- package/dist/components/Button/Button.d.ts +37 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/Button.js +52 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/DataTable/DataTable.d.ts +71 -0
- package/dist/components/DataTable/DataTable.d.ts.map +1 -0
- package/dist/components/DataTable/DataTable.js +122 -0
- package/dist/components/DataTable/index.d.ts +3 -0
- package/dist/components/DataTable/index.d.ts.map +1 -0
- package/dist/components/DataTable/index.js +1 -0
- package/dist/components/Form/Checkbox.d.ts +36 -0
- package/dist/components/Form/Checkbox.d.ts.map +1 -0
- package/dist/components/Form/Checkbox.js +39 -0
- package/dist/components/Form/Fieldset.d.ts +33 -0
- package/dist/components/Form/Fieldset.d.ts.map +1 -0
- package/dist/components/Form/Fieldset.js +34 -0
- package/dist/components/Form/Input.d.ts +37 -0
- package/dist/components/Form/Input.d.ts.map +1 -0
- package/dist/components/Form/Input.js +41 -0
- package/dist/components/Form/Label.d.ts +30 -0
- package/dist/components/Form/Label.d.ts.map +1 -0
- package/dist/components/Form/Label.js +30 -0
- package/dist/components/Form/Radio.d.ts +53 -0
- package/dist/components/Form/Radio.d.ts.map +1 -0
- package/dist/components/Form/Radio.js +39 -0
- package/dist/components/Form/Select.d.ts +51 -0
- package/dist/components/Form/Select.d.ts.map +1 -0
- package/dist/components/Form/Select.js +49 -0
- package/dist/components/Form/Textarea.d.ts +44 -0
- package/dist/components/Form/Textarea.d.ts.map +1 -0
- package/dist/components/Form/Textarea.js +43 -0
- package/dist/components/Form/index.d.ts +8 -0
- package/dist/components/Form/index.d.ts.map +1 -0
- package/dist/components/Form/index.js +7 -0
- package/dist/components/Link/Link.d.ts +34 -0
- package/dist/components/Link/Link.d.ts.map +1 -0
- package/dist/components/Link/Link.js +48 -0
- package/dist/components/Link/index.d.ts +3 -0
- package/dist/components/Link/index.d.ts.map +1 -0
- package/dist/components/Link/index.js +1 -0
- package/dist/components/Modal/Modal.d.ts +64 -0
- package/dist/components/Modal/Modal.d.ts.map +1 -0
- package/dist/components/Modal/Modal.js +108 -0
- package/dist/components/Modal/index.d.ts +3 -0
- package/dist/components/Modal/index.d.ts.map +1 -0
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/Tabs/Tabs.d.ts +63 -0
- package/dist/components/Tabs/Tabs.d.ts.map +1 -0
- package/dist/components/Tabs/Tabs.js +134 -0
- package/dist/components/Tabs/index.d.ts +3 -0
- package/dist/components/Tabs/index.d.ts.map +1 -0
- package/dist/components/Tabs/index.js +1 -0
- package/dist/components/Toast/Toast.d.ts +59 -0
- package/dist/components/Toast/Toast.d.ts.map +1 -0
- package/dist/components/Toast/Toast.js +91 -0
- package/dist/components/Toast/ToastProvider.d.ts +22 -0
- package/dist/components/Toast/ToastProvider.d.ts.map +1 -0
- package/dist/components/Toast/ToastProvider.js +33 -0
- package/dist/components/Toast/index.d.ts +5 -0
- package/dist/components/Toast/index.d.ts.map +1 -0
- package/dist/components/Toast/index.js +2 -0
- package/dist/hooks/useAriaLive.d.ts +9 -0
- package/dist/hooks/useAriaLive.d.ts.map +1 -0
- package/dist/hooks/useAriaLive.js +39 -0
- package/dist/hooks/useFocusReturn.d.ts +9 -0
- package/dist/hooks/useFocusReturn.d.ts.map +1 -0
- package/dist/hooks/useFocusReturn.js +33 -0
- package/dist/hooks/useFocusTrap.d.ts +9 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -0
- package/dist/hooks/useFocusTrap.js +68 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/{packages/design-system/src/index.ts → dist/index.js} +0 -4
- package/dist/styles/index.d.ts +3 -0
- package/dist/styles/index.d.ts.map +1 -0
- package/dist/styles/index.js +1 -0
- package/dist/tokens/breakpoints.d.ts +25 -0
- package/dist/tokens/breakpoints.d.ts.map +1 -0
- package/dist/tokens/breakpoints.js +23 -0
- package/dist/tokens/colors.d.ts +81 -0
- package/dist/tokens/colors.d.ts.map +1 -0
- package/dist/tokens/colors.js +86 -0
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +5 -0
- package/dist/tokens/motion.d.ts +30 -0
- package/dist/tokens/motion.d.ts.map +1 -0
- package/dist/tokens/motion.js +34 -0
- package/dist/tokens/spacing.d.ts +22 -0
- package/dist/tokens/spacing.d.ts.map +1 -0
- package/dist/tokens/spacing.js +20 -0
- package/dist/tokens/theme.d.ts +159 -0
- package/dist/tokens/theme.d.ts.map +1 -0
- package/dist/tokens/theme.js +15 -0
- package/dist/tokens/typography.d.ts +45 -0
- package/dist/tokens/typography.d.ts.map +1 -0
- package/dist/tokens/typography.js +56 -0
- package/dist/utils/aria.d.ts +60 -0
- package/dist/utils/aria.d.ts.map +1 -0
- package/dist/utils/aria.js +86 -0
- package/dist/utils/focus.d.ts +30 -0
- package/dist/utils/focus.d.ts.map +1 -0
- package/dist/utils/focus.js +80 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/keyboard.d.ts +38 -0
- package/dist/utils/keyboard.d.ts.map +1 -0
- package/dist/utils/keyboard.js +59 -0
- package/package.json +49 -31
- package/.storybook/custom.css +0 -69
- package/.storybook/main.ts +0 -46
- package/.storybook/manager.ts +0 -26
- package/.storybook/package.json +0 -6
- package/.storybook/preview.tsx +0 -31
- package/.storybook/public/logo.png +0 -0
- package/.storybook/vite.config.ts +0 -24
- package/.storybook/welcome.mdx +0 -97
- package/DEPLOYMENT.md +0 -154
- package/apps/web/app/(docs)/audit/audit.css +0 -269
- package/apps/web/app/(docs)/audit/page.tsx +0 -271
- package/apps/web/app/(docs)/components/button/page.tsx +0 -49
- package/apps/web/app/(docs)/components/form/page.tsx +0 -92
- package/apps/web/app/(docs)/components/link/page.tsx +0 -31
- package/apps/web/app/(docs)/components/modal/page.tsx +0 -41
- package/apps/web/app/(docs)/components/page.tsx +0 -37
- package/apps/web/app/(docs)/components/table/page.tsx +0 -54
- package/apps/web/app/(docs)/components/tabs/page.tsx +0 -61
- package/apps/web/app/(docs)/components/toast/page.tsx +0 -51
- package/apps/web/app/api/audit/route.ts +0 -128
- package/apps/web/app/favicon.ico +0 -0
- package/apps/web/app/layout.tsx +0 -20
- package/apps/web/app/page.tsx +0 -17
- package/apps/web/app/styles/globals.css +0 -5
- package/apps/web/next-env.d.ts +0 -5
- package/apps/web/next.config.js +0 -21
- package/apps/web/package.json +0 -28
- package/apps/web/public/_headers +0 -17
- package/apps/web/public/_redirects +0 -31
- package/apps/web/public/logo.png +0 -0
- package/apps/web/tsconfig.json +0 -29
- package/netlify/functions/audit.ts +0 -163
- package/netlify.toml +0 -37
- package/packages/design-system/README.md +0 -252
- package/packages/design-system/package.json +0 -68
- package/packages/design-system/scripts/copy-css.js +0 -63
- package/packages/design-system/src/components/Button/Button.stories.tsx +0 -228
- package/packages/design-system/src/components/Button/Button.tsx +0 -137
- package/packages/design-system/src/components/Button/index.ts +0 -3
- package/packages/design-system/src/components/DataTable/DataTable.stories.tsx +0 -211
- package/packages/design-system/src/components/DataTable/DataTable.tsx +0 -293
- package/packages/design-system/src/components/DataTable/index.ts +0 -3
- package/packages/design-system/src/components/Form/Checkbox.stories.tsx +0 -252
- package/packages/design-system/src/components/Form/Checkbox.tsx +0 -114
- package/packages/design-system/src/components/Form/Fieldset.stories.tsx +0 -210
- package/packages/design-system/src/components/Form/Fieldset.tsx +0 -71
- package/packages/design-system/src/components/Form/Input.stories.tsx +0 -164
- package/packages/design-system/src/components/Form/Input.tsx +0 -113
- package/packages/design-system/src/components/Form/Label.tsx +0 -56
- package/packages/design-system/src/components/Form/Radio.stories.tsx +0 -265
- package/packages/design-system/src/components/Form/Radio.tsx +0 -147
- package/packages/design-system/src/components/Form/Select.stories.tsx +0 -295
- package/packages/design-system/src/components/Form/Select.tsx +0 -160
- package/packages/design-system/src/components/Form/Textarea.stories.tsx +0 -253
- package/packages/design-system/src/components/Form/Textarea.tsx +0 -145
- package/packages/design-system/src/components/Form/index.ts +0 -8
- package/packages/design-system/src/components/Link/Link.stories.tsx +0 -128
- package/packages/design-system/src/components/Link/Link.tsx +0 -117
- package/packages/design-system/src/components/Link/index.ts +0 -3
- package/packages/design-system/src/components/Modal/Modal.stories.tsx +0 -165
- package/packages/design-system/src/components/Modal/Modal.tsx +0 -202
- package/packages/design-system/src/components/Modal/index.ts +0 -3
- package/packages/design-system/src/components/Tabs/Tabs.stories.tsx +0 -213
- package/packages/design-system/src/components/Tabs/Tabs.tsx +0 -248
- package/packages/design-system/src/components/Tabs/index.ts +0 -3
- package/packages/design-system/src/components/Toast/Toast.stories.tsx +0 -153
- package/packages/design-system/src/components/Toast/Toast.tsx +0 -175
- package/packages/design-system/src/components/Toast/ToastProvider.tsx +0 -73
- package/packages/design-system/src/components/Toast/index.ts +0 -5
- package/packages/design-system/src/hooks/useAriaLive.ts +0 -51
- package/packages/design-system/src/hooks/useFocusReturn.ts +0 -40
- package/packages/design-system/src/hooks/useFocusTrap.ts +0 -82
- package/packages/design-system/src/styles/index.ts +0 -3
- package/packages/design-system/src/tokens/breakpoints.ts +0 -28
- package/packages/design-system/src/tokens/colors.ts +0 -98
- package/packages/design-system/src/tokens/index.ts +0 -6
- package/packages/design-system/src/tokens/motion.ts +0 -41
- package/packages/design-system/src/tokens/spacing.ts +0 -24
- package/packages/design-system/src/tokens/theme.ts +0 -19
- package/packages/design-system/src/tokens/typography.ts +0 -64
- package/packages/design-system/src/utils/aria.ts +0 -108
- package/packages/design-system/src/utils/focus.ts +0 -87
- package/packages/design-system/src/utils/index.ts +0 -4
- package/packages/design-system/src/utils/keyboard.ts +0 -77
- package/packages/design-system/tsconfig.json +0 -17
- package/public/logo.png +0 -0
- package/scripts/fix-storybook-paths.js +0 -53
- package/tsconfig.json +0 -20
- /package/{packages/design-system/src → dist}/components/Button/Button.css +0 -0
- /package/{packages/design-system/src → dist}/components/DataTable/DataTable.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Checkbox.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Fieldset.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Input.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Label.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Radio.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Select.css +0 -0
- /package/{packages/design-system/src → dist}/components/Form/Textarea.css +0 -0
- /package/{packages/design-system/src → dist}/components/Link/Link.css +0 -0
- /package/{packages/design-system/src → dist}/components/Modal/Modal.css +0 -0
- /package/{packages/design-system/src → dist}/components/Tabs/Tabs.css +0 -0
- /package/{packages/design-system/src → dist}/components/Toast/Toast.css +0 -0
- /package/{packages/design-system/src → dist}/components/Toast/ToastProvider.css +0 -0
- /package/{packages/design-system/src → dist}/styles/components.css +0 -0
- /package/{packages/design-system/src → dist}/styles/global.css +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focus management utilities
|
|
3
|
+
* Helpers for programmatic focus control
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Get all focusable elements within a container
|
|
7
|
+
*/
|
|
8
|
+
export declare function getFocusableElements(container: HTMLElement): HTMLElement[];
|
|
9
|
+
/**
|
|
10
|
+
* Get the first focusable element in a container
|
|
11
|
+
*/
|
|
12
|
+
export declare function getFirstFocusable(container: HTMLElement): HTMLElement | null;
|
|
13
|
+
/**
|
|
14
|
+
* Get the last focusable element in a container
|
|
15
|
+
*/
|
|
16
|
+
export declare function getLastFocusable(container: HTMLElement): HTMLElement | null;
|
|
17
|
+
/**
|
|
18
|
+
* Check if an element is focusable
|
|
19
|
+
*/
|
|
20
|
+
export declare function isFocusable(element: HTMLElement): boolean;
|
|
21
|
+
export declare function saveFocus(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Restore focus to the previously saved element
|
|
24
|
+
*/
|
|
25
|
+
export declare function restoreFocus(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Focus an element safely (with error handling)
|
|
28
|
+
*/
|
|
29
|
+
export declare function safeFocus(element: HTMLElement | null): void;
|
|
30
|
+
//# sourceMappingURL=focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/utils/focus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,WAAW,GACrB,WAAW,EAAE,CAWf;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAG5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAG3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAQzD;AAOD,wBAAgB,SAAS,IAAI,IAAI,CAIhC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAKnC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAS3D"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focus management utilities
|
|
3
|
+
* Helpers for programmatic focus control
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Get all focusable elements within a container
|
|
7
|
+
*/
|
|
8
|
+
export function getFocusableElements(container) {
|
|
9
|
+
const focusableSelectors = [
|
|
10
|
+
'a[href]',
|
|
11
|
+
'button:not([disabled])',
|
|
12
|
+
'textarea:not([disabled])',
|
|
13
|
+
'input:not([disabled])',
|
|
14
|
+
'select:not([disabled])',
|
|
15
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
16
|
+
].join(', ');
|
|
17
|
+
return Array.from(container.querySelectorAll(focusableSelectors));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the first focusable element in a container
|
|
21
|
+
*/
|
|
22
|
+
export function getFirstFocusable(container) {
|
|
23
|
+
const focusable = getFocusableElements(container);
|
|
24
|
+
return focusable[0] || null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the last focusable element in a container
|
|
28
|
+
*/
|
|
29
|
+
export function getLastFocusable(container) {
|
|
30
|
+
const focusable = getFocusableElements(container);
|
|
31
|
+
return focusable[focusable.length - 1] || null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if an element is focusable
|
|
35
|
+
*/
|
|
36
|
+
export function isFocusable(element) {
|
|
37
|
+
if (element.tabIndex < 0)
|
|
38
|
+
return false;
|
|
39
|
+
if (element.hasAttribute('disabled'))
|
|
40
|
+
return false;
|
|
41
|
+
if (element.hasAttribute('hidden'))
|
|
42
|
+
return false;
|
|
43
|
+
if (element.style.display === 'none')
|
|
44
|
+
return false;
|
|
45
|
+
if (element.style.visibility === 'hidden')
|
|
46
|
+
return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Save the currently focused element
|
|
51
|
+
*/
|
|
52
|
+
let savedFocusElement = null;
|
|
53
|
+
export function saveFocus() {
|
|
54
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
55
|
+
savedFocusElement = document.activeElement;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Restore focus to the previously saved element
|
|
60
|
+
*/
|
|
61
|
+
export function restoreFocus() {
|
|
62
|
+
if (savedFocusElement) {
|
|
63
|
+
savedFocusElement.focus();
|
|
64
|
+
savedFocusElement = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Focus an element safely (with error handling)
|
|
69
|
+
*/
|
|
70
|
+
export function safeFocus(element) {
|
|
71
|
+
if (element && typeof element.focus === 'function') {
|
|
72
|
+
try {
|
|
73
|
+
element.focus();
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
// Silently fail if focus fails
|
|
77
|
+
console.warn('Failed to focus element:', error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard event utilities
|
|
3
|
+
* Helpers for handling keyboard interactions
|
|
4
|
+
*/
|
|
5
|
+
export type KeyboardHandler = (event: React.KeyboardEvent) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Check if a key is an activation key (Enter or Space)
|
|
8
|
+
*/
|
|
9
|
+
export declare function isActivationKey(key: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Check if a key is an arrow key
|
|
12
|
+
*/
|
|
13
|
+
export declare function isArrowKey(key: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a key is a navigation key (Home, End, PageUp, PageDown)
|
|
16
|
+
*/
|
|
17
|
+
export declare function isNavigationKey(key: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Check if a key is an escape key
|
|
20
|
+
*/
|
|
21
|
+
export declare function isEscapeKey(key: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Check if modifier keys are pressed
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasModifierKey(event: React.KeyboardEvent): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Create a keyboard handler that only fires on specific keys
|
|
28
|
+
*/
|
|
29
|
+
export declare function createKeyHandler(keys: string[], handler: KeyboardHandler): KeyboardHandler;
|
|
30
|
+
/**
|
|
31
|
+
* Create a keyboard handler for activation keys (Enter/Space)
|
|
32
|
+
*/
|
|
33
|
+
export declare function createActivationHandler(handler: KeyboardHandler): KeyboardHandler;
|
|
34
|
+
/**
|
|
35
|
+
* Create a keyboard handler for arrow keys
|
|
36
|
+
*/
|
|
37
|
+
export declare function createArrowKeyHandler(handler: KeyboardHandler): KeyboardHandler;
|
|
38
|
+
//# sourceMappingURL=keyboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/utils/keyboard.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAA;AAElE;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAElE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,eAAe,GACvB,eAAe,CAMjB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,eAAe,GACvB,eAAe,CAKjB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,GACvB,eAAe,CAEjB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard event utilities
|
|
3
|
+
* Helpers for handling keyboard interactions
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if a key is an activation key (Enter or Space)
|
|
7
|
+
*/
|
|
8
|
+
export function isActivationKey(key) {
|
|
9
|
+
return key === 'Enter' || key === ' ';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if a key is an arrow key
|
|
13
|
+
*/
|
|
14
|
+
export function isArrowKey(key) {
|
|
15
|
+
return ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(key);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if a key is a navigation key (Home, End, PageUp, PageDown)
|
|
19
|
+
*/
|
|
20
|
+
export function isNavigationKey(key) {
|
|
21
|
+
return ['Home', 'End', 'PageUp', 'PageDown'].includes(key);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if a key is an escape key
|
|
25
|
+
*/
|
|
26
|
+
export function isEscapeKey(key) {
|
|
27
|
+
return key === 'Escape';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if modifier keys are pressed
|
|
31
|
+
*/
|
|
32
|
+
export function hasModifierKey(event) {
|
|
33
|
+
return event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a keyboard handler that only fires on specific keys
|
|
37
|
+
*/
|
|
38
|
+
export function createKeyHandler(keys, handler) {
|
|
39
|
+
return (event) => {
|
|
40
|
+
if (keys.includes(event.key)) {
|
|
41
|
+
handler(event);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a keyboard handler for activation keys (Enter/Space)
|
|
47
|
+
*/
|
|
48
|
+
export function createActivationHandler(handler) {
|
|
49
|
+
return createKeyHandler(['Enter', ' '], (event) => {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
handler(event);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a keyboard handler for arrow keys
|
|
56
|
+
*/
|
|
57
|
+
export function createArrowKeyHandler(handler) {
|
|
58
|
+
return createKeyHandler(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'], handler);
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -1,40 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a11ypros/a11y-ui-components",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "An accessibility-first React UI component library built with WCAG 2.1/2.2 compliance",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"accessibility",
|
|
8
|
+
"a11y",
|
|
9
|
+
"wcag",
|
|
10
|
+
"design-system",
|
|
11
|
+
"components",
|
|
12
|
+
"typescript"
|
|
8
13
|
],
|
|
14
|
+
"author": "Ryan Mack <ryan@a11ypros.com>",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"module": "./dist/index.js",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./styles": {
|
|
31
|
+
"import": "./dist/styles/global.css"
|
|
32
|
+
},
|
|
33
|
+
"./styles/components": {
|
|
34
|
+
"import": "./dist/styles/components.css"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/ryan0122/a11ypros-components.git",
|
|
41
|
+
"directory": "packages/design-system"
|
|
42
|
+
},
|
|
9
43
|
"scripts": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"build
|
|
14
|
-
"build:local": "mv apps/web/app/api apps/web/app/api.disabled 2>/dev/null || true && yarn install && yarn build-storybook && yarn workspace @apps/web build && mv apps/web/app/api.disabled apps/web/app/api 2>/dev/null || true",
|
|
15
|
-
"build:local:clean": "rm -rf apps/web/.next apps/web/out apps/web/public/storybook-static node_modules/.cache && yarn build:local",
|
|
16
|
-
"build:simulate": "netlify build --offline",
|
|
17
|
-
"storybook": "storybook dev -p 6006 --config-dir .storybook",
|
|
18
|
-
"build-storybook": "storybook build --config-dir .storybook --output-dir apps/web/public/storybook-static && node scripts/fix-storybook-paths.js"
|
|
44
|
+
"build": "tsc && node scripts/copy-css.js",
|
|
45
|
+
"prepublishOnly": "npm run build",
|
|
46
|
+
"storybook": "cd ../.. && npm run storybook",
|
|
47
|
+
"build-storybook": "cd ../.. && npm run build-storybook"
|
|
19
48
|
},
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
51
|
+
"react-dom": "^18.2.0 || ^19.0.0"
|
|
23
52
|
},
|
|
24
53
|
"devDependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@
|
|
27
|
-
"
|
|
28
|
-
"@storybook/react": "9.1.17",
|
|
29
|
-
"@storybook/react-vite": "9.1.17",
|
|
30
|
-
"react": "^18.2.0",
|
|
31
|
-
"react-dom": "^18.2.0",
|
|
32
|
-
"storybook": "9.1.17",
|
|
33
|
-
"typescript": "^5.3.3",
|
|
34
|
-
"vite": "^5.0.0"
|
|
35
|
-
},
|
|
36
|
-
"engines": {
|
|
37
|
-
"node": ">=18.0.0"
|
|
54
|
+
"@types/react": "^19.0.0",
|
|
55
|
+
"@types/react-dom": "^19.0.0",
|
|
56
|
+
"typescript": "^5.3.3"
|
|
38
57
|
}
|
|
39
58
|
}
|
|
40
|
-
|
package/.storybook/custom.css
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/* Custom Storybook styles */
|
|
2
|
-
|
|
3
|
-
/* Override Storybook's default bright blue link color */
|
|
4
|
-
.sbdocs a,
|
|
5
|
-
.sbdocs a:link,
|
|
6
|
-
.docs-story a,
|
|
7
|
-
.docs-story a:link {
|
|
8
|
-
color: #0e8168 !important;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.sbdocs a:hover,
|
|
12
|
-
.docs-story a:hover {
|
|
13
|
-
color: #075985 !important;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.sbdocs a:visited,
|
|
17
|
-
.docs-story a:visited {
|
|
18
|
-
color: #0369a1 !important;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/* Fix controls pane button hover states - ensure text is visible */
|
|
22
|
-
.sb-controls button:hover,
|
|
23
|
-
.sb-controls button:focus,
|
|
24
|
-
[data-testid="control-buttons-container"] button:hover,
|
|
25
|
-
[data-testid="control-buttons-container"] button:focus,
|
|
26
|
-
button[aria-label*="Set"]:hover,
|
|
27
|
-
button[aria-label*="Set"]:focus,
|
|
28
|
-
button[aria-label*="Reset"]:hover,
|
|
29
|
-
button[aria-label*="Reset"]:focus,
|
|
30
|
-
[id*="storybook-panel"] button:hover,
|
|
31
|
-
[id*="storybook-panel"] button:focus {
|
|
32
|
-
color: #171717 !important;
|
|
33
|
-
background-color: #f5f5f5 !important;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/* Ensure button text is visible in all states */
|
|
37
|
-
.sb-controls button,
|
|
38
|
-
[data-testid="control-buttons-container"] button,
|
|
39
|
-
button[aria-label*="Set"],
|
|
40
|
-
button[aria-label*="Reset"],
|
|
41
|
-
[id*="storybook-panel"] button {
|
|
42
|
-
color: #171717 !important;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* Override left sidebar navigation hover colors to match color scheme */
|
|
46
|
-
.sidebar-container [role="menuitem"]:hover,
|
|
47
|
-
.sidebar-container [role="menuitem"]:focus,
|
|
48
|
-
.sidebar-container a:hover,
|
|
49
|
-
.sidebar-container a:focus,
|
|
50
|
-
[data-nodetype="story"]:hover,
|
|
51
|
-
[data-nodetype="story"]:focus,
|
|
52
|
-
[data-nodetype="component"]:hover,
|
|
53
|
-
[data-nodetype="component"]:focus,
|
|
54
|
-
[data-nodetype="group"]:hover,
|
|
55
|
-
[data-nodetype="group"]:focus {
|
|
56
|
-
background-color: #f5f5f5 !important;
|
|
57
|
-
color: #0e8168 !important;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/* Override selected state to use primary color */
|
|
61
|
-
.sidebar-container [role="menuitem"][aria-selected="true"],
|
|
62
|
-
.sidebar-container [role="menuitem"][aria-current="true"],
|
|
63
|
-
[data-nodetype="story"][aria-selected="true"],
|
|
64
|
-
[data-nodetype="component"][aria-selected="true"] {
|
|
65
|
-
background-color: #f0f9ff !important;
|
|
66
|
-
color: #0e8168 !important;
|
|
67
|
-
border-left-color: #0e8168 !important;
|
|
68
|
-
}
|
|
69
|
-
|
package/.storybook/main.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { StorybookConfig } from '@storybook/react-vite'
|
|
2
|
-
|
|
3
|
-
const config: StorybookConfig = {
|
|
4
|
-
stories: [
|
|
5
|
-
'../.storybook/welcome.mdx',
|
|
6
|
-
'../packages/design-system/src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
|
7
|
-
addons: [
|
|
8
|
-
'@storybook/addon-links',
|
|
9
|
-
'@storybook/addon-a11y',
|
|
10
|
-
'@storybook/addon-docs',
|
|
11
|
-
],
|
|
12
|
-
framework: {
|
|
13
|
-
name: '@storybook/react-vite',
|
|
14
|
-
options: {
|
|
15
|
-
viteConfigPath: '.storybook/vite.config.ts',
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
viteFinal: async (config) => {
|
|
19
|
-
config.define = {
|
|
20
|
-
...config.define,
|
|
21
|
-
'process.env': {},
|
|
22
|
-
'process': { env: {} },
|
|
23
|
-
}
|
|
24
|
-
return config
|
|
25
|
-
},
|
|
26
|
-
docs: {
|
|
27
|
-
autodocs: 'tag',
|
|
28
|
-
},
|
|
29
|
-
typescript: {
|
|
30
|
-
check: false,
|
|
31
|
-
reactDocgen: 'react-docgen-typescript',
|
|
32
|
-
reactDocgenTypescriptOptions: {
|
|
33
|
-
shouldExtractLiteralValuesFromEnum: true,
|
|
34
|
-
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
core: {
|
|
38
|
-
disableTelemetry: true,
|
|
39
|
-
},
|
|
40
|
-
staticDirs: ['../public'],
|
|
41
|
-
// Base path is configured in vite.config.ts to use /storybook-static/
|
|
42
|
-
// This ensures assets use absolute paths that match where files are located
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default config
|
|
46
|
-
|
package/.storybook/manager.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { addons } from '@storybook/manager-api'
|
|
2
|
-
import { create } from '@storybook/theming'
|
|
3
|
-
import './custom.css'
|
|
4
|
-
|
|
5
|
-
const theme = create({
|
|
6
|
-
base: 'light',
|
|
7
|
-
brandTitle: 'A11y Pros Design System',
|
|
8
|
-
brandUrl: '/storybook',
|
|
9
|
-
brandImage: '/storybook-static/logo.png', // Path to your logo file (served from staticDirs)
|
|
10
|
-
brandTarget: '_self',
|
|
11
|
-
|
|
12
|
-
colorPrimary: '#0e8168',
|
|
13
|
-
colorSecondary: '#001d2f',
|
|
14
|
-
|
|
15
|
-
// Toolbar colors
|
|
16
|
-
barTextColor: '#171717',
|
|
17
|
-
barSelectedColor: '#0e8168', // Selected nav item color (matches colorPrimary)
|
|
18
|
-
barHoverColor: '#f5f5f5', // Hover color for nav items in left sidebar
|
|
19
|
-
barBg: '#ffffff',
|
|
20
|
-
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
addons.setConfig({
|
|
24
|
-
theme,
|
|
25
|
-
})
|
|
26
|
-
|
package/.storybook/package.json
DELETED
package/.storybook/preview.tsx
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Preview } from '@storybook/react'
|
|
2
|
-
import '../packages/design-system/src/styles/global.css'
|
|
3
|
-
import './custom.css'
|
|
4
|
-
|
|
5
|
-
const preview: Preview = {
|
|
6
|
-
parameters: {
|
|
7
|
-
actions: { argTypesRegex: '^on[A-Z].*' },
|
|
8
|
-
controls: {
|
|
9
|
-
matchers: {
|
|
10
|
-
color: /(background|color)$/i,
|
|
11
|
-
date: /Date$/i,
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
a11y: {
|
|
15
|
-
config: {
|
|
16
|
-
rules: [
|
|
17
|
-
{
|
|
18
|
-
id: 'color-contrast',
|
|
19
|
-
enabled: true,
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
docs: {
|
|
25
|
-
toc: false,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default preview
|
|
31
|
-
|
|
Binary file
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite'
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
base: '/storybook-static/',
|
|
5
|
-
define: {
|
|
6
|
-
'process.env': {},
|
|
7
|
-
'process': {
|
|
8
|
-
env: {},
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
|
-
build: {
|
|
12
|
-
// Ensure assets use absolute paths
|
|
13
|
-
assetsDir: 'assets',
|
|
14
|
-
// Disable source maps in production to avoid eval issues
|
|
15
|
-
sourcemap: false,
|
|
16
|
-
// Ensure proper minification
|
|
17
|
-
minify: 'esbuild',
|
|
18
|
-
},
|
|
19
|
-
// Ensure proper module resolution
|
|
20
|
-
resolve: {
|
|
21
|
-
preserveSymlinks: false,
|
|
22
|
-
},
|
|
23
|
-
})
|
|
24
|
-
|
package/.storybook/welcome.mdx
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { Meta } from '@storybook/blocks';
|
|
2
|
-
|
|
3
|
-
<Meta title="Welcome" />
|
|
4
|
-
|
|
5
|
-
# Welcome to the A11y Pros Accessible Design System
|
|
6
|
-
|
|
7
|
-
Welcome to our **accessibility-first React UI component library**. This design system provides a comprehensive collection of fully accessible components built with React, TypeScript, and modern web standards.
|
|
8
|
-
|
|
9
|
-
[View on GitHub](https://github.com/ryan0122/a11ypros-components) • [Live Documentation](https://ui.a11ypros.com)
|
|
10
|
-
|
|
11
|
-
## About This Design System
|
|
12
|
-
|
|
13
|
-
This design system is **authored with accessibility in mind by a certified WAS (Web Accessibility Specialist)**. Every component has been carefully crafted to meet WCAG 2.1/2.2 Level AA standards, ensuring that your applications are usable by everyone, regardless of their abilities or the assistive technologies they use.
|
|
14
|
-
|
|
15
|
-
**Note**: Currently, English is the only supported language for screen reader text and ARIA labels. Internationalization (i18n) support is coming soon.
|
|
16
|
-
|
|
17
|
-
### Key Features
|
|
18
|
-
|
|
19
|
-
- **Fully Accessible Components**: All React UI components are fully accessible, featuring proper ARIA attributes, keyboard navigation, and screen reader support
|
|
20
|
-
- **WCAG 2.1/2.2 Compliant**: Components follow accessibility best practices and meet WCAG Level AA standards
|
|
21
|
-
- **Keyboard Navigation**: Complete keyboard support for all interactive elements
|
|
22
|
-
- **Focus Management**: Proper focus trapping and return focus patterns for modals and dialogs
|
|
23
|
-
- **Semantic HTML**: Components use semantic HTML with ARIA enhancements where needed
|
|
24
|
-
- **Reduced Motion Support**: Respects `prefers-reduced-motion` media query
|
|
25
|
-
- **High Contrast Support**: Supports `prefers-contrast` for better visibility
|
|
26
|
-
- **Design Token System**: Consistent spacing, colors, typography, and motion tokens
|
|
27
|
-
|
|
28
|
-
## Available Components
|
|
29
|
-
|
|
30
|
-
Our component library includes:
|
|
31
|
-
|
|
32
|
-
- **Button**: Accessible button with variants, sizes, and loading states
|
|
33
|
-
- **Link**: Semantic link component with external link detection
|
|
34
|
-
- **Modal**: Focus-trapped modal dialog with ARIA support
|
|
35
|
-
- **DataTable**: Accessible table with keyboard navigation and sorting
|
|
36
|
-
- **Toast**: Notification system with ARIA live regions
|
|
37
|
-
- **Tabs**: Tab component with arrow key navigation
|
|
38
|
-
- **Form Components**: Input, Textarea, Select, Checkbox, Radio, Fieldset, Label
|
|
39
|
-
|
|
40
|
-
## Coming Soon
|
|
41
|
-
|
|
42
|
-
The following components are currently in development and will be available soon:
|
|
43
|
-
|
|
44
|
-
- **DatePicker**: Accessible date selection component with keyboard navigation
|
|
45
|
-
- **Banner**: Alert banner component with ARIA live region support
|
|
46
|
-
- **Phone Text Field**: Specialized input field for phone numbers with formatting
|
|
47
|
-
- **Combobox**: Accessible autocomplete/combobox component with ARIA 1.2 patterns
|
|
48
|
-
|
|
49
|
-
## Getting Started
|
|
50
|
-
|
|
51
|
-
Browse the component stories in the sidebar to explore each component's:
|
|
52
|
-
- Usage examples
|
|
53
|
-
- Accessibility features
|
|
54
|
-
- Keyboard interaction patterns
|
|
55
|
-
- WCAG compliance information
|
|
56
|
-
- Props and API documentation
|
|
57
|
-
|
|
58
|
-
## Accessibility First
|
|
59
|
-
|
|
60
|
-
As a **certified WAS web accessibility specialist**, I've ensured that every component in this library:
|
|
61
|
-
|
|
62
|
-
- Uses semantic HTML elements
|
|
63
|
-
- Implements proper ARIA attributes
|
|
64
|
-
- Supports full keyboard navigation
|
|
65
|
-
- Provides visible focus indicators
|
|
66
|
-
- Meets WCAG contrast requirements
|
|
67
|
-
- Works seamlessly with screen readers
|
|
68
|
-
- Handles focus management appropriately
|
|
69
|
-
|
|
70
|
-
Each component story includes detailed accessibility documentation, so you can understand how to use these components in an accessible way.
|
|
71
|
-
|
|
72
|
-
## Important Note on Accessibility
|
|
73
|
-
|
|
74
|
-
> **Note**: While these components are built with accessibility in mind and meet WCAG 2.1/2.2 Level AA standards, **simply using these components does not guarantee an accessible application**. These components are foundational building blocks that must be used properly within the larger consuming application with accessibility in mind.
|
|
75
|
-
|
|
76
|
-
To ensure your application is truly accessible, consider:
|
|
77
|
-
|
|
78
|
-
- **Proper Implementation**: Use components according to their documented patterns and accessibility guidelines
|
|
79
|
-
- **Application-Level Considerations**: Ensure proper page structure, heading hierarchy, and landmark regions
|
|
80
|
-
- **Content Accessibility**: Write clear, descriptive text and provide alternative text for images
|
|
81
|
-
- **Testing**: Regularly test your application with keyboard navigation and screen readers
|
|
82
|
-
- **User Experience**: Consider the full user journey and how components work together
|
|
83
|
-
|
|
84
|
-
These components provide a solid foundation, but accessibility is achieved through thoughtful implementation across your entire application.
|
|
85
|
-
|
|
86
|
-
## Design Tokens
|
|
87
|
-
|
|
88
|
-
The design system uses CSS custom properties for theming, ensuring consistency across your application while maintaining accessibility standards for color contrast and spacing.
|
|
89
|
-
|
|
90
|
-
## Need Help?
|
|
91
|
-
|
|
92
|
-
Explore the component stories to see examples, accessibility notes, and implementation details. Each component is documented with its WCAG compliance information and keyboard interaction patterns.
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
**Built with accessibility in mind by a certified WAS web accessibility specialist.**
|
|
97
|
-
|