vision-accessibility 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.
- package/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/components/AccessibilityPanel/AccessibilityPanel.d.ts +12 -0
- package/dist/components/AccessibilityPanel/AccessibilityPanel.d.ts.map +1 -0
- package/dist/components/AccessibilityToggle/AccessibilityToggle.d.ts +18 -0
- package/dist/components/AccessibilityToggle/AccessibilityToggle.d.ts.map +1 -0
- package/dist/components/ColorSchemeControl/ColorSchemeControl.d.ts +18 -0
- package/dist/components/ColorSchemeControl/ColorSchemeControl.d.ts.map +1 -0
- package/dist/components/FontSizeControl/FontSizeControl.d.ts +18 -0
- package/dist/components/FontSizeControl/FontSizeControl.d.ts.map +1 -0
- package/dist/components/ImageControl/ImageControl.d.ts +18 -0
- package/dist/components/ImageControl/ImageControl.d.ts.map +1 -0
- package/dist/context/AccessibilityContext.d.ts +25 -0
- package/dist/context/AccessibilityContext.d.ts.map +1 -0
- package/dist/hooks/useAccessibilitySettings.d.ts +25 -0
- package/dist/hooks/useAccessibilitySettings.d.ts.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +1151 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.umd.js +11 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/lib/accessibility-storage.d.ts +23 -0
- package/dist/lib/accessibility-storage.d.ts.map +1 -0
- package/dist/lib/css-applier.d.ts +50 -0
- package/dist/lib/css-applier.d.ts.map +1 -0
- package/dist/lib/dom-manipulator.d.ts +29 -0
- package/dist/lib/dom-manipulator.d.ts.map +1 -0
- package/dist/lib/font-size-manager.d.ts +26 -0
- package/dist/lib/font-size-manager.d.ts.map +1 -0
- package/dist/style.css +1 -0
- package/dist/types/index.d.ts +61 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +58 -0
- package/src/components/AccessibilityPanel/AccessibilityPanel.module.scss +214 -0
- package/src/components/AccessibilityPanel/AccessibilityPanel.tsx +151 -0
- package/src/components/AccessibilityToggle/AccessibilityToggle.module.scss +158 -0
- package/src/components/AccessibilityToggle/AccessibilityToggle.tsx +85 -0
- package/src/components/ColorSchemeControl/ColorSchemeControl.module.scss +175 -0
- package/src/components/ColorSchemeControl/ColorSchemeControl.tsx +116 -0
- package/src/components/FontSizeControl/FontSizeControl.module.scss +175 -0
- package/src/components/FontSizeControl/FontSizeControl.tsx +116 -0
- package/src/components/ImageControl/ImageControl.module.scss +163 -0
- package/src/components/ImageControl/ImageControl.tsx +85 -0
- package/src/context/AccessibilityContext.tsx +54 -0
- package/src/hooks/useAccessibilitySettings.ts +228 -0
- package/src/index.ts +80 -0
- package/src/lib/accessibility-storage.ts +82 -0
- package/src/lib/css-applier.ts +168 -0
- package/src/lib/dom-manipulator.ts +75 -0
- package/src/lib/font-size-manager.ts +185 -0
- package/src/styles/global.scss +60 -0
- package/src/styles/variables.scss +80 -0
- package/src/types/index.ts +72 -0
- package/src/types/scss.d.ts +9 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-applier.d.ts","sourceRoot":"","sources":["../../src/lib/css-applier.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAaxE;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,WAAW,KAAG,IAyBtD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,QAAQ,KAAG,IAG9C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,YAAY,OAAO,KAAG,IAc1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,QAAO,IAiB/C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU,qBAAqB,KAAG,IAWlE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,WAAW,OAAO,EAClB,aAAa,aAAa,GAAG,UAAU,GAAG,iBAAiB,EAC3D,OAAO,WAAW,GAAG,QAAQ,GAAG,OAAO,KACtC,IAkBF,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Модуль для работы с DOM элементами
|
|
3
|
+
* Предоставляет функции для поиска и манипуляции элементами страницы
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Поиск всех текстовых элементов на странице
|
|
7
|
+
*/
|
|
8
|
+
export declare const getTextElements: () => NodeListOf<HTMLElement>;
|
|
9
|
+
/**
|
|
10
|
+
* Поиск всех изображений на странице
|
|
11
|
+
*/
|
|
12
|
+
export declare const getImageElements: () => NodeListOf<HTMLElement>;
|
|
13
|
+
/**
|
|
14
|
+
* Применение CSS класса к коллекции элементов
|
|
15
|
+
*/
|
|
16
|
+
export declare const applyClassToElements: (elements: NodeListOf<HTMLElement>, className: string) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Удаление CSS класса с коллекции элементов
|
|
19
|
+
*/
|
|
20
|
+
export declare const removeClassFromElements: (elements: NodeListOf<HTMLElement>, className: string) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Безопасное выполнение операций с DOM
|
|
23
|
+
*/
|
|
24
|
+
export declare const safeDOMOperation: (operation: () => void, errorMessage: string) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Проверка доступности DOM
|
|
27
|
+
*/
|
|
28
|
+
export declare const isDOMAvailable: () => boolean;
|
|
29
|
+
//# sourceMappingURL=dom-manipulator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-manipulator.d.ts","sourceRoot":"","sources":["../../src/lib/dom-manipulator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;GAEG;AACH,eAAO,MAAM,eAAe,QAAO,UAAU,CAAC,WAAW,CAKxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAO,UAAU,CAAC,WAAW,CAKzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,MAAM,KAAG,IAM3F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,UAAU,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,MAAM,KAAG,IAM9F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,IAAI,EAAE,cAAc,MAAM,KAAG,IAO9E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,QAAO,OAEjC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FontSize } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Применение размера шрифта ко всем текстовым элементам
|
|
5
|
+
*
|
|
6
|
+
* @param size - Размер шрифта (small, standard, large)
|
|
7
|
+
*/
|
|
8
|
+
export declare const applyDynamicFontSize: (size: FontSize) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Сброс всех изменений размера шрифта
|
|
11
|
+
*/
|
|
12
|
+
export declare const resetAllFontSizes: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Обновление размеров шрифта для новых элементов
|
|
15
|
+
* Используется когда на страницу добавляются новые элементы динамически
|
|
16
|
+
*
|
|
17
|
+
* @param size - Текущий размер шрифта
|
|
18
|
+
*/
|
|
19
|
+
export declare const updateNewElementsFontSize: (size: FontSize) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Проверка, применены ли изменения размера шрифта
|
|
22
|
+
*
|
|
23
|
+
* @returns true, если размер шрифта изменен
|
|
24
|
+
*/
|
|
25
|
+
export declare const isFontSizeModified: () => boolean;
|
|
26
|
+
//# sourceMappingURL=font-size-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-size-manager.d.ts","sourceRoot":"","sources":["../../src/lib/font-size-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAgFpC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,QAAQ,KAAG,IA2BrD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAO,IAcpC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,MAAM,QAAQ,KAAG,IAuB1D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAO,OAUrC,CAAC"}
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@charset "UTF-8";._accessibilityToggle_jwfla_9{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid #dee2e6}._toggleContainer_jwfla_15{display:flex;flex-direction:column;gap:8px}._toggleLabel_jwfla_21{display:flex;align-items:center;gap:16px;cursor:pointer;padding:16px;border:2px solid #007bff;border-radius:8px;transition:all .2s ease;background:#f8f9ff}._toggleLabel_jwfla_21:hover{background:#e3f2fd;border-color:#0056b3}._toggleLabel_jwfla_21:focus-within{background:#e3f2fd;border-color:#0056b3;box-shadow:0 0 0 3px #007bff40}._toggleInput_jwfla_42{position:absolute;opacity:0;width:0;height:0;margin:0}._toggleInput_jwfla_42:focus+._toggleSlider_jwfla_49{box-shadow:0 0 0 3px #007bff40}._toggleInput_jwfla_42:checked+._toggleSlider_jwfla_49{background:#28a745}._toggleInput_jwfla_42:checked+._toggleSlider_jwfla_49 ._toggleThumb_jwfla_55{transform:translate(28px)}._toggleSlider_jwfla_49{position:relative;width:56px;height:28px;background:#ced4da;border-radius:14px;transition:all .3s ease;flex-shrink:0}._toggleThumb_jwfla_55{position:absolute;top:2px;left:2px;width:24px;height:24px;background:#fff;border-radius:50%;transition:transform .3s ease;box-shadow:0 2px 6px #0000004d}._toggleContent_jwfla_81{flex:1;display:flex;flex-direction:column;gap:4px}._toggleTitle_jwfla_88{font-size:16px;font-weight:600;color:#343a40;line-height:1.3}._toggleStatus_jwfla_95{font-size:14px;font-weight:500;color:#007bff;line-height:1.2}._description_jwfla_102{font-size:13px;color:#6c757d;line-height:1.4;margin:0;padding:0 16px}.accessibility-high-contrast ._accessibilityToggle_jwfla_9{border-bottom-color:#fff!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleLabel_jwfla_21{background:#000!important;border-color:#fff!important;color:#fff!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleLabel_jwfla_21:hover,.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleLabel_jwfla_21:focus-within{background:#343a40!important;border-color:#ff0!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleTitle_jwfla_88{color:#fff!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleStatus_jwfla_95{color:#ff0!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._description_jwfla_102{color:#ced4da!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleSlider_jwfla_49{background:#6c757d!important;border:2px solid #ffffff!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleInput_jwfla_42:checked+._toggleSlider_jwfla_49{background:#ff0!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleInput_jwfla_42:checked+._toggleSlider_jwfla_49 ._toggleThumb_jwfla_55{background:#000!important;border:2px solid #ffffff!important}.accessibility-high-contrast ._accessibilityToggle_jwfla_9 ._toggleThumb_jwfla_55{background:#fff!important;border:2px solid #000000!important}._colorSchemeControl_tkb2w_9{margin-bottom:16px}._colorSchemeControl_tkb2w_9._disabled_tkb2w_12 ._title_tkb2w_12{opacity:.6}._title_tkb2w_12{font-size:14px;font-weight:600;margin:0 0 12px;color:#343a40}._optionsContainer_tkb2w_23{display:flex;flex-direction:column;gap:8px}._option_tkb2w_23{display:flex;align-items:flex-start;gap:12px;cursor:pointer;padding:12px;border:1px solid #dee2e6;border-radius:6px;transition:all .2s ease;position:relative;background:#fff}._option_tkb2w_23:hover{background:#f8f9fa;border-color:#007bff}._option_tkb2w_23:focus-within{background:#f8f9fa;border-color:#007bff;box-shadow:0 0 0 2px #007bff40}._option_tkb2w_23._selected_tkb2w_50{background:#e3f2fd;border-color:#007bff}._option_tkb2w_23._selected_tkb2w_50 ._radioIndicator_tkb2w_54{background:#007bff;border-color:#007bff}._option_tkb2w_23._selected_tkb2w_50 ._radioIndicator_tkb2w_54:after{opacity:1;transform:scale(1)}._option_tkb2w_23._optionDisabled_tkb2w_62{opacity:.5;cursor:not-allowed;pointer-events:none}._option_tkb2w_23._optionDisabled_tkb2w_62:hover{background:#fff;border-color:#dee2e6}._radioInput_tkb2w_72{position:absolute;opacity:0;width:0;height:0;margin:0}._radioInput_tkb2w_72:focus+._optionContent_tkb2w_79{outline:2px solid #007bff;outline-offset:2px}._optionContent_tkb2w_79{flex:1;display:flex;flex-direction:column;gap:4px}._optionLabel_tkb2w_91{font-size:14px;font-weight:500;color:#343a40;line-height:1.4}._optionDescription_tkb2w_98{font-size:12px;color:#6c757d;line-height:1.3}._radioIndicator_tkb2w_54{width:18px;height:18px;border:2px solid #ced4da;border-radius:50%;background:#fff;transition:all .2s ease;position:relative;flex-shrink:0;margin-top:1px}._radioIndicator_tkb2w_54:after{content:"";position:absolute;top:50%;left:50%;width:8px;height:8px;background:#fff;border-radius:50%;transform:translate(-50%,-50%) scale(0);transition:all .2s ease;opacity:0}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._title_tkb2w_12{color:#fff!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._option_tkb2w_23{background:#000!important;border-color:#fff!important;color:#fff!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._option_tkb2w_23:hover,.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._option_tkb2w_23:focus-within{background:#343a40!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._option_tkb2w_23._selected_tkb2w_50{background:#343a40!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._optionLabel_tkb2w_91{color:#fff!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._optionDescription_tkb2w_98{color:#ced4da!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._radioIndicator_tkb2w_54{border-color:#fff!important;background:#000!important}.accessibility-high-contrast ._colorSchemeControl_tkb2w_9 ._radioIndicator_tkb2w_54:after{background:#fff!important}._fontSizeControl_xe2rx_9{margin-bottom:16px}._fontSizeControl_xe2rx_9._disabled_xe2rx_12 ._title_xe2rx_12{opacity:.6}._title_xe2rx_12{font-size:14px;font-weight:600;margin:0 0 12px;color:#343a40}._optionsContainer_xe2rx_23{display:flex;flex-direction:column;gap:8px}._option_xe2rx_23{display:flex;align-items:flex-start;gap:12px;cursor:pointer;padding:12px;border:1px solid #dee2e6;border-radius:6px;transition:all .2s ease;position:relative;background:#fff}._option_xe2rx_23:hover{background:#f8f9fa;border-color:#007bff}._option_xe2rx_23:focus-within{background:#f8f9fa;border-color:#007bff;box-shadow:0 0 0 2px #007bff40}._option_xe2rx_23._selected_xe2rx_50{background:#e3f2fd;border-color:#007bff}._option_xe2rx_23._selected_xe2rx_50 ._radioIndicator_xe2rx_54{background:#007bff;border-color:#007bff}._option_xe2rx_23._selected_xe2rx_50 ._radioIndicator_xe2rx_54:after{opacity:1;transform:scale(1)}._option_xe2rx_23._optionDisabled_xe2rx_62{opacity:.5;cursor:not-allowed;pointer-events:none}._option_xe2rx_23._optionDisabled_xe2rx_62:hover{background:#fff;border-color:#dee2e6}._radioInput_xe2rx_72{position:absolute;opacity:0;width:0;height:0;margin:0}._radioInput_xe2rx_72:focus+._optionContent_xe2rx_79{outline:2px solid #007bff;outline-offset:2px}._optionContent_xe2rx_79{flex:1;display:flex;flex-direction:column;gap:4px}._optionLabel_xe2rx_91{font-size:14px;font-weight:500;color:#343a40;line-height:1.4}._optionDescription_xe2rx_98{font-size:12px;color:#6c757d;line-height:1.3}._radioIndicator_xe2rx_54{width:18px;height:18px;border:2px solid #ced4da;border-radius:50%;background:#fff;transition:all .2s ease;position:relative;flex-shrink:0;margin-top:1px}._radioIndicator_xe2rx_54:after{content:"";position:absolute;top:50%;left:50%;width:8px;height:8px;background:#fff;border-radius:50%;transform:translate(-50%,-50%) scale(0);transition:all .2s ease;opacity:0}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._title_xe2rx_12{color:#fff!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._option_xe2rx_23{background:#000!important;border-color:#fff!important;color:#fff!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._option_xe2rx_23:hover,.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._option_xe2rx_23:focus-within{background:#343a40!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._option_xe2rx_23._selected_xe2rx_50{background:#343a40!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._optionLabel_xe2rx_91{color:#fff!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._optionDescription_xe2rx_98{color:#ced4da!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._radioIndicator_xe2rx_54{border-color:#fff!important;background:#000!important}.accessibility-high-contrast ._fontSizeControl_xe2rx_9 ._radioIndicator_xe2rx_54:after{background:#fff!important}._imageControl_rczak_9{margin-bottom:16px}._imageControl_rczak_9._disabled_rczak_12 ._title_rczak_12{opacity:.6}._title_rczak_12{font-size:14px;font-weight:600;margin:0 0 12px;color:#343a40}._switchContainer_rczak_23{display:flex;flex-direction:column;gap:8px}._switchLabel_rczak_29{display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px;border:1px solid #dee2e6;border-radius:6px;transition:all .2s ease;background:#fff}._switchLabel_rczak_29:hover{background:#f8f9fa;border-color:#007bff}._switchLabel_rczak_29:focus-within{background:#f8f9fa;border-color:#007bff;box-shadow:0 0 0 2px #007bff40}._switchLabel_rczak_29._switchDisabled_rczak_49{opacity:.5;cursor:not-allowed;pointer-events:none}._switchLabel_rczak_29._switchDisabled_rczak_49:hover{background:#fff;border-color:#dee2e6}._switchInput_rczak_59{position:absolute;opacity:0;width:0;height:0;margin:0}._switchInput_rczak_59:focus+._switchSlider_rczak_66{box-shadow:0 0 0 2px #007bff40}._switchInput_rczak_59:checked+._switchSlider_rczak_66{background:#007bff}._switchInput_rczak_59:checked+._switchSlider_rczak_66 ._switchThumb_rczak_72{transform:translate(20px)}._switchSlider_rczak_66{position:relative;width:44px;height:24px;background:#ced4da;border-radius:12px;transition:all .2s ease;flex-shrink:0}._switchThumb_rczak_72{position:absolute;top:2px;left:2px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s ease;box-shadow:0 2px 4px #0003}._switchText_rczak_98{font-size:14px;font-weight:500;color:#343a40;line-height:1.4;flex:1}._description_rczak_106{font-size:12px;color:#6c757d;line-height:1.3;margin:0;padding-left:56px}.accessibility-high-contrast ._imageControl_rczak_9 ._title_rczak_12{color:#fff!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchLabel_rczak_29{background:#000!important;border-color:#fff!important;color:#fff!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchLabel_rczak_29:hover,.accessibility-high-contrast ._imageControl_rczak_9 ._switchLabel_rczak_29:focus-within{background:#343a40!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchText_rczak_98{color:#fff!important}.accessibility-high-contrast ._imageControl_rczak_9 ._description_rczak_106{color:#ced4da!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchSlider_rczak_66{background:#6c757d!important;border:1px solid #ffffff!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchInput_rczak_59:checked+._switchSlider_rczak_66{background:#fff!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchInput_rczak_59:checked+._switchSlider_rczak_66 ._switchThumb_rczak_72{background:#000!important}.accessibility-high-contrast ._imageControl_rczak_9 ._switchThumb_rczak_72{background:#fff!important;border:1px solid #000000!important}._stickyContainer_1xqyi_9{position:fixed;top:70px;right:0;left:0;pointer-events:none;z-index:1000}@media (max-width: 767px){._stickyContainer_1xqyi_9{top:60px}}._panel_1xqyi_23{position:sticky;top:20px;width:360px;max-width:calc(100vw - 40px);max-height:calc(100vh - 40px);background:#fff;border:1px solid #dee2e6;border-radius:12px;box-shadow:0 8px 32px #0000001f;overflow:hidden;display:flex;flex-direction:column;pointer-events:auto}._panel_1xqyi_23._topRight_1xqyi_38{margin-left:auto;margin-right:20px}._panel_1xqyi_23._topLeft_1xqyi_42{margin-left:20px;margin-right:auto}@media (max-width: 767px){._panel_1xqyi_23{width:calc(100vw - 32px);max-height:calc(100vh - 100px);margin-left:16px;margin-right:16px}._panel_1xqyi_23._topRight_1xqyi_38,._panel_1xqyi_23._topLeft_1xqyi_42{margin-left:16px;margin-right:16px}}._header_1xqyi_59{display:flex;justify-content:space-between;align-items:center;padding:20px 24px 16px;border-bottom:1px solid #e9ecef;background:#f8f9fa}._title_1xqyi_68{margin:0;font-size:18px;font-weight:600;color:#343a40;line-height:1.3}._closeButton_1xqyi_76{background:none;border:none;font-size:24px;font-weight:300;color:#6c757d;cursor:pointer;padding:4px 8px;border-radius:4px;transition:all .2s ease;line-height:1;width:32px;height:32px;display:flex;align-items:center;justify-content:center}._closeButton_1xqyi_76:hover{background:#e9ecef;color:#343a40}._closeButton_1xqyi_76:focus{outline:2px solid #007bff;outline-offset:2px;background:#e9ecef;color:#343a40}._closeButton_1xqyi_76:active{background:#dee2e6}._description_1xqyi_107{padding:16px 24px 0;font-size:14px;color:#6c757d;line-height:1.4;margin:0}._content_1xqyi_115{flex:1;padding:20px 24px 24px;overflow-y:auto}._content_1xqyi_115::-webkit-scrollbar{width:6px}._content_1xqyi_115::-webkit-scrollbar-track{background:#e9ecef;border-radius:3px}._content_1xqyi_115::-webkit-scrollbar-thumb{background:#ced4da;border-radius:3px}._content_1xqyi_115::-webkit-scrollbar-thumb:hover{background:#adb5bd}._controls_1xqyi_135{display:flex;flex-direction:column;gap:4px}.accessibility-high-contrast ._panel_1xqyi_23{background:#000!important;border-color:#fff!important;color:#fff!important}.accessibility-high-contrast ._panel_1xqyi_23 ._header_1xqyi_59{background:#000!important;border-bottom-color:#fff!important}.accessibility-high-contrast ._panel_1xqyi_23 ._title_1xqyi_68{color:#fff!important}.accessibility-high-contrast ._panel_1xqyi_23 ._closeButton_1xqyi_76{color:#fff!important;border:1px solid #ffffff!important}.accessibility-high-contrast ._panel_1xqyi_23 ._closeButton_1xqyi_76:hover,.accessibility-high-contrast ._panel_1xqyi_23 ._closeButton_1xqyi_76:focus{background:#343a40!important;color:#ff0!important}.accessibility-high-contrast ._panel_1xqyi_23 ._closeButton_1xqyi_76:active{background:#6c757d!important}.accessibility-high-contrast ._panel_1xqyi_23 ._description_1xqyi_107{color:#ced4da!important}.accessibility-high-contrast ._panel_1xqyi_23 ._content_1xqyi_115::-webkit-scrollbar-track{background:#343a40!important}.accessibility-high-contrast ._panel_1xqyi_23 ._content_1xqyi_115::-webkit-scrollbar-thumb{background:#6c757d!important}.accessibility-high-contrast ._panel_1xqyi_23 ._content_1xqyi_115::-webkit-scrollbar-thumb:hover{background:#adb5bd!important}@keyframes _slideIn_1xqyi_1{0%{opacity:0;transform:translateY(-10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}._panel_1xqyi_23{animation:_slideIn_1xqyi_1 .2s ease}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Типы для панели доступности
|
|
3
|
+
* Определяет интерфейсы и типы для настроек доступности
|
|
4
|
+
*/
|
|
5
|
+
export type ColorScheme = 'standard' | 'high-contrast' | 'grayscale';
|
|
6
|
+
export type FontSize = 'small' | 'standard' | 'large';
|
|
7
|
+
/**
|
|
8
|
+
* Интерфейс настроек доступности
|
|
9
|
+
*/
|
|
10
|
+
export interface AccessibilitySettings {
|
|
11
|
+
/** Включен ли режим доступности */
|
|
12
|
+
isEnabled: boolean;
|
|
13
|
+
/** Цветовая схема */
|
|
14
|
+
colorScheme: ColorScheme;
|
|
15
|
+
/** Размер шрифта */
|
|
16
|
+
fontSize: FontSize;
|
|
17
|
+
/** Показывать ли изображения */
|
|
18
|
+
showImages: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Контекст для управления настройками доступности
|
|
22
|
+
*/
|
|
23
|
+
export interface AccessibilityContextType {
|
|
24
|
+
/** Текущие настройки */
|
|
25
|
+
settings: AccessibilitySettings;
|
|
26
|
+
/** Обновление настроек */
|
|
27
|
+
updateSettings: (updates: Partial<AccessibilitySettings>) => void;
|
|
28
|
+
/** Сброс настроек к значениям по умолчанию */
|
|
29
|
+
resetSettings: () => void;
|
|
30
|
+
/** Загружены ли настройки из localStorage */
|
|
31
|
+
isLoaded: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Свойства основного компонента панели доступности
|
|
35
|
+
*/
|
|
36
|
+
export interface AccessibilityPanelProps {
|
|
37
|
+
/** Открыта ли панель */
|
|
38
|
+
isOpen: boolean;
|
|
39
|
+
/** Обработчик закрытия панели */
|
|
40
|
+
onClose: () => void;
|
|
41
|
+
/** Позиция панели относительно кнопки */
|
|
42
|
+
position?: 'top-right' | 'top-left';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Свойства компонентов управления настройками
|
|
46
|
+
*/
|
|
47
|
+
export interface ControlComponentProps {
|
|
48
|
+
/** Текущие настройки */
|
|
49
|
+
settings: AccessibilitySettings;
|
|
50
|
+
/** Обработчик обновления настроек */
|
|
51
|
+
onUpdate: (updates: Partial<AccessibilitySettings>) => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Настройки по умолчанию
|
|
55
|
+
*/
|
|
56
|
+
export declare const DEFAULT_ACCESSIBILITY_SETTINGS: AccessibilitySettings;
|
|
57
|
+
/**
|
|
58
|
+
* Ключ для сохранения в localStorage
|
|
59
|
+
*/
|
|
60
|
+
export declare const STORAGE_KEY = "accessibility-settings";
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,eAAe,GAAG,WAAW,CAAC;AACrE,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,oBAAoB;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,gCAAgC;IAChC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,wBAAwB;IACxB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,0BAA0B;IAC1B,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,qBAAqB,CAAC,KAAK,IAAI,CAAC;IAClE,8CAA8C;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,wBAAwB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,iCAAiC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wBAAwB;IACxB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,qCAAqC;IACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,qBAAqB,CAAC,KAAK,IAAI,CAAC;CAC7D;AAED;;GAEG;AACH,eAAO,MAAM,8BAA8B,EAAE,qBAK5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,2BAA2B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vision-accessibility",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Универсальный компонент панели доступности для слабовидящих пользователей",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "vite build",
|
|
15
|
+
"dev": "vite build --watch",
|
|
16
|
+
"type-check": "tsc --noEmit",
|
|
17
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"accessibility",
|
|
22
|
+
"a11y",
|
|
23
|
+
"vision",
|
|
24
|
+
"react",
|
|
25
|
+
"typescript",
|
|
26
|
+
"слабовидящие",
|
|
27
|
+
"доступность"
|
|
28
|
+
],
|
|
29
|
+
"author": "Your Name",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=16.8.0",
|
|
33
|
+
"react-dom": ">=16.8.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/react": "^18.0.0",
|
|
37
|
+
"@types/react-dom": "^18.0.0",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
39
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
40
|
+
"@vitejs/plugin-react": "^4.0.0",
|
|
41
|
+
"eslint": "^8.0.0",
|
|
42
|
+
"eslint-plugin-react": "^7.0.0",
|
|
43
|
+
"eslint-plugin-react-hooks": "^4.0.0",
|
|
44
|
+
"sass": "^1.69.0",
|
|
45
|
+
"terser": "^5.46.0",
|
|
46
|
+
"typescript": "^5.0.0",
|
|
47
|
+
"vite": "^5.0.0",
|
|
48
|
+
"vite-plugin-dts": "^3.0.0"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/your-username/vision-accessibility.git"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/your-username/vision-accessibility/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/your-username/vision-accessibility#readme"
|
|
58
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Стили для основного компонента панели доступности
|
|
3
|
+
* Реализует sticky панель с настройками доступности
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.stickyContainer {
|
|
7
|
+
position: fixed;
|
|
8
|
+
top: 70px;
|
|
9
|
+
right: 0;
|
|
10
|
+
left: 0;
|
|
11
|
+
pointer-events: none;
|
|
12
|
+
z-index: 1000;
|
|
13
|
+
|
|
14
|
+
// Адаптивность для мобильных устройств
|
|
15
|
+
@include respond-down(md) {
|
|
16
|
+
top: 60px;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.panel {
|
|
21
|
+
position: sticky;
|
|
22
|
+
top: 20px;
|
|
23
|
+
width: 360px;
|
|
24
|
+
max-width: calc(100vw - 40px);
|
|
25
|
+
max-height: calc(100vh - 40px);
|
|
26
|
+
background: $white;
|
|
27
|
+
border: 1px solid $gray-300;
|
|
28
|
+
border-radius: $border-radius-xl;
|
|
29
|
+
box-shadow: $shadow-lg;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
pointer-events: auto;
|
|
34
|
+
|
|
35
|
+
// Позиционирование панели
|
|
36
|
+
&.topRight {
|
|
37
|
+
margin-left: auto;
|
|
38
|
+
margin-right: $spacing-xl;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&.topLeft {
|
|
42
|
+
margin-left: $spacing-xl;
|
|
43
|
+
margin-right: auto;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Адаптивность для мобильных устройств
|
|
47
|
+
@include respond-down(md) {
|
|
48
|
+
width: calc(100vw - 32px);
|
|
49
|
+
max-height: calc(100vh - 100px);
|
|
50
|
+
margin-left: $spacing-lg;
|
|
51
|
+
margin-right: $spacing-lg;
|
|
52
|
+
|
|
53
|
+
&.topRight,
|
|
54
|
+
&.topLeft {
|
|
55
|
+
margin-left: $spacing-lg;
|
|
56
|
+
margin-right: $spacing-lg;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.header {
|
|
62
|
+
display: flex;
|
|
63
|
+
justify-content: space-between;
|
|
64
|
+
align-items: center;
|
|
65
|
+
padding: $spacing-xl $spacing-xxl $spacing-lg;
|
|
66
|
+
border-bottom: 1px solid $gray-200;
|
|
67
|
+
background: $gray-100;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.title {
|
|
71
|
+
margin: 0;
|
|
72
|
+
font-size: 18px;
|
|
73
|
+
font-weight: 600;
|
|
74
|
+
color: $gray-800;
|
|
75
|
+
line-height: 1.3;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.closeButton {
|
|
79
|
+
background: none;
|
|
80
|
+
border: none;
|
|
81
|
+
font-size: 24px;
|
|
82
|
+
font-weight: 300;
|
|
83
|
+
color: $gray-600;
|
|
84
|
+
cursor: pointer;
|
|
85
|
+
padding: $spacing-xs $spacing-sm;
|
|
86
|
+
border-radius: $spacing-xs;
|
|
87
|
+
transition: all $transition-fast;
|
|
88
|
+
line-height: 1;
|
|
89
|
+
width: 32px;
|
|
90
|
+
height: 32px;
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
|
|
95
|
+
&:hover {
|
|
96
|
+
background: $gray-200;
|
|
97
|
+
color: $gray-800;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&:focus {
|
|
101
|
+
outline: 2px solid $primary;
|
|
102
|
+
outline-offset: 2px;
|
|
103
|
+
background: $gray-200;
|
|
104
|
+
color: $gray-800;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&:active {
|
|
108
|
+
background: $gray-300;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.description {
|
|
113
|
+
padding: $spacing-lg $spacing-xxl 0;
|
|
114
|
+
font-size: 14px;
|
|
115
|
+
color: $gray-600;
|
|
116
|
+
line-height: 1.4;
|
|
117
|
+
margin: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.content {
|
|
121
|
+
flex: 1;
|
|
122
|
+
padding: $spacing-xl $spacing-xxl $spacing-xxl;
|
|
123
|
+
overflow-y: auto;
|
|
124
|
+
|
|
125
|
+
// Кастомный скроллбар
|
|
126
|
+
&::-webkit-scrollbar {
|
|
127
|
+
width: 6px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&::-webkit-scrollbar-track {
|
|
131
|
+
background: $gray-200;
|
|
132
|
+
border-radius: 3px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&::-webkit-scrollbar-thumb {
|
|
136
|
+
background: $gray-400;
|
|
137
|
+
border-radius: 3px;
|
|
138
|
+
|
|
139
|
+
&:hover {
|
|
140
|
+
background: $gray-500;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.controls {
|
|
146
|
+
display: flex;
|
|
147
|
+
flex-direction: column;
|
|
148
|
+
gap: $spacing-xs;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Высококонтрастная тема - адаптация стилей только для панели
|
|
152
|
+
:global(.accessibility-high-contrast) .panel {
|
|
153
|
+
background: $black !important;
|
|
154
|
+
border-color: $white !important;
|
|
155
|
+
color: $white !important;
|
|
156
|
+
|
|
157
|
+
.header {
|
|
158
|
+
background: $black !important;
|
|
159
|
+
border-bottom-color: $white !important;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.title {
|
|
163
|
+
color: $white !important;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.closeButton {
|
|
167
|
+
color: $white !important;
|
|
168
|
+
border: 1px solid $white !important;
|
|
169
|
+
|
|
170
|
+
&:hover,
|
|
171
|
+
&:focus {
|
|
172
|
+
background: $gray-800 !important;
|
|
173
|
+
color: $yellow !important;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
&:active {
|
|
177
|
+
background: $gray-600 !important;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.description {
|
|
182
|
+
color: $gray-400 !important;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.content {
|
|
186
|
+
&::-webkit-scrollbar-track {
|
|
187
|
+
background: $gray-800 !important;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
&::-webkit-scrollbar-thumb {
|
|
191
|
+
background: $gray-600 !important;
|
|
192
|
+
|
|
193
|
+
&:hover {
|
|
194
|
+
background: $gray-500 !important;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Анимация появления панели
|
|
201
|
+
@keyframes slideIn {
|
|
202
|
+
from {
|
|
203
|
+
opacity: 0;
|
|
204
|
+
transform: translateY(-10px) scale(0.95);
|
|
205
|
+
}
|
|
206
|
+
to {
|
|
207
|
+
opacity: 1;
|
|
208
|
+
transform: translateY(0) scale(1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.panel {
|
|
213
|
+
animation: slideIn $transition-fast;
|
|
214
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Основной компонент панели доступности
|
|
3
|
+
* Объединяет все подкомпоненты управления настройками доступности
|
|
4
|
+
*
|
|
5
|
+
* Реализует требования:
|
|
6
|
+
* - 1.1: Отображение панели доступности при клике на кнопку
|
|
7
|
+
* - 1.2: Закрытие панели кликом вне области или по кнопке закрытия
|
|
8
|
+
* - 1.3: Скрытие панели без изменения текущих настроек
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React, { useEffect, useRef } from 'react';
|
|
12
|
+
import { AccessibilityPanelProps } from '../../types';
|
|
13
|
+
import { AccessibilityProvider } from '../../context/AccessibilityContext';
|
|
14
|
+
import { AccessibilityToggle } from '../AccessibilityToggle/AccessibilityToggle';
|
|
15
|
+
import { ColorSchemeControl } from '../ColorSchemeControl/ColorSchemeControl';
|
|
16
|
+
import { FontSizeControl } from '../FontSizeControl/FontSizeControl';
|
|
17
|
+
import { ImageControl } from '../ImageControl/ImageControl';
|
|
18
|
+
import styles from './AccessibilityPanel.module.scss';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Внутренний компонент панели доступности
|
|
22
|
+
* Содержит всю логику панели, обернутый в провайдер контекста
|
|
23
|
+
*/
|
|
24
|
+
const AccessibilityPanelInner: React.FC<AccessibilityPanelProps> = ({
|
|
25
|
+
isOpen,
|
|
26
|
+
onClose,
|
|
27
|
+
position = 'top-right'
|
|
28
|
+
}) => {
|
|
29
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Обработка клика вне области панели для закрытия
|
|
33
|
+
* Реализует требование 1.2: Закрытие панели кликом вне области
|
|
34
|
+
*/
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!isOpen) return;
|
|
37
|
+
|
|
38
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
39
|
+
if (panelRef.current && !panelRef.current.contains(event.target as Node)) {
|
|
40
|
+
onClose();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Добавляем обработчик с небольшой задержкой, чтобы избежать немедленного закрытия
|
|
45
|
+
const timeoutId = setTimeout(() => {
|
|
46
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
47
|
+
}, 100);
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
clearTimeout(timeoutId);
|
|
51
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
52
|
+
};
|
|
53
|
+
}, [isOpen, onClose]);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Обработка нажатия клавиши Escape для закрытия панели
|
|
57
|
+
* Реализует требование 1.2: Закрытие панели по клавише Escape
|
|
58
|
+
*/
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!isOpen) return;
|
|
61
|
+
|
|
62
|
+
const handleEscapeKey = (event: KeyboardEvent) => {
|
|
63
|
+
if (event.key === 'Escape') {
|
|
64
|
+
onClose();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
document.addEventListener('keydown', handleEscapeKey);
|
|
69
|
+
|
|
70
|
+
return () => {
|
|
71
|
+
document.removeEventListener('keydown', handleEscapeKey);
|
|
72
|
+
};
|
|
73
|
+
}, [isOpen, onClose]);
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Обработчик закрытия панели по кнопке
|
|
77
|
+
*
|
|
78
|
+
* @param event - Событие клика
|
|
79
|
+
*/
|
|
80
|
+
const handleCloseClick = (event: React.MouseEvent) => {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
onClose();
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Если панель закрыта, не рендерим её
|
|
87
|
+
if (!isOpen) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div className={`${styles.stickyContainer} accessibility-panel-container`}>
|
|
93
|
+
<div
|
|
94
|
+
ref={panelRef}
|
|
95
|
+
className={`${styles.panel} ${styles[position]}`}
|
|
96
|
+
role="dialog"
|
|
97
|
+
aria-modal="true"
|
|
98
|
+
aria-labelledby="accessibility-panel-title"
|
|
99
|
+
aria-describedby="accessibility-panel-description"
|
|
100
|
+
>
|
|
101
|
+
<div className={styles.header}>
|
|
102
|
+
<h3 id="accessibility-panel-title" className={styles.title}>
|
|
103
|
+
Настройки доступности
|
|
104
|
+
</h3>
|
|
105
|
+
|
|
106
|
+
<button
|
|
107
|
+
onClick={handleCloseClick}
|
|
108
|
+
className={styles.closeButton}
|
|
109
|
+
aria-label="Закрыть панель настроек доступности"
|
|
110
|
+
type="button"
|
|
111
|
+
>
|
|
112
|
+
×
|
|
113
|
+
</button>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div
|
|
117
|
+
id="accessibility-panel-description"
|
|
118
|
+
className={styles.description}
|
|
119
|
+
>
|
|
120
|
+
Настройте отображение страницы для улучшения доступности
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div className={styles.content}>
|
|
124
|
+
<AccessibilityToggle />
|
|
125
|
+
|
|
126
|
+
<div className={styles.controls}>
|
|
127
|
+
<ColorSchemeControl />
|
|
128
|
+
<FontSizeControl />
|
|
129
|
+
<ImageControl />
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Основной компонент панели доступности с провайдером контекста
|
|
139
|
+
*
|
|
140
|
+
* @param props - Свойства компонента
|
|
141
|
+
* @returns JSX элемент с полной панелью настроек доступности
|
|
142
|
+
*/
|
|
143
|
+
export const AccessibilityPanel: React.FC<AccessibilityPanelProps> = (props) => {
|
|
144
|
+
return (
|
|
145
|
+
<AccessibilityProvider>
|
|
146
|
+
<AccessibilityPanelInner {...props} />
|
|
147
|
+
</AccessibilityProvider>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export default AccessibilityPanel;
|