@m00rl0ck/a11y-widget 0.1.0 → 0.2.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.
@@ -0,0 +1,78 @@
1
+ export const questions = [
2
+ {
3
+ id: 'q1',
4
+ promptKey: 'question1',
5
+ options: [
6
+ { labelKey: 'optRedGreen', value: 'red-green' },
7
+ { labelKey: 'optBlueYellow', value: 'blue-yellow' },
8
+ { labelKey: 'optNone', value: 'none' },
9
+ ],
10
+ },
11
+ {
12
+ id: 'q2',
13
+ promptKey: 'question2',
14
+ options: [
15
+ { labelKey: 'optNumber74', value: 'number' },
16
+ { labelKey: 'optNumber21', value: 'number' },
17
+ { labelKey: 'optNoNumber', value: 'none' },
18
+ ],
19
+ },
20
+ {
21
+ id: 'q3',
22
+ promptKey: 'question3',
23
+ options: [
24
+ { labelKey: 'optLeft', value: 'left' },
25
+ { labelKey: 'optRight', value: 'right' },
26
+ { labelKey: 'optSame', value: 'same' },
27
+ ],
28
+ },
29
+ ]
30
+
31
+ export function suggestType(answers) {
32
+ let deutScore = 0
33
+ let protScore = 0
34
+ let tritScore = 0
35
+ let monoScore = 0
36
+
37
+ if (answers.q1 === 'red-green') {
38
+ protScore += 3
39
+ deutScore += 3
40
+ } else if (answers.q1 === 'none') {
41
+ monoScore += 2
42
+ }
43
+
44
+ if (answers.q2 === 'none') {
45
+ deutScore += 3
46
+ protScore += 2
47
+ monoScore += 2
48
+ }
49
+
50
+ if (answers.q3 === 'same') {
51
+ monoScore += 3
52
+ deutScore += 1
53
+ protScore += 1
54
+ }
55
+
56
+ const scores = [
57
+ { type: 'monochromacy', score: monoScore },
58
+ { type: 'deuteranopia', score: deutScore },
59
+ { type: 'protanopia', score: protScore },
60
+ { type: 'tritanopia', score: tritScore },
61
+ ]
62
+
63
+ scores.sort((a, b) => b.score - a.score)
64
+
65
+ if (scores[0].score === 0) {
66
+ return { type: 'normal', severity: 'none' }
67
+ }
68
+
69
+ const maxScore = scores[0].score
70
+ const secondScore = scores[1].score
71
+ const ratio = secondScore > 0 ? maxScore / secondScore : 99
72
+
73
+ let severity = 'mild'
74
+ if (maxScore >= 7) severity = 'severe'
75
+ else if (maxScore >= 4) severity = 'moderate'
76
+
77
+ return { type: scores[0].type, severity }
78
+ }
@@ -0,0 +1,175 @@
1
+ const styleId = 'colorblind-adapt-styles'
2
+
3
+ export function injectStyles(type, severity) {
4
+ removeStyles()
5
+
6
+ if (type === 'normal' || !type) return
7
+
8
+ const sheet = document.createElement('style')
9
+ sheet.id = styleId
10
+ sheet.textContent = buildCSS(type, severity || 'moderate')
11
+ document.head.appendChild(sheet)
12
+ }
13
+
14
+ export function removeStyles() {
15
+ document.getElementById(styleId)?.remove()
16
+ }
17
+
18
+ function buildCSS(type, severity) {
19
+ const intensity = severity === 'severe' ? 1 : severity === 'moderate' ? 0.6 : 0.3
20
+
21
+ const blocks = [baseOverrides(type, intensity)]
22
+ return blocks.join('\n')
23
+ }
24
+
25
+ function baseOverrides(type, intensity) {
26
+ switch (type) {
27
+ case 'deuteranopia':
28
+ return deuteranopiaCSS(intensity)
29
+ case 'protanopia':
30
+ return protanopiaCSS(intensity)
31
+ case 'tritanopia':
32
+ return tritanopiaCSS(intensity)
33
+ case 'monochromacy':
34
+ return monochromacyCSS(intensity)
35
+ default:
36
+ return ''
37
+ }
38
+ }
39
+
40
+ function deuteranopiaCSS(i) {
41
+ return `
42
+ html[data-cba-active] * {
43
+ --cba-green: hsl(140, ${30 * i}%, 50%);
44
+ --cba-red: hsl(0, 100%, 40%);
45
+ --cba-bg: hsl(220, ${5 * i}%, 97%);
46
+ }
47
+ html[data-cba-active] a,
48
+ html[data-cba-active] a:visited {
49
+ text-decoration: underline;
50
+ text-decoration-thickness: 2px;
51
+ }
52
+ html[data-cba-active] .success,
53
+ html[data-cba-active] [class*="success"],
54
+ html[data-cba-active] [class*="valid"],
55
+ html[data-cba-active] [class*="positive"] {
56
+ color: #0055aa !important;
57
+ border-color: #0055aa !important;
58
+ }
59
+ html[data-cba-active] .error,
60
+ html[data-cba-active] [class*="error"],
61
+ html[data-cba-active] [class*="invalid"],
62
+ html[data-cba-active] [class*="danger"],
63
+ html[data-cba-active] [class*="negative"] {
64
+ color: #cc4400 !important;
65
+ border-color: #cc4400 !important;
66
+ }
67
+ html[data-cba-active] button:not([class*="active"]):not([class*="selected"]):not([class*="primary"]) {
68
+ border: 2px solid currentColor;
69
+ }
70
+ `
71
+ }
72
+
73
+ function protanopiaCSS(i) {
74
+ return `
75
+ html[data-cba-active] * {
76
+ --cba-red: hsl(10, ${80 * i}%, 40%);
77
+ --cba-green: hsl(140, ${60 * i}%, 40%);
78
+ --cba-bg: hsl(220, ${5 * i}%, 97%);
79
+ }
80
+ html[data-cba-active] a,
81
+ html[data-cba-active] a:visited {
82
+ text-decoration: underline;
83
+ text-decoration-thickness: 2px;
84
+ }
85
+ html[data-cba-active] .success,
86
+ html[data-cba-active] [class*="success"],
87
+ html[data-cba-active] [class*="valid"],
88
+ html[data-cba-active] [class*="positive"] {
89
+ color: #007744 !important;
90
+ border-color: #007744 !important;
91
+ }
92
+ html[data-cba-active] .error,
93
+ html[data-cba-active] [class*="error"],
94
+ html[data-cba-active] [class*="invalid"],
95
+ html[data-cba-active] [class*="danger"],
96
+ html[data-cba-active] [class*="negative"] {
97
+ color: #cc0033 !important;
98
+ border-color: #cc0033 !important;
99
+ }
100
+ html[data-cba-active] button:not([class*="active"]):not([class*="selected"]):not([class*="primary"]) {
101
+ border: 2px solid currentColor;
102
+ }
103
+ `
104
+ }
105
+
106
+ function tritanopiaCSS(i) {
107
+ return `
108
+ html[data-cba-active] * {
109
+ --cba-blue: hsl(200, ${80 * i}%, 45%);
110
+ --cba-yellow: hsl(40, ${80 * i}%, 50%);
111
+ --cba-bg: hsl(220, ${5 * i}%, 97%);
112
+ }
113
+ html[data-cba-active] a,
114
+ html[data-cba-active] a:visited {
115
+ text-decoration: underline;
116
+ text-decoration-style: dotted;
117
+ text-decoration-thickness: 2px;
118
+ }
119
+ html[data-cba-active] [class*="blue"],
120
+ html[data-cba-active] [class*="info"],
121
+ html[data-cba-active] [class*="primary"] {
122
+ color: #0066aa !important;
123
+ border-color: #0066aa !important;
124
+ }
125
+ html[data-cba-active] [class*="yellow"],
126
+ html[data-cba-active] [class*="warning"] {
127
+ color: #885500 !important;
128
+ border-color: #885500 !important;
129
+ }
130
+ html[data-cba-active] button:not([class*="active"]):not([class*="selected"]):not([class*="primary"]) {
131
+ border: 2px solid currentColor;
132
+ }
133
+ `
134
+ }
135
+
136
+ function monochromacyCSS(i) {
137
+ return `
138
+ html[data-cba-active] {
139
+ filter: grayscale(${i});
140
+ }
141
+ html[data-cba-active] img,
142
+ html[data-cba-active] video,
143
+ html[data-cba-active] canvas {
144
+ filter: grayscale(${i});
145
+ }
146
+ html[data-cba-active] a {
147
+ text-decoration: underline;
148
+ text-decoration-thickness: 2px;
149
+ font-weight: 700;
150
+ }
151
+ html[data-cba-active] [class*="error"],
152
+ html[data-cba-active] [class*="danger"],
153
+ html[data-cba-active] [class*="negative"],
154
+ html[data-cba-active] [class*="invalid"] {
155
+ border-left: 4px solid #666 !important;
156
+ padding-left: 8px !important;
157
+ }
158
+ html[data-cba-active] [class*="success"],
159
+ html[data-cba-active] [class*="valid"],
160
+ html[data-cba-active] [class*="positive"] {
161
+ border-left: 4px solid #999 !important;
162
+ padding-left: 8px !important;
163
+ }
164
+ html[data-cba-active] button,
165
+ html[data-cba-active] .btn,
166
+ html[data-cba-active] [role="button"] {
167
+ border: 2px solid currentColor;
168
+ }
169
+ html[data-cba-active] button:hover,
170
+ html[data-cba-active] .btn:hover {
171
+ outline: 3px solid #ffcc00;
172
+ outline-offset: 2px;
173
+ }
174
+ `
175
+ }
package/src/index.js CHANGED
@@ -1 +1,3 @@
1
1
  export { VisionAccessibilityWidget, default as VisionA11y } from './vision-a11y/index.js'
2
+
3
+ export { ColorblindAdaptWidget, default as ColorblindAdapt } from './colorblind-adapt/index.js'