@tanstack/devtools-a11y 0.0.1 → 0.1.1

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 (110) hide show
  1. package/LICENSE +21 -0
  2. package/dist/esm/core/components/IssueCard.d.ts +10 -0
  3. package/dist/esm/core/components/IssueCard.js +83 -0
  4. package/dist/esm/core/components/IssueCard.js.map +1 -0
  5. package/dist/esm/core/components/IssueList.d.ts +6 -0
  6. package/dist/esm/core/components/IssueList.js +134 -0
  7. package/dist/esm/core/components/IssueList.js.map +1 -0
  8. package/dist/esm/core/components/Settings.d.ts +6 -0
  9. package/dist/esm/core/components/Settings.js +251 -0
  10. package/dist/esm/core/components/Settings.js.map +1 -0
  11. package/dist/esm/core/components/Shell.d.ts +2 -0
  12. package/dist/esm/core/components/Shell.js +214 -0
  13. package/dist/esm/core/components/Shell.js.map +1 -0
  14. package/dist/esm/core/components/index.d.ts +2 -0
  15. package/dist/esm/core/components/index.js +14 -0
  16. package/dist/esm/core/components/index.js.map +1 -0
  17. package/dist/esm/core/contexts/allyContext.d.ts +17 -0
  18. package/dist/esm/core/contexts/allyContext.js +66 -0
  19. package/dist/esm/core/contexts/allyContext.js.map +1 -0
  20. package/dist/esm/core/core.d.ts +19 -0
  21. package/dist/esm/core/core.js +8 -0
  22. package/dist/esm/core/core.js.map +1 -0
  23. package/dist/esm/core/index.d.ts +9 -0
  24. package/dist/esm/core/index.js +9 -0
  25. package/dist/esm/core/index.js.map +1 -0
  26. package/dist/esm/core/production.d.ts +2 -0
  27. package/dist/esm/core/production.js +4 -0
  28. package/dist/esm/core/styles/styles.d.ts +85 -0
  29. package/dist/esm/core/styles/styles.js +547 -0
  30. package/dist/esm/core/styles/styles.js.map +1 -0
  31. package/dist/esm/core/types/types.d.ts +141 -0
  32. package/dist/esm/core/utils/ally-audit.utils.d.ts +19 -0
  33. package/dist/esm/core/utils/ally-audit.utils.js +226 -0
  34. package/dist/esm/core/utils/ally-audit.utils.js.map +1 -0
  35. package/dist/esm/core/utils/config.utils.d.ts +17 -0
  36. package/dist/esm/core/utils/config.utils.js +63 -0
  37. package/dist/esm/core/utils/config.utils.js.map +1 -0
  38. package/dist/esm/core/utils/custom-audit.utils.d.ts +13 -0
  39. package/dist/esm/core/utils/custom-audit.utils.js +426 -0
  40. package/dist/esm/core/utils/custom-audit.utils.js.map +1 -0
  41. package/dist/esm/core/utils/export-audit.uitls.d.ts +17 -0
  42. package/dist/esm/core/utils/export-audit.uitls.js +83 -0
  43. package/dist/esm/core/utils/export-audit.uitls.js.map +1 -0
  44. package/dist/esm/core/utils/ui.utils.d.ts +24 -0
  45. package/dist/esm/core/utils/ui.utils.js +330 -0
  46. package/dist/esm/core/utils/ui.utils.js.map +1 -0
  47. package/dist/esm/react/A11yDevtools.d.ts +5 -0
  48. package/dist/esm/react/A11yDevtools.js +8 -0
  49. package/dist/esm/react/A11yDevtools.js.map +1 -0
  50. package/dist/esm/react/index.d.ts +8 -0
  51. package/dist/esm/react/index.js +11 -0
  52. package/dist/esm/react/index.js.map +1 -0
  53. package/dist/esm/react/plugin.d.ts +12 -0
  54. package/dist/esm/react/plugin.js +11 -0
  55. package/dist/esm/react/plugin.js.map +1 -0
  56. package/dist/esm/react/production/A11yDevtools.d.ts +5 -0
  57. package/dist/esm/react/production/A11yDevtools.js +8 -0
  58. package/dist/esm/react/production/A11yDevtools.js.map +1 -0
  59. package/dist/esm/react/production/plugin.d.ts +7 -0
  60. package/dist/esm/react/production/plugin.js +11 -0
  61. package/dist/esm/react/production/plugin.js.map +1 -0
  62. package/dist/esm/react/production.d.ts +3 -0
  63. package/dist/esm/react/production.js +5 -0
  64. package/dist/esm/solid/A11yDevtools.d.ts +5 -0
  65. package/dist/esm/solid/A11yDevtools.js +8 -0
  66. package/dist/esm/solid/A11yDevtools.js.map +1 -0
  67. package/dist/esm/solid/index.d.ts +8 -0
  68. package/dist/esm/solid/index.js +9 -0
  69. package/dist/esm/solid/index.js.map +1 -0
  70. package/dist/esm/solid/plugin.d.ts +12 -0
  71. package/dist/esm/solid/plugin.js +11 -0
  72. package/dist/esm/solid/plugin.js.map +1 -0
  73. package/dist/esm/solid/production/A11yDevtools.d.ts +5 -0
  74. package/dist/esm/solid/production/A11yDevtools.js +8 -0
  75. package/dist/esm/solid/production/A11yDevtools.js.map +1 -0
  76. package/dist/esm/solid/production/plugin.d.ts +7 -0
  77. package/dist/esm/solid/production/plugin.js +11 -0
  78. package/dist/esm/solid/production/plugin.js.map +1 -0
  79. package/dist/esm/solid/production.d.ts +3 -0
  80. package/dist/esm/solid/production.js +3 -0
  81. package/package.json +110 -7
  82. package/src/core/components/IssueCard.tsx +75 -0
  83. package/src/core/components/IssueList.tsx +155 -0
  84. package/src/core/components/Settings.tsx +221 -0
  85. package/src/core/components/Shell.tsx +154 -0
  86. package/src/core/components/index.tsx +12 -0
  87. package/src/core/contexts/allyContext.tsx +118 -0
  88. package/src/core/core.tsx +11 -0
  89. package/src/core/index.ts +10 -0
  90. package/src/core/production.ts +5 -0
  91. package/src/core/styles/styles.ts +556 -0
  92. package/src/core/types/types.ts +177 -0
  93. package/src/core/utils/ally-audit.utils.ts +345 -0
  94. package/src/core/utils/config.utils.ts +68 -0
  95. package/src/core/utils/custom-audit.utils.ts +643 -0
  96. package/src/core/utils/export-audit.uitls.ts +180 -0
  97. package/src/core/utils/ui.utils.ts +483 -0
  98. package/src/react/A11yDevtools.ts +12 -0
  99. package/src/react/index.ts +16 -0
  100. package/src/react/plugin.ts +9 -0
  101. package/src/react/production/A11yDevtools.ts +11 -0
  102. package/src/react/production/plugin.ts +9 -0
  103. package/src/react/production.ts +7 -0
  104. package/src/solid/A11yDevtools.ts +11 -0
  105. package/src/solid/index.ts +14 -0
  106. package/src/solid/plugin.ts +9 -0
  107. package/src/solid/production/A11yDevtools.ts +10 -0
  108. package/src/solid/production/plugin.ts +9 -0
  109. package/src/solid/production.ts +5 -0
  110. package/README.md +0 -45
