@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.
Files changed (217) hide show
  1. package/README.md +182 -157
  2. package/dist/components/Button/Button.d.ts +37 -0
  3. package/dist/components/Button/Button.d.ts.map +1 -0
  4. package/dist/components/Button/Button.js +52 -0
  5. package/dist/components/Button/index.d.ts +3 -0
  6. package/dist/components/Button/index.d.ts.map +1 -0
  7. package/dist/components/Button/index.js +1 -0
  8. package/dist/components/DataTable/DataTable.d.ts +71 -0
  9. package/dist/components/DataTable/DataTable.d.ts.map +1 -0
  10. package/dist/components/DataTable/DataTable.js +122 -0
  11. package/dist/components/DataTable/index.d.ts +3 -0
  12. package/dist/components/DataTable/index.d.ts.map +1 -0
  13. package/dist/components/DataTable/index.js +1 -0
  14. package/dist/components/Form/Checkbox.d.ts +36 -0
  15. package/dist/components/Form/Checkbox.d.ts.map +1 -0
  16. package/dist/components/Form/Checkbox.js +39 -0
  17. package/dist/components/Form/Fieldset.d.ts +33 -0
  18. package/dist/components/Form/Fieldset.d.ts.map +1 -0
  19. package/dist/components/Form/Fieldset.js +34 -0
  20. package/dist/components/Form/Input.d.ts +37 -0
  21. package/dist/components/Form/Input.d.ts.map +1 -0
  22. package/dist/components/Form/Input.js +41 -0
  23. package/dist/components/Form/Label.d.ts +30 -0
  24. package/dist/components/Form/Label.d.ts.map +1 -0
  25. package/dist/components/Form/Label.js +30 -0
  26. package/dist/components/Form/Radio.d.ts +53 -0
  27. package/dist/components/Form/Radio.d.ts.map +1 -0
  28. package/dist/components/Form/Radio.js +39 -0
  29. package/dist/components/Form/Select.d.ts +51 -0
  30. package/dist/components/Form/Select.d.ts.map +1 -0
  31. package/dist/components/Form/Select.js +49 -0
  32. package/dist/components/Form/Textarea.d.ts +44 -0
  33. package/dist/components/Form/Textarea.d.ts.map +1 -0
  34. package/dist/components/Form/Textarea.js +43 -0
  35. package/dist/components/Form/index.d.ts +8 -0
  36. package/dist/components/Form/index.d.ts.map +1 -0
  37. package/dist/components/Form/index.js +7 -0
  38. package/dist/components/Link/Link.d.ts +34 -0
  39. package/dist/components/Link/Link.d.ts.map +1 -0
  40. package/dist/components/Link/Link.js +48 -0
  41. package/dist/components/Link/index.d.ts +3 -0
  42. package/dist/components/Link/index.d.ts.map +1 -0
  43. package/dist/components/Link/index.js +1 -0
  44. package/dist/components/Modal/Modal.d.ts +64 -0
  45. package/dist/components/Modal/Modal.d.ts.map +1 -0
  46. package/dist/components/Modal/Modal.js +108 -0
  47. package/dist/components/Modal/index.d.ts +3 -0
  48. package/dist/components/Modal/index.d.ts.map +1 -0
  49. package/dist/components/Modal/index.js +1 -0
  50. package/dist/components/Tabs/Tabs.d.ts +63 -0
  51. package/dist/components/Tabs/Tabs.d.ts.map +1 -0
  52. package/dist/components/Tabs/Tabs.js +134 -0
  53. package/dist/components/Tabs/index.d.ts +3 -0
  54. package/dist/components/Tabs/index.d.ts.map +1 -0
  55. package/dist/components/Tabs/index.js +1 -0
  56. package/dist/components/Toast/Toast.d.ts +59 -0
  57. package/dist/components/Toast/Toast.d.ts.map +1 -0
  58. package/dist/components/Toast/Toast.js +91 -0
  59. package/dist/components/Toast/ToastProvider.d.ts +22 -0
  60. package/dist/components/Toast/ToastProvider.d.ts.map +1 -0
  61. package/dist/components/Toast/ToastProvider.js +33 -0
  62. package/dist/components/Toast/index.d.ts +5 -0
  63. package/dist/components/Toast/index.d.ts.map +1 -0
  64. package/dist/components/Toast/index.js +2 -0
  65. package/dist/hooks/useAriaLive.d.ts +9 -0
  66. package/dist/hooks/useAriaLive.d.ts.map +1 -0
  67. package/dist/hooks/useAriaLive.js +39 -0
  68. package/dist/hooks/useFocusReturn.d.ts +9 -0
  69. package/dist/hooks/useFocusReturn.d.ts.map +1 -0
  70. package/dist/hooks/useFocusReturn.js +33 -0
  71. package/dist/hooks/useFocusTrap.d.ts +9 -0
  72. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  73. package/dist/hooks/useFocusTrap.js +68 -0
  74. package/dist/index.d.ts +22 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/{packages/design-system/src/index.ts → dist/index.js} +0 -4
  77. package/dist/styles/index.d.ts +3 -0
  78. package/dist/styles/index.d.ts.map +1 -0
  79. package/dist/styles/index.js +1 -0
  80. package/dist/tokens/breakpoints.d.ts +25 -0
  81. package/dist/tokens/breakpoints.d.ts.map +1 -0
  82. package/dist/tokens/breakpoints.js +23 -0
  83. package/dist/tokens/colors.d.ts +81 -0
  84. package/dist/tokens/colors.d.ts.map +1 -0
  85. package/dist/tokens/colors.js +86 -0
  86. package/dist/tokens/index.d.ts +6 -0
  87. package/dist/tokens/index.d.ts.map +1 -0
  88. package/dist/tokens/index.js +5 -0
  89. package/dist/tokens/motion.d.ts +30 -0
  90. package/dist/tokens/motion.d.ts.map +1 -0
  91. package/dist/tokens/motion.js +34 -0
  92. package/dist/tokens/spacing.d.ts +22 -0
  93. package/dist/tokens/spacing.d.ts.map +1 -0
  94. package/dist/tokens/spacing.js +20 -0
  95. package/dist/tokens/theme.d.ts +159 -0
  96. package/dist/tokens/theme.d.ts.map +1 -0
  97. package/dist/tokens/theme.js +15 -0
  98. package/dist/tokens/typography.d.ts +45 -0
  99. package/dist/tokens/typography.d.ts.map +1 -0
  100. package/dist/tokens/typography.js +56 -0
  101. package/dist/utils/aria.d.ts +60 -0
  102. package/dist/utils/aria.d.ts.map +1 -0
  103. package/dist/utils/aria.js +86 -0
  104. package/dist/utils/focus.d.ts +30 -0
  105. package/dist/utils/focus.d.ts.map +1 -0
  106. package/dist/utils/focus.js +80 -0
  107. package/dist/utils/index.d.ts +4 -0
  108. package/dist/utils/index.d.ts.map +1 -0
  109. package/dist/utils/index.js +3 -0
  110. package/dist/utils/keyboard.d.ts +38 -0
  111. package/dist/utils/keyboard.d.ts.map +1 -0
  112. package/dist/utils/keyboard.js +59 -0
  113. package/package.json +49 -31
  114. package/.storybook/custom.css +0 -69
  115. package/.storybook/main.ts +0 -46
  116. package/.storybook/manager.ts +0 -26
  117. package/.storybook/package.json +0 -6
  118. package/.storybook/preview.tsx +0 -31
  119. package/.storybook/public/logo.png +0 -0
  120. package/.storybook/vite.config.ts +0 -24
  121. package/.storybook/welcome.mdx +0 -97
  122. package/DEPLOYMENT.md +0 -154
  123. package/apps/web/app/(docs)/audit/audit.css +0 -269
  124. package/apps/web/app/(docs)/audit/page.tsx +0 -271
  125. package/apps/web/app/(docs)/components/button/page.tsx +0 -49
  126. package/apps/web/app/(docs)/components/form/page.tsx +0 -92
  127. package/apps/web/app/(docs)/components/link/page.tsx +0 -31
  128. package/apps/web/app/(docs)/components/modal/page.tsx +0 -41
  129. package/apps/web/app/(docs)/components/page.tsx +0 -37
  130. package/apps/web/app/(docs)/components/table/page.tsx +0 -54
  131. package/apps/web/app/(docs)/components/tabs/page.tsx +0 -61
  132. package/apps/web/app/(docs)/components/toast/page.tsx +0 -51
  133. package/apps/web/app/api/audit/route.ts +0 -128
  134. package/apps/web/app/favicon.ico +0 -0
  135. package/apps/web/app/layout.tsx +0 -20
  136. package/apps/web/app/page.tsx +0 -17
  137. package/apps/web/app/styles/globals.css +0 -5
  138. package/apps/web/next-env.d.ts +0 -5
  139. package/apps/web/next.config.js +0 -21
  140. package/apps/web/package.json +0 -28
  141. package/apps/web/public/_headers +0 -17
  142. package/apps/web/public/_redirects +0 -31
  143. package/apps/web/public/logo.png +0 -0
  144. package/apps/web/tsconfig.json +0 -29
  145. package/netlify/functions/audit.ts +0 -163
  146. package/netlify.toml +0 -37
  147. package/packages/design-system/README.md +0 -252
  148. package/packages/design-system/package.json +0 -68
  149. package/packages/design-system/scripts/copy-css.js +0 -63
  150. package/packages/design-system/src/components/Button/Button.stories.tsx +0 -228
  151. package/packages/design-system/src/components/Button/Button.tsx +0 -137
  152. package/packages/design-system/src/components/Button/index.ts +0 -3
  153. package/packages/design-system/src/components/DataTable/DataTable.stories.tsx +0 -211
  154. package/packages/design-system/src/components/DataTable/DataTable.tsx +0 -293
  155. package/packages/design-system/src/components/DataTable/index.ts +0 -3
  156. package/packages/design-system/src/components/Form/Checkbox.stories.tsx +0 -252
  157. package/packages/design-system/src/components/Form/Checkbox.tsx +0 -114
  158. package/packages/design-system/src/components/Form/Fieldset.stories.tsx +0 -210
  159. package/packages/design-system/src/components/Form/Fieldset.tsx +0 -71
  160. package/packages/design-system/src/components/Form/Input.stories.tsx +0 -164
  161. package/packages/design-system/src/components/Form/Input.tsx +0 -113
  162. package/packages/design-system/src/components/Form/Label.tsx +0 -56
  163. package/packages/design-system/src/components/Form/Radio.stories.tsx +0 -265
  164. package/packages/design-system/src/components/Form/Radio.tsx +0 -147
  165. package/packages/design-system/src/components/Form/Select.stories.tsx +0 -295
  166. package/packages/design-system/src/components/Form/Select.tsx +0 -160
  167. package/packages/design-system/src/components/Form/Textarea.stories.tsx +0 -253
  168. package/packages/design-system/src/components/Form/Textarea.tsx +0 -145
  169. package/packages/design-system/src/components/Form/index.ts +0 -8
  170. package/packages/design-system/src/components/Link/Link.stories.tsx +0 -128
  171. package/packages/design-system/src/components/Link/Link.tsx +0 -117
  172. package/packages/design-system/src/components/Link/index.ts +0 -3
  173. package/packages/design-system/src/components/Modal/Modal.stories.tsx +0 -165
  174. package/packages/design-system/src/components/Modal/Modal.tsx +0 -202
  175. package/packages/design-system/src/components/Modal/index.ts +0 -3
  176. package/packages/design-system/src/components/Tabs/Tabs.stories.tsx +0 -213
  177. package/packages/design-system/src/components/Tabs/Tabs.tsx +0 -248
  178. package/packages/design-system/src/components/Tabs/index.ts +0 -3
  179. package/packages/design-system/src/components/Toast/Toast.stories.tsx +0 -153
  180. package/packages/design-system/src/components/Toast/Toast.tsx +0 -175
  181. package/packages/design-system/src/components/Toast/ToastProvider.tsx +0 -73
  182. package/packages/design-system/src/components/Toast/index.ts +0 -5
  183. package/packages/design-system/src/hooks/useAriaLive.ts +0 -51
  184. package/packages/design-system/src/hooks/useFocusReturn.ts +0 -40
  185. package/packages/design-system/src/hooks/useFocusTrap.ts +0 -82
  186. package/packages/design-system/src/styles/index.ts +0 -3
  187. package/packages/design-system/src/tokens/breakpoints.ts +0 -28
  188. package/packages/design-system/src/tokens/colors.ts +0 -98
  189. package/packages/design-system/src/tokens/index.ts +0 -6
  190. package/packages/design-system/src/tokens/motion.ts +0 -41
  191. package/packages/design-system/src/tokens/spacing.ts +0 -24
  192. package/packages/design-system/src/tokens/theme.ts +0 -19
  193. package/packages/design-system/src/tokens/typography.ts +0 -64
  194. package/packages/design-system/src/utils/aria.ts +0 -108
  195. package/packages/design-system/src/utils/focus.ts +0 -87
  196. package/packages/design-system/src/utils/index.ts +0 -4
  197. package/packages/design-system/src/utils/keyboard.ts +0 -77
  198. package/packages/design-system/tsconfig.json +0 -17
  199. package/public/logo.png +0 -0
  200. package/scripts/fix-storybook-paths.js +0 -53
  201. package/tsconfig.json +0 -20
  202. /package/{packages/design-system/src → dist}/components/Button/Button.css +0 -0
  203. /package/{packages/design-system/src → dist}/components/DataTable/DataTable.css +0 -0
  204. /package/{packages/design-system/src → dist}/components/Form/Checkbox.css +0 -0
  205. /package/{packages/design-system/src → dist}/components/Form/Fieldset.css +0 -0
  206. /package/{packages/design-system/src → dist}/components/Form/Input.css +0 -0
  207. /package/{packages/design-system/src → dist}/components/Form/Label.css +0 -0
  208. /package/{packages/design-system/src → dist}/components/Form/Radio.css +0 -0
  209. /package/{packages/design-system/src → dist}/components/Form/Select.css +0 -0
  210. /package/{packages/design-system/src → dist}/components/Form/Textarea.css +0 -0
  211. /package/{packages/design-system/src → dist}/components/Link/Link.css +0 -0
  212. /package/{packages/design-system/src → dist}/components/Modal/Modal.css +0 -0
  213. /package/{packages/design-system/src → dist}/components/Tabs/Tabs.css +0 -0
  214. /package/{packages/design-system/src → dist}/components/Toast/Toast.css +0 -0
  215. /package/{packages/design-system/src → dist}/components/Toast/ToastProvider.css +0 -0
  216. /package/{packages/design-system/src → dist}/styles/components.css +0 -0
  217. /package/{packages/design-system/src → dist}/styles/global.css +0 -0
