chuijs 4.0.3 → 4.0.4

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 (258) hide show
  1. package/CHANGELOG.md +536 -0
  2. package/framework/appLayout/default/chui_app_layout.js +361 -303
  3. package/framework/appLayout/default/global_style.css +243 -89
  4. package/framework/appLayout/default/main_theme_style.css +188 -101
  5. package/framework/components/chui_accordion/accordion.js +17 -17
  6. package/framework/components/chui_accordion/styles.css +7 -7
  7. package/framework/components/chui_action_sheet/action_sheet.js +35 -32
  8. package/framework/components/chui_action_sheet/styles.css +10 -4
  9. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  10. package/framework/components/chui_actions_bar/styles.css +139 -0
  11. package/framework/components/chui_affix/affix.js +4 -4
  12. package/framework/components/chui_affix/styles.css +5 -0
  13. package/framework/components/chui_alert/alert.js +11 -5
  14. package/framework/components/chui_alert/styles.css +7 -0
  15. package/framework/components/chui_avatar/avatar.js +13 -13
  16. package/framework/components/chui_avatar/styles.css +1 -1
  17. package/framework/components/chui_avatar_group/avatar_group.js +4 -4
  18. package/framework/components/chui_avatar_group/styles.css +1 -1
  19. package/framework/components/chui_backtop/backtop.js +25 -2
  20. package/framework/components/chui_backtop/styles.css +21 -0
  21. package/framework/components/chui_badge/badge.js +15 -15
  22. package/framework/components/chui_badge/styles.css +6 -6
  23. package/framework/components/chui_banner/banner.js +222 -0
  24. package/framework/components/chui_banner/styles.css +170 -0
  25. package/framework/components/chui_breadcrumb/styles.css +1 -1
  26. package/framework/components/chui_button/button.js +24 -28
  27. package/framework/components/chui_button/styles.css +5 -5
  28. package/framework/components/chui_calendar/calendar.js +6 -6
  29. package/framework/components/chui_card/card.js +14 -14
  30. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  31. package/framework/components/chui_card_scroll/styles.css +86 -0
  32. package/framework/components/chui_chat/chat.js +73 -51
  33. package/framework/components/chui_chat/styles.css +18 -7
  34. package/framework/components/chui_clipboard_history/clipboard_history.js +25 -20
  35. package/framework/components/chui_clipboard_history/styles.css +10 -8
  36. package/framework/components/chui_code/code.js +8 -8
  37. package/framework/components/chui_code/styles.css +2 -2
  38. package/framework/components/chui_code_editor/code_editor.js +26 -26
  39. package/framework/components/chui_code_editor/styles.css +3 -3
  40. package/framework/components/chui_command_palette/command_palette.js +29 -29
  41. package/framework/components/chui_command_palette/styles.css +5 -5
  42. package/framework/components/chui_console/console.js +9 -9
  43. package/framework/components/chui_console/styles.css +5 -2
  44. package/framework/components/chui_content_block/content_block.js +2 -2
  45. package/framework/components/chui_context_menu/context_menu.js +162 -54
  46. package/framework/components/chui_context_menu/styles.css +82 -8
  47. package/framework/components/chui_custom_element/custom_element.js +11 -11
  48. package/framework/components/chui_data_grid/data_grid.js +268 -268
  49. package/framework/components/chui_data_grid/styles.css +14 -14
  50. package/framework/components/chui_descriptions/styles.css +1 -1
  51. package/framework/components/chui_details/details.js +12 -12
  52. package/framework/components/chui_details/styles.css +7 -7
  53. package/framework/components/chui_diff_viewer/diff_viewer.js +88 -88
  54. package/framework/components/chui_diff_viewer/styles.css +9 -9
  55. package/framework/components/chui_divider/divider.js +6 -6
  56. package/framework/components/chui_divider/styles.css +2 -2
  57. package/framework/components/chui_drawer/drawer.js +37 -14
  58. package/framework/components/chui_drawer/styles.css +18 -4
  59. package/framework/components/chui_drop_zone/drop_zone.js +6 -6
  60. package/framework/components/chui_drop_zone/styles.css +10 -6
  61. package/framework/components/chui_fieldset/fieldset.js +6 -6
  62. package/framework/components/chui_fieldset/styles.css +5 -5
  63. package/framework/components/chui_file_explorer/file_explorer.js +115 -115
  64. package/framework/components/chui_file_explorer/styles.css +6 -6
  65. package/framework/components/chui_form/form.js +11 -11
  66. package/framework/components/chui_gantt/gantt.js +41 -41
  67. package/framework/components/chui_gantt/styles.css +5 -5
  68. package/framework/components/chui_graphs/graphs.js +82 -46
  69. package/framework/components/chui_graphs/styles.css +26 -5
  70. package/framework/components/chui_hero/hero.js +63 -20
  71. package/framework/components/chui_hero/styles.css +176 -7
  72. package/framework/components/chui_html_block/html_block.js +5 -5
  73. package/framework/components/chui_html_block/styles.css +1 -1
  74. package/framework/components/chui_hx/styles.css +2 -2
  75. package/framework/components/chui_icons/icons.js +7 -7
  76. package/framework/components/chui_icons/styles.css +2 -1
  77. package/framework/components/chui_inputs/chui_check_box/styles.css +12 -3
  78. package/framework/components/chui_inputs/chui_chips/chips.js +92 -31
  79. package/framework/components/chui_inputs/chui_chips/styles.css +28 -5
  80. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +20 -15
  81. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  82. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +58 -58
  83. package/framework/components/chui_inputs/chui_combo_box/styles.css +9 -9
  84. package/framework/components/chui_inputs/chui_date/date.js +93 -95
  85. package/framework/components/chui_inputs/chui_date/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_date_range/date_range.js +22 -22
  87. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  88. package/framework/components/chui_inputs/chui_datetime/datetime.js +12 -12
  89. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  90. package/framework/components/chui_inputs/chui_email/email.js +10 -10
  91. package/framework/components/chui_inputs/chui_email/styles.css +6 -6
  92. package/framework/components/chui_inputs/chui_file/file.js +8 -8
  93. package/framework/components/chui_inputs/chui_file/styles.css +12 -9
  94. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +39 -39
  95. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_masked/masked.js +44 -44
  97. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  98. package/framework/components/chui_inputs/chui_mention/mention.js +13 -13
  99. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  100. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +147 -137
  101. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +14 -8
  102. package/framework/components/chui_inputs/chui_number/number.js +42 -45
  103. package/framework/components/chui_inputs/chui_number/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_otp/otp.js +32 -32
  105. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_password/password.js +30 -36
  107. package/framework/components/chui_inputs/chui_password/styles.css +7 -7
  108. package/framework/components/chui_inputs/chui_radio_button/styles.css +2 -2
  109. package/framework/components/chui_inputs/chui_rating/rating.js +28 -28
  110. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  111. package/framework/components/chui_inputs/chui_select_box/select_box.js +54 -54
  112. package/framework/components/chui_inputs/chui_select_box/styles.css +10 -10
  113. package/framework/components/chui_inputs/chui_slider/slider.js +14 -14
  114. package/framework/components/chui_inputs/chui_slider/styles.css +5 -4
  115. package/framework/components/chui_inputs/chui_text/styles.css +7 -7
  116. package/framework/components/chui_inputs/chui_text/text.js +13 -17
  117. package/framework/components/chui_inputs/chui_text_area/styles.css +8 -8
  118. package/framework/components/chui_inputs/chui_text_area/text_area.js +23 -23
  119. package/framework/components/chui_inputs/chui_time/styles.css +13 -17
  120. package/framework/components/chui_inputs/chui_time/time.js +35 -24
  121. package/framework/components/chui_inputs/chui_toggle/styles.css +10 -3
  122. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  123. package/framework/components/chui_json_editor/json_editor.js +87 -87
  124. package/framework/components/chui_json_editor/styles.css +5 -5
  125. package/framework/components/chui_json_viewer/json_viewer.js +80 -80
  126. package/framework/components/chui_json_viewer/styles.css +6 -6
  127. package/framework/components/chui_kanban/kanban.js +27 -27
  128. package/framework/components/chui_kanban/styles.css +8 -4
  129. package/framework/components/chui_kbd/styles.css +1 -1
  130. package/framework/components/chui_label/label.js +17 -17
  131. package/framework/components/chui_label/styles.css +1 -1
  132. package/framework/components/chui_link/link.js +9 -9
  133. package/framework/components/chui_link/styles.css +11 -4
  134. package/framework/components/chui_list/list.js +11 -11
  135. package/framework/components/chui_list/styles.css +2 -2
  136. package/framework/components/chui_markdown_editor/markdown_editor.js +66 -66
  137. package/framework/components/chui_markdown_editor/styles.css +5 -5
  138. package/framework/components/chui_media/audio.js +240 -246
  139. package/framework/components/chui_media/audio_styles.css +41 -23
  140. package/framework/components/chui_media/image.js +49 -46
  141. package/framework/components/chui_media/image_compare.js +35 -35
  142. package/framework/components/chui_media/image_compare_styles.css +5 -5
  143. package/framework/components/chui_media/image_styles.css +1 -1
  144. package/framework/components/chui_media/video.js +148 -148
  145. package/framework/components/chui_media/video_styles.css +27 -11
  146. package/framework/components/chui_menu_bar/menu_bar.js +54 -54
  147. package/framework/components/chui_menu_bar/styles.css +10 -10
  148. package/framework/components/chui_message_bar/message_bar.js +551 -0
  149. package/framework/components/chui_message_bar/styles.css +248 -0
  150. package/framework/components/chui_modal/modal.js +37 -13
  151. package/framework/components/chui_notification/notification.js +76 -54
  152. package/framework/components/chui_notification/notification_download.js +26 -81
  153. package/framework/components/chui_notification/notification_download_card.js +115 -0
  154. package/framework/components/chui_notification/notification_download_progress.css +2 -2
  155. package/framework/components/chui_notification/notification_download_progress.js +70 -108
  156. package/framework/components/chui_notification/notification_update.js +31 -31
  157. package/framework/components/chui_notification/status_plate.css +3 -3
  158. package/framework/components/chui_notification/styles.css +6 -1
  159. package/framework/components/chui_notification/styles_download.css +1 -1
  160. package/framework/components/chui_notification/styles_update.css +2 -2
  161. package/framework/components/chui_org_chart/org_chart.js +29 -29
  162. package/framework/components/chui_org_chart/styles.css +2 -2
  163. package/framework/components/chui_pagination/pagination.js +3 -3
  164. package/framework/components/chui_pagination/styles.css +1 -1
  165. package/framework/components/chui_paragraph/styles.css +2 -2
  166. package/framework/components/chui_popover/popover.js +29 -23
  167. package/framework/components/chui_popover/styles.css +1 -1
  168. package/framework/components/chui_popups/popups.js +124 -124
  169. package/framework/components/chui_popups/styles.css +5 -5
  170. package/framework/components/chui_print_button/print_button.js +15 -10
  171. package/framework/components/chui_progress_bar/progress_bar.js +34 -12
  172. package/framework/components/chui_progress_bar/styles.css +4 -4
  173. package/framework/components/chui_progress_ring/progress_ring.js +15 -15
  174. package/framework/components/chui_progress_ring/styles.css +1 -1
  175. package/framework/components/chui_qrcode/qrcode.js +12 -12
  176. package/framework/components/chui_query_builder/query_builder.js +46 -46
  177. package/framework/components/chui_query_builder/styles.css +4 -4
  178. package/framework/components/chui_radio_group/styles.css +1 -1
  179. package/framework/components/chui_result/result.js +15 -15
  180. package/framework/components/chui_result/styles.css +3 -3
  181. package/framework/components/chui_scheduler/scheduler.js +74 -74
  182. package/framework/components/chui_scheduler/styles.css +5 -5
  183. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  184. package/framework/components/chui_screen_spinner/styles.css +49 -0
  185. package/framework/components/chui_segmented_control/segmented_control.js +63 -6
  186. package/framework/components/chui_segmented_control/styles.css +32 -6
  187. package/framework/components/chui_settings/settings.js +45 -46
  188. package/framework/components/chui_settings/styles.css +4 -4
  189. package/framework/components/chui_shortcut_help/shortcut_help.js +32 -34
  190. package/framework/components/chui_sidebar_nav/sidebar_nav.js +98 -29
  191. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  192. package/framework/components/chui_slideshow/slideshow.js +85 -85
  193. package/framework/components/chui_slideshow/styles.css +6 -6
  194. package/framework/components/chui_spinner/spinner.js +10 -10
  195. package/framework/components/chui_split_button/split_button.js +30 -12
  196. package/framework/components/chui_split_button/styles.css +21 -5
  197. package/framework/components/chui_splitter/splitter.js +11 -11
  198. package/framework/components/chui_splitter/styles.css +2 -2
  199. package/framework/components/chui_statistic/statistic.js +47 -47
  200. package/framework/components/chui_status_bar/styles.css +2 -2
  201. package/framework/components/chui_stepper/stepper.js +202 -31
  202. package/framework/components/chui_stepper/styles.css +79 -14
  203. package/framework/components/chui_sticky_bar/sticky_bar.js +44 -13
  204. package/framework/components/chui_sticky_bar/styles.css +10 -8
  205. package/framework/components/chui_tabs/chui_tabs.js +74 -26
  206. package/framework/components/chui_tabs/styles.css +40 -12
  207. package/framework/components/chui_text_editor/styles.css +7 -7
  208. package/framework/components/chui_text_editor/text_editor.js +56 -56
  209. package/framework/components/chui_text_editor/text_editor_panel.js +173 -174
  210. package/framework/components/chui_theme_toggle/theme_toggle.js +21 -5
  211. package/framework/components/chui_timeline/styles.css +3 -1
  212. package/framework/components/chui_toast_queue/styles.css +11 -11
  213. package/framework/components/chui_toast_queue/toast_queue.js +30 -27
  214. package/framework/components/chui_toolbar/styles.css +2 -2
  215. package/framework/components/chui_tooltip/styles.css +2 -2
  216. package/framework/components/chui_tooltip/tooltip.js +3 -3
  217. package/framework/components/chui_tour/styles.css +8 -8
  218. package/framework/components/chui_tour/tour.js +72 -72
  219. package/framework/components/chui_transfer/styles.css +6 -6
  220. package/framework/components/chui_transfer/transfer.js +93 -106
  221. package/framework/components/chui_tree_table/styles.css +4 -4
  222. package/framework/components/chui_tree_table/tree_table.js +45 -45
  223. package/framework/components/chui_tree_view/styles.css +10 -8
  224. package/framework/components/chui_tree_view/tree_view.js +185 -183
  225. package/framework/components/chui_user_bar/styles.css +145 -0
  226. package/framework/components/chui_user_bar/user_bar.js +402 -0
  227. package/framework/components/chui_user_list_bar/styles.css +173 -0
  228. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  229. package/framework/components/chui_watermark/watermark.js +17 -17
  230. package/framework/components/chui_webview/webview.js +9 -9
  231. package/framework/components/chui_write_bar/styles.css +172 -0
  232. package/framework/components/chui_write_bar/write_bar.js +320 -0
  233. package/framework/main_window.js +1234 -0
  234. package/framework/modules/chui_a11y/chui_a11y.js +78 -79
  235. package/framework/modules/chui_animations/animations.js +77 -15
  236. package/framework/modules/chui_animations/motion.js +120 -0
  237. package/framework/modules/chui_animations/styles.css +36 -3
  238. package/framework/modules/chui_functions.js +31 -27
  239. package/framework/modules/chui_highlight/styles.css +13 -10
  240. package/framework/modules/chui_i18n/chui_i18n.js +3 -3
  241. package/framework/modules/chui_i18n/locales/feedback.js +62 -0
  242. package/framework/modules/chui_i18n/locales/navigation.js +4 -0
  243. package/framework/modules/chui_json/chui_json.js +2 -2
  244. package/framework/modules/chui_logger/chui_logger.js +23 -8
  245. package/framework/modules/chui_page/page.js +10 -10
  246. package/framework/modules/chui_palette/palette.js +61 -0
  247. package/framework/modules/chui_qr/chui_qr.js +23 -23
  248. package/framework/modules/chui_scrollbar/chui_scrollbar.js +45 -45
  249. package/framework/modules/chui_scrollbar/styles.css +3 -3
  250. package/framework/modules/chui_services/chui_services.js +8 -8
  251. package/framework/modules/chui_services/desktop.js +77 -71
  252. package/framework/modules/chui_sortable/chui_sortable.js +17 -17
  253. package/framework/modules/chui_validate/chui_validate.js +3 -3
  254. package/framework/tray_bar/chui_menu_items.js +2 -2
  255. package/index.d.ts +266 -34
  256. package/index.js +20 -1168
  257. package/package.json +6 -4
  258. package/framework/components/telegram_bot/chui_telegram_bot.js +0 -191
