vision-accessibility 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 (41) hide show
  1. package/README.md +70 -1
  2. package/dist/components/AccessibilityPanel/AccessibilityPanel.d.ts.map +1 -1
  3. package/dist/components/AccessibilityToggle/AccessibilityToggle.d.ts +2 -0
  4. package/dist/components/AccessibilityToggle/AccessibilityToggle.d.ts.map +1 -1
  5. package/dist/components/ColorSchemeControl/ColorSchemeControl.d.ts +2 -0
  6. package/dist/components/ColorSchemeControl/ColorSchemeControl.d.ts.map +1 -1
  7. package/dist/components/FontSizeControl/FontSizeControl.d.ts +2 -0
  8. package/dist/components/FontSizeControl/FontSizeControl.d.ts.map +1 -1
  9. package/dist/components/ImageControl/ImageControl.d.ts +2 -0
  10. package/dist/components/ImageControl/ImageControl.d.ts.map +1 -1
  11. package/dist/config/translations.d.ts +57 -0
  12. package/dist/config/translations.d.ts.map +1 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.esm.js +371 -202
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.umd.js +3 -3
  18. package/dist/index.umd.js.map +1 -1
  19. package/dist/lib/css-applier.d.ts +1 -0
  20. package/dist/lib/css-applier.d.ts.map +1 -1
  21. package/dist/style.css +1 -1
  22. package/dist/types/index.d.ts +39 -1
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/AccessibilityPanel/AccessibilityPanel.module.scss +22 -33
  26. package/src/components/AccessibilityPanel/AccessibilityPanel.stories.tsx +50 -10
  27. package/src/components/AccessibilityPanel/AccessibilityPanel.tsx +72 -44
  28. package/src/components/AccessibilityToggle/AccessibilityToggle.stories.tsx +11 -0
  29. package/src/components/AccessibilityToggle/AccessibilityToggle.tsx +17 -10
  30. package/src/components/ColorSchemeControl/ColorSchemeControl.stories.tsx +15 -0
  31. package/src/components/ColorSchemeControl/ColorSchemeControl.tsx +99 -61
  32. package/src/components/FontSizeControl/FontSizeControl.stories.tsx +15 -0
  33. package/src/components/FontSizeControl/FontSizeControl.tsx +99 -61
  34. package/src/components/ImageControl/ImageControl.stories.tsx +11 -0
  35. package/src/components/ImageControl/ImageControl.tsx +17 -10
  36. package/src/config/translations.ts +82 -0
  37. package/src/hooks/useAccessibilitySettings.ts +12 -12
  38. package/src/index.ts +12 -8
  39. package/src/lib/css-applier.ts +54 -38
  40. package/src/styles/global.scss +2 -5
  41. package/src/types/index.ts +43 -1
package/dist/index.esm.js CHANGED
@@ -1,4 +1,5 @@
1
- import require$$0, { useCallback, useState, useEffect, createContext, useContext, useRef } from "react";
1
+ import require$$0, { useCallback, useState, useEffect, createContext, useContext, useRef, useLayoutEffect } from "react";
2
+ import { createPortal } from "react-dom";
2
3
  const DEFAULT_ACCESSIBILITY_SETTINGS = {
3
4
  isEnabled: false,
4
5
  colorScheme: "standard",
@@ -6,6 +7,31 @@ const DEFAULT_ACCESSIBILITY_SETTINGS = {
6
7
  showImages: true
7
8
  };
8
9
  const STORAGE_KEY = "accessibility-settings";
10
+ const defaultTranslations = {
11
+ panelTitle: "Настройки доступности",
12
+ panelDescription: "Настройте отображение страницы для улучшения доступности",
13
+ closePanelLabel: "Закрыть панель настроек доступности",
14
+ colorSchemeTitle: "Цветовая схема",
15
+ colorSchemeStandardLabel: "Стандартный",
16
+ colorSchemeStandardDescription: "Обычная цветовая схема сайта",
17
+ colorSchemeHighContrastLabel: "Контрастный белый на черном",
18
+ colorSchemeHighContrastDescription: "Высококонтрастная схема для лучшей читаемости",
19
+ colorSchemeGrayscaleLabel: "Черно-белый",
20
+ colorSchemeGrayscaleDescription: "Преобразование всех цветов в оттенки серого",
21
+ fontSizeTitle: "Размер шрифта",
22
+ fontSizeSmallLabel: "Мелкий",
23
+ fontSizeSmallDescription: "Уменьшенный размер текста (80%)",
24
+ fontSizeStandardLabel: "Стандартный",
25
+ fontSizeStandardDescription: "Обычный размер текста",
26
+ fontSizeLargeLabel: "Крупный",
27
+ fontSizeLargeDescription: "Увеличенный размер текста (130%)",
28
+ imageControlTitle: "Изображения",
29
+ imageControlShowLabel: "Показывать изображения",
30
+ imageControlHideLabel: "Скрывать изображения",
31
+ accessibilityToggleLabel: "Режим доступности",
32
+ accessibilityEnableDescription: "Все настройки доступности активны. Используйте элементы управления ниже для точной настройки.",
33
+ accessibilityDisableDescription: "Включите режим доступности для активации всех настроек. При выключении все изменения будут сброшены."
34
+ };
9
35
  const saveToStorage = (settings) => {
10
36
  try {
11
37
  if (typeof window === "undefined") return;
@@ -281,17 +307,24 @@ const applyColorScheme = (scheme) => {
281
307
  }
282
308
  }, `Ошибка при применении цветовой схемы: ${scheme}`);
283
309
  };