@@ -0,0 +1,154 @@
1
+ /** @jsxImportSource solid-js */
2
+
3
+ import { Match, Show, Switch, createMemo, createSignal } from 'solid-js'
4
+ import { Button, Header, MainPanel } from '@tanstack/devtools-ui'
5
+ import { useAllyContext } from '../contexts/allyContext'
6
+ import { RULE_SET_LABELS, SEVERITY_LABELS } from '../utils/ui.utils'
7
+ import { useStyles } from '../styles/styles'
8
+ import { A11yIssueList } from './IssueList'
9
+ import { A11ySettingsOverlay } from './Settings'
10
+
11
+ export function Shell() {
12
+ const styles = useStyles()
13
+
14
+ // ally context
15
+ const { filteredIssues, allyResult, config, setConfig, triggerAllyScan } =
16
+ useAllyContext()
17
+
18
+ // ui state
19
+ const selectedIssueSignal = createSignal<string>('')
20
+ const [displaySettings, setDisplaySettings] = createSignal<boolean>(false)
21
+
22
+ const handleExport = (format: 'json' | 'csv') => {
23
+ if (allyResult.audit) return
24
+ // Keep export logic in runtime via event -> overlay? export is still a direct helper.
25
+ // We keep this import local to avoid pulling export code into the runtime module.
26
+
27
+ void import('../utils/export-audit.uitls').then((m) =>
28
+ m.exportAuditResults(allyResult.audit!, { format }),
29
+ )
30
+ }
31
+
32
+ const showOverlayState = createMemo(() => config.showOverlays)
33
+
34
+ return (
35
+ <MainPanel class={styles().root} withPadding={false}>
36
+ <Header class={styles().header}>
37
+ <div class={styles().headerTitleRow}>
38
+ <h2 class={styles().headerTitle}>Accessibility Audit</h2>
39
+
40
+ <Show when={allyResult.state === 'done' && filteredIssues()}>
41
+ <span class={styles().headerSub}>
42
+ {`${filteredIssues().length} issue${filteredIssues().length !== 1 ? 's' : ''}`}
43
+ </span>
44
+ </Show>
45
+ </div>
46
+
47
+ <div class={styles().headerActions}>
48
+ <Button
49
+ variant="primary"
50
+ onClick={triggerAllyScan}
51
+ disabled={allyResult.state === 'scanning'}
52
+ >
53
+ {allyResult.state === 'scanning' ? 'Scanning...' : 'Run Audit'}
54
+ </Button>
55
+
56
+ <Show
57
+ when={
58
+ allyResult.state === 'done' &&
59
+ allyResult.audit &&
60
+ allyResult.audit.issues.length > 0
61
+ }
62
+ >
63
+ <div class={styles().buttonRow}>
64
+ <Button
65
+ variant="secondary"
66
+ outline
67
+ onClick={() => handleExport('json')}
68
+ >
69
+ Export JSON
70
+ </Button>
71
+
72
+ <Button
73
+ variant="secondary"
74
+ outline
75
+ onClick={() => handleExport('csv')}
76
+ >
77
+ Export CSV
78
+ </Button>
79
+ </div>
80
+
81
+ <Button
82
+ variant={showOverlayState() ? 'success' : 'warning'}
83
+ onClick={() => setConfig('showOverlays', !config.showOverlays)}
84
+ >
85
+ {showOverlayState() ? 'Hide' : 'Show'} Overlays
86
+ </Button>
87
+ </Show>
88
+ </div>
89
+ </Header>
90
+
91
+ <div class={styles().statusBar}>
92
+ <span>
93
+ <Show when={allyResult.state === 'done'}>
94
+ {`${SEVERITY_LABELS[config.threshold]}+ | ${RULE_SET_LABELS[config.ruleSet]}`}
95
+
96
+ <Show when={config.disabledRules.length > 0}>
97
+ {` | ${config.disabledRules.length} rule(s) disabled`}
98
+ </Show>
99
+ </Show>
100
+ </span>
101
+
102
+ <div class={styles().statusSpacer} />
103
+
104
+ <Button
105
+ variant="secondary"
106
+ outline
107
+ onClick={() => setDisplaySettings(true)}
108
+ >
109
+ Settings
110
+ </Button>
111
+ </div>
112
+
113
+ <div class={styles().content}>
114
+ <Switch>
115
+ <Match when={allyResult.state === 'init'}>
116
+ <div class={styles().emptyState}>
117
+ <p class={styles().emptyPrimary}>No audit results yet</p>
118
+
119
+ <p class={styles().emptySecondary}>
120
+ Click "Run Audit" to scan for accessibility issues
121
+ </p>
122
+ </div>
123
+ </Match>
124
+
125
+ <Match
126
+ when={
127
+ allyResult.state === 'done' &&
128
+ allyResult.audit &&
129
+ allyResult.audit.issues.length === 0
130
+ }
131
+ >
132
+ <div class={styles().successState}>
133
+ <p class={styles().successTitle}>
134
+ No accessibility issues found!
135
+ </p>
136
+
137
+ <p class={styles().successSub}>
138
+ Scanned in {allyResult.audit!.duration.toFixed(0)}ms
139
+ </p>
140
+ </div>
141
+ </Match>
142
+
143
+ <Match when={allyResult.audit && allyResult.audit.issues.length > 0}>
144
+ <A11yIssueList selectedIssueSignal={selectedIssueSignal} />
145
+ </Match>
146
+ </Switch>
147
+ </div>
148
+
149
+ <Show when={displaySettings()}>
150
+ <A11ySettingsOverlay onClose={() => setDisplaySettings(false)} />
151
+ </Show>
152
+ </MainPanel>
153
+ )
154
+ }
@@ -0,0 +1,12 @@
1
+ /** @jsxImportSource solid-js */
2
+
3
+ import { AllyProvider } from '../contexts/allyContext'
4
+ import { Shell } from './Shell'
5
+
6
+ export default function Devtools() {
7
+ return (
8
+ <AllyProvider>
9
+ <Shell />
10
+ </AllyProvider>
11
+ )
12
+ }
@@ -0,0 +1,118 @@
1
+ /** @jsxImportSource solid-js */
2
+
3
+ import {
4
+ createContext,
5
+ createEffect,
6
+ createMemo,
7
+ createSignal,
8
+ useContext,
9
+ } from 'solid-js'
10
+ import { createStore } from 'solid-js/store'
11
+ import { filterIssuesAboveThreshold, runAudit } from '../utils/ally-audit.utils'
12
+ import { mergeConfig, saveConfig } from '../utils/config.utils'
13
+ import { clearHighlights, highlightAllIssues } from '../utils/ui.utils'
14
+
15
+ // types
16
+ import type {
17
+ A11yAuditResult,
18
+ A11yPluginOptions,
19
+ SeverityThreshold,
20
+ } from '../types/types'
21
+ import type { ParentComponent } from 'solid-js'
22
+
23
+ //
24
+ // context state
25
+ //
26
+
27
+ function useAllyValue() {
28
+ const [config, setConfig] =
29
+ createStore<Required<A11yPluginOptions>>(mergeConfig())
30
+
31
+ const [allyResult, setAllyResult] = createStore<{
32
+ audit?: A11yAuditResult
33
+ state: 'init' | 'scanning' | 'done'
34
+ }>({ state: 'init' })
35
+
36
+ const [impactKey, setImpactKey] = createSignal<SeverityThreshold | 'all'>(
37
+ 'all',
38
+ )
39
+
40
+ const triggerAllyScan = async () => {
41
+ setAllyResult('state', 'scanning')
42
+ setAllyResult({ audit: await runAudit(config), state: 'done' })
43
+ }
44
+
45
+ const filteredIssues = createMemo(() => {
46
+ if (allyResult.state !== 'done' || !allyResult.audit?.issues) return []
47
+ let results = allyResult.audit.issues
48
+
49
+ results = filterIssuesAboveThreshold(results, config.threshold)
50
+
51
+ // removes excluded rules
52
+ if (config.disabledRules.length > 0) {
53
+ results = results.filter(
54
+ (issue) => !config.disabledRules.includes(issue.ruleId),
55
+ )
56
+ }
57
+
58
+ // early return if all impacts selected
59
+ if (impactKey() === 'all') return results
60
+
61
+ return results.filter((val) => val.impact === impactKey())
62
+ })
63
+
64
+ createEffect(() => {
65
+ if (config.showOverlays === false) {
66
+ clearHighlights()
67
+ return
68
+ }
69
+
70
+ if (allyResult.state === 'done') highlightAllIssues(filteredIssues())
71
+ })
72
+
73
+ createEffect(() => {
74
+ saveConfig(config)
75
+ })
76
+
77
+ return {
78
+ impactKey,
79
+ setImpactKey,
80
+
81
+ filteredIssues,
82
+
83
+ triggerAllyScan,
84
+
85
+ setConfig,
86
+ config,
87
+
88
+ allyResult,
89
+ }
90
+ }
91
+
92
+ type ContextType = ReturnType<typeof useAllyValue>
93
+
94
+ //
95
+ // context
96
+ //
97
+
98
+ const AllyContext = createContext<ContextType | null>(null)
99
+
100
+ type AllyProviderProps = {}
101
+
102
+ export const AllyProvider: ParentComponent<AllyProviderProps> = (props) => {
103
+ const value = useAllyValue()
104
+
105
+ return (
106
+ <AllyContext.Provider value={value}>{props.children}</AllyContext.Provider>
107
+ )
108
+ }
109
+
110
+ export function useAllyContext() {
111
+ const context = useContext(AllyContext)
112
+
113
+ if (context === null) {
114
+ throw new Error('useAllyContext must be used within an AllyProvider')
115
+ }
116
+
117
+ return context
118
+ }
@@ -0,0 +1,11 @@
1
+ /** @jsxImportSource solid-js */
2
+
3
+ import { constructCoreClass } from '@tanstack/devtools-utils/solid'
4
+
5
+ export interface A11yDevtoolsInit {}
6
+
7
+ const [A11yDevtoolsCore, A11yDevtoolsCoreNoOp] = constructCoreClass(
8
+ () => import('./components'),
9
+ )
10
+
11
+ export { A11yDevtoolsCore, A11yDevtoolsCoreNoOp }
@@ -0,0 +1,10 @@
1
+ 'use client'
2
+
3
+ import * as Devtools from './core'
4
+
5
+ export const A11yDevtoolsCore =
6
+ process.env.NODE_ENV !== 'development'
7
+ ? Devtools.A11yDevtoolsCoreNoOp
8
+ : Devtools.A11yDevtoolsCore
9
+
10
+ export type { A11yDevtoolsInit } from './core'
@@ -0,0 +1,5 @@
1
+ 'use client'
2
+
3
+ export { A11yDevtoolsCore } from './core'
4
+
5
+ export type { A11yDevtoolsInit } from './core'