@accessibility-rn-js/react-native-accessibility-toolkit 1.0.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,223 @@
1
+ // Accessibility utility functions and constants
2
+
3
+ export const ACCESSIBILITY_PROFILES = {
4
+ NONE: 'none',
5
+ BLIND: 'blind',
6
+ DYSLEXIA: 'dyslexia',
7
+ LOW_VISION: 'low_vision',
8
+ COGNITIVE: 'cognitive',
9
+ EPILEPSY_SAFE: 'epilepsy_safe',
10
+ ADHD_FOCUS: 'adhd_focus',
11
+ };
12
+
13
+ export const COLOR_THEMES = {
14
+ LIGHT: 'light',
15
+ DARK: 'dark',
16
+ HIGH_CONTRAST: 'high_contrast',
17
+ SEPIA: 'sepia',
18
+ };
19
+
20
+ export const TEXT_ALIGNMENT = {
21
+ LEFT: 'left',
22
+ CENTER: 'center',
23
+ RIGHT: 'right',
24
+ JUSTIFY: 'justify',
25
+ };
26
+
27
+ // Default accessibility state
28
+ export const DEFAULT_ACCESSIBILITY_STATE = {
29
+ // Font & Text
30
+ fontScale: 1.0,
31
+ lineHeight: 1.5,
32
+ letterSpacing: 0,
33
+ textAlignment: TEXT_ALIGNMENT.LEFT,
34
+
35
+ // Colors & Display
36
+ highContrast: false,
37
+ whiteHighContrast: false,
38
+ darkHighContrast: false,
39
+ colorInversion: false,
40
+ greyscale: false,
41
+ lowSaturation: false,
42
+ highSaturation: false,
43
+ colorTheme: COLOR_THEMES.LIGHT,
44
+ accentColor: '#007AFF',
45
+ textColor: null,
46
+ backgroundColor: null,
47
+
48
+ // Visual Aids
49
+ hideImages: false,
50
+ enlargeButtons: false,
51
+ reducedMotion: false,
52
+ highlightLinks: false,
53
+
54
+ // Reading Assistance
55
+ readingMask: false,
56
+ readingLine: false,
57
+ textMagnifier: false,
58
+ textToSpeech: false,
59
+ dictionary: false,
60
+
61
+ // Accessibility Features
62
+ screenReader: false,
63
+
64
+ // Native Settings (from system)
65
+ nativeScreenReader: false,
66
+ nativeReducedMotion: false,
67
+ nativeBoldText: false,
68
+ nativeGrayscale: false,
69
+ nativeInvertColors: false,
70
+ nativeReduceTransparency: false,
71
+
72
+ // Active Profile
73
+ activeProfile: ACCESSIBILITY_PROFILES.NONE,
74
+ };
75
+
76
+ // Profile configurations with detailed feature sets
77
+ export const PROFILE_CONFIGS = {
78
+ [ACCESSIBILITY_PROFILES.BLIND]: {
79
+ textToSpeech: true,
80
+ screenReader: true,
81
+ highContrast: true,
82
+ colorTheme: COLOR_THEMES.HIGH_CONTRAST,
83
+ hideImages: true,
84
+ fontScale: 1.2,
85
+ reducedMotion: true,
86
+ enlargeButtons: true,
87
+ highlightLinks: true,
88
+ dictionary: true,
89
+ },
90
+
91
+ [ACCESSIBILITY_PROFILES.DYSLEXIA]: {
92
+ fontScale: 1.5,
93
+ lineHeight: 2.4,
94
+ letterSpacing: 0.5,
95
+ highlightLinks: true,
96
+ enlargeButtons: true,
97
+ colorTheme: COLOR_THEMES.LIGHT,
98
+ textAlignment: TEXT_ALIGNMENT.LEFT,
99
+ readingLine: true,
100
+ },
101
+
102
+ [ACCESSIBILITY_PROFILES.LOW_VISION]: {
103
+ fontScale: 2.0,
104
+ highContrast: true,
105
+ whiteHighContrast: true,
106
+ colorTheme: COLOR_THEMES.HIGH_CONTRAST,
107
+ enlargeButtons: true,
108
+ textMagnifier: true,
109
+ lineHeight: 2.2,
110
+ letterSpacing: 0.6,
111
+ highlightLinks: true,
112
+ dictionary: true,
113
+ },
114
+
115
+ [ACCESSIBILITY_PROFILES.COGNITIVE]: {
116
+ readingLine: true,
117
+ readingMask: false,
118
+ dictionary: true,
119
+ reducedMotion: true,
120
+ highlightLinks: true,
121
+ fontScale: 1.3,
122
+ lineHeight: 2.0,
123
+ letterSpacing: 0.3,
124
+ colorTheme: COLOR_THEMES.LIGHT,
125
+ enlargeButtons: true,
126
+ },
127
+
128
+ [ACCESSIBILITY_PROFILES.EPILEPSY_SAFE]: {
129
+ reducedMotion: true,
130
+ colorTheme: COLOR_THEMES.DARK,
131
+ lowSaturation: true,
132
+ greyscale: false,
133
+ hideImages: false,
134
+ fontScale: 1.1,
135
+ highlightLinks: true,
136
+ },
137
+
138
+ [ACCESSIBILITY_PROFILES.ADHD_FOCUS]: {
139
+ readingMask: true,
140
+ readingLine: true,
141
+ hideImages: true,
142
+ reducedMotion: true,
143
+ fontScale: 1.3,
144
+ lineHeight: 2.0,
145
+ highlightLinks: true,
146
+ enlargeButtons: true,
147
+ colorTheme: COLOR_THEMES.LIGHT,
148
+ },
149
+ };
150
+
151
+ // Apply profile settings
152
+ export const applyProfile = (profile) => {
153
+ if (profile === ACCESSIBILITY_PROFILES.NONE) {
154
+ return DEFAULT_ACCESSIBILITY_STATE;
155
+ }
156
+
157
+ const profileConfig = PROFILE_CONFIGS[profile];
158
+ return {
159
+ ...DEFAULT_ACCESSIBILITY_STATE,
160
+ ...profileConfig,
161
+ activeProfile: profile,
162
+ };
163
+ };
164
+
165
+ // Color theme values
166
+ export const COLOR_THEME_VALUES = {
167
+ [COLOR_THEMES.LIGHT]: {
168
+ background: '#FFFFFF',
169
+ text: '#000000',
170
+ primary: '#007AFF',
171
+ secondary: '#5856D6',
172
+ border: '#C7C7CC',
173
+ },
174
+ [COLOR_THEMES.DARK]: {
175
+ background: '#000000',
176
+ text: '#FFFFFF',
177
+ primary: '#0A84FF',
178
+ secondary: '#5E5CE6',
179
+ border: '#38383A',
180
+ },
181
+ [COLOR_THEMES.HIGH_CONTRAST]: {
182
+ background: '#000000',
183
+ text: '#FFFF00',
184
+ primary: '#FFFFFF',
185
+ secondary: '#00FF00',
186
+ border: '#FFFFFF',
187
+ },
188
+ [COLOR_THEMES.SEPIA]: {
189
+ background: '#F4ECD8',
190
+ text: '#5C4B37',
191
+ primary: '#8B4513',
192
+ secondary: '#A0522D',
193
+ border: '#D2B48C',
194
+ },
195
+ };
196
+
197
+ // Calculate adjusted font size
198
+ export const getAdjustedFontSize = (baseFontSize, fontScale) => {
199
+ return baseFontSize * fontScale;
200
+ };
201
+
202
+ // Calculate adjusted line height
203
+ export const getAdjustedLineHeight = (baseFontSize, lineHeightMultiplier, fontScale) => {
204
+ return baseFontSize * fontScale * lineHeightMultiplier;
205
+ };
206
+
207
+ // Get button padding adjustment
208
+ export const getButtonPadding = (baseSize, enlargeButtons) => {
209
+ return enlargeButtons ? baseSize * 1.5 : baseSize;
210
+ };
211
+
212
+ // Minimum touch target size (48dp)
213
+ export const MIN_TOUCH_TARGET = 48;
214
+
215
+ // Apply color inversion filter
216
+ export const applyColorInversion = (enabled) => {
217
+ return enabled ? 'invert(100%)' : 'none';
218
+ };
219
+
220
+ // Apply greyscale filter
221
+ export const applyGreyscale = (enabled) => {
222
+ return enabled ? 'grayscale(100%)' : 'none';
223
+ };
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Colors.js
3
+ * Dynamic color provider for accessibility plugin
4
+ */
5
+
6
+ // Base color definitions
7
+ const BASE_COLORS = {
8
+ primaryButtonColor: '#8B63FF',
9
+ secondaryButtonColor: '#FF974F',
10
+ primaryTextColor: '#2D3142',
11
+ primaryInactive: '#9c9eb9',
12
+ textInputBorder: '#d6d9e0',
13
+ successColor: '#4fab53',
14
+ placeholderTextColor: "#A9B2C2",
15
+ modalBackground: 'rgba(0, 0, 0, 0.5)',
16
+ red: "#ff3b30",
17
+ defaultBackground: '#FFFFFF',
18
+ boxBackground: '#F4F6FA',
19
+ lightBlue: '#E4DFFF',
20
+ };
21
+
22
+ // Helper to convert hex to RGB
23
+ const hexToRgb = (hex) => {
24
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
25
+ return result
26
+ ? {
27
+ r: parseInt(result[1], 16),
28
+ g: parseInt(result[2], 16),
29
+ b: parseInt(result[3], 16),
30
+ }
31
+ : null;
32
+ };
33
+
34
+ // Helper to convert RGB to hex
35
+ const rgbToHex = (r, g, b) => {
36
+ return '#' + [r, g, b].map((x) => {
37
+ const hex = Math.round(Math.max(0, Math.min(255, x))).toString(16);
38
+ return hex.length === 1 ? '0' + hex : hex;
39
+ }).join('');
40
+ };
41
+
42
+ // Helper to determine if a color is light or dark
43
+ const isLightColor = (hex) => {
44
+ if (hex.startsWith('rgba')) return true;
45
+ const rgb = hexToRgb(hex);
46
+ if (!rgb) return true;
47
+ const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
48
+ return luminance > 0.5;
49
+ };
50
+
51
+ // Apply grayscale to a color
52
+ const applyGrayscale = (hex) => {
53
+ if (hex.startsWith('rgba')) return hex;
54
+ const rgb = hexToRgb(hex);
55
+ if (!rgb) return hex;
56
+ const gray = Math.round(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b);
57
+ return rgbToHex(gray, gray, gray);
58
+ };
59
+
60
+ // Apply saturation adjustment
61
+ const applySaturation = (hex, factor) => {
62
+ if (hex.startsWith('rgba')) return hex;
63
+ const rgb = hexToRgb(hex);
64
+ if (!rgb) return hex;
65
+
66
+ const gray = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;
67
+ const r = gray + factor * (rgb.r - gray);
68
+ const g = gray + factor * (rgb.g - gray);
69
+ const b = gray + factor * (rgb.b - gray);
70
+
71
+ return rgbToHex(r, g, b);
72
+ };
73
+
74
+ // Invert a color
75
+ const invertColor = (hex) => {
76
+ if (hex.startsWith('rgba')) return hex;
77
+ const rgb = hexToRgb(hex);
78
+ if (!rgb) return hex;
79
+ return rgbToHex(255 - rgb.r, 255 - rgb.g, 255 - rgb.b);
80
+ };
81
+
82
+ // Process colors based on accessibility settings
83
+ const processColors = (colors, settings) => {
84
+ if (!settings) return colors;
85
+
86
+ let processed = { ...colors };
87
+
88
+ // Apply grayscale
89
+ if (settings.greyscale) {
90
+ processed = Object.keys(processed).reduce((acc, key) => {
91
+ acc[key] = applyGrayscale(processed[key]);
92
+ return acc;
93
+ }, {});
94
+ }
95
+
96
+ // Apply saturation adjustments
97
+ if (settings.lowSaturation && !settings.greyscale) {
98
+ processed = Object.keys(processed).reduce((acc, key) => {
99
+ if (key !== 'modalBackground') {
100
+ acc[key] = applySaturation(processed[key], 0.3);
101
+ } else {
102
+ acc[key] = processed[key];
103
+ }
104
+ return acc;
105
+ }, {});
106
+ }
107
+
108
+ if (settings.highSaturation && !settings.greyscale && !settings.lowSaturation) {
109
+ processed = Object.keys(processed).reduce((acc, key) => {
110
+ if (key !== 'modalBackground') {
111
+ acc[key] = applySaturation(processed[key], 2.0);
112
+ } else {
113
+ acc[key] = processed[key];
114
+ }
115
+ return acc;
116
+ }, {});
117
+ }
118
+
119
+ // Apply color inversion
120
+ if (settings.colorInversion) {
121
+ processed = Object.keys(processed).reduce((acc, key) => {
122
+ if (key !== 'modalBackground') {
123
+ acc[key] = invertColor(processed[key]);
124
+ } else {
125
+ acc[key] = processed[key];
126
+ }
127
+ return acc;
128
+ }, {});
129
+ }
130
+
131
+ return processed;
132
+ };
133
+
134
+ // Get colors with accessibility transformations applied
135
+ export const getColors = (accessibilitySettings) => {
136
+ const settings = accessibilitySettings || {};
137
+
138
+ // Apply dark mode first
139
+ let colors = { ...BASE_COLORS };
140
+ if (settings.colorTheme === 'dark' || settings.darkMode) {
141
+ colors = {
142
+ ...colors,
143
+ primaryTextColor: '#FFFFFF',
144
+ defaultBackground: '#1E1E1E',
145
+ boxBackground: '#2C2C2E',
146
+ textInputBorder: '#3A3A3C',
147
+ placeholderTextColor: '#8E8E93',
148
+ primaryInactive: '#6E6E73',
149
+ };
150
+ }
151
+
152
+ // Apply high contrast
153
+ if (settings.highContrast) {
154
+ if (settings.colorTheme === 'dark' || settings.darkMode) {
155
+ if (settings.darkHighContrast) {
156
+ colors = {
157
+ ...colors,
158
+ defaultBackground: '#000000',
159
+ primaryTextColor: '#FFFFFF',
160
+ boxBackground: '#1A1A1A',
161
+ primaryButtonColor: '#FFFFFF',
162
+ secondaryButtonColor: '#FFFF00',
163
+ textInputBorder: '#FFFFFF',
164
+ };
165
+ }
166
+ } else {
167
+ if (settings.whiteHighContrast) {
168
+ colors = {
169
+ ...colors,
170
+ defaultBackground: '#FFFFFF',
171
+ primaryTextColor: '#000000',
172
+ boxBackground: '#F5F5F5',
173
+ primaryButtonColor: '#0000FF',
174
+ secondaryButtonColor: '#000080',
175
+ textInputBorder: '#000000',
176
+ };
177
+ }
178
+ }
179
+ }
180
+
181
+ // Apply color filters
182
+ const processedColors = processColors(colors, settings);
183
+
184
+ // Apply custom text and background color overrides
185
+ if (settings.textColor) {
186
+ processedColors.primaryTextColor = settings.textColor;
187
+ processedColors.buttonTextColor = settings.textColor;
188
+ } else {
189
+ processedColors.buttonTextColor = processedColors.boxBackground;
190
+ }
191
+
192
+ if (settings.backgroundColor) {
193
+ processedColors.defaultBackground = settings.backgroundColor;
194
+ if (!settings.textColor) {
195
+ const isLight = isLightColor(settings.backgroundColor);
196
+ processedColors.buttonTextColor = isLight ? '#000000' : '#FFFFFF';
197
+ }
198
+ }
199
+
200
+ return processedColors;
201
+ };
202
+
203
+ export default BASE_COLORS;
@@ -0,0 +1,24 @@
1
+ import { StyleSheet, Platform } from 'react-native';
2
+
3
+ /**
4
+ * Default font styles for accessibility plugin
5
+ * Users can override these by providing custom fonts in their app
6
+ */
7
+ export default StyleSheet.create({
8
+ Regular: {
9
+ fontFamily: Platform.OS === 'ios' ? 'System' : 'sans-serif',
10
+ fontWeight: '400',
11
+ },
12
+ Medium: {
13
+ fontFamily: Platform.OS === 'ios' ? 'System' : 'sans-serif-medium',
14
+ fontWeight: '500',
15
+ },
16
+ SemiBold: {
17
+ fontFamily: Platform.OS === 'ios' ? 'System' : 'sans-serif',
18
+ fontWeight: '600',
19
+ },
20
+ Bold: {
21
+ fontFamily: Platform.OS === 'ios' ? 'System' : 'sans-serif',
22
+ fontWeight: '700',
23
+ },
24
+ });