310
+ const isAccessibilityPanelElement = (element) => {
311
+ return element.hasAttribute("data-accessibility-panel-container") || element.closest("[data-accessibility-panel-container]") !== null;
312
+ };
284
313
  const applyFontSize = (size) => {
285
314
  applyDynamicFontSize(size);
286
315
  };
287
316
  const applyImageVisibility = (showImages) => {
288
317
  safeDOMOperation(() => {
289
318
  if (!isDOMAvailable()) return;
290
- const elements = getImageElements();
319
+ const images = document.querySelectorAll("img");
291
320
  if (showImages) {
292
- removeClassFromElements(elements, CSS_CLASSES.HIDE_IMAGES);
321
+ images.forEach((img) => {
322
+ img.style.visibility = "";
323
+ });
293
324
  } else {
294
- applyClassToElements(elements, CSS_CLASSES.HIDE_IMAGES);
325
+ images.forEach((img) => {
326
+ img.style.visibility = "hidden";
327
+ });
295
328
  }
296
329
  }, `Ошибка при управлении отображением изображений: ${showImages}`);
297
330
  };
@@ -303,18 +336,18 @@ const removeAllAccessibilityStyles = () => {
303
336
  document.body.classList.remove(CSS_CLASSES.FONT_LARGE);
304
337
  document.body.style.filter = "";
305
338
  resetAllFontSizes();
306
- const imageElements = getImageElements();
307
- removeClassFromElements(imageElements, CSS_CLASSES.HIDE_IMAGES);
339
+ const images = document.querySelectorAll("img");
340
+ images.forEach((img) => {
341
+ img.style.visibility = "";
342
+ });
308
343
  removeHighContrastStylesFromAllElements();
309
344
  }, "Ошибка при удалении всех стилей доступности");
310
345
  };