package/DEPLOYMENT.md DELETED
@@ -1,154 +0,0 @@
1
- # Deployment Guide for ui.a11ypros.com
2
-
3
- This guide covers deploying the component library and Storybook to Netlify at `ui.a11ypros.com`.
4
-
5
- ## What's Configured
6
-
7
- ✅ **Netlify Configuration** (`netlify.toml`)
8
- - Builds Storybook and Next.js app
9
- - Serves Storybook at `/storybook`
10
- - Routes API calls to Netlify Functions
11
-
12
- ✅ **Next.js Static Export**
13
- - Configured for static site generation
14
- - Outputs to `apps/web/out`
15
-
16
- ✅ **Storybook Build**
17
- - Builds to `apps/web/public/storybook-static`
18
- - Accessible at `ui.a11ypros.com/storybook`
19
-
20
- ✅ **Netlify Function**
21
- - Audit API converted to serverless function
22
- - Located at `netlify/functions/audit.ts`
23
- - Accessible via `/api/audit` (auto-redirected)
24
-
25
- ## Deployment Steps
26
-
27
- ### 1. Connect Repository to Netlify
28
-
29
- 1. Go to [Netlify Dashboard](https://app.netlify.com)
30
- 2. Click "Add new site" → "Import an existing project"
31
- 3. Connect your Git provider and select this repository
32
-
33
- ### 2. Configure Build Settings
34
-
35
- Netlify should auto-detect `netlify.toml`, but verify:
36
- - **Base directory:** `.` (root)
37
- - **Build command:** `npm install && npm run build-storybook && npm run build --workspace=apps/web`
38
- - **Publish directory:** `apps/web/out`
39
-
40
- ### 3. Set Environment Variables
41
-
42
- Go to **Site settings → Environment variables** and add:
43
- - `ANTHROPIC_API_KEY` - Your Anthropic API key for the audit function
44
-
45
- ### 4. Configure Custom Domain
46
-
47
- 1. Go to **Site settings → Domain management**
48
- 2. Click "Add custom domain"
49
- 3. Enter `ui.a11ypros.com`
50
- 4. Follow Netlify's DNS instructions:
51
- - Add a **CNAME** record at your domain provider:
52
- ```
53
- Type: CNAME
54
- Name: ui
55
- Value: [your-netlify-site-name].netlify.app
56
- ```
57
- 5. Wait for DNS propagation (5-60 minutes)
58
-
59
- ### 5. Deploy
60
-
61
- - Netlify will automatically deploy on every push to your main branch
62
- - Or click "Deploy site" to deploy manually
63
-
64
- ## URLs After Deployment
65
-
66
- - **Main App:** `https://ui.a11ypros.com`
67
- - **Storybook:** `https://ui.a11ypros.com/storybook`
68
- - **Audit API:** `https://ui.a11ypros.com/api/audit` (POST)
69
-
70
- ## How It Works
71
-
72
- 1. **Build Process:**
73
- - Installs dependencies
74
- - Builds Storybook → `apps/web/public/storybook-static`
75
- - Builds Next.js app → `apps/web/out` (includes Storybook from public/)
76
-
77
- 2. **Routing:**
78
- - `/storybook/*` → Served from `/storybook-static/*`
79
- - `/api/audit` → Redirected to `/.netlify/functions/audit`
80
- - `/*` → Next.js SPA routes
81
-
82
- 3. **Netlify Function:**
83
- - Serverless function handles the audit API
84
- - Uses `ANTHROPIC_API_KEY` environment variable
85
- - Supports CORS for cross-origin requests
86
-
87
- ## Troubleshooting
88
-
89
- ### Build Fails
90
-
91
- - Check Node.js version (should be 18+)
92
- - Verify all dependencies are in `package.json`
93
- - Check build logs in Netlify dashboard
94
-
95
- ### Storybook Not Loading
96
-
97
- - Verify Storybook build completed successfully
98
- - Check that `apps/web/public/storybook-static` exists
99
- - Verify redirect rules in `netlify.toml`
100
-
101
- ### API Not Working
102
-
103
- - Ensure `ANTHROPIC_API_KEY` is set in Netlify environment variables
104
- - Check Netlify Function logs in dashboard
105
- - Verify the function is deployed (check Functions tab)
106
-
107
- ### DNS Issues
108
-
109
- - Wait for DNS propagation (can take up to 48 hours, usually 5-60 minutes)
110
- - Verify CNAME record is correct
111
- - Check DNS propagation with `dig ui.a11ypros.com`
112
-
113
- ## Local Testing
114
-
115
- Test the build locally before deploying:
116
-
117
- ```bash
118
- # Install dependencies
119
- npm install
120
-
121
- # Build Storybook
122
- npm run build-storybook
123
-
124
- # Build Next.js app
125
- npm run build --workspace=apps/web
126
-
127
- # Test locally (optional)
128
- npx serve apps/web/out
129
- ```
130
-
131
- Visit `http://localhost:3000` for the app and `http://localhost:3000/storybook` for Storybook.
132
-
133
- ## File Structure
134
-
135
- ```
136
- ├── netlify.toml # Netlify configuration
137
- ├── netlify/
138
- │ └── functions/
139
- │ └── audit.ts # Netlify Function for audit API
140
- ├── apps/
141
- │ └── web/
142
- │ ├── public/
143
- │ │ └── storybook-static/ # Storybook build output
144
- │ └── out/ # Next.js build output
145
- └── package.json # Root dependencies
146
- ```
147
-
148
- ## Notes
149
-
150
- - The Next.js app uses static export, so no server-side features
151
- - API routes are converted to Netlify Functions
152
- - Storybook is served as static files alongside the app
153
- - All routes are client-side (SPA mode)
154
-
@@ -1,269 +0,0 @@
1
- .audit-page {
2
- min-height: 100vh;
3
- padding: var(--spacing-6, 1.5rem);
4
- background-color: var(--color-background-secondary, #fafafa);
5
-
6
-
7
- /* Override design system colors to match your brand */
8
- --color-primary-500: #0e8168; /* Your primary teal color */
9
- --color-primary-600: #075985; /* Darker shade for hover */
10
- --color-primary-700: #0369a1; /* Even darker for active */
11
- }
12
-
13
- .audit-container {
14
- max-width: 64rem; /* 1024px */
15
- margin: 0 auto;
16
- }
17
-
18
- .audit-header {
19
- margin-bottom: var(--spacing-8, 2rem);
20
- }
21
-
22
- .audit-header-top {
23
- display: flex;
24
- align-items: baseline;
25
- justify-content: space-between;
26
- gap: var(--spacing-4, 1rem);
27
- margin-bottom: var(--spacing-4, 1rem);
28
- }
29
-
30
- .audit-header-logo {
31
- flex-shrink: 0;
32
- }
33
-
34
- .audit-header h1 {
35
- font-size: var(--font-size-3xl, 1.875rem);
36
- font-weight: var(--font-weight-bold, 700);
37
- margin-bottom: var(--spacing-4, 1rem);
38
- color: var(--color-text-primary, #171717);
39
- }
40
-
41
- .audit-header p {
42
- font-size: var(--font-size-lg, 1.125rem);
43
- color: var(--color-text-secondary, #525252);
44
- line-height: var(--line-height-relaxed, 1.625);
45
- }
46
-
47
- .audit-input-section {
48
- background-color: var(--color-background-default, #ffffff);
49
- padding: var(--spacing-6, 1.5rem);
50
- border-radius: 0.5rem;
51
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
52
- margin-bottom: var(--spacing-6, 1.5rem);
53
- }
54
-
55
- .audit-label {
56
- display: block;
57
- font-size: var(--font-size-base, 1rem);
58
- font-weight: var(--font-weight-semibold, 600);
59
- color: var(--color-text-primary, #171717);
60
- margin-bottom: var(--spacing-2, 0.5rem);
61
- }
62
-
63
- .audit-textarea {
64
- width: 100%;
65
- padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);
66
- font-family: var(--font-family-mono, Menlo, Monaco, 'Courier New', monospace);
67
- font-size: var(--font-size-sm, 0.875rem);
68
- line-height: var(--line-height-relaxed, 1.625);
69
- color: var(--color-text-primary, #171717);
70
- background-color: var(--color-background-default, #ffffff);
71
- border: 1px solid var(--color-border-default, #bbbbbb);
72
- border-radius: 0.375rem;
73
- resize: vertical;
74
- transition: border-color var(--motion-duration-normal, 200ms) var(--motion-easing-ease-out, cubic-bezier(0, 0, 0.2, 1));
75
- }
76
-
77
- .audit-page .btn--primary {
78
- background-color: var(--color-primary-500);
79
- border-color: var(--color-primary-500);
80
- }
81
-
82
- .audit-page .btn--primary:hover:not(:disabled) {
83
- background-color: var(--color-primary-600);
84
- border-color: var(--color-primary-600);
85
- }
86
-
87
- .audit-page .btn--primary:focus-visible {
88
- outline-color: var(--color-primary-500);
89
- box-shadow: 0 0 0 3px rgba(14, 129, 104, 0.2); /* Adjust to match your primary */
90
- }
91
-
92
- .audit-textarea:focus {
93
- outline: none;
94
- border-color: var(--color-border-focus, #0ea5e9);
95
- box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
96
- }
97
-
98
- .audit-textarea:focus-visible {
99
- outline: 2px solid var(--color-border-focus, #0ea5e9);
100
- outline-offset: 2px;
101
- }
102
-
103
- .audit-help-text {
104
- font-size: var(--font-size-sm, 0.875rem);
105
- color: var(--color-text-secondary, #525252);
106
- margin-top: var(--spacing-2, 0.5rem);
107
- margin-bottom: var(--spacing-4, 1rem);
108
- }
109
-
110
- .audit-error {
111
- padding: var(--spacing-4, 1rem);
112
- background-color: rgba(239, 68, 68, 0.1);
113
- border: 1px solid var(--color-error-500, #ef4444);
114
- border-radius: 0.375rem;
115
- color: var(--color-error-700, #b91c1c);
116
- margin-bottom: var(--spacing-6, 1.5rem);
117
- }
118
-
119
- .audit-results {
120
- background-color: var(--color-background-default, #ffffff);
121
- padding: var(--spacing-6, 1.5rem);
122
- border-radius: 0.5rem;
123
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
124
- }
125
-
126
- .audit-results h2 {
127
- font-size: var(--font-size-2xl, 1.5rem);
128
- font-weight: var(--font-weight-semibold, 600);
129
- margin-bottom: var(--spacing-4, 1rem);
130
- color: var(--color-text-primary, #171717);
131
- }
132
-
133
- .audit-summary {
134
- font-size: var(--font-size-lg, 1.125rem);
135
- color: var(--color-text-secondary, #525252);
136
- margin-bottom: var(--spacing-6, 1.5rem);
137
- padding-bottom: var(--spacing-4, 1rem);
138
- border-bottom: 1px solid var(--color-border-default, #bbbbbb);
139
- }
140
-
141
- .audit-success {
142
- padding: var(--spacing-6, 1.5rem);
143
- background-color: rgba(34, 197, 94, 0.1);
144
- border: 1px solid var(--color-success-500, #22c55e);
145
- border-radius: 0.375rem;
146
- color: var(--color-success-700, #15803d);
147
- text-align: center;
148
- font-size: var(--font-size-lg, 1.125rem);
149
- }
150
-
151
- .audit-issues {
152
- display: flex;
153
- flex-direction: column;
154
- gap: var(--spacing-6, 1.5rem);
155
- }
156
-
157
- .audit-sc-group {
158
- border: 1px solid var(--color-border-default, #bbbbbb);
159
- border-radius: 0.375rem;
160
- padding: var(--spacing-4, 1rem);
161
- }
162
-
163
- .audit-sc-title {
164
- font-size: var(--font-size-xl, 1.25rem);
165
- font-weight: var(--font-weight-semibold, 600);
166
- color: var(--color-text-primary, #171717);
167
- margin-bottom: var(--spacing-4, 1rem);
168
- }
169
-
170
- .audit-sc-count {
171
- font-weight: var(--font-weight-normal, 400);
172
- color: var(--color-text-secondary, #525252);
173
- }
174
-
175
- .audit-issue {
176
- border-left: 4px solid;
177
- padding: var(--spacing-3, 0.75rem);
178
- margin-bottom: var(--spacing-3, 0.75rem);
179
- background-color: var(--color-background-secondary, #fafafa);
180
- border-radius: 0.25rem;
181
- }
182
-
183
- .audit-issue--error {
184
- border-left-color: var(--color-error-500, #ef4444);
185
- }
186
-
187
- .audit-issue--warning {
188
- border-left-color: var(--color-warning-500, #f59e0b);
189
- }
190
-
191
- .audit-issue--info {
192
- border-left-color: var(--color-primary-500, #0ea5e9);
193
- }
194
-
195
- .audit-issue-header {
196
- width: 100%;
197
- display: flex;
198
- align-items: center;
199
- gap: var(--spacing-3, 0.75rem);
200
- background: none;
201
- border: none;
202
- padding: 0;
203
- cursor: pointer;
204
- text-align: left;
205
- }
206
-
207
- .audit-severity-badge {
208
- display: inline-block;
209
- padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);
210
- border-radius: 0.25rem;
211
- color: var(--color-white, #ffffff);
212
- font-size: var(--font-size-xs, 0.75rem);
213
- font-weight: var(--font-weight-semibold, 600);
214
- text-transform: uppercase;
215
- flex-shrink: 0;
216
- }
217
-
218
- .audit-issue-message {
219
- flex: 1;
220
- font-weight: var(--font-weight-medium, 500);
221
- color: var(--color-text-primary, #171717);
222
- }
223
-
224
- .audit-issue-toggle {
225
- color: var(--color-text-secondary, #525252);
226
- font-size: var(--font-size-sm, 0.875rem);
227
- flex-shrink: 0;
228
- }
229
-
230
- .audit-issue-details {
231
- margin-top: var(--spacing-3, 0.75rem);
232
- padding-top: var(--spacing-3, 0.75rem);
233
- border-top: 1px solid var(--color-border-default, #bbbbbb);
234
- }
235
-
236
- .audit-issue-suggestion {
237
- margin-bottom: var(--spacing-3, 0.75rem);
238
- color: var(--color-text-primary, #171717);
239
- line-height: var(--line-height-relaxed, 1.625);
240
- }
241
-
242
- .audit-issue-code {
243
- margin-top: var(--spacing-3, 0.75rem);
244
- }
245
-
246
- .audit-issue-code strong {
247
- display: block;
248
- margin-bottom: var(--spacing-2, 0.5rem);
249
- color: var(--color-text-primary, #171717);
250
- }
251
-
252
- /* High contrast mode support */
253
- @media (prefers-contrast: high) {
254
- .audit-issue {
255
- border-left-width: 6px;
256
- }
257
-
258
- .audit-textarea:focus-visible {
259
- outline-width: 3px;
260
- }
261
- }
262
-
263
- /* Reduced motion */
264
- @media (prefers-reduced-motion: reduce) {
265
- .audit-textarea {
266
- transition: none;
267
- }
268
- }
269
-
@@ -1,271 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, useEffect } from 'react'
4
- import dynamic from 'next/dynamic'
5
- import Image from 'next/image'
6
- import { Button } from '@a11ypros/a11y-ui-components'
7
- import './audit.css'
8
-
9
- // Dynamically import SyntaxHighlighter to avoid SSR/build issues
10
- const SyntaxHighlighter = dynamic(
11
- () => import('react-syntax-highlighter').then((mod) => mod.Prism as any),
12
- { ssr: false }
13
- )
14
-
15
- interface AuditIssue {
16
- wcagSC: string
17
- severity: 'error' | 'warning' | 'info'
18
- message: string
19
- suggestion: string
20
- codeSuggestion?: string
21
- }
22
-
23
- interface AuditResponse {
24
- issues: AuditIssue[]
25
- summary: string
26
- }
27
-
28
- export default function AuditPage() {
29
- const [code, setCode] = useState('')
30
- const [loading, setLoading] = useState(false)
31
- const [result, setResult] = useState<AuditResponse | null>(null)
32
- const [error, setError] = useState<string | null>(null)
33
- const [expandedIssues, setExpandedIssues] = useState<Set<number>>(new Set())
34
- const [codeStyle, setCodeStyle] = useState<any>(null)
35
-
36
- // Load the style on client side only
37
- useEffect(() => {
38
- import('react-syntax-highlighter/dist/cjs/styles/prism').then((mod) => {
39
- setCodeStyle(mod.vscDarkPlus)
40
- })
41
- }, [])
42
-
43
- const handleAudit = async () => {
44
- if (!code.trim()) {
45
- setError('Please enter JSX code to audit')
46
- return
47
- }
48
-
49
- setLoading(true)
50
- setError(null)
51
- setResult(null)
52
-
53
- try {
54
- const response = await fetch('/api/audit', {
55
- method: 'POST',
56
- headers: {
57
- 'Content-Type': 'application/json',
58
- },
59
- body: JSON.stringify({ code }),
60
- })
61
-
62
- if (!response.ok) {
63
- const errorData = await response.json()
64
- throw new Error(errorData.error || 'Failed to perform audit')
65
- }
66
-
67
- const data: AuditResponse = await response.json()
68
- setResult(data)
69
- // Expand all issues by default
70
- setExpandedIssues(new Set(data.issues.map((_, i) => i)))
71
- } catch (err) {
72
- setError(err instanceof Error ? err.message : 'An error occurred')
73
- } finally {
74
- setLoading(false)
75
- }
76
- }
77
-
78
- const toggleIssue = (index: number) => {
79
- const newExpanded = new Set(expandedIssues)
80
- if (newExpanded.has(index)) {
81
- newExpanded.delete(index)
82
- } else {
83
- newExpanded.add(index)
84
- }
85
- setExpandedIssues(newExpanded)
86
- }
87
-
88
- const getSeverityColor = (severity: string) => {
89
- switch (severity) {
90
- case 'error':
91
- return 'var(--color-error-500, #ef4444)'
92
- case 'warning':
93
- return 'var(--color-warning-500, #f59e0b)'
94
- case 'info':
95
- return 'var(--color-primary-500, #0ea5e9)'
96
- default:
97
- return 'var(--color-neutral-500, #737373)'
98
- }
99
- }
100
-
101
- const getSeverityLabel = (severity: string) => {
102
- return severity.charAt(0).toUpperCase() + severity.slice(1)
103
- }
104
-
105
- // Group issues by WCAG SC
106
- const groupedIssues = result?.issues.reduce((acc, issue, index) => {
107
- if (!acc[issue.wcagSC]) {
108
- acc[issue.wcagSC] = []
109
- }
110
- acc[issue.wcagSC].push({ ...issue, originalIndex: index })
111
- return acc
112
- }, {} as Record<string, Array<AuditIssue & { originalIndex: number }>>)
113
-
114
- return (
115
- <main className="audit-page">
116
- <div className="audit-container">
117
- <header className="audit-header">
118
- <div className="audit-header-top">
119
- <h1>AI Accessibility Audit Assistant</h1>
120
- <div className="audit-header-logo">
121
- <Image
122
- src="/logo.png"
123
- alt="A11y Pros Logo"
124
- width={150}
125
- height={25}
126
- priority
127
- />
128
- </div>
129
-
130
- </div>
131
- <p>
132
- Paste your JSX code snippet below to get an AI-powered accessibility review
133
- based on WCAG 2.1 and 2.2 guidelines.
134
- </p>
135
- </header>
136
-
137
- <div className="audit-input-section">
138
- <label htmlFor="code-input" className="audit-label">
139
- JSX Code Snippet
140
- </label>
141
- <textarea
142
- id="code-input"
143
- className="audit-textarea"
144
- value={code}
145
- onChange={(e) => setCode(e.target.value)}
146
- placeholder="<button onClick={handleClick}>Click me</button>"
147
- rows={12}
148
- aria-describedby="code-input-help"
149
- />
150
- <p id="code-input-help" className="audit-help-text">
151
- Enter your JSX/React component code to analyze for accessibility issues.
152
- </p>
153
- <Button
154
- onClick={handleAudit}
155
- loading={loading}
156
- disabled={!code.trim() || loading}
157
- variant="primary"
158
- size="lg"
159
- className='audit-button'
160
- >
161
- {loading ? 'Auditing...' : 'Run Accessibility Audit'}
162
- </Button>
163
- </div>
164
-
165
- {error && (
166
- <div className="audit-error" role="alert">
167
- <strong>Error:</strong> {error}
168
- </div>
169
- )}
170
-
171
- {result && (
172
- <div className="audit-results">
173
- <h2>Audit Results</h2>
174
- <p className="audit-summary">{result.summary}</p>
175
-
176
- {result.issues.length === 0 ? (
177
- <div className="audit-success">
178
- <p>✓ No accessibility issues found!</p>
179
- </div>
180
- ) : (
181
- <div className="audit-issues">
182
- {groupedIssues &&
183
- Object.entries(groupedIssues).map(([wcagSC, issues]) => (
184
- <div key={wcagSC} className="audit-sc-group">
185
- <h3 className="audit-sc-title">
186
- WCAG {wcagSC}
187
- <span className="audit-sc-count">
188
- {' '}
189
- ({issues.length} issue{issues.length !== 1 ? 's' : ''})
190
- </span>
191
- </h3>
192
- {issues.map((issue, idx) => {
193
- const globalIndex = issue.originalIndex
194
- const isExpanded = expandedIssues.has(globalIndex)
195
- return (
196
- <div
197
- key={globalIndex}
198
- className={`audit-issue audit-issue--${issue.severity}`}
199
- >
200
- <button
201
- className="audit-issue-header"
202
- onClick={() => toggleIssue(globalIndex)}
203
- aria-expanded={isExpanded}
204
- aria-controls={`issue-${globalIndex}`}
205
- >
206
- <span
207
- className="audit-severity-badge"
208
- style={{ backgroundColor: getSeverityColor(issue.severity) }}
209
- >
210
- {getSeverityLabel(issue.severity)}
211
- </span>
212
- <span className="audit-issue-message">{issue.message}</span>
213
- <span className="audit-issue-toggle" aria-hidden="true">
214
- {isExpanded ? '▼' : '▶'}
215
- </span>
216
- </button>
217
- {isExpanded && (
218
- <div
219
- id={`issue-${globalIndex}`}
220
- className="audit-issue-details"
221
- >
222
- <div className="audit-issue-suggestion">
223
- <strong>Suggestion:</strong> {issue.suggestion}
224
- </div>
225
- {issue.codeSuggestion && (
226
- <div className="audit-issue-code">
227
- <strong>Code suggestion:</strong>
228
- {codeStyle ? (
229
- // @ts-expect-error - react-syntax-highlighter type issues with dynamic import
230
- <SyntaxHighlighter
231
- language="jsx"
232
- style={codeStyle}
233
- customStyle={{
234
- marginTop: '0.5rem',
235
- borderRadius: '0.375rem',
236
- fontSize: '0.875rem',
237
- }}
238
- >
239
- {issue.codeSuggestion}
240
- </SyntaxHighlighter>
241
- ) : (
242
- <pre style={{
243
- padding: '1rem',
244
- background: '#1e1e1e',
245
- color: '#d4d4d4',
246
- borderRadius: '0.375rem',
247
- marginTop: '0.5rem',
248
- fontSize: '0.875rem',
249
- overflow: 'auto'
250
- }}>
251
- {issue.codeSuggestion}
252
- </pre>
253
- )}
254
- </div>
255
- )}
256
- </div>
257
- )}
258
- </div>
259
- )
260
- })}
261
- </div>
262
- ))}
263
- </div>
264
- )}
265
- </div>
266
- )}
267
- </div>
268
- </main>
269
- )
270
- }
271
-