chuijs 4.0.2 → 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 (292) hide show
  1. package/CHANGELOG.md +597 -0
  2. package/README.md +43 -644
  3. package/framework/appLayout/default/chui_app_layout.js +602 -496
  4. package/framework/appLayout/default/global_style.css +288 -97
  5. package/framework/appLayout/default/main_theme_style.css +188 -101
  6. package/framework/components/chui_accordion/accordion.js +38 -35
  7. package/framework/components/chui_accordion/styles.css +13 -12
  8. package/framework/components/chui_action_sheet/action_sheet.js +93 -64
  9. package/framework/components/chui_action_sheet/styles.css +12 -5
  10. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  11. package/framework/components/chui_actions_bar/styles.css +139 -0
  12. package/framework/components/chui_affix/affix.js +16 -11
  13. package/framework/components/chui_affix/styles.css +5 -0
  14. package/framework/components/chui_alert/alert.js +34 -19
  15. package/framework/components/chui_alert/styles.css +7 -0
  16. package/framework/components/chui_avatar/avatar.js +36 -35
  17. package/framework/components/chui_avatar/styles.css +1 -1
  18. package/framework/components/chui_avatar_group/avatar_group.js +25 -23
  19. package/framework/components/chui_avatar_group/styles.css +1 -1
  20. package/framework/components/chui_backtop/backtop.js +60 -21
  21. package/framework/components/chui_backtop/styles.css +21 -0
  22. package/framework/components/chui_badge/badge.js +30 -28
  23. package/framework/components/chui_badge/styles.css +6 -6
  24. package/framework/components/chui_banner/banner.js +222 -0
  25. package/framework/components/chui_banner/styles.css +170 -0
  26. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  27. package/framework/components/chui_breadcrumb/styles.css +1 -1
  28. package/framework/components/chui_button/button.js +52 -36
  29. package/framework/components/chui_button/styles.css +7 -7
  30. package/framework/components/chui_calendar/calendar.js +18 -16
  31. package/framework/components/chui_card/card.js +52 -32
  32. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  33. package/framework/components/chui_card_scroll/styles.css +86 -0
  34. package/framework/components/chui_chat/chat.js +140 -79
  35. package/framework/components/chui_chat/styles.css +18 -7
  36. package/framework/components/chui_clipboard_history/clipboard_history.js +53 -39
  37. package/framework/components/chui_clipboard_history/styles.css +13 -9
  38. package/framework/components/chui_code/code.js +10 -10
  39. package/framework/components/chui_code/styles.css +4 -4
  40. package/framework/components/chui_code_editor/code_editor.js +73 -57
  41. package/framework/components/chui_code_editor/styles.css +6 -5
  42. package/framework/components/chui_command_palette/command_palette.js +87 -64
  43. package/framework/components/chui_command_palette/styles.css +5 -5
  44. package/framework/components/chui_console/console.js +13 -13
  45. package/framework/components/chui_console/styles.css +6 -3
  46. package/framework/components/chui_content_block/content_block.js +35 -21
  47. package/framework/components/chui_content_block/styles.css +2 -2
  48. package/framework/components/chui_context_menu/context_menu.js +171 -58
  49. package/framework/components/chui_context_menu/styles.css +82 -8
  50. package/framework/components/chui_custom_element/custom_element.js +25 -18
  51. package/framework/components/chui_data_grid/data_grid.js +633 -471
  52. package/framework/components/chui_data_grid/styles.css +24 -22
  53. package/framework/components/chui_descriptions/descriptions.js +34 -17
  54. package/framework/components/chui_descriptions/styles.css +1 -1
  55. package/framework/components/chui_details/details.js +42 -36
  56. package/framework/components/chui_details/styles.css +12 -11
  57. package/framework/components/chui_diff_viewer/diff_viewer.js +172 -147
  58. package/framework/components/chui_diff_viewer/styles.css +10 -10
  59. package/framework/components/chui_divider/divider.js +19 -17
  60. package/framework/components/chui_divider/styles.css +2 -2
  61. package/framework/components/chui_drawer/drawer.js +63 -38
  62. package/framework/components/chui_drawer/styles.css +18 -4
  63. package/framework/components/chui_drop_zone/drop_zone.js +37 -27
  64. package/framework/components/chui_drop_zone/styles.css +10 -6
  65. package/framework/components/chui_empty_state/empty_state.js +20 -15
  66. package/framework/components/chui_fieldset/fieldset.js +40 -23
  67. package/framework/components/chui_fieldset/styles.css +6 -6
  68. package/framework/components/chui_file_explorer/file_explorer.js +260 -189
  69. package/framework/components/chui_file_explorer/styles.css +8 -7
  70. package/framework/components/chui_form/form.js +40 -28
  71. package/framework/components/chui_form/styles.css +1 -1
  72. package/framework/components/chui_gantt/gantt.js +102 -78
  73. package/framework/components/chui_gantt/styles.css +5 -5
  74. package/framework/components/chui_graphs/graphs.js +376 -239
  75. package/framework/components/chui_graphs/styles.css +27 -6
  76. package/framework/components/chui_hero/hero.js +98 -37
  77. package/framework/components/chui_hero/styles.css +176 -7
  78. package/framework/components/chui_html_block/html_block.js +8 -8
  79. package/framework/components/chui_html_block/styles.css +3 -3
  80. package/framework/components/chui_hx/hx.js +3 -3
  81. package/framework/components/chui_hx/styles.css +13 -6
  82. package/framework/components/chui_icons/icons.js +2115 -2115
  83. package/framework/components/chui_icons/styles.css +4 -3
  84. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  85. package/framework/components/chui_inputs/chui_check_box/styles.css +30 -21
  86. package/framework/components/chui_inputs/chui_chips/chips.js +141 -70
  87. package/framework/components/chui_inputs/chui_chips/styles.css +32 -7
  88. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +55 -38
  89. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  90. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +127 -109
  91. package/framework/components/chui_inputs/chui_combo_box/styles.css +23 -21
  92. package/framework/components/chui_inputs/chui_date/date.js +161 -127
  93. package/framework/components/chui_inputs/chui_date/styles.css +20 -19
  94. package/framework/components/chui_inputs/chui_date_range/date_range.js +61 -50
  95. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  96. package/framework/components/chui_inputs/chui_datetime/datetime.js +47 -39
  97. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  98. package/framework/components/chui_inputs/chui_email/email.js +48 -36
  99. package/framework/components/chui_inputs/chui_email/styles.css +11 -11
  100. package/framework/components/chui_inputs/chui_file/file.js +71 -44
  101. package/framework/components/chui_inputs/chui_file/styles.css +23 -19
  102. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +101 -76
  103. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_masked/masked.js +83 -72
  105. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_mention/mention.js +87 -40
  107. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  108. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +242 -212
  109. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +23 -15
  110. package/framework/components/chui_inputs/chui_number/number.js +84 -70
  111. package/framework/components/chui_inputs/chui_number/styles.css +13 -13
  112. package/framework/components/chui_inputs/chui_otp/otp.js +71 -62
  113. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  114. package/framework/components/chui_inputs/chui_password/password.js +72 -56
  115. package/framework/components/chui_inputs/chui_password/styles.css +15 -15
  116. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  117. package/framework/components/chui_inputs/chui_radio_button/styles.css +22 -22
  118. package/framework/components/chui_inputs/chui_rating/rating.js +54 -50
  119. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  120. package/framework/components/chui_inputs/chui_select_box/select_box.js +132 -108
  121. package/framework/components/chui_inputs/chui_select_box/styles.css +21 -21
  122. package/framework/components/chui_inputs/chui_slider/slider.js +41 -38
  123. package/framework/components/chui_inputs/chui_slider/styles.css +7 -5
  124. package/framework/components/chui_inputs/chui_text/styles.css +14 -14
  125. package/framework/components/chui_inputs/chui_text/text.js +69 -52
  126. package/framework/components/chui_inputs/chui_text_area/styles.css +14 -14
  127. package/framework/components/chui_inputs/chui_text_area/text_area.js +59 -36
  128. package/framework/components/chui_inputs/chui_time/styles.css +18 -20
  129. package/framework/components/chui_inputs/chui_time/time.js +71 -49
  130. package/framework/components/chui_inputs/chui_toggle/styles.css +13 -6
  131. package/framework/components/chui_inputs/chui_toggle/toggle.js +27 -27
  132. package/framework/components/chui_json_editor/json_editor.js +137 -127
  133. package/framework/components/chui_json_editor/styles.css +5 -5
  134. package/framework/components/chui_json_viewer/json_viewer.js +133 -114
  135. package/framework/components/chui_json_viewer/styles.css +9 -8
  136. package/framework/components/chui_kanban/kanban.js +78 -60
  137. package/framework/components/chui_kanban/styles.css +8 -4
  138. package/framework/components/chui_kbd/kbd.js +12 -10
  139. package/framework/components/chui_kbd/styles.css +1 -1
  140. package/framework/components/chui_label/label.js +31 -29
  141. package/framework/components/chui_label/styles.css +3 -3
  142. package/framework/components/chui_link/link.js +36 -29
  143. package/framework/components/chui_link/styles.css +11 -4
  144. package/framework/components/chui_list/list.js +42 -38
  145. package/framework/components/chui_list/styles.css +4 -3
  146. package/framework/components/chui_markdown_editor/markdown_editor.js +125 -109
  147. package/framework/components/chui_markdown_editor/styles.css +5 -5
  148. package/framework/components/chui_media/audio.js +457 -364
  149. package/framework/components/chui_media/audio_styles.css +74 -37
  150. package/framework/components/chui_media/image.js +99 -64
  151. package/framework/components/chui_media/image_compare.js +86 -55
  152. package/framework/components/chui_media/image_compare_styles.css +5 -5
  153. package/framework/components/chui_media/image_styles.css +4 -4
  154. package/framework/components/chui_media/video.js +264 -171
  155. package/framework/components/chui_media/video_styles.css +57 -24
  156. package/framework/components/chui_menu_bar/menu_bar.js +67 -65
  157. package/framework/components/chui_menu_bar/styles.css +14 -12
  158. package/framework/components/chui_message_bar/message_bar.js +551 -0
  159. package/framework/components/chui_message_bar/styles.css +248 -0
  160. package/framework/components/chui_modal/modal.js +81 -56
  161. package/framework/components/chui_modal/styles.css +3 -2
  162. package/framework/components/chui_notification/notification.js +107 -69
  163. package/framework/components/chui_notification/notification_download.js +28 -77
  164. package/framework/components/chui_notification/notification_download_card.js +115 -0
  165. package/framework/components/chui_notification/notification_download_progress.css +5 -4
  166. package/framework/components/chui_notification/notification_download_progress.js +73 -105
  167. package/framework/components/chui_notification/notification_update.js +44 -37
  168. package/framework/components/chui_notification/status_plate.css +3 -3
  169. package/framework/components/chui_notification/status_plate.js +2 -2
  170. package/framework/components/chui_notification/styles.css +6 -1
  171. package/framework/components/chui_notification/styles_download.css +2 -2
  172. package/framework/components/chui_notification/styles_update.css +3 -3
  173. package/framework/components/chui_org_chart/org_chart.js +101 -62
  174. package/framework/components/chui_org_chart/styles.css +2 -2
  175. package/framework/components/chui_pagination/pagination.js +65 -30
  176. package/framework/components/chui_pagination/styles.css +1 -1
  177. package/framework/components/chui_paragraph/paragraph.js +2 -2
  178. package/framework/components/chui_paragraph/styles.css +3 -3
  179. package/framework/components/chui_popover/popover.js +77 -50
  180. package/framework/components/chui_popover/styles.css +1 -1
  181. package/framework/components/chui_popups/popups.js +210 -181
  182. package/framework/components/chui_popups/styles.css +7 -7
  183. package/framework/components/chui_print_button/print_button.js +48 -33
  184. package/framework/components/chui_progress_bar/progress_bar.js +49 -19
  185. package/framework/components/chui_progress_bar/styles.css +6 -6
  186. package/framework/components/chui_progress_ring/progress_ring.js +32 -30
  187. package/framework/components/chui_progress_ring/styles.css +1 -1
  188. package/framework/components/chui_qrcode/qrcode.js +85 -41
  189. package/framework/components/chui_query_builder/query_builder.js +263 -170
  190. package/framework/components/chui_query_builder/styles.css +4 -4
  191. package/framework/components/chui_radio_group/radio_group.js +36 -26
  192. package/framework/components/chui_radio_group/styles.css +2 -2
  193. package/framework/components/chui_result/result.js +41 -31
  194. package/framework/components/chui_result/styles.css +3 -3
  195. package/framework/components/chui_scheduler/scheduler.js +126 -104
  196. package/framework/components/chui_scheduler/styles.css +11 -7
  197. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  198. package/framework/components/chui_screen_spinner/styles.css +49 -0
  199. package/framework/components/chui_segmented_control/segmented_control.js +90 -27
  200. package/framework/components/chui_segmented_control/styles.css +32 -6
  201. package/framework/components/chui_settings/settings.js +160 -87
  202. package/framework/components/chui_settings/styles.css +4 -4
  203. package/framework/components/chui_shortcut_help/shortcut_help.js +82 -61
  204. package/framework/components/chui_sidebar_nav/sidebar_nav.js +132 -53
  205. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  206. package/framework/components/chui_skeleton/skeleton.js +29 -24
  207. package/framework/components/chui_slideshow/slideshow.js +122 -103
  208. package/framework/components/chui_slideshow/styles.css +22 -16
  209. package/framework/components/chui_spinner/spinner.js +17 -17
  210. package/framework/components/chui_spinner/styles.css +0 -1
  211. package/framework/components/chui_split_button/split_button.js +53 -30
  212. package/framework/components/chui_split_button/styles.css +22 -6
  213. package/framework/components/chui_splitter/splitter.js +46 -39
  214. package/framework/components/chui_splitter/styles.css +2 -2
  215. package/framework/components/chui_statistic/statistic.js +111 -84
  216. package/framework/components/chui_status_bar/status_bar.js +11 -9
  217. package/framework/components/chui_status_bar/styles.css +2 -2
  218. package/framework/components/chui_stepper/stepper.js +230 -54
  219. package/framework/components/chui_stepper/styles.css +79 -14
  220. package/framework/components/chui_sticky_bar/sticky_bar.js +53 -17
  221. package/framework/components/chui_sticky_bar/styles.css +11 -7
  222. package/framework/components/chui_tabs/chui_tabs.js +100 -46
  223. package/framework/components/chui_tabs/styles.css +43 -15
  224. package/framework/components/chui_text_editor/styles.css +24 -23
  225. package/framework/components/chui_text_editor/text_editor.js +103 -79
  226. package/framework/components/chui_text_editor/text_editor_panel.js +428 -367
  227. package/framework/components/chui_theme_toggle/theme_toggle.js +46 -25
  228. package/framework/components/chui_timeline/styles.css +3 -1
  229. package/framework/components/chui_timeline/timeline.js +14 -12
  230. package/framework/components/chui_toast_queue/styles.css +11 -11
  231. package/framework/components/chui_toast_queue/toast_queue.js +82 -73
  232. package/framework/components/chui_toolbar/styles.css +2 -2
  233. package/framework/components/chui_toolbar/toolbar.js +20 -13
  234. package/framework/components/chui_tooltip/styles.css +2 -2
  235. package/framework/components/chui_tooltip/tooltip.js +40 -27
  236. package/framework/components/chui_tour/styles.css +12 -7
  237. package/framework/components/chui_tour/tour.js +132 -98
  238. package/framework/components/chui_transfer/styles.css +8 -7
  239. package/framework/components/chui_transfer/transfer.js +143 -123
  240. package/framework/components/chui_tree_table/styles.css +4 -4
  241. package/framework/components/chui_tree_table/tree_table.js +88 -74
  242. package/framework/components/chui_tree_view/styles.css +14 -10
  243. package/framework/components/chui_tree_view/tree_view.js +298 -253
  244. package/framework/components/chui_user_bar/styles.css +145 -0
  245. package/framework/components/chui_user_bar/user_bar.js +402 -0
  246. package/framework/components/chui_user_list_bar/styles.css +173 -0
  247. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  248. package/framework/components/chui_watermark/watermark.js +41 -33
  249. package/framework/components/chui_webview/styles.css +2 -2
  250. package/framework/components/chui_webview/webview.js +64 -52
  251. package/framework/components/chui_write_bar/styles.css +172 -0
  252. package/framework/components/chui_write_bar/write_bar.js +320 -0
  253. package/framework/main_window.js +1234 -0
  254. package/framework/modules/chui_a11y/chui_a11y.js +153 -123
  255. package/framework/modules/chui_animations/animations.js +105 -43
  256. package/framework/modules/chui_animations/motion.js +120 -0
  257. package/framework/modules/chui_animations/styles.css +37 -4
  258. package/framework/modules/chui_bridge/preload.js +36 -25
  259. package/framework/modules/chui_functions.js +69 -63
  260. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  261. package/framework/modules/chui_highlight/styles.css +13 -10
  262. package/framework/modules/chui_i18n/chui_i18n.js +12 -10
  263. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  264. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  265. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  266. package/framework/modules/chui_i18n/locales/common.js +3 -3
  267. package/framework/modules/chui_i18n/locales/data.js +36 -26
  268. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  269. package/framework/modules/chui_i18n/locales/feedback.js +65 -3
  270. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  271. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  272. package/framework/modules/chui_i18n/locales/media.js +4 -4
  273. package/framework/modules/chui_i18n/locales/navigation.js +12 -8
  274. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  275. package/framework/modules/chui_json/chui_json.js +11 -11
  276. package/framework/modules/chui_layout/chui_layout.js +12 -10
  277. package/framework/modules/chui_logger/chui_logger.js +47 -28
  278. package/framework/modules/chui_page/page.js +39 -33
  279. package/framework/modules/chui_palette/palette.js +61 -0
  280. package/framework/modules/chui_qr/chui_qr.js +179 -88
  281. package/framework/modules/chui_scrollbar/chui_scrollbar.js +79 -68
  282. package/framework/modules/chui_scrollbar/styles.css +4 -2
  283. package/framework/modules/chui_services/chui_channels.js +27 -13
  284. package/framework/modules/chui_services/chui_services.js +47 -39
  285. package/framework/modules/chui_services/desktop.js +108 -101
  286. package/framework/modules/chui_sortable/chui_sortable.js +33 -28
  287. package/framework/modules/chui_validate/chui_validate.js +10 -7
  288. package/framework/tray_bar/chui_menu_items.js +136 -46
  289. package/index.d.ts +5046 -0
  290. package/index.js +199 -1254
  291. package/package.json +81 -68
  292. package/framework/components/telegram_bot/chui_telegram_bot.js +0 -184