311
346
  const applyAllSettings = (settings) => {
312
- if (!settings.isEnabled) {
313
- removeAllAccessibilityStyles();
314
- return;
347
+ if (settings.isEnabled) {
348
+ applyColorScheme(settings.colorScheme);
349
+ applyFontSize(settings.fontSize);
315
350
  }
316
- applyColorScheme(settings.colorScheme);
317
- applyFontSize(settings.fontSize);
318
351
  applyImageVisibility(settings.showImages);
319
352
  };
320
353
  const applyHighContrastStylesToAllElements = () => {
@@ -322,35 +355,35 @@ const applyHighContrastStylesToAllElements = () => {
322
355
  if (!isDOMAvailable()) return;
323
356
  const allElements = document.querySelectorAll("*");
324
357
  allElements.forEach((element) => {
325
- if (element instanceof HTMLElement) {
358
+ if (element instanceof HTMLElement && !isAccessibilityPanelElement(element)) {
326
359
  element.style.backgroundColor = "#000";
327
360
  element.style.color = "#fff";
328
361
  element.style.borderColor = "#fff";
329
362
  }
330
363
  });
331
- const links = document.querySelectorAll("a");
364
+ const links = document.querySelectorAll("a:not([data-accessibility-panel-container])");
332
365
  links.forEach((link) => {
333
- if (link instanceof HTMLElement) {
366
+ if (link instanceof HTMLElement && !isAccessibilityPanelElement(link)) {
334
367
  link.style.color = "#ffff00";
335
368
  }
336
369
  });
337
- const visitedLinks = document.querySelectorAll("a:visited");
370
+ const visitedLinks = document.querySelectorAll("a:visited:not([data-accessibility-panel-container])");
338
371
  visitedLinks.forEach((link) => {
339
- if (link instanceof HTMLElement) {
372
+ if (link instanceof HTMLElement && !isAccessibilityPanelElement(link)) {
340
373
  link.style.color = "#ff00ff";
341
374
  }
342
375
  });
343
- const buttons = document.querySelectorAll("button");
376
+ const buttons = document.querySelectorAll("button:not([data-accessibility-panel-container])");
344
377
  buttons.forEach((button) => {
345
- if (button instanceof HTMLElement) {
378
+ if (button instanceof HTMLElement && !isAccessibilityPanelElement(button)) {
346
379
  button.style.backgroundColor = "#fff";
347
380
  button.style.color = "#000";
348
381
  button.style.border = "2px solid #fff";
349
382
  }
350
383
  });
351
- const inputs = document.querySelectorAll("input, textarea, select");
384
+ const inputs = document.querySelectorAll("input, textarea, select:not([data-accessibility-panel-container])");
352
385
  inputs.forEach((input) => {
353
- if (input instanceof HTMLElement) {
386
+ if (input instanceof HTMLElement && !isAccessibilityPanelElement(input)) {
354
387
  input.style.backgroundColor = "#fff";
355
388
  input.style.color = "#000";
356
389
  input.style.border = "2px solid #fff";
@@ -363,35 +396,35 @@ const removeHighContrastStylesFromAllElements = () => {
363
396
  if (!isDOMAvailable()) return;
364
397
  const allElements = document.querySelectorAll("*");
365
398
  allElements.forEach((element) => {
366
- if (element instanceof HTMLElement) {
399
+ if (element instanceof HTMLElement && !isAccessibilityPanelElement(element)) {
367
400
  element.style.backgroundColor = "";
368
401
  element.style.color = "";
369
402
  element.style.borderColor = "";
370
403
  }
371
404
  });
372
- const links = document.querySelectorAll("a");
405
+ const links = document.querySelectorAll("a:not([data-accessibility-panel-container])");
373
406
  links.forEach((link) => {
374
- if (link instanceof HTMLElement) {
407
+ if (link instanceof HTMLElement && !isAccessibilityPanelElement(link)) {
375
408
  link.style.color = "";
376
409
  }
377
410
  });
378
- const visitedLinks = document.querySelectorAll("a:visited");
411
+ const visitedLinks = document.querySelectorAll("a:visited:not([data-accessibility-panel-container])");
379
412
  visitedLinks.forEach((link) => {
380
- if (link instanceof HTMLElement) {
413
+ if (link instanceof HTMLElement && !isAccessibilityPanelElement(link)) {
381
414
  link.style.color = "";
382
415
  }
383
416
  });
384
- const buttons = document.querySelectorAll("button");
417
+ const buttons = document.querySelectorAll("button:not([data-accessibility-panel-container])");
385
418
  buttons.forEach((button) => {
386
- if (button instanceof HTMLElement) {
419
+ if (button instanceof HTMLElement && !isAccessibilityPanelElement(button)) {
387
420
  button.style.backgroundColor = "";
388
421
  button.style.color = "";
389
422
  button.style.border = "";
390
423
  }
391
424
  });
392
- const inputs = document.querySelectorAll("input, textarea, select");
425
+ const inputs = document.querySelectorAll("input, textarea, select:not([data-accessibility-panel-container])");
393
426
  inputs.forEach((input) => {
394
- if (input instanceof HTMLElement) {
427
+ if (input instanceof HTMLElement && !isAccessibilityPanelElement(input)) {
395
428
  input.style.backgroundColor = "";
396
429
  input.style.color = "";
397
430
  input.style.border = "";
@@ -400,7 +433,7 @@ const removeHighContrastStylesFromAllElements = () => {
400
433
  }, "Ошибка при удалении стилей высокого контраста со всех элементов");
401
434
  };
402
435
  const applySettingIfEnabled = (isEnabled, settingType, value) => {
403
- if (!isEnabled) {
436
+ if (!isEnabled && settingType !== "imageVisibility") {
404
437
  return;
405
438
  }
406
439
  switch (settingType) {
@@ -871,8 +904,10 @@ const styles$4 = {
871
904
  highContrastMode: highContrastMode$4
872
905
  };
873
906
  const AccessibilityToggle = ({
874
- className
907
+ className,
908
+ translations = {}
875
909
  }) => {
910
+ const mergedTranslations = { ...defaultTranslations, ...translations };
876
911
  const { settings, updateSettings } = useAccessibilityContext();
877
912
  const isEnabled = settings.isEnabled;
878
913
  const handleToggleChange = (event) => {
@@ -892,8 +927,8 @@ const AccessibilityToggle = ({
892
927
  ),
893
928
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$4.toggleSlider, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$4.toggleThumb }) }),
894
929
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$4.toggleContent, children: [
895
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$4.toggleTitle, children: "Режим доступности" }),
896
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$4.toggleStatus, children: isEnabled ? "Включен" : "Выключен" })
930
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$4.toggleTitle, children: mergedTranslations.accessibilityToggleLabel }),
931
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$4.toggleStatus, children: isEnabled ? mergedTranslations.accessibilityEnableLabel : mergedTranslations.accessibilityDisableLabel })
897
932
  ] })
898
933
  ] }),
899
934
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -901,7 +936,7 @@ const AccessibilityToggle = ({
901
936
  {
902
937
  id: "accessibility-toggle-description",
903
938
  className: styles$4.description,
904
- children: isEnabled ? "Все настройки доступности активны. Используйте элементы управления ниже для точной настройки." : "Включите режим доступности для активации всех настроек. При выключении все изменения будут сброшены."
939
+ children: isEnabled ? mergedTranslations.accessibilityEnableDescription || "Все настройки доступности активны. Используйте элементы управления ниже для точной настройки." : mergedTranslations.accessibilityDisableDescription || "Включите режим доступности для активации всех настроек. При выключении все изменения будут сброшены."
905
940
  }
906
941
  )
907
942
  ] }) });
@@ -934,26 +969,11 @@ const styles$3 = {
934
969
  optionDescription: optionDescription$1,
935
970
  highContrastMode: highContrastMode$3
936
971
  };
937
- const COLOR_SCHEME_OPTIONS = [
938
- {
939
- value: "standard",
940
- label: "Стандартный",
941
- description: "Обычная цветовая схема сайта"
942
- },
943
- {
944
- value: "high-contrast",
945
- label: "Контрастный белый на черном",
946
- description: "Высококонтрастная схема для лучшей читаемости"
947
- },
948
- {
949
- value: "grayscale",
950
- label: "Черно-белый",
951
- description: "Преобразование всех цветов в оттенки серого"
952
- }
953
- ];
954
972
  const ColorSchemeControl = ({
955
- className
973
+ className,
974
+ translations = {}
956
975
  }) => {
976
+ const mergedTranslations = { ...defaultTranslations, ...translations };
957
977
  const { settings, updateSettings } = useAccessibilityContext();
958
978
  const colorScheme = settings.colorScheme;
959
979
  const isEnabled = settings.isEnabled;
@@ -962,41 +982,111 @@ const ColorSchemeControl = ({
962
982
  updateSettings({ colorScheme: newColorScheme });
963
983
  };
964
984
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `${styles$3.colorSchemeControl} ${className || ""} ${!isEnabled ? styles$3.disabled : ""} ${colorScheme === "high-contrast" ? styles$3.highContrastMode : ""}`, children: [
965
- /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: styles$3.title, children: "Цветовая схема" }),
966
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$3.optionsContainer, role: "radiogroup", "aria-labelledby": "color-scheme-title", children: COLOR_SCHEME_OPTIONS.map((option2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
967
- "label",
968
- {
969
- className: `${styles$3.option} ${colorScheme === option2.value ? styles$3.selected : ""} ${!isEnabled ? styles$3.optionDisabled : ""}`,
970
- children: [
971
- /* @__PURE__ */ jsxRuntimeExports.jsx(
972
- "input",
973
- {
974
- type: "radio",
975
- name: "colorScheme",
976
- value: option2.value,
977
- checked: colorScheme === option2.value,
978
- onChange: handleColorSchemeChange,
979
- className: styles$3.radioInput,
980
- "aria-describedby": `color-scheme-${option2.value}-description`,
981
- disabled: !isEnabled
982
- }
983
- ),
984
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$3.optionContent, children: [
985
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$3.optionLabel, children: option2.label }),
985
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: styles$3.title, children: mergedTranslations.colorSchemeTitle }),
986
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$3.optionsContainer, role: "radiogroup", "aria-labelledby": "color-scheme-title", children: [
987
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
988
+ "label",
989
+ {
990
+ className: `${styles$3.option} ${colorScheme === "standard" ? styles$3.selected : ""} ${!isEnabled ? styles$3.optionDisabled : ""}`,
991
+ children: [
986
992
  /* @__PURE__ */ jsxRuntimeExports.jsx(
987
- "span",
993
+ "input",
988
994
  {
989
- id: `color-scheme-${option2.value}-description`,
990
- className: styles$3.optionDescription,
991
- children: option2.description
995
+ type: "radio",
996
+ name: "colorScheme",
997
+ value: "standard",
998
+ checked: colorScheme === "standard",
999
+ onChange: handleColorSchemeChange,
1000
+ className: styles$3.radioInput,
1001
+ "aria-describedby": "color-scheme-standard-description",
1002
+ disabled: !isEnabled
992
1003
  }
993
- )
994
- ] }),
995
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$3.radioIndicator, "aria-hidden": "true" })
996
- ]
997
- },
998
- option2.value
999
- )) })
1004
+ ),
1005
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$3.optionContent, children: [
1006
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$3.optionLabel, children: mergedTranslations.colorSchemeStandardLabel }),
1007
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1008
+ "span",
1009
+ {
1010
+ id: "color-scheme-standard-description",
1011
+ className: styles$3.optionDescription,
1012
+ children: mergedTranslations.colorSchemeStandardDescription
1013
+ }
1014
+ )
1015
+ ] }),
1016
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$3.radioIndicator, "aria-hidden": "true" })
1017
+ ]
1018
+ },
1019
+ "standard"
1020
+ ),
1021
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1022
+ "label",
1023
+ {
1024
+ className: `${styles$3.option} ${colorScheme === "high-contrast" ? styles$3.selected : ""} ${!isEnabled ? styles$3.optionDisabled : ""}`,
1025
+ children: [
1026
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1027
+ "input",
1028
+ {
1029
+ type: "radio",
1030
+ name: "colorScheme",
1031
+ value: "high-contrast",
1032
+ checked: colorScheme === "high-contrast",
1033
+ onChange: handleColorSchemeChange,
1034
+ className: styles$3.radioInput,
1035
+ "aria-describedby": "color-scheme-high-contrast-description",
1036
+ disabled: !isEnabled
1037
+ }
1038
+ ),
1039
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$3.optionContent, children: [
1040
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$3.optionLabel, children: mergedTranslations.colorSchemeHighContrastLabel }),
1041
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1042
+ "span",
1043
+ {
1044
+ id: "color-scheme-high-contrast-description",
1045
+ className: styles$3.optionDescription,
1046
+ children: mergedTranslations.colorSchemeHighContrastDescription
1047
+ }
1048
+ )
1049
+ ] }),
1050
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$3.radioIndicator, "aria-hidden": "true" })
1051
+ ]
1052
+ },
1053
+ "high-contrast"
1054
+ ),
1055
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1056
+ "label",
1057
+ {
1058
+ className: `${styles$3.option} ${colorScheme === "grayscale" ? styles$3.selected : ""} ${!isEnabled ? styles$3.optionDisabled : ""}`,
1059
+ children: [
1060
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1061
+ "input",
1062
+ {
1063
+ type: "radio",
1064
+ name: "colorScheme",
1065
+ value: "grayscale",
1066
+ checked: colorScheme === "grayscale",
1067
+ onChange: handleColorSchemeChange,
1068
+ className: styles$3.radioInput,
1069
+ "aria-describedby": "color-scheme-grayscale-description",
1070
+ disabled: !isEnabled
1071
+ }
1072
+ ),
1073
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$3.optionContent, children: [
1074
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$3.optionLabel, children: mergedTranslations.colorSchemeGrayscaleLabel }),
1075
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1076
+ "span",
1077
+ {
1078
+ id: "color-scheme-grayscale-description",
1079
+ className: styles$3.optionDescription,
1080
+ children: mergedTranslations.colorSchemeGrayscaleDescription
1081
+ }
1082
+ )
1083
+ ] }),
1084
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$3.radioIndicator, "aria-hidden": "true" })
1085
+ ]
1086
+ },
1087
+ "grayscale"
1088
+ )
1089
+ ] })
1000
1090
  ] });