@@ -48,8 +48,11 @@ class SegmentedControl {
48
48
  // Вариант с tabindex="0": с ним же работает обход Tab; за фокусом и выбором следит отдельно
49
49
  #active = undefined;
50
50
  #disabled = new Set();
51
- #on_change = undefined;
52
- #activate_on_focus = false;
51
+ #onChange = undefined;
52
+ #activateOnFocus = false;
53
+ // Подложка выбора измеряется по вёрстке: наблюдатель и отложенный кадр держат её на месте
54
+ #observer = undefined;
55
+ #frame = undefined;
53
56
 
54
57
  constructor(
55
58
  options = {
@@ -66,8 +69,8 @@ class SegmentedControl {
66
69
  setStyles(__dirname + "/styles.css", "chUiJS_SegmentedControl");
67
70
  SegmentedControl.#counter += 1;
68
71
  this.#id = options.id === undefined ? `chui_segmented_control_${SegmentedControl.#counter}` : options.id;
69
- this.#on_change = options.onChange;
70
- this.#activate_on_focus = options.activateOnFocus === true;
72
+ this.#onChange = options.onChange;
73
+ this.#activateOnFocus = options.activateOnFocus === true;
71
74
  this.#root.id = this.#id;
72
75
  this.#root.setAttribute("role", "radiogroup");
73
76
  this.setSize(options.size === undefined ? SegmentedControl.SIZE.DEFAULT : options.size);
@@ -80,6 +83,28 @@ class SegmentedControl {
80
83
  // Пустая заготовка опции — это «выбор не сделан», а не значение «»
81
84
  const value = optionOr(options.value, undefined);
82
85
  if (value !== undefined) this.setValue(value, true);
86
+ // Ширина меняется от раскладки (растянутый контрол, поворот окна): без пересчёта
87
+ // подложка осталась бы на прежнем варианте
88
+ if (typeof ResizeObserver === "function") {
89
+ this.#observer = new ResizeObserver(() => this.#syncIndicator());
90
+ this.#observer.observe(this.#root);
91
+ }
92
+ }
93
+
94
+ /** Полное удаление: снять наблюдатель, отложенный кадр и слушатели */
95
+ destroy() {
96
+ if (this.#observer !== undefined) {
97
+ this.#observer.disconnect();
98
+ this.#observer = undefined;
99
+ }
100
+ if (this.#frame !== undefined) {
101
+ cancelAnimationFrame(this.#frame);
102
+ this.#frame = undefined;
103
+ }
104
+ this.#root.removeEventListener("keydown", this.#onKeyDown);
105
+ this.#root.removeEventListener("click", this.#onClick);
106
+ this.#root.remove();
107
+ return this;
83
108
  }
84
109
 
85
110
  // GET
@@ -152,7 +177,7 @@ class SegmentedControl {
152
177
  this.#value = next;
153
178
  this.#active = next;
154
179
  this.#sync();
155
- if (!silent && changed && this.#on_change !== undefined) this.#on_change(next);
180
+ if (!silent && changed && this.#onChange !== undefined) this.#onChange(next);
156
181
  return this;
157
182
  }
158
183
 
@@ -266,13 +291,45 @@ class SegmentedControl {
266
291
  record.node.setAttribute("aria-checked", value === this.#value ? "true" : "false");
267
292
  record.node.setAttribute("tabindex", value === this.#active ? "0" : "-1");
268
293
  }
294
+ this.#scheduleIndicator();
295
+ }
296
+
297
+ /** Подложку двигают после раскладки: место варианта читается только из вёрстки */
298
+ #scheduleIndicator() {
299
+ if (typeof requestAnimationFrame !== "function") {
300
+ this.#syncIndicator();
301
+ return;
302
+ }
303
+ if (this.#frame !== undefined) return;
304
+ this.#frame = requestAnimationFrame(() => {
305
+ this.#frame = undefined;
306
+ this.#syncIndicator();
307
+ });
308
+ }
309
+
310
+ /**
311
+ * Место и ширина подложки выбора. Ноль — выбора нет или вёрстки ещё нет: подложки
312
+ * нулевой ширины не видно, поэтому до первой раскладки контрол выглядит как прежде.
313
+ */
314
+ #syncIndicator() {
315
+ const record = this.#value === undefined ? undefined : this.#options.get(this.#value);
316
+ if (record === undefined || record.node.offsetWidth === 0) {
317
+ this.#root.style.setProperty("--segmented_width", "0px");
318
+ return;
319
+ }
320
+ // В RTL началом ряда служит правый край: подложка стоит у него и едет влево
321
+ const rtl = window.getComputedStyle(this.#root).direction === "rtl";
322
+ const node = record.node;
323
+ const x = rtl ? this.#root.clientWidth - (node.offsetLeft + node.offsetWidth) : node.offsetLeft;
324
+ this.#root.style.setProperty("--segmented_offset", `${rtl ? -x : x}px`);
325
+ this.#root.style.setProperty("--segmented_width", `${node.offsetWidth}px`);
269
326
  }
270
327
 
271
328
  #focus(value = String()) {
272
329
  this.#active = value;
273
330
  this.#sync();
274
331
  this.#options.get(value).node.focus();
275
- if (this.#activate_on_focus) this.setValue(value);
332
+ if (this.#activateOnFocus) this.setValue(value);
276
333
  }
277
334
 
278
335
  // Варианты — кастомные теги, поэтому клик приходит и от мыши, и от Enter/Space
@@ -1,5 +1,5 @@
1
1
  /* Сегментированный переключатель: рамка — общая заливка контрола,
2
- выбранный вариант — акцент (--blue_prime_background) */
2
+ выбранный вариант — подвижная подложка акцента */
3
3
  chui_segmented_control {
4
4
  display: inline-flex;
5
5
  align-items: center;
@@ -7,8 +7,30 @@ chui_segmented_control {
7
7
  padding: 2px;
8
8
  width: max-content;
9
9
  box-sizing: border-box;
10
- border-radius: var(--border_radius);
10
+ border-radius: var(--radius_sm);
11
11
  background: var(--element_background);
12
+ /* Место и ширина подложки: считает JS по вёрстке, нули — выбор не сделан */
13
+ --segmented_offset: 0px;
14
+ --segmented_width: 0px;
15
+ }
16
+
17
+ /* Подвижная подложка выбранного варианта: одна и та же деталь переезжает между
18
+ вариантами, вместо мгновенной смены заливки — как у системного переключателя.
19
+ Внутренний отступ равен отступу контейнера, поэтому подложка встаёт в ряд вариантов */
20
+ chui_segmented_control::before {
21
+ content: "";
22
+ position: absolute;
23
+ z-index: 0;
24
+ inset-block: 2px;
25
+ inset-inline-start: 0;
26
+ width: var(--segmented_width);
27
+ border-radius: var(--radius_sm);
28
+ background: var(--blue_prime_background);
29
+ transform: translateX(var(--segmented_offset));
30
+ transition:
31
+ transform var(--motion_base) var(--motion_ease),
32
+ width var(--motion_base) var(--motion_ease);
33
+ pointer-events: none;
12
34
  }
13
35
 
14
36
  segmented_option {
@@ -17,7 +39,7 @@ segmented_option {
17
39
  gap: 6px;
18
40
  padding: 4px 10px;
19
41
  border: none;
20
- border-radius: var(--border_radius);
42
+ border-radius: var(--radius_sm);
21
43
  background: transparent;
22
44
  color: var(--text_color);
23
45
  font-family: inherit;
@@ -26,14 +48,18 @@ segmented_option {
26
48
  cursor: pointer;
27
49
  outline: none;
28
50
  user-select: none;
51
+ /* Вариант выше подложки: иначе акцент остался бы за текстом */
52
+ z-index: 1;
29
53
  }
30
54
 
31
- segmented_option:hover {
55
+ /* Наведение — только у невыбранных: у выбранного заливку несёт подложка, и вторая
56
+ заливка читалась бы как другой цвет */
57
+ segmented_option:not([aria-checked="true"]):hover {
32
58
  background: var(--element_background_hover);
33
59
  }
34
60
 
35
61
  segmented_option[aria-checked="true"] {
36
- background: var(--blue_prime_background);
62
+ background: transparent;
37
63
  color: var(--text_color_hover);
38
64
  }
39
65
 
@@ -56,7 +82,7 @@ segmented_option[aria-disabled="true"]:hover {
56
82
 
57
83
  segmented_option[aria-disabled="true"][aria-checked="true"] {
58
84
  background: var(--blue_prime_background);
59
- color: var(--text_color_hover_disable);
85
+ color: var(--text_color_hover_disabled);
60
86
  }
61
87
 
62
88
  /* chui_icon задаёт собственный цвет, поэтому без этого правила глиф остаётся белым */
@@ -1,6 +1,6 @@
1
1
  const { setStyles } = require("../../modules/chui_functions");
2
2
  const { A11Y_FOCUSABLE_SELECTOR } = require("../../modules/chui_a11y/chui_a11y");
3
- const { store: shared_store } = require("../../modules/chui_store/chui_store");
3
+ const { store: sharedStore } = require("../../modules/chui_store/chui_store");
4
4
  const { ThemeToggle } = require("../chui_theme_toggle/theme_toggle");
5
5
  const { Toggle } = require("../chui_inputs/chui_toggle/toggle");
6
6
  const { I18n } = require("../../modules/chui_i18n/chui_i18n");
@@ -74,10 +74,10 @@ class Settings {
74
74
  #rows = [];
75
75
  /** Хранилище и ключ, под которым панель держит свои значения (без ключа — не держит) */
76
76
  #store = undefined;
77
- #store_key = undefined;
77
+ #storeKey = undefined;
78
78
  /** Подписчики правки строки и её обработчик из опций */
79
- #change_listeners = [];
80
- #on_change = undefined;
79
+ #changeListeners = [];
80
+ #onChange = undefined;
81
81
  /** Последние известные значения строк: расхождение со снимком и есть правка пользователя */
82
82
  #seen = new Map();
83
83
 
@@ -95,9 +95,9 @@ class Settings {
95
95
  setStyles(__dirname + "/styles.css", "chUiJS_Settings");
96
96
  Settings.#counter += 1;
97
97
  this.#id = options.id === undefined ? `chui_settings_${Settings.#counter}` : options.id;
98
- this.#store = options.store === undefined ? shared_store : options.store;
99
- this.#store_key = hasText(options.storeKey) ? String(options.storeKey) : undefined;
100
- this.#on_change = options.onChange;
98
+ this.#store = options.store === undefined ? sharedStore : options.store;
99
+ this.#storeKey = hasText(options.storeKey) ? String(options.storeKey) : undefined;
100
+ this.#onChange = options.onChange;
101
101
  this.#root.id = this.#id;
102
102
  if (options.title !== undefined) {
103
103
  const title = document.createElement("settings_title");
@@ -114,7 +114,7 @@ class Settings {
114
114
  // контролы (сегментированный, оценка), у которых своего события в DOM нет
115
115
  this.#root.addEventListener("change", this.#onUserEdit);
116
116
  this.#root.addEventListener("click", this.#onUserEdit);
117
- if (this.#store_key !== undefined) this.restore();
117
+ if (this.#storeKey !== undefined) this.restore();
118
118
  // Снимок значений: от него панель отсчитывает правки пользователя
119
119
  this.#remember();
120
120
  }
@@ -146,8 +146,8 @@ class Settings {
146
146
  }
147
147
 
148
148
  /** Значение строки: адрес — описание из `Settings.Row(...)`, название или имя */
149
- getValue(row_or_title = undefined) {
150
- const record = this.#findRow(row_or_title);
149
+ getValue(rowOrTitle = undefined) {
150
+ const record = this.#findRow(rowOrTitle);
151
151
  return record === undefined ? undefined : this.#readValue(record.control);
152
152
  }
153
153
 
@@ -161,14 +161,14 @@ class Settings {
161
161
  }
162
162
 
163
163
  /** Значения строк раздела: адрес — описание из `Settings.Section(...)` или заголовок */
164
- getSectionValues(section_or_title = undefined) {
165
- const section = this.#findSection(section_or_title);
164
+ getSectionValues(sectionOrTitle = undefined) {
165
+ const section = this.#findSection(sectionOrTitle);
166
166
  return section === undefined ? {} : this.#valuesOf((record) => record.section === section);
167
167
  }
168
168
 
169
169
  /** Выключена ли строка: `false` и для несуществующей */
170
- isRowDisabled(row_or_title = undefined) {
171
- const record = this.#findRow(row_or_title);
170
+ isRowDisabled(rowOrTitle = undefined) {
171
+ const record = this.#findRow(rowOrTitle);
172
172
  return record === undefined ? false : record.disabled;
173
173
  }
174
174
 
@@ -179,27 +179,27 @@ class Settings {
179
179
  * может вернуть), а программная запись уведомления не рождает.
180
180
  */
181
181
  addChangeListener(listener = () => {}) {
182
- this.#change_listeners.push(listener);
182
+ this.#changeListeners.push(listener);
183
183
  return this;
184
184
  }
185
185
 
186
186
  // ХРАНЕНИЕ
187
187
  /** Ключ панели в хранилище; `undefined` — панель значения не хранит */
188
188
  getStoreKey() {
189
- return this.#store_key;
189
+ return this.#storeKey;
190
190
  }
191
191
 
192
192
  /** Записать значения панели в хранилище; без ключа — ничего не делает */
193
193
  save() {
194
- if (this.#store_key === undefined) return this;
195
- this.#store.set(this.#store_key, this.#storageValues());
194
+ if (this.#storeKey === undefined) return this;
195
+ this.#store.set(this.#storeKey, this.#storageValues());
196
196
  return this;
197
197
  }
198
198
 
199
199
  /** Прочитать значения из хранилища и заполнить строки; без сохранённого панель не меняется */
200
200
  restore() {
201
- if (this.#store_key === undefined) return this;
202
- return this.setValues(this.#store.get(this.#store_key, {}));
201
+ if (this.#storeKey === undefined) return this;
202
+ return this.setValues(this.#store.get(this.#storeKey, {}));
203
203
  }
204
204
 
205
205
  // SET
@@ -207,8 +207,8 @@ class Settings {
207
207
  * Записать значение строки: адрес — описание из `Settings.Row(...)`, название или имя.
208
208
  * Несуществующая строка и строка без писателя (кнопка) — без изменений.
209
209
  */
210
- setValue(row_or_title = undefined, value = undefined) {
211
- const record = this.#findRow(row_or_title);
210
+ setValue(rowOrTitle = undefined, value = undefined) {
211
+ const record = this.#findRow(rowOrTitle);
212
212
  if (record === undefined) return this;
213
213
  this.#writeValue(record.control, value);
214
214
  this.#remember();
@@ -225,8 +225,8 @@ class Settings {
225
225
  }
226
226
 
227
227
  /** Заполнить строки раздела: адрес — описание из `Settings.Section(...)` или заголовок */
228
- setSectionValues(section_or_title = undefined, values = Object()) {
229
- const section = this.#findSection(section_or_title);
228
+ setSectionValues(sectionOrTitle = undefined, values = Object()) {
229
+ const section = this.#findSection(sectionOrTitle);
230
230
  if (section === undefined) return this;
231
231
  return this.#writeValues(values, (record) => record.section === section);
232
232
  }
@@ -242,8 +242,8 @@ class Settings {
242
242
  }
243
243
 
244
244
  /** Выключить или включить строку: адресуется описанием из `Settings.Row(...)`, названием или именем */
245
- setRowDisabled(row_or_title = undefined, disabled = Boolean()) {
246
- const record = this.#findRow(row_or_title);
245
+ setRowDisabled(rowOrTitle = undefined, disabled = Boolean()) {
246
+ const record = this.#findRow(rowOrTitle);
247
247
  if (record === undefined) return this;
248
248
  this.#setRowDisabled(record, disabled);
249
249
  return this;
@@ -262,11 +262,10 @@ class Settings {
262
262
  #onUserEdit = (event) => {
263
263
  if (event.type === "click" && event.target instanceof Element && event.target.closest("button") !== null)
264
264
  return;
265
- if (this.#store_key === undefined && this.#change_listeners.length === 0 && this.#on_change === undefined)
266
- return;
265
+ if (this.#storeKey === undefined && this.#changeListeners.length === 0 && this.#onChange === undefined) return;
267
266
  const changed = this.#changedRows();
268
267
  if (changed.length === 0) return;
269
- if (this.#store_key !== undefined) this.save();
268
+ if (this.#storeKey !== undefined) this.save();
270
269
  for (const record of changed) this.#emitChange(record);
271
270
  };
272
271
 
@@ -296,8 +295,8 @@ class Settings {
296
295
  name: record.name,
297
296
  value: this.#readValue(record.control),
298
297
  };
299
- for (const listener of [...this.#change_listeners]) listener(change, this);
300
- if (this.#on_change !== undefined) this.#on_change(change, this);
298
+ for (const listener of [...this.#changeListeners]) listener(change, this);
299
+ if (this.#onChange !== undefined) this.#onChange(change, this);
301
300
  }
302
301
 
303
302
  /** Снимок значений строк: от него панель отсчитывает следующие правки */
@@ -361,13 +360,13 @@ class Settings {
361
360
  const named = hasText(row.name);
362
361
  node.classList.toggle("settings_row_control_only", solo);
363
362
  node.classList.toggle("settings_row_stretch", row.stretch === true);
364
- const description_id = solo ? undefined : this.#buildRowText(row, node);
363
+ const descriptionId = solo ? undefined : this.#buildRowText(row, node);
365
364
  const holder = document.createElement("settings_row_control");
366
365
  const control =
367
366
  row.control === undefined ? undefined : row.control instanceof Element ? row.control : row.control.set();
368
367
  if (control !== undefined) {
369
368
  holder.appendChild(control);
370
- this.#applyControlA11y(control, titled ? String(row.title) : String(), description_id);
369
+ this.#applyControlA11y(control, titled ? String(row.title) : String(), descriptionId);
371
370
  }
372
371
  node.appendChild(holder);
373
372
  // Храним исходный контрол (компонент или узел): findControl() возвращает его вместе с методами
@@ -395,7 +394,7 @@ class Settings {
395
394
  /** Текст строки — название и описание; возвращает id описания (на него ссылается контрол) */
396
395
  #buildRowText(row = Object(), node = new HTMLElement()) {
397
396
  const text = document.createElement("settings_row_text");
398
- let description_id = undefined;
397
+ let descriptionId = undefined;
399
398
  if (hasText(row.title)) {
400
399
  const title = document.createElement("settings_row_title");
401
400
  title.innerText = String(row.title);
@@ -405,11 +404,11 @@ class Settings {
405
404
  const description = document.createElement("settings_row_description");
406
405
  description.innerText = String(row.description);
407
406
  description.id = `${this.#id}_row_${this.#rows.length}_description`;
408
- description_id = description.id;
407
+ descriptionId = description.id;
409
408
  text.appendChild(description);
410
409
  }
411
410
  node.appendChild(text);
412
- return description_id;
411
+ return descriptionId;
413
412
  }
414
413
 
415
414
  /**
@@ -430,22 +429,22 @@ class Settings {
430
429
  }
431
430
 
432
431
  /** Строка по описанию из `Settings.Row(...)`, названию или имени (у строки-контрола их может и не быть) */
433
- #findRow(row_or_title = undefined) {
434
- if (row_or_title === undefined || row_or_title === null) return undefined;
432
+ #findRow(rowOrTitle = undefined) {
433
+ if (rowOrTitle === undefined || rowOrTitle === null) return undefined;
435
434
  return this.#rows.find(
436
435
  (row) =>
437
- row.row === row_or_title ||
438
- (row.title.length > 0 && row.title === row_or_title) ||
439
- (row.name.length > 0 && row.name === row_or_title)
436
+ row.row === rowOrTitle ||
437
+ (row.title.length > 0 && row.title === rowOrTitle) ||
438
+ (row.name.length > 0 && row.name === rowOrTitle)
440
439
  );
441
440
  }
442
441
 
443
442
  /** Раздел по описанию из `Settings.Section(...)` или по заголовку (у раздела без заголовка — только описание) */
444
- #findSection(section_or_title = undefined) {
445
- if (section_or_title === undefined || section_or_title === null) return undefined;
443
+ #findSection(sectionOrTitle = undefined) {
444
+ if (sectionOrTitle === undefined || sectionOrTitle === null) return undefined;
446
445
  return this.#sections.find(
447
446
  (section) =>
448
- section === section_or_title || (hasText(section.title) && String(section.title) === section_or_title)
447
+ section === sectionOrTitle || (hasText(section.title) && String(section.title) === sectionOrTitle)
449
448
  );
450
449
  }
451
450
 
@@ -538,7 +537,7 @@ class Settings {
538
537
  * а связь через `<label>` признаём только когда в нём есть текст: у `Toggle` разметка —
539
538
  * пустой `<label>` вокруг `input`, и без `aria-label` флажок остался бы без имени.
540
539
  */
541
- #applyControlA11y(control = new HTMLElement(), label = String(), description_id = undefined) {
540
+ #applyControlA11y(control = new HTMLElement(), label = String(), descriptionId = undefined) {
542
541
  const role = control.getAttribute("role");
543
542
  const target =
544
543
  role === null || role === "presentation"
@@ -547,7 +546,7 @@ class Settings {
547
546
  : control.querySelector(Settings.#FOCUSABLE)
548
547
  : control;
549
548
  if (target === null) return;
550
- if (description_id !== undefined) target.setAttribute("aria-describedby", description_id);
549
+ if (descriptionId !== undefined) target.setAttribute("aria-describedby", descriptionId);
551
550
  if (label.length === 0) return;
552
551
  if (target.getAttribute("aria-label") !== null) return;
553
552
  const wrapper = target.closest("label");
@@ -3,7 +3,7 @@ chui_settings {
3
3
  display: block;
4
4
  width: -webkit-fill-available;
5
5
  box-sizing: border-box;
6
- margin: var(--margin);
6
+ margin: var(--block_margin);
7
7
  color: var(--text_color);
8
8
  font-size: var(--font_default_size);
9
9
  }
@@ -28,14 +28,14 @@ settings_section {
28
28
  display: block;
29
29
  margin-bottom: 12px;
30
30
  border: 1px solid var(--border_color);
31
- border-radius: var(--border_radius);
31
+ border-radius: var(--radius_sm);
32
32
  background: var(--element_background_2);
33
33
  overflow: hidden;
34
34
  }
35
35
 
36
36
  settings_section_head {
37
37
  display: block;
38
- padding: var(--main_padding);
38
+ padding: var(--block_padding);
39
39
  border-bottom: 1px solid var(--border_color);
40
40
  }
41
41
 
@@ -60,7 +60,7 @@ settings_row {
60
60
  align-items: center;
61
61
  justify-content: space-between;
62
62
  gap: 16px;
63
- padding: var(--main_padding);
63
+ padding: var(--block_padding);
64
64
  }
65
65
 
66
66
  /* Разделитель только между строками: у первой он уже есть в шапке раздела */
@@ -41,23 +41,23 @@ class ShortcutHelp {
41
41
 
42
42
  #root = document.createElement("chui_shortcut_help");
43
43
  #id = undefined;
44
- #id_title = undefined;
44
+ #idTitle = undefined;
45
45
  #title = document.createElement("shortcut_help_title");
46
46
  #search = document.createElement("shortcut_help_search");
47
47
  #input = undefined;
48
48
  #status = document.createElement("shortcut_help_status");
49
- #groups_node = document.createElement("shortcut_help_groups");
49
+ #groupsNode = document.createElement("shortcut_help_groups");
50
50
  #empty = document.createElement("shortcut_help_empty");
51
51
  #source = [];
52
52
  #groups = [];
53
- #title_hidden = false;
54
- #title_value = undefined;
53
+ #titleHidden = false;
54
+ #titleValue = undefined;
55
55
  #label = undefined;
56
56
  #columns = 1;
57
57
  #searchable = false;
58
58
  #placeholder = undefined;
59
- #empty_text = undefined;
60
- #kbd_size = Kbd.SIZE.DEFAULT;
59
+ #emptyText = undefined;
60
+ #kbdSize = Kbd.SIZE.DEFAULT;
61
61
 
62
62
  constructor(
63
63
  options = {
@@ -76,9 +76,9 @@ class ShortcutHelp {
76
76
  setStyles(__dirname + "/styles.css", "chUiJS_ShortcutHelp");
77
77
  ShortcutHelp.#counter += 1;
78
78
  this.#id = optionOr(options.id, `chui_shortcut_help_${ShortcutHelp.#counter}`);
79
- this.#id_title = `${this.#id}_title`;
79
+ this.#idTitle = `${this.#id}_title`;
80
80
  this.#root.id = this.#id;
81
- this.#title.id = this.#id_title;
81
+ this.#title.id = this.#idTitle;
82
82
  // Заголовок — настоящий заголовок: к шпаргалке можно перейти навигацией по заголовкам
83
83
  this.#title.setAttribute("role", "heading");
84
84
  this.#title.setAttribute("aria-level", "2");
@@ -89,16 +89,16 @@ class ShortcutHelp {
89
89
  this.#root.appendChild(this.#title);
90
90
  this.#root.appendChild(this.#search);
91
91
  this.#root.appendChild(this.#status);
92
- this.#root.appendChild(this.#groups_node);
92
+ this.#root.appendChild(this.#groupsNode);
93
93
  this.#root.appendChild(this.#empty);
94
94
  this.#label = options.label;
95
- this.#title_hidden = options.title === null;
96
- this.#title_value = typeof options.title === "string" && options.title !== "" ? options.title : undefined;
95
+ this.#titleHidden = options.title === null;
96
+ this.#titleValue = typeof options.title === "string" && options.title !== "" ? options.title : undefined;
97
97
  this.#placeholder = options.searchPlaceholder;
98
- this.#empty_text = options.emptyText;
99
- if (options.kbdSize !== undefined) this.#kbd_size = options.kbdSize;
98
+ this.#emptyText = options.emptyText;
99
+ if (options.kbdSize !== undefined) this.#kbdSize = options.kbdSize;
100
100
  this.setColumns(options.columns === undefined ? 1 : options.columns);
101
- this.setTitle(this.#title_hidden ? null : this.#title_value);
101
+ this.setTitle(this.#titleHidden ? null : this.#titleValue);
102
102
  if (options.searchable === true) this.setSearchable(true);
103
103
  else this.#syncSearch();
104
104
  this.#source = ShortcutHelp.#normalizeSource(options);
@@ -112,7 +112,7 @@ class ShortcutHelp {
112
112
 
113
113
  /** Заголовок на экране (`""`, если он убран) */
114
114
  getTitle() {
115
- return this.#title_hidden ? "" : this.#title.innerText;
115
+ return this.#titleHidden ? "" : this.#title.innerText;
116
116
  }
117
117
 
118
118
  /** Группы со строками: `[{title, items: [{keys, description, label}]}]` */
@@ -157,12 +157,10 @@ class ShortcutHelp {
157
157
 
158
158
  /** Заголовок; `null` убирает его (тогда блок называется по `label`) */
159
159
  setTitle(text = undefined) {
160
- this.#title_hidden = text === null;
161
- this.#title_value = typeof text === "string" && text !== "" ? text : undefined;
162
- this.#title.innerText = this.#title_hidden
163
- ? ""
164
- : optionOr(this.#title_value, I18n.t("navigation.shortcutHelp"));
165
- this.#title.hidden = this.#title_hidden;
160
+ this.#titleHidden = text === null;
161
+ this.#titleValue = typeof text === "string" && text !== "" ? text : undefined;
162
+ this.#title.innerText = this.#titleHidden ? "" : optionOr(this.#titleValue, I18n.t("navigation.shortcutHelp"));
163
+ this.#title.hidden = this.#titleHidden;
166
164
  this.#syncAria();
167
165
  return this;
168
166
  }
@@ -193,9 +191,9 @@ class ShortcutHelp {
193
191
  inputListener: () => this.#syncSearch(),
194
192
  });
195
193
  // Видимой подписи у поля нет, а пл҃ейсхолдер — не имя: имя ставим явно
196
- const search_field = this.#input.set().querySelector("input");
197
- if (search_field !== null) {
198
- search_field.setAttribute(
194
+ const searchField = this.#input.set().querySelector("input");
195
+ if (searchField !== null) {
196
+ searchField.setAttribute(
199
197
  "aria-label",
200
198
  optionOr(this.#placeholder, I18n.t("navigation.shortcutHelpSearch"))
201
199
  );
@@ -266,21 +264,21 @@ class ShortcutHelp {
266
264
  }
267
265
 
268
266
  #render() {
269
- this.#groups_node.innerHTML = "";
267
+ this.#groupsNode.innerHTML = "";
270
268
  this.#groups = [];
271
269
  this.#source.forEach((group, index) => {
272
270
  const node = document.createElement("div");
273
271
  node.className = "shortcut_help_group";
274
- const id_group_title = `${this.#id}_group_${index}`;
272
+ const idGroupTitle = `${this.#id}_group_${index}`;
275
273
  node.setAttribute("role", "group");
276
274
  const title = document.createElement("shortcut_help_group_title");
277
- title.id = id_group_title;
275
+ title.id = idGroupTitle;
278
276
  title.setAttribute("role", "heading");
279
277
  title.setAttribute("aria-level", "3");
280
278
  title.innerText = group.title;
281
279
  title.hidden = group.title === "";
282
280
  node.appendChild(title);
283
- if (group.title !== "") node.setAttribute("aria-labelledby", id_group_title);
281
+ if (group.title !== "") node.setAttribute("aria-labelledby", idGroupTitle);
284
282
  const list = document.createElement("ul");
285
283
  list.className = "shortcut_help_list";
286
284
  const rows = [];
@@ -294,7 +292,7 @@ class ShortcutHelp {
294
292
  if (item.keys.length > 0) {
295
293
  const keys = document.createElement("shortcut_help_keys");
296
294
  // Сочетание рисует Kbd: клавиша — настоящий <kbd>, значковым нужен label
297
- keys.appendChild(new Kbd({ keys: item.keys, size: this.#kbd_size, label: item.label }).set());
295
+ keys.appendChild(new Kbd({ keys: item.keys, size: this.#kbdSize, label: item.label }).set());
298
296
  line.appendChild(keys);
299
297
  }
300
298
  const text = document.createElement("shortcut_help_text");
@@ -305,10 +303,10 @@ class ShortcutHelp {
305
303
  rows.push({ node: row, search: `${item.description} ${item.keys.join(" ")}`.toLowerCase() });
306
304
  }
307
305
  node.appendChild(list);
308
- this.#groups_node.appendChild(node);
306
+ this.#groupsNode.appendChild(node);
309
307
  this.#groups.push({ node: node, rows: rows });
310
308
  });
311
- this.#empty.innerText = optionOr(this.#empty_text, I18n.t("navigation.shortcutHelpEmpty"));
309
+ this.#empty.innerText = optionOr(this.#emptyText, I18n.t("navigation.shortcutHelpEmpty"));
312
310
  this.#syncSearch();
313
311
  this.#syncAria();
314
312
  }
@@ -328,7 +326,7 @@ class ShortcutHelp {
328
326
  visible += shown;
329
327
  }
330
328
  const nothing = visible === 0 && this.#groups.length > 0;
331
- this.#groups_node.hidden = nothing;
329
+ this.#groupsNode.hidden = nothing;
332
330
  this.#empty.hidden = !nothing;
333
331
  return visible;
334
332
  }
@@ -344,7 +342,7 @@ class ShortcutHelp {
344
342
  }
345
343
 
346
344
  #syncAria() {
347
- if (this.#title_hidden) {
345
+ if (this.#titleHidden) {
348
346
  this.#root.setAttribute("role", "group");
349
347
  this.#root.removeAttribute("aria-labelledby");
350
348
  this.#root.setAttribute("aria-label", optionOr(this.#label, I18n.t("navigation.shortcutHelp")));
@@ -352,7 +350,7 @@ class ShortcutHelp {
352
350
  }
353
351
  this.#root.setAttribute("role", "region");
354
352
  this.#root.removeAttribute("aria-label");
355
- this.#root.setAttribute("aria-labelledby", this.#id_title);
353
+ this.#root.setAttribute("aria-labelledby", this.#idTitle);
356
354
  }
357
355
  }
358
356