@@ -1,7 +1,7 @@
1
- const {setStyles, optionOr} = require('../../modules/chui_functions');
2
- const {TextInput} = require('../chui_inputs/chui_text/text');
3
- const {Kbd} = require('../chui_kbd/kbd');
4
- const {I18n} = require('../../modules/chui_i18n/chui_i18n');
1
+ const { setStyles, optionOr } = require("../../modules/chui_functions");
2
+ const { TextInput } = require("../chui_inputs/chui_text/text");
3
+ const { Kbd } = require("../chui_kbd/kbd");
4
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
5
5
 
6
6
  /**
7
7
  * Шпаргалка горячих клавиш: сочетания с пояснениями, разложенные по группам.
@@ -41,35 +41,44 @@ 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
- constructor(options = {
63
- id: String(), title: undefined, groups: [], items: [],
64
- columns: Number(), searchable: Boolean(), searchPlaceholder: String(),
65
- emptyText: String(), label: String(), kbdSize: String()
66
- }) {
62
+ constructor(
63
+ options = {
64
+ id: String(),
65
+ title: undefined,
66
+ groups: [],
67
+ items: [],
68
+ columns: Number(),
69
+ searchable: Boolean(),
70
+ searchPlaceholder: String(),
71
+ emptyText: String(),
72
+ label: String(),
73
+ kbdSize: String(),
74
+ }
75
+ ) {
67
76
  setStyles(__dirname + "/styles.css", "chUiJS_ShortcutHelp");
68
77
  ShortcutHelp.#counter += 1;
69
78
  this.#id = optionOr(options.id, `chui_shortcut_help_${ShortcutHelp.#counter}`);
70
- this.#id_title = `${this.#id}_title`;
79
+ this.#idTitle = `${this.#id}_title`;
71
80
  this.#root.id = this.#id;
72
- this.#title.id = this.#id_title;
81
+ this.#title.id = this.#idTitle;
73
82
  // Заголовок — настоящий заголовок: к шпаргалке можно перейти навигацией по заголовкам
74
83
  this.#title.setAttribute("role", "heading");
75
84
  this.#title.setAttribute("aria-level", "2");
@@ -80,16 +89,16 @@ class ShortcutHelp {
80
89
  this.#root.appendChild(this.#title);
81
90
  this.#root.appendChild(this.#search);
82
91
  this.#root.appendChild(this.#status);
83
- this.#root.appendChild(this.#groups_node);
92
+ this.#root.appendChild(this.#groupsNode);
84
93
  this.#root.appendChild(this.#empty);
85
94
  this.#label = options.label;
86
- this.#title_hidden = options.title === null;
87
- 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;
88
97
  this.#placeholder = options.searchPlaceholder;
89
- this.#empty_text = options.emptyText;
90
- if (options.kbdSize !== undefined) this.#kbd_size = options.kbdSize;
98
+ this.#emptyText = options.emptyText;
99
+ if (options.kbdSize !== undefined) this.#kbdSize = options.kbdSize;
91
100
  this.setColumns(options.columns === undefined ? 1 : options.columns);
92
- this.setTitle(this.#title_hidden ? null : this.#title_value);
101
+ this.setTitle(this.#titleHidden ? null : this.#titleValue);
93
102
  if (options.searchable === true) this.setSearchable(true);
94
103
  else this.#syncSearch();
95
104
  this.#source = ShortcutHelp.#normalizeSource(options);
@@ -103,14 +112,18 @@ class ShortcutHelp {
103
112
 
104
113
  /** Заголовок на экране (`""`, если он убран) */