1001
1091
  };
1002
1092
  const fontSizeControl = "_fontSizeControl_1c68l_9";
@@ -1027,26 +1117,11 @@ const styles$2 = {
1027
1117
  optionDescription,
1028
1118
  highContrastMode: highContrastMode$2
1029
1119
  };
1030
- const FONT_SIZE_OPTIONS = [
1031
- {
1032
- value: "small",
1033
- label: "Мелкий",
1034
- description: "Уменьшенный размер текста (80%)"
1035
- },
1036
- {
1037
- value: "standard",
1038
- label: "Стандартный",
1039
- description: "Обычный размер текста"
1040
- },
1041
- {
1042
- value: "large",
1043
- label: "Крупный",
1044
- description: "Увеличенный размер текста (130%)"
1045
- }
1046
- ];
1047
1120
  const FontSizeControl = ({
1048
- className
1121
+ className,
1122
+ translations = {}
1049
1123
  }) => {
1124
+ const mergedTranslations = { ...defaultTranslations, ...translations };
1050
1125
  const { settings, updateSettings } = useAccessibilityContext();
1051
1126
  const fontSize = settings.fontSize;
1052
1127
  const isEnabled = settings.isEnabled;
@@ -1055,41 +1130,111 @@ const FontSizeControl = ({
1055
1130
  updateSettings({ fontSize: newFontSize });
1056
1131
  };
1057
1132
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `${styles$2.fontSizeControl} ${className || ""} ${!isEnabled ? styles$2.disabled : ""} ${settings.colorScheme === "high-contrast" ? styles$2.highContrastMode : ""}`, children: [
1058
- /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: styles$2.title, children: "Размер шрифта" }),
1059
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$2.optionsContainer, role: "radiogroup", "aria-labelledby": "font-size-title", children: FONT_SIZE_OPTIONS.map((option2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1060
- "label",
1061
- {
1062
- className: `${styles$2.option} ${fontSize === option2.value ? styles$2.selected : ""} ${!isEnabled ? styles$2.optionDisabled : ""}`,
1063
- children: [
1064
- /* @__PURE__ */ jsxRuntimeExports.jsx(
1065
- "input",
1066
- {
1067
- type: "radio",
1068
- name: "fontSize",
1069
- value: option2.value,
1070
- checked: fontSize === option2.value,
1071
- onChange: handleFontSizeChange,
1072
- className: styles$2.radioInput,
1073
- "aria-describedby": `font-size-${option2.value}-description`,
1074
- disabled: !isEnabled
1075
- }
1076
- ),
1077
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$2.optionContent, children: [
1078
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$2.optionLabel, children: option2.label }),
1133
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: styles$2.title, children: mergedTranslations.fontSizeTitle }),
1134
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$2.optionsContainer, role: "radiogroup", "aria-labelledby": "font-size-title", children: [
1135
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1136
+ "label",
1137
+ {
1138
+ className: `${styles$2.option} ${fontSize === "small" ? styles$2.selected : ""} ${!isEnabled ? styles$2.optionDisabled : ""}`,
1139
+ children: [
1079
1140
  /* @__PURE__ */ jsxRuntimeExports.jsx(
1080
- "span",
1141
+ "input",
1081
1142
  {
1082
- id: `font-size-${option2.value}-description`,
1083
- className: styles$2.optionDescription,
1084
- children: option2.description
1143
+ type: "radio",
1144
+ name: "fontSize",
1145
+ value: "small",
1146
+ checked: fontSize === "small",
1147
+ onChange: handleFontSizeChange,
1148
+ className: styles$2.radioInput,
1149
+ "aria-describedby": "font-size-small-description",
1150
+ disabled: !isEnabled
1085
1151
  }
1086
- )
1087
- ] }),
1088
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$2.radioIndicator, "aria-hidden": "true" })
1089
- ]
1090
- },
1091
- option2.value
1092
- )) })
1152
+ ),
1153
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$2.optionContent, children: [
1154
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$2.optionLabel, children: mergedTranslations.fontSizeSmallLabel }),
1155
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1156
+ "span",
1157
+ {
1158
+ id: "font-size-small-description",
1159
+ className: styles$2.optionDescription,
1160
+ children: mergedTranslations.fontSizeSmallDescription
1161
+ }
1162
+ )
1163
+ ] }),
1164
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$2.radioIndicator, "aria-hidden": "true" })
1165
+ ]
1166
+ },
1167
+ "small"
1168
+ ),
1169
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1170
+ "label",
1171
+ {
1172
+ className: `${styles$2.option} ${fontSize === "standard" ? styles$2.selected : ""} ${!isEnabled ? styles$2.optionDisabled : ""}`,
1173
+ children: [
1174
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1175
+ "input",
1176
+ {
1177
+ type: "radio",
1178
+ name: "fontSize",
1179
+ value: "standard",
1180
+ checked: fontSize === "standard",
1181
+ onChange: handleFontSizeChange,
1182
+ className: styles$2.radioInput,
1183
+ "aria-describedby": "font-size-standard-description",
1184
+ disabled: !isEnabled
1185
+ }
1186
+ ),
1187
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$2.optionContent, children: [
1188
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$2.optionLabel, children: mergedTranslations.fontSizeStandardLabel }),
1189
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1190
+ "span",
1191
+ {
1192
+ id: "font-size-standard-description",
1193
+ className: styles$2.optionDescription,
1194
+ children: mergedTranslations.fontSizeStandardDescription
1195
+ }
1196
+ )
1197
+ ] }),
1198
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$2.radioIndicator, "aria-hidden": "true" })
1199
+ ]
1200
+ },
1201
+ "standard"
1202
+ ),
1203
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
1204
+ "label",
1205
+ {
1206
+ className: `${styles$2.option} ${fontSize === "large" ? styles$2.selected : ""} ${!isEnabled ? styles$2.optionDisabled : ""}`,
1207
+ children: [
1208
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1209
+ "input",
1210
+ {
1211
+ type: "radio",
1212
+ name: "fontSize",
1213
+ value: "large",
1214
+ checked: fontSize === "large",
1215
+ onChange: handleFontSizeChange,
1216
+ className: styles$2.radioInput,
1217
+ "aria-describedby": "font-size-large-description",
1218
+ disabled: !isEnabled
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$2.optionContent, children: [
1222
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$2.optionLabel, children: mergedTranslations.fontSizeLargeLabel }),
1223
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1224
+ "span",
1225
+ {
1226
+ id: "font-size-large-description",
1227
+ className: styles$2.optionDescription,
1228
+ children: mergedTranslations.fontSizeLargeDescription
1229
+ }
1230
+ )
1231
+ ] }),
1232
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$2.radioIndicator, "aria-hidden": "true" })
1233
+ ]
1234
+ },
1235
+ "large"
1236
+ )
1237
+ ] })
1093
1238
  ] });
1094
1239
  };
1095
1240
  const imageControl = "_imageControl_hkxkm_9";
@@ -1119,8 +1264,10 @@ const styles$1 = {
1119
1264
  highContrastMode: highContrastMode$1
1120
1265
  };
1121
1266
  const ImageControl = ({
1122
- className
1267
+ className,
1268
+ translations = {}
1123
1269
  }) => {
1270
+ const mergedTranslations = { ...defaultTranslations, ...translations };
1124
1271
  const { settings, updateSettings } = useAccessibilityContext();
1125
1272
  const showImages = settings.showImages;
1126
1273
  const isEnabled = settings.isEnabled;
@@ -1128,7 +1275,7 @@ const ImageControl = ({
1128
1275
  updateSettings({ showImages: event.target.checked });
1129
1276
  };
1130
1277
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `${styles$1.imageControl} ${className || ""} ${!isEnabled ? styles$1.disabled : ""} ${settings.colorScheme === "high-contrast" ? styles$1.highContrastMode : ""}`, children: [
1131
- /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: styles$1.title, children: "Изображения" }),
1278
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: styles$1.title, children: mergedTranslations.imageControlTitle }),
1132
1279
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$1.switchContainer, children: [
1133
1280
  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `${styles$1.switchLabel} ${!isEnabled ? styles$1.switchDisabled : ""}`, children: [
1134
1281
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -1143,43 +1290,44 @@ const ImageControl = ({
1143
1290
  }
1144
1291
  ),
1145
1292
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$1.switchSlider, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$1.switchThumb }) }),
1146
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$1.switchText, children: showImages ? "Показывать изображения" : "Скрывать изображения" })
1293
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$1.switchText, children: showImages ? mergedTranslations.imageControlShowLabel : mergedTranslations.imageControlHideLabel })
1147
1294
  ] }),