105
114
  getTitle() {
106
- return this.#title_hidden ? "" : this.#title.innerText;
115
+ return this.#titleHidden ? "" : this.#title.innerText;
107
116
  }
108
117
 
109
118
  /** Группы со строками: `[{title, items: [{keys, description, label}]}]` */
110
119
  getGroups() {
111
120
  return this.#source.map((group) => ({
112
121
  title: group.title,
113
- items: group.items.map((item) => ({keys: [...item.keys], description: item.description, label: item.label}))
122
+ items: group.items.map((item) => ({
123
+ keys: [...item.keys],
124
+ description: item.description,
125
+ label: item.label,
126
+ })),
114
127
  }));
115
128
  }
116
129
 
@@ -129,7 +142,10 @@ class ShortcutHelp {
129
142
 
130
143
  /** Сколько строк видно с учётом фильтра */
131
144
  getVisibleCount() {
132
- return this.#groups.reduce((sum, group) => sum + group.rows.filter((row) => row.node.hidden !== true).length, 0);
145
+ return this.#groups.reduce(
146
+ (sum, group) => sum + group.rows.filter((row) => row.node.hidden !== true).length,
147
+ 0
148
+ );
133
149
  }
134
150
 
135
151
  // SET
@@ -141,10 +157,10 @@ class ShortcutHelp {
141
157
 
142
158
  /** Заголовок; `null` убирает его (тогда блок называется по `label`) */
143
159
  setTitle(text = undefined) {
144
- this.#title_hidden = text === null;
145
- this.#title_value = typeof text === "string" && text !== "" ? text : undefined;
146
- this.#title.innerText = this.#title_hidden ? "" : optionOr(this.#title_value, I18n.t("navigation.shortcutHelp"));
147
- 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;
148
164
  this.#syncAria();
149
165
  return this;
150
166
  }
@@ -172,12 +188,15 @@ class ShortcutHelp {
172
188
  placeholder: optionOr(this.#placeholder, I18n.t("navigation.shortcutHelpSearch")),
173
189
  width: "100%",
174
190
  // Слушатель обновляет и строки, и объявление найденного числа
175
- inputListener: () => this.#syncSearch()
191
+ inputListener: () => this.#syncSearch(),
176
192
  });
177
193
  // Видимой подписи у поля нет, а пл҃ейсхолдер — не имя: имя ставим явно
178
- const search_field = this.#input.set().querySelector("input");
179
- if (search_field !== null) {
180
- search_field.setAttribute("aria-label", optionOr(this.#placeholder, I18n.t("navigation.shortcutHelpSearch")));
194
+ const searchField = this.#input.set().querySelector("input");
195
+ if (searchField !== null) {
196
+ searchField.setAttribute(
197
+ "aria-label",
198
+ optionOr(this.#placeholder, I18n.t("navigation.shortcutHelpSearch"))
199
+ );
181
200
  }
182
201
  this.#search.appendChild(this.#input.set());
183
202
  }
@@ -189,7 +208,7 @@ class ShortcutHelp {
189
208
 
190
209
  /** Заменить содержимое целиком */
191
210
  setGroups(groups = []) {
192
- this.#source = ShortcutHelp.#normalizeSource({groups: groups});
211
+ this.#source = ShortcutHelp.#normalizeSource({ groups: groups });
193
212
  this.#render();
194
213
  return this;
195
214
  }
@@ -197,7 +216,7 @@ class ShortcutHelp {
197
216
  /** Добавить группу: `add({title: 'Правка', items: [...]})` */
198
217
  addGroup(group = undefined) {
199
218
  if (group === undefined || group === null) return this;
200
- this.#source = ShortcutHelp.#normalizeSource({groups: [...this.#source, group]});
219
+ this.#source = ShortcutHelp.#normalizeSource({ groups: [...this.#source, group] });
201
220
  this.#render();
202
221
  return this;
203
222
  }
@@ -217,46 +236,49 @@ class ShortcutHelp {
217
236
  /** `groups` плюс короткая форма `items` (одна группа без заголовка) */
218
237
  static #normalizeSource(options = {}) {
219
238
  const groups = [];
220
- const items = (options.items === undefined ? [] : options.items).map((item) => ShortcutHelp.#normalizeItem(item));
221
- if (items.length > 0) groups.push({title: "", items: items});
239
+ const items = (options.items === undefined ? [] : options.items).map((item) =>
240
+ ShortcutHelp.#normalizeItem(item)
241
+ );
242
+ if (items.length > 0) groups.push({ title: "", items: items });
222
243
  for (const group of options.groups === undefined ? [] : options.groups) {
223
244
  groups.push({
224
245
  title: group.title === undefined ? "" : String(group.title),
225
- items: (group.items === undefined ? [] : group.items).map((item) => ShortcutHelp.#normalizeItem(item))
246
+ items: (group.items === undefined ? [] : group.items).map((item) => ShortcutHelp.#normalizeItem(item)),
226
247
  });
227
248
  }
228
249
  return groups;
229
250
  }
230
251
 
231
252
  static #normalizeItem(item = {}) {
232
- const keys = item.keys === undefined || item.keys === null
233
- ? []
234
- : (Array.isArray(item.keys) ? item.keys : String(item.keys).split("+"))
235
- .map((key) => String(key).trim())
236
- .filter((key) => key.length > 0);
253
+ const keys =
254
+ item.keys === undefined || item.keys === null
255
+ ? []
256
+ : (Array.isArray(item.keys) ? item.keys : String(item.keys).split("+"))
257
+ .map((key) => String(key).trim())
258
+ .filter((key) => key.length > 0);
237
259
  return {
238
260
  keys: keys,
239
261
  description: item.description === undefined ? "" : String(item.description),
240
- label: item.label
262
+ label: item.label,
241
263
  };
242
264
  }
243
265
 
244
266
  #render() {
245
- this.#groups_node.innerHTML = "";
267
+ this.#groupsNode.innerHTML = "";
246
268
  this.#groups = [];
247
269
  this.#source.forEach((group, index) => {
248
270
  const node = document.createElement("div");
249
271
  node.className = "shortcut_help_group";
250
- const id_group_title = `${this.#id}_group_${index}`;
272
+ const idGroupTitle = `${this.#id}_group_${index}`;
251
273
  node.setAttribute("role", "group");
252
274
  const title = document.createElement("shortcut_help_group_title");
253
- title.id = id_group_title;
275
+ title.id = idGroupTitle;
254
276
  title.setAttribute("role", "heading");
255
277
  title.setAttribute("aria-level", "3");
256
278
  title.innerText = group.title;
257
279
  title.hidden = group.title === "";
258
280
  node.appendChild(title);
259
- if (group.title !== "") node.setAttribute("aria-labelledby", id_group_title);
281
+ if (group.title !== "") node.setAttribute("aria-labelledby", idGroupTitle);
260
282
  const list = document.createElement("ul");
261
283
  list.className = "shortcut_help_list";
262
284
  const rows = [];
@@ -270,7 +292,7 @@ class ShortcutHelp {
270
292
  if (item.keys.length > 0) {
271
293
  const keys = document.createElement("shortcut_help_keys");
272
294
  // Сочетание рисует Kbd: клавиша — настоящий <kbd>, значковым нужен label
273
- 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());
274
296
  line.appendChild(keys);
275
297
  }
276
298
  const text = document.createElement("shortcut_help_text");
@@ -278,13 +300,13 @@ class ShortcutHelp {
278
300
  line.appendChild(text);
279
301
  row.appendChild(line);
280
302
  list.appendChild(row);
281
- rows.push({node: row, search: `${item.description} ${item.keys.join(" ")}`.toLowerCase()});
303
+ rows.push({ node: row, search: `${item.description} ${item.keys.join(" ")}`.toLowerCase() });
282
304
  }
283
305
  node.appendChild(list);
284
- this.#groups_node.appendChild(node);
285
- this.#groups.push({node: node, rows: rows});
306
+ this.#groupsNode.appendChild(node);
307
+ this.#groups.push({ node: node, rows: rows });
286
308
  });
287
- this.#empty.innerText = optionOr(this.#empty_text, I18n.t("navigation.shortcutHelpEmpty"));
309
+ this.#empty.innerText = optionOr(this.#emptyText, I18n.t("navigation.shortcutHelpEmpty"));
288
310
  this.#syncSearch();
289
311
  this.#syncAria();
290
312
  }
@@ -304,7 +326,7 @@ class ShortcutHelp {
304
326
  visible += shown;
305
327
  }
306
328
  const nothing = visible === 0 && this.#groups.length > 0;
307
- this.#groups_node.hidden = nothing;
329
+ this.#groupsNode.hidden = nothing;
308
330
  this.#empty.hidden = !nothing;
309
331
  return visible;
310
332
  }
@@ -313,15 +335,14 @@ class ShortcutHelp {
313
335
  #syncSearch() {
314
336
  this.#search.hidden = this.#searchable !== true;
315
337
  const visible = this.#filter(this.#input === undefined ? "" : this.#input.getValue());
316
- this.#status.innerText = this.#searchable === true
317
- ? I18n.t("navigation.shortcutHelpCount", {count: visible})
318
- : "";
338
+ this.#status.innerText =
339
+ this.#searchable === true ? I18n.t("navigation.shortcutHelpCount", { count: visible }) : "";
319
340
  // Без поиска пустая строка не показывается: скрывать нечего
320
341
  if (this.#searchable !== true) this.#empty.hidden = true;
321
342
  }
322
343
 
323
344
  #syncAria() {
324
- if (this.#title_hidden) {
345
+ if (this.#titleHidden) {
325
346
  this.#root.setAttribute("role", "group");
326
347
  this.#root.removeAttribute("aria-labelledby");
327
348
  this.#root.setAttribute("aria-label", optionOr(this.#label, I18n.t("navigation.shortcutHelp")));
@@ -329,8 +350,8 @@ class ShortcutHelp {
329
350
  }
330
351
  this.#root.setAttribute("role", "region");
331
352
  this.#root.removeAttribute("aria-label");
332
- this.#root.setAttribute("aria-labelledby", this.#id_title);
353
+ this.#root.setAttribute("aria-labelledby", this.#idTitle);
333
354
  }
334
355
  }
335
356
 
336
- exports.ShortcutHelp = ShortcutHelp
357
+ exports.ShortcutHelp = ShortcutHelp;
@@ -1,6 +1,7 @@
1
- const {setStyles} = require("../../modules/chui_functions");
2
- const {Icon, Icons} = require("../chui_icons/icons");
3
- const {I18n} = require("../../modules/chui_i18n/chui_i18n");
1
+ const { setStyles } = require("../../modules/chui_functions");
2
+ const { reducedMotion } = require("../../modules/chui_animations/motion");
3
+ const { Icon, Icons } = require("../chui_icons/icons");
4
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
4
5
 
5
6
  /** Служебные ключи пункта: всё остальное — данные пункта */
6
7
  const SERVICE_KEYS = ["id", "type", "title", "icon", "badge", "children", "disabled", "href"];
@@ -61,33 +62,35 @@ class SidebarNav {
61
62
  #collapsed = false;
62
63
  #collapsible = false;
63
64
  #id = undefined;
64
- #title_text = undefined;
65
- #label_text = undefined;
66
- #on_select = undefined;
67
- #on_toggle = undefined;
65
+ #titleText = undefined;
66
+ #labelText = undefined;
67
+ #onSelect = undefined;
68
+ #onToggle = undefined;
68
69
  #listeners = [];
69
- #active_id = undefined;
70
- #focus_id = undefined;
71
-
72
- constructor(options = {
73
- id: String(),
74
- title: String(),
75
- label: String(),
76
- items: Array(),
77
- value: String(),
78
- collapsible: Boolean(),
79
- collapsed: Boolean(),
80
- onSelect: undefined,
81
- onToggle: undefined,
82
- changeEvent: undefined
83
- }) {
70
+ #activeId = undefined;
71
+ #focusId = undefined;
72
+
73
+ constructor(
74
+ options = {
75
+ id: String(),
76
+ title: String(),
77
+ label: String(),
78
+ items: Array(),
79
+ value: String(),
80
+ collapsible: Boolean(),
81
+ collapsed: Boolean(),
82
+ onSelect: undefined,
83
+ onToggle: undefined,
84
+ changeEvent: undefined,
85
+ }
86
+ ) {
84
87
  setStyles(__dirname + "/styles.css", "chUiJS_SidebarNav");
85
88
  SidebarNav.#counter += 1;
86
89
  this.#id = options.id === undefined ? `chui_sidebar_nav_${SidebarNav.#counter}` : options.id;
87
90
  this.#root.id = this.#id;
88
91
  this.#root.setAttribute("role", "navigation");
89
- this.#on_select = options.onSelect;
90
- this.#on_toggle = options.onToggle;
92
+ this.#onSelect = options.onSelect;
93
+ this.#onToggle = options.onToggle;
91
94
  this.#collapsible = options.collapsible === true;
92
95
  if (options.changeEvent !== undefined) this.addChangeListener(options.changeEvent);
93
96
  this.#title.className = "sidebar_nav_title";
@@ -116,12 +119,12 @@ class SidebarNav {
116
119
  }
117
120
 
118
121
  getTitle() {
119
- return this.#title_text;
122
+ return this.#titleText;
120
123
  }
121
124
 
122
125
  /** Доступное имя навигации, заданное в `label` */
123
126
  getLabel() {
124
- return this.#label_text;
127
+ return this.#labelText;
125
128
  }
126
129
 
127
130
  /** Пункты деревом: `{id, title, icon, badge, disabled, expanded, children}`; разделы — `{type: "section", title, children}` */
@@ -174,7 +177,7 @@ class SidebarNav {
174
177
 
175
178
  /** Подпись в шапке навигации; `undefined` её убирает */
176
179
  setTitle(text = undefined) {
177
- this.#title_text = text;
180
+ this.#titleText = text;
178
181
  if (text === undefined || text === "") {
179
182
  this.#title.innerText = "";
180
183
  this.#title.hidden = true;
@@ -189,7 +192,7 @@ class SidebarNav {
189
192
 
190
193
  /** Имя навигации, когда подписи в шапке нет */
191
194
  setLabel(text = undefined) {
192
- this.#label_text = text;
195
+ this.#labelText = text;
193
196
  this.#syncLabel();
194
197
  return this;
195
198
  }
@@ -203,7 +206,7 @@ class SidebarNav {
203
206
  let section = undefined;
204
207
  for (const item of Array.isArray(items) ? items : []) {
205
208
  if (item !== null && typeof item === "object" && item.type === "section") {
206
- section = {type: "section", title: item.title === undefined ? "" : String(item.title), children: []};
209
+ section = { type: "section", title: item.title === undefined ? "" : String(item.title), children: [] };
207
210
  this.#items.push(section);
208
211
  continue;
209
212
  }
@@ -274,8 +277,76 @@ class SidebarNav {
274
277
  if (next === this.#expanded.has(node.id)) return this;
275
278
  if (next) this.#expanded.add(node.id);
276
279
  else this.#expanded.delete(node.id);
277
- this.#render();
278
- if (!silent && this.#on_toggle !== undefined) this.#on_toggle(this.#describe(node), next, this);
280
+ // Панель переключается на месте, а не пересборкой списка: новый узел не помнит прошлого
281
+ // состояния, поэтому и стрелка, и содержимое появлялись готовыми — без движения
282
+ this.#setPanel(node, next);
283
+ if (!silent && this.#onToggle !== undefined) this.#onToggle(this.#describe(node), next, this);
284
+ return this;
285
+ }
286
+
287
+ /** Узел панели пункта — по её id, тому же, что в `aria-controls` пункта */
288
+ #panelNode(node = Object()) {
289
+ return this.#root.querySelector(`[id="${this.#id}_panel_${node.id}"]`);
290
+ }
291
+
292
+ /** Узел пункта: он несёт `aria-expanded` (по нему поворачивается стрелка)
293
+ и панель */
294
+ #linkNode(node = Object()) {
295
+ return this.#links().find((link) => link.dataset.id === node.id) ?? null;
296
+ }
297
+
298
+ /**
299
+ * Раскрытие и сворачивание панели пункта.
300
+ *
301
+ * Высоту списка ведёт компонент, а время и кривую берут токены движения из стилей: высоту
302
+ * кадром не задать — её знает только раскладка, поэтому её считает JS и переводит переходом.
303
+ * `overflow` на время движения прячет содержимое, которое ещё не помещается в панель,
304
+ * а после снимается: иначе вложенные списки и счётчики обрезались бы по краю.
305
+ */
306
+ #setPanel(node = Object(), open = Boolean()) {
307
+ const panel = this.#panelNode(node);
308
+ const link = this.#linkNode(node);
309
+ // В свёрнутой навигации подписи скрыты, поэтому пункт всегда заявляет себя свёрнутым
310
+ if (link !== null) link.setAttribute("aria-expanded", open && !this.#collapsed ? "true" : "false");
311
+ if (panel === null) return this;
312
+ if (open) {
313
+ panel.hidden = false;
314
+ this.#slidePanel(panel, 0, panel.scrollHeight);
315
+ } else {
316
+ this.#slidePanel(panel, panel.scrollHeight, 0, () => {
317
+ panel.hidden = true;
318
+ });
319
+ }
320
+ this.#applyStop();
321
+ return this;
322
+ }
323
+
324
+ /** Перевод высоты панели от `from` к `to`; `done` — по концу перехода */
325
+ #slidePanel(panel = undefined, from = Number(), to = Number(), done = () => {}) {
326
+ const finish = (event) => {
327
+ if (event !== undefined && event.propertyName !== "max-height") return;
328
+ panel.removeEventListener("transitionend", finish);
329
+ panel.style.removeProperty("max-height");
330
+ panel.style.removeProperty("opacity");
331
+ panel.style.removeProperty("overflow");
332
+ done();
333
+ };
334
+ // Уменьшенное движение: состояние применяется сразу — перехода не будет,
335
+ // и `transitionend` не придёт
336
+ if (reducedMotion()) {
337
+ finish();
338
+ return this;
339
+ }
340
+ panel.style.overflow = "hidden";
341
+ panel.style.maxHeight = `${from}px`;
342
+ panel.style.opacity = from === 0 ? "0" : "1";
343
+ panel.addEventListener("transitionend", finish);
344
+ // Следующий кадр — уже с конечными значениями: в том же кадре браузер не увидел бы
345
+ // перехода, и панель встала бы готовой
346
+ requestAnimationFrame(() => {
347
+ panel.style.maxHeight = `${to}px`;
348
+ panel.style.opacity = to === 0 ? "0" : "1";
349
+ });
279
350
  return this;
280
351
  }
281
352
 
@@ -285,7 +356,10 @@ class SidebarNav {
285
356
  this.#root.classList.toggle("sidebar_nav_collapsed", this.#collapsed);
286
357
  if (this.#collapse !== undefined) {
287
358
  this.#collapse.setAttribute("aria-expanded", this.#collapsed ? "false" : "true");
288
- this.#collapse.setAttribute("aria-label", this.#collapsed ? I18n.t("navigation.sidebarExpand") : I18n.t("navigation.sidebarCollapse"));
359
+ this.#collapse.setAttribute(
360
+ "aria-label",
361
+ this.#collapsed ? I18n.t("navigation.sidebarExpand") : I18n.t("navigation.sidebarCollapse")
362
+ );
289
363
  }
290
364
  this.#render();
291
365
  return this;
@@ -319,14 +393,14 @@ class SidebarNav {
319
393
 
320
394
  // === ВНУТРЕННЕЕ ===
321
395
  static #toNode(item = Object()) {
322
- const source = typeof item === "string" ? {title: item} : item;
396
+ const source = typeof item === "string" ? { title: item } : item;
323
397
  const data = {};
324
398
  for (const key of Object.keys(source === null ? {} : source)) {
325
399
  if (!SERVICE_KEYS.includes(key)) data[key] = source[key];
326
400
  }
327
- SidebarNav.#item_counter += 1;
401
+ SidebarNav.#itemCounter += 1;
328
402
  return {
329
- id: source.id === undefined ? `sidebar_nav_item_${SidebarNav.#item_counter}` : String(source.id),
403
+ id: source.id === undefined ? `sidebar_nav_item_${SidebarNav.#itemCounter}` : String(source.id),
330
404
  title: source.title === undefined ? "" : String(source.title),
331
405
  icon: source.icon,
332
406
  badge: source.badge === undefined ? undefined : String(source.badge),
@@ -337,17 +411,21 @@ class SidebarNav {
337
411
  };
338
412
  }
339
413
 
340
- static #item_counter = 0;
414
+ static #itemCounter = 0;
341
415
 
342
416
  #describeEntry(node) {
343
417
  if (node.type === "section") {
344
- return {type: "section", title: node.title, children: node.children.map((child) => this.#describeEntry(child))};
418
+ return {
419
+ type: "section",
420
+ title: node.title,
421
+ children: node.children.map((child) => this.#describeEntry(child)),
422
+ };
345
423
  }
346
424
  return this.#describe(node);
347
425
  }
348
426
 
349
427
  #describe(node) {
350
- const descriptor = {id: node.id, title: node.title, icon: node.icon};
428
+ const descriptor = { id: node.id, title: node.title, icon: node.icon };
351
429
  if (node.badge !== undefined) descriptor.badge = node.badge;
352
430
  for (const key of Object.keys(node.data)) descriptor[key] = node.data[key];
353
431
  descriptor.disabled = node.disabled;
@@ -377,18 +455,19 @@ class SidebarNav {
377
455
  #siblingsOf(node) {
378
456
  const parent = this.#parentNode(node);
379
457
  if (parent !== undefined) return parent.children;
380
- for (const entry of this.#items) if (entry.type === "section" && entry.children.includes(node)) return entry.children;
458
+ for (const entry of this.#items)
459
+ if (entry.type === "section" && entry.children.includes(node)) return entry.children;
381
460
  return this.#items;
382
461
  }
383
462
 
384
463
  #accessibleName() {
385
- if (this.#title_text !== undefined && this.#title_text !== "") return this.#title_text;
386
- if (this.#label_text !== undefined && this.#label_text !== "") return this.#label_text;
464
+ if (this.#titleText !== undefined && this.#titleText !== "") return this.#titleText;
465
+ if (this.#labelText !== undefined && this.#labelText !== "") return this.#labelText;
387
466
  return I18n.t("navigation.sidebarNav");
388
467
  }
389
468
 
390
469
  #syncLabel() {
391
- if (this.#title_text !== undefined && this.#title_text !== "") {
470
+ if (this.#titleText !== undefined && this.#titleText !== "") {
392
471
  this.#root.setAttribute("aria-labelledby", this.#title.id);
393
472
  this.#root.removeAttribute("aria-label");
394
473
  return;
@@ -420,7 +499,7 @@ class SidebarNav {
420
499
  // Пункты пересобираются: запоминаем, где стоял фокус, чтобы вернуть его
421
500
  const active = document.activeElement;
422
501
  const focused = active === null || !this.#root.contains(active) ? null : active.closest(".sidebar_nav_link");
423
- if (focused !== null) this.#focus_id = focused.dataset.id;
502
+ if (focused !== null) this.#focusId = focused.dataset.id;
424
503
  this.#body.innerHTML = "";
425
504
  this.#head.hidden = this.#title.hidden === true && this.#collapse === undefined;
426
505
  this.#body.appendChild(this.#listsNode(this.#items));
@@ -549,13 +628,13 @@ class SidebarNav {
549
628
  const list = this.#visibleLinks();
550
629
  if (list.length === 0) return;
551
630
  const stop =
552
- list.find((link) => link.dataset.id === this.#active_id) ??
553
- list.find((link) => link.dataset.id === this.#focus_id) ??
631
+ list.find((link) => link.dataset.id === this.#activeId) ??
632
+ list.find((link) => link.dataset.id === this.#focusId) ??
554
633
  list[0];
555
- this.#active_id = stop.dataset.id;
634
+ this.#activeId = stop.dataset.id;
556
635
  for (const link of this.#links()) link.setAttribute("tabindex", link === stop ? "0" : "-1");
557
- if (this.#focus_id !== undefined && stop.dataset.id === this.#focus_id) {
558
- this.#focus_id = undefined;
636
+ if (this.#focusId !== undefined && stop.dataset.id === this.#focusId) {
637
+ this.#focusId = undefined;
559
638
  stop.focus();
560
639
  }
561
640
  return this;
@@ -564,7 +643,7 @@ class SidebarNav {
564
643
  #focusLink(id = String()) {
565
644
  const link = this.#links().find((node) => node.dataset.id === id);
566
645
  if (link === undefined) return;
567
- this.#active_id = id;
646
+ this.#activeId = id;
568
647
  for (const other of this.#links()) other.setAttribute("tabindex", other === link ? "0" : "-1");
569
648
  link.focus();
570
649
  }
@@ -597,14 +676,14 @@ class SidebarNav {
597
676
  const node = this.#value === undefined ? undefined : this.#index.get(this.#value);
598
677
  const item = node === undefined ? undefined : this.#describe(node);
599
678
  for (const listener of [...this.#listeners]) listener(item, this);
600
- if (this.#on_select !== undefined) this.#on_select(item, this);
679
+ if (this.#onSelect !== undefined) this.#onSelect(item, this);
601
680
  }
602
681
 
603
682
  #currentLink(target = undefined) {
604
683
  const link = target === undefined ? null : target.closest(".sidebar_nav_link");
605
684
  if (link !== null && link !== undefined) return link;
606
- const id = this.#active_id;
607
- return id === undefined ? null : this.#links().find((node) => node.dataset.id === id) ?? null;
685
+ const id = this.#activeId;
686
+ return id === undefined ? null : (this.#links().find((node) => node.dataset.id === id) ?? null);
608
687
  }
609
688
 
610
689
  #onClick = (event) => {
@@ -663,4 +742,4 @@ class SidebarNav {
663
742
  };
664
743
  }
665
744
 
666
- exports.SidebarNav = SidebarNav
745
+ exports.SidebarNav = SidebarNav;
@@ -8,9 +8,9 @@ chui_sidebar_nav {
8
8
  width: 260px;
9
9
  max-width: 100%;
10
10
  height: max-content;
11
- margin: var(--margin);
11
+ margin: var(--block_margin);
12
12
  border: 1px solid var(--border_color);
13
- border-radius: var(--border_radius);
13
+ border-radius: var(--radius_sm);
14
14
  background: var(--element_background_2);
15
15
  color: var(--text_color);
16
16
  }
@@ -223,7 +223,7 @@ chui_sidebar_nav {
223
223
  .sidebar_nav_arrow chui_icon {
224
224
  color: inherit;
225
225
  font-size: 18px;
226
- transition: transform var(--transition_time) ease;
226
+ transition: transform var(--motion_base) var(--motion_ease);
227
227
  }
228
228
 
229
229
  /* Раскрытие показывает стрелка: состояние берётся из aria-expanded самого пункта */
@@ -238,6 +238,12 @@ chui_sidebar_nav {
238
238
  .sidebar_nav_panel {
239
239
  display: block;
240
240
  padding-inline-start: 14px;
241
+ /* Высоту списка ведёт компонент (`max-height` инлайном: её знает только раскладка),
242
+ а время и кривую берут токены движения. Свойство `transition` на элементе заменяет
243
+ общий список целиком — у самой панели других переходов нет, список короткий и намеренный */
244
+ transition:
245
+ max-height var(--motion_base) var(--motion_ease),
246
+ opacity var(--motion_base) var(--motion_ease);
241
247
  }
242
248
 
243
249
  .sidebar_nav_panel[hidden] {