1148
1295
  /* @__PURE__ */ jsxRuntimeExports.jsx(
1149
1296
  "p",
1150
1297
  {
1151
1298
  id: "image-control-description",
1152
1299
  className: styles$1.description,
1153
- children: showImages ? "Изображения отображаются на странице" : "Изображения скрыты для лучшей концентрации на тексте"
1300
+ children: showImages ? mergedTranslations.imageControlShowDescription : mergedTranslations.imageControlHideDescription
1154
1301
  }
1155
1302
  )
1156
1303
  ] })
1157
1304
  ] });
1158
1305
  };
1159
- const stickyContainer = "_stickyContainer_lzoik_9";
1160
- const panel = "_panel_lzoik_23";
1161
- const topRight = "_top-right_lzoik_38";
1162
- const topLeft = "_top-left_lzoik_42";
1163
- const bottomRight = "_bottom-right_lzoik_46";
1164
- const bottomLeft = "_bottom-left_lzoik_54";
1165
- const header = "_header_lzoik_75";
1166
- const title = "_title_lzoik_84";
1167
- const closeButton = "_closeButton_lzoik_92";
1168
- const description = "_description_lzoik_123";
1169
- const content = "_content_lzoik_131";
1170
- const controls = "_controls_lzoik_151";
1171
- const highContrastMode = "_highContrastMode_lzoik_157";
1172
- const slideIn = "_slideIn_lzoik_1";
1306
+ const stickyContainer = "_stickyContainer_1xq4j_9";
1307
+ const topRight = "_top-right_1xq4j_16";
1308
+ const topLeft = "_top-left_1xq4j_20";
1309
+ const panel = "_panel_1xq4j_31";
1310
+ const bottomRight = "_bottom-right_1xq4j_53";
1311
+ const bottomLeft = "_bottom-left_1xq4j_53";
1312
+ const header = "_header_1xq4j_59";
1313
+ const title = "_title_1xq4j_68";
1314
+ const closeButton = "_closeButton_1xq4j_76";
1315
+ const description = "_description_1xq4j_107";
1316
+ const content = "_content_1xq4j_115";
1317
+ const controls = "_controls_1xq4j_135";
1318
+ const highContrastMode = "_highContrastMode_1xq4j_141";
1319
+ const slideIn = "_slideIn_1xq4j_1";
1320
+ const grayscaleMode = "_grayscaleMode_1xq4j_191";
1173
1321
  const AccessibilityPanel_module = {
1174
1322
  stickyContainer,
1175
- panel,
1176
- "top-right": "_top-right_lzoik_38",
1323
+ "top-right": "_top-right_1xq4j_16",
1177
1324
  topRight,
1178
- "top-left": "_top-left_lzoik_42",
1325
+ "top-left": "_top-left_1xq4j_20",
1179
1326
  topLeft,
1180
- "bottom-right": "_bottom-right_lzoik_46",
1327
+ panel,
1328
+ "bottom-right": "_bottom-right_1xq4j_53",
1181
1329
  bottomRight,
1182
- "bottom-left": "_bottom-left_lzoik_54",
1330
+ "bottom-left": "_bottom-left_1xq4j_53",
1183
1331
  bottomLeft,
1184
1332
  header,
1185
1333
  title,
@@ -1188,7 +1336,8 @@ const AccessibilityPanel_module = {
1188
1336
  content,
1189
1337
  controls,
1190
1338
  highContrastMode,
1191
- slideIn
1339
+ slideIn,
1340
+ grayscaleMode
1192
1341
  };
1193
1342
  const stylesImport = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1194
1343
  __proto__: null,
@@ -1199,6 +1348,7 @@ const stylesImport = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.define
1199
1348
  controls,
1200
1349
  default: AccessibilityPanel_module,
1201
1350
  description,
1351
+ grayscaleMode,
1202
1352
  header,
1203
1353
  highContrastMode,
1204
1354
  panel,
@@ -1212,9 +1362,23 @@ const styles = typeof stylesImport === "object" && AccessibilityPanel_module ? A
1212
1362
  const AccessibilityPanelInner = ({
1213
1363
  isOpen,
1214
1364
  onClose,
1215
- position = "top-right"
1365
+ position = "top-right",
1366
+ translations = {}
1216
1367
  }) => {
1217
1368
  const panelRef = useRef(null);
1369
+ const mergedTranslations = { ...defaultTranslations, ...translations };
1370
+ const [portalContainer, setPortalContainer] = require$$0.useState(null);
1371
+ useLayoutEffect(() => {
1372
+ const container = document.createElement("div");
1373
+ container.setAttribute("data-accessibility-panel-container", "true");
1374
+ document.documentElement.appendChild(container);
1375
+ setPortalContainer(container);
1376
+ return () => {
1377
+ if (container.parentNode) {
1378
+ container.parentNode.removeChild(container);
1379
+ }
1380
+ };
1381
+ }, []);
1218
1382
  useEffect(() => {
1219
1383
  if (!isOpen) return;
1220
1384
  const handleClickOutside = (event) => {
@@ -1247,56 +1411,60 @@ const AccessibilityPanelInner = ({
1247
1411
  event.stopPropagation();
1248
1412
  onClose();
1249
1413
  };
1250
- if (!isOpen) {
1414
+ if (!isOpen || !portalContainer) {
1251
1415
  return null;
1252
1416
  }
1253
1417
  const { settings } = useAccessibilityContext();
1254
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn(styles.stickyContainer), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1255
- "div",
1256
- {
1257
- ref: panelRef,
1258
- className: cn(
1259
- styles.panel,
1260
- styles[position],
1261
- settings.colorScheme === "high-contrast" && styles.highContrastMode
1262
- ),
1263
- role: "dialog",
1264
- "aria-modal": "true",
1265
- "aria-labelledby": "accessibility-panel-title",
1266
- "aria-describedby": "accessibility-panel-description",
1267
- children: [
1268
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(styles.header), children: [
1269
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { id: "accessibility-panel-title", className: cn(styles.title), children: "Настройки доступности" }),
1418
+ return createPortal(
1419
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn(styles.stickyContainer, styles[position]), children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1420
+ "div",
1421
+ {
1422
+ ref: panelRef,
1423
+ className: cn(
1424
+ styles.panel,
1425
+ settings.colorScheme === "high-contrast" && styles.highContrastMode,
1426
+ settings.colorScheme === "grayscale" && styles.grayscaleMode
1427
+ ),
1428
+ role: "dialog",
1429
+ "aria-modal": "true",
1430
+ "aria-labelledby": "accessibility-panel-title",
1431
+ "aria-describedby": "accessibility-panel-description",
1432
+ children: [
1433
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(styles.header), children: [
1434
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { id: "accessibility-panel-title", className: cn(styles.title), children: mergedTranslations.panelTitle }),
1435
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1436
+ "button",
1437
+ {
1438
+ onClick: handleCloseClick,
1439
+ className: cn(styles.closeButton),
1440
+ "aria-label": mergedTranslations.closePanelLabel,
1441
+ type: "button",
1442
+ children: "×"
1443
+ }
1444
+ )
1445
+ ] }),
1270
1446
  /* @__PURE__ */ jsxRuntimeExports.jsx(
1271
- "button",
1447
+ "div",
1272
1448
  {
1273
- onClick: handleCloseClick,
1274
- className: cn(styles.closeButton),
1275
- "aria-label": "Закрыть панель настроек доступности",
1276
- type: "button",
1277
- children: "×"
1449
+ id: "accessibility-panel-description",
1450
+ className: cn(styles.description),
1451
+ children: mergedTranslations.panelDescription
1278
1452
  }
1279
- )
1280
- ] }),
1281
- /* @__PURE__ */ jsxRuntimeExports.jsx(
1282
- "div",
1283
- {
1284
- id: "accessibility-panel-description",
1285
- className: cn(styles.description),
1286
- children: "Настройте отображение страницы для улучшения доступности"
1287
- }
1288
- ),
1289
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(styles.content), children: [
1290
- /* @__PURE__ */ jsxRuntimeExports.jsx(AccessibilityToggle, {}),
1291
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(styles.controls), children: [
1292
- /* @__PURE__ */ jsxRuntimeExports.jsx(ColorSchemeControl, {}),
1293
- /* @__PURE__ */ jsxRuntimeExports.jsx(FontSizeControl, {}),
1294
- /* @__PURE__ */ jsxRuntimeExports.jsx(ImageControl, {})
1453
+ ),
1454
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(styles.content), children: [
1455
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AccessibilityToggle, { translations: mergedTranslations }),
1456
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(styles.controls), children: [
1457
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ColorSchemeControl, { translations: mergedTranslations }),
1458
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FontSizeControl, { translations: mergedTranslations }),
1459
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ImageControl, { translations: mergedTranslations })
1460
+ ] })
1295
1461
  ] })
1296
- ] })
1297
- ]
1298
- }
1299
- ) });
1462
+ ]
1463
+ }
1464
+ ) }),
1465
+ portalContainer
1466
+ // Рендерим в отдельный контейнер вне document.body, чтобы избежать влияния фильтров
1467
+ );
1300
1468
  };
1301
1469
  const AccessibilityPanel = (props) => {
1302
1470
  return /* @__PURE__ */ jsxRuntimeExports.jsx(AccessibilityProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(AccessibilityPanelInner, { ...props }) });
@@ -1319,6 +1487,7 @@ export {
1319
1487
  applyImageVisibility,
1320
1488
  applySettingIfEnabled,
1321
1489
  clearStorage,
1490
+ defaultTranslations,
1322
1491
  getImageElements,
1323
1492
  getTextElements,
1324
1493
  isDOMAvailable,