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,8 +1,8 @@
1
- const {Animation} = require('../../modules/chui_animations/animations');
2
- const {OverlayA11y} = require('../../modules/chui_a11y/chui_a11y');
3
- const {Icon} = require('../chui_icons/icons');
4
- const {setStyles, optionOr} = require('../../modules/chui_functions');
5
- const {I18n} = require('../../modules/chui_i18n/chui_i18n');
1
+ const { Animation } = require("../../modules/chui_animations/animations");
2
+ const { OverlayA11y } = require("../../modules/chui_a11y/chui_a11y");
3
+ const { Icon } = require("../chui_icons/icons");
4
+ const { setStyles, optionOr } = require("../../modules/chui_functions");
5
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
6
6
 
7
7
  /**
8
8
  * Список действий из нижней части экрана (action sheet): заголовок, пояснение,
@@ -43,7 +43,7 @@ const {I18n} = require('../../modules/chui_i18n/chui_i18n');
43
43
  class ActionSheet {
44
44
  static STYLE = {
45
45
  DEFAULT: "default",
46
- DESTRUCTIVE: "destructive"
46
+ DESTRUCTIVE: "destructive",
47
47
  };
48
48
  static #counter = 0;
49
49
 
@@ -55,34 +55,43 @@ class ActionSheet {
55
55
  #head = document.createElement("action_sheet_head");
56
56
  #title = document.createElement("action_sheet_title");
57
57
  #message = document.createElement("action_sheet_message");
58
- #actions_node = document.createElement("action_sheet_actions");
58
+ #actionsNode = document.createElement("action_sheet_actions");
59
59
  #cancel = document.createElement("button");
60
60
  #actions = [];
61
61
  #rows = [];
62
- #cancel_text = undefined;
62
+ #cancelText = undefined;
63
63
  #closable = true;
64
- #close_outside = true;
65
- #labelled_by_title = false;
64
+ #closeOutside = true;
65
+ #labelledByTitle = false;
66
66
  #chosen = undefined;
67
67
  #a11y = undefined;
68
- #on_select = undefined;
69
- #on_close = undefined;
68
+ #onSelect = undefined;
69
+ #onClose = undefined;
70
70
  isOpen = false;
71
71
 
72
- constructor(options = {
73
- id: String(), title: String(), message: String(), label: String(), actions: [],
74
- cancelText: String(), closable: Boolean(), closeOnOutsideClick: Boolean(),
75
- onSelect: undefined, onClose: undefined
76
- }) {
72
+ constructor(
73
+ options = {
74
+ id: String(),
75
+ title: String(),
76
+ message: String(),
77
+ label: String(),
78
+ actions: [],
79
+ cancelText: String(),
80
+ closable: Boolean(),
81
+ closeOnOutsideClick: Boolean(),
82
+ onSelect: undefined,
83
+ onClose: undefined,
84
+ }
85
+ ) {
77
86
  setStyles(__dirname + "/styles.css", "chUiJS_ActionSheet");
78
87
  ActionSheet.#counter += 1;
79
88
  this.#id = options.id === undefined ? `chui_action_sheet_${ActionSheet.#counter}` : options.id;
80
89
  this.#sheet.id = this.#id;
81
90
  this.#closable = options.closable !== false;
82
- if (options.closeOnOutsideClick !== undefined) this.#close_outside = options.closeOnOutsideClick !== false;
83
- this.#cancel_text = options.cancelText;
84
- this.#on_select = options.onSelect;
85
- this.#on_close = options.onClose;
91
+ if (options.closeOnOutsideClick !== undefined) this.#closeOutside = options.closeOnOutsideClick !== false;
92
+ this.#cancelText = options.cancelText;
93
+ this.#onSelect = options.onSelect;
94
+ this.#onClose = options.onClose;
86
95
 
87
96
  this.#title.id = `${this.#id}_title`;
88
97
  this.#message.id = `${this.#id}_message`;
@@ -91,21 +100,21 @@ class ActionSheet {
91
100
  this.#cancel.addEventListener("click", this.#onCancelClick);
92
101
 
93
102
  this.#group.appendChild(this.#head);
94
- this.#group.appendChild(this.#actions_node);
103
+ this.#group.appendChild(this.#actionsNode);
95
104
  this.#panel.appendChild(this.#group);
96
105
  this.#panel.appendChild(this.#cancel);
97
106
  this.#sheet.appendChild(this.#panel);
98
107
  document.body.appendChild(this.#sheet);
99
108
  // Заголовок в разметке — имя слоя; иначе имя берётся из label или словаря
100
109
  const title = optionOr(options.title, undefined);
101
- this.#labelled_by_title = title !== undefined;
110
+ this.#labelledByTitle = title !== undefined;
102
111
  if (title !== undefined) this.setTitle(title);
103
112
  if (optionOr(options.message, undefined) !== undefined) this.setMessage(options.message);
104
113
  this.#a11y = new OverlayA11y(this.#sheet, {
105
114
  role: "dialog",
106
- labelNode: this.#labelled_by_title ? this.#title : undefined,
107
- label: this.#labelled_by_title ? undefined : optionOr(options.label, I18n.t("feedback.actionSheet")),
108
- onEscape: () => this.close()
115
+ labelNode: this.#labelledByTitle ? this.#title : undefined,
116
+ label: this.#labelledByTitle ? undefined : optionOr(options.label, I18n.t("feedback.actionSheet")),
117
+ onEscape: () => this.close(),
109
118
  });
110
119
  this.#syncCancelText();
111
120
  this.setActions(options.actions === undefined ? [] : options.actions);
@@ -116,18 +125,28 @@ class ActionSheet {
116
125
  }
117
126
 
118
127
  // GET
119
- getId() { return this.#id; }
120
- getTitle() { return this.#title.innerText; }
121
- getMessage() { return this.#message.innerText; }
128
+ getId() {
129
+ return this.#id;
130
+ }
131
+ getTitle() {
132
+ return this.#title.innerText;
133
+ }
134
+ getMessage() {
135
+ return this.#message.innerText;
136
+ }
122
137
  /** Описания действий — те же объекты, что вернула фабрика `ActionSheet.Item` */
123
- getActions() { return [...this.#actions]; }
124
- getCancelText() { return this.#cancel.innerText; }
138
+ getActions() {
139
+ return [...this.#actions];
140
+ }
141
+ getCancelText() {
142
+ return this.#cancel.innerText;
143
+ }
125
144
 
126
145
  // SET
127
146
  setTitle(text = String()) {
128
147
  this.#title.innerText = text;
129
148
  this.#syncHead();
130
- if (!this.#labelled_by_title) this.#a11y.setLabel(text);
149
+ if (!this.#labelledByTitle) this.#a11y.setLabel(text);
131
150
  return this;
132
151
  }
133
152
  setMessage(text = String()) {
@@ -136,7 +155,7 @@ class ActionSheet {
136
155
  return this;
137
156
  }
138
157
  setCancelText(text = String()) {
139
- this.#cancel_text = text;
158
+ this.#cancelText = text;
140
159
  this.#syncCancelText();
141
160
  return this;
142
161
  }
@@ -144,7 +163,7 @@ class ActionSheet {
144
163
  setActions(actions = []) {
145
164
  this.#actions = [];
146
165
  this.#rows = [];
147
- this.#actions_node.innerHTML = "";
166
+ this.#actionsNode.innerHTML = "";
148
167
  for (const action of actions) this.#appendAction(action);
149
168
  return this;
150
169
  }
@@ -158,6 +177,7 @@ class ActionSheet {
158
177
  this.isOpen = true;
159
178
  this.#chosen = undefined;
160
179
  this.#panel.style.animationName = "action_sheet_in";
180
+ this.#panel.dataset.motion = "enter";
161
181
  new Animation(this.#sheet).fadeIn();
162
182
  this.#a11y.open();
163
183
  return this;
@@ -171,8 +191,9 @@ class ActionSheet {
171
191
  this.isOpen = false;
172
192
  this.#a11y.close();
173
193
  this.#panel.style.animationName = "action_sheet_out";
194
+ this.#panel.dataset.motion = "exit";
174
195
  new Animation(this.#sheet).fadeOut();
175
- if (this.#chosen === undefined && this.#on_close !== undefined) this.#on_close();
196
+ if (this.#chosen === undefined && this.#onClose !== undefined) this.#onClose();
176
197
  return this;
177
198
  }
178
199
  /** Полное удаление: закрыть слой, снять слушатели и убрать занавес из документа */
@@ -184,24 +205,32 @@ class ActionSheet {
184
205
  this.#sheet.remove();
185
206
  return this;
186
207
  }
187
- set() { return this.#sheet; }
208
+ set() {
209
+ return this.#sheet;
210
+ }
188
211
 
189
212
  /** Готовое обещание: выбор даёт описание действия (`value` — ваше поле), отмена — `undefined`.
190
213
  * Временный слой после ответа убирается: иначе каждый вызов оставлял бы узел в документе */
191
214
  static show(options = {}) {
192
215
  return new Promise((resolve) => {
193
- let sheet;
194
- const answer = (value) => { resolve(value); sheet.destroy(); };
195
- sheet = new ActionSheet(Object.assign({}, options, {
196
- onSelect: (action, index) => {
197
- if (options.onSelect !== undefined) options.onSelect(action, index);
198
- answer(action);
199
- },
200
- onClose: () => {
201
- if (options.onClose !== undefined) options.onClose();
202
- answer(undefined);
203
- }
204
- }));
216
+ const answer = (value) => {
217
+ resolve(value);
218
+ sheet.destroy();
219
+ };
220
+ // Слой собирается один раз, и `answer` зовут только после сборки:
221
+ // к моменту вызова имя уже определено, поэтому здесь можно `const`
222
+ const sheet = new ActionSheet(
223
+ Object.assign({}, options, {
224
+ onSelect: (action, index) => {
225
+ if (options.onSelect !== undefined) options.onSelect(action, index);
226
+ answer(action);
227
+ },
228
+ onClose: () => {
229
+ if (options.onClose !== undefined) options.onClose();
230
+ answer(undefined);
231
+ },
232
+ })
233
+ );
205
234
  sheet.open();
206
235
  });
207
236
  }
@@ -230,45 +259,45 @@ class ActionSheet {
230
259
  row.addEventListener("click", () => this.#choose(action, this.#actions.indexOf(action)));
231
260
  this.#actions.push(action);
232
261
  this.#rows.push(row);
233
- this.#actions_node.appendChild(row);
262
+ this.#actionsNode.appendChild(row);
234
263
  return row;
235
264
  }
236
265
  #choose(action = {}, index = -1) {
237
266
  if (action.disabled === true) return;
238
267
  this.#chosen = action;
239
268
  if (action.onClick !== undefined) action.onClick(action, index);
240
- if (this.#on_select !== undefined) this.#on_select(action, index);
269
+ if (this.#onSelect !== undefined) this.#onSelect(action, index);
241
270
  this.close();
242
271
  }
243
272
  #onCancelClick = () => this.close();
244
273
  #onSheetClick = (event) => {
245
- if (!this.#close_outside || event.target !== this.#sheet) return;
274
+ if (!this.#closeOutside || event.target !== this.#sheet) return;
246
275
  this.close();
247
- }
276
+ };
248
277
  // После анимации имя снимается: иначе следующий показ не проиграется заново
249
278
  #onPanelAnimationEnd = (event) => {
250
279
  if (event.target !== this.#panel) return;
251
280
  this.#panel.style.animationName = "";
252
- }
281
+ };
253
282
  /** Заголовок и пояснение показываются, только когда заданы; пояснение — описание слоя */
254
283
  #syncHead() {
255
- const has_title = this.#title.innerText.trim() !== "";
256
- const has_message = this.#message.innerText.trim() !== "";
257
- if (has_title && this.#title.parentElement === null) this.#head.appendChild(this.#title);
258
- if (!has_title && this.#title.parentElement !== null) this.#title.remove();
259
- if (has_message && this.#message.parentElement === null) this.#head.appendChild(this.#message);
260
- if (!has_message && this.#message.parentElement !== null) this.#message.remove();
261
- this.#head.style.display = has_title || has_message ? "" : "none";
262
- if (has_message) this.#sheet.setAttribute("aria-describedby", this.#message.id);
284
+ const hasTitle = this.#title.innerText.trim() !== "";
285
+ const hasMessage = this.#message.innerText.trim() !== "";
286
+ if (hasTitle && this.#title.parentElement === null) this.#head.appendChild(this.#title);
287
+ if (!hasTitle && this.#title.parentElement !== null) this.#title.remove();
288
+ if (hasMessage && this.#message.parentElement === null) this.#head.appendChild(this.#message);
289
+ if (!hasMessage && this.#message.parentElement !== null) this.#message.remove();
290
+ this.#head.style.display = hasTitle || hasMessage ? "" : "none";
291
+ if (hasMessage) this.#sheet.setAttribute("aria-describedby", this.#message.id);
263
292
  else this.#sheet.removeAttribute("aria-describedby");
264
293
  }
265
294
  #syncCancelText() {
266
- this.#cancel.innerText = this.#cancel_text === undefined ? I18n.t("common.cancel") : this.#cancel_text;
295
+ this.#cancel.innerText = this.#cancelText === undefined ? I18n.t("common.cancel") : this.#cancelText;
267
296
  this.#cancel.style.display = this.#closable ? "" : "none";
268
297
  }
269
298
  }
270
299
 
271
- exports.ActionSheet = ActionSheet
300
+ exports.ActionSheet = ActionSheet;
272
301
 
273
302
  // Описание действия собирает фабрика — как у ContextMenu и SplitButton
274
- ActionSheet.Item = (options = {}) => Object.assign({style: ActionSheet.STYLE.DEFAULT}, options);
303
+ ActionSheet.Item = (options = {}) => Object.assign({ style: ActionSheet.STYLE.DEFAULT }, options);
@@ -26,7 +26,13 @@ action_sheet_panel {
26
26
  width: min(480px, 100%);
27
27
  max-height: 80vh;
28
28
  overflow-y: auto;
29
- animation: action_sheet_in var(--transition_time) ease;
29
+ animation: action_sheet_in var(--motion_base) var(--motion_ease);
30
+ }
31
+
32
+ /* Вид движения ставит action_sheet.js: выезд идёт базовым временем из правила выше, а уход
33
+ берёт короткое — закрытие не задерживает следующий экран */
34
+ action_sheet_panel[data-motion="exit"] {
35
+ animation-duration: var(--motion_fast);
30
36
  }
31
37
 
32
38
  @keyframes action_sheet_in {
@@ -68,7 +74,7 @@ action_sheet_head {
68
74
  display: flex;
69
75
  flex-direction: column;
70
76
  gap: 2px;
71
- padding: var(--control_padding) var(--main_padding);
77
+ padding: var(--control_padding) var(--block_padding);
72
78
  text-align: center;
73
79
  border-bottom: 1px solid var(--border_color);
74
80
  }
@@ -102,7 +108,7 @@ action_sheet_actions {
102
108
  width: 100%;
103
109
  box-sizing: border-box;
104
110
  min-height: 44px;
105
- padding: var(--main_padding);
111
+ padding: var(--block_padding);
106
112
  background: transparent;
107
113
  border: none;
108
114
  border-top: 1px solid var(--border_color);
@@ -121,7 +127,8 @@ action_sheet_actions .action_sheet_action:first-child {
121
127
  }
122
128
 
123
129
  .action_sheet_action:active {
124
- background: var(--element_background_prime); color: var(--text_color_hover);
130
+ background: var(--element_background_prime);
131
+ color: var(--text_color_hover);
125
132
  }
126
133
 
127
134
  .action_sheet_action:disabled {
@@ -171,7 +178,7 @@ action_sheet_action_description {
171
178
  width: 100%;
172
179
  box-sizing: border-box;
173
180
  min-height: 44px;
174
- padding: var(--main_padding);
181
+ padding: var(--block_padding);
175
182
  border-radius: var(--radius_md);
176
183
  background: var(--modal_background);
177
184
  border: 1px solid var(--border_color);
@@ -0,0 +1,338 @@
1
+ const { Icon } = require("../chui_icons/icons");
2
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
3
+ const { Toolbar } = require("../chui_toolbar/toolbar");
4
+ const { optionOr, setStyles } = require("../../modules/chui_functions");
5
+
6
+ /**
7
+ * Действие панели: значок с подписью, состоянием переключателя и счётчиком.
8
+ *
9
+ * Это настоящий `<button>`: клавиатура, фокус и роль у него уже есть. Переключатель
10
+ * (`toggle`) объявляет себя `aria-pressed` — «закреплено», «без звука» это состояние,
11
+ * а не действие, и скринридер обязан его читать. Опасное действие (удалить, очистить)
12
+ * помечается `danger` — подписью красного цвета, без отдельной иконки-предупреждения.
13
+ */
14
+ class ActionsBarButton {
15
+ static #counter = 0;
16
+
17
+ #root = document.createElement("button");
18
+ #iconNode = document.createElement("actions_bar_button_icon");
19
+ #text = document.createElement("actions_bar_button_text");
20
+ #badge = document.createElement("actions_bar_badge");
21
+ #id = undefined;
22
+ #label = undefined;
23
+ #active = false;
24
+ #toggle = false;
25
+ #disabled = false;
26
+ #danger = false;
27
+ #onClick = undefined;
28
+ #onToggle = undefined;
29
+
30
+ constructor(options = {}) {
31
+ const id = optionOr(options.id, undefined);
32
+ this.#id = id === undefined ? String((ActionsBarButton.#counter += 1)) : String(id);
33
+ this.#label = options.label === undefined ? "" : String(options.label);
34
+ this.#toggle = options.toggle === true;
35
+ this.#danger = options.danger === true;
36
+ this.#onClick = typeof options.onClick === "function" ? options.onClick : undefined;
37
+ // Свой слушатель состояния — им о переключении узнаёт панель (публичного `onToggle` нет)
38
+ this.#onToggle = typeof options.onToggle === "function" ? options.onToggle : undefined;
39
+ this.#root.type = "button";
40
+ this.#root.className = "actions_bar_button";
41
+ this.#root.dataset.id = this.#id;
42
+ if (optionOr(options.icon, undefined) !== undefined)
43
+ this.#iconNode.innerHTML = new Icon(options.icon, "18px").getHTML();
44
+ this.#iconNode.setAttribute("aria-hidden", "true");
45
+ this.#text.innerText = this.#label;
46
+ this.#root.append(this.#iconNode, this.#text);
47
+ // Значка нет — кнопка подписью не обходится: имя ей даёт подсказка или словарь
48
+ if (this.#label === "") this.setLabel(optionOr(options.hint, I18n.t("feedback.actionsBarButton")));
49
+ else this.#syncName();
50
+ if (this.#danger === true) this.#root.dataset.danger = "true";
51
+ if (this.#toggle === true) this.setActive(options.active === true);
52
+ if (options.badge !== undefined) this.setBadge(options.badge);
53
+ if (options.disabled === true) this.setDisabled(true);
54
+ this.#root.addEventListener("click", () => {
55
+ if (this.#disabled === true) return;
56
+ if (this.#toggle === true) {
57
+ this.setActive(this.#active === false);
58
+ if (this.#onToggle !== undefined) this.#onToggle(this);
59
+ }
60
+ if (this.#onClick !== undefined) this.#onClick(this, this.#active);
61
+ });
62
+ }
63
+
64
+ getId() {
65
+ return this.#id;
66
+ }
67
+ getLabel() {
68
+ return this.#text.innerText;
69
+ }
70
+ /** Переключатель включён: «закреплено», «без звука» */
71
+ isActive() {
72
+ return this.#active;
73
+ }
74
+ isDisabled() {
75
+ return this.#disabled;
76
+ }
77
+
78
+ /**
79
+ * Состояние переключателя: видно подложкой, скринридеру — через `aria-pressed`.
80
+ * У обычного действия состояния нет: `setActive` на нём ничего не делает — подсветка
81
+ * без программного состояния читалась бы как выбранное действие
82
+ */
83
+ setActive(boolean = Boolean()) {
84
+ if (this.#toggle !== true) return this;
85
+ this.#active = boolean === true;
86
+ this.#root.dataset.active = this.#active ? "true" : "false";
87
+ this.#root.setAttribute("aria-pressed", this.#active ? "true" : "false");
88
+ return this;
89
+ }
90
+ setDisabled(boolean = Boolean()) {
91
+ this.#disabled = boolean === true;
92
+ this.#root.disabled = this.#disabled;
93
+ return this;
94
+ }
95
+ /** Счётчик действия: число показывает плашка, скринридеру оно попадает в имя */
96
+ setBadge(count = Number()) {
97
+ const value = Number(count);
98
+ const shown = Number.isFinite(value) && value > 0 ? String(value) : "";
99
+ this.#badge.innerText = shown;
100
+ this.#badge.hidden = shown === "";
101
+ if (shown !== "" && this.#badge.parentNode === null) this.#root.appendChild(this.#badge);
102
+ this.#syncName(shown);
103
+ return this;
104
+ }
105
+ setLabel(text = String()) {
106
+ const label = String(text);
107
+ if (this.#label === "") {
108
+ // Кнопка без подписи: имя живёт только в атрибутах и подсказке
109
+ this.#root.setAttribute("aria-label", label);
110
+ this.#root.title = label;
111
+ return this;
112
+ }
113
+ this.#root.setAttribute("aria-label", label);
114
+ this.#text.innerText = label;
115
+ return this;
116
+ }
117
+ /** Имя кнопки: своя подпись или значок с подсказкой, плюс счётчик, если он есть */
118
+ #syncName(count = undefined) {
119
+ if (this.#label === "") return;
120
+ const shown = count === undefined ? (this.#badge.hidden ? "" : this.#badge.innerText) : count;
121
+ this.#root.setAttribute(
122
+ "aria-label",
123
+ shown === "" ? this.#label : `${this.#label}, ${I18n.t("feedback.actionsBarBadge", { value: shown })}`
124
+ );
125
+ }
126
+
127
+ set() {
128
+ return this.#root;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Панель действий — что можно сделать с тем, о чём сейчас речь.
134
+ *
135
+ * Пятая часть мессенджера: список разговоров слева, шапка разговора, **панель действий**,
136
+ * лента сообщений и панель ввода — так собирается экран переписки. Панель ставят и под
137
+ * шапкой разговора, и в карточке файла или профиля: она не полагает, о чём именно действия.
138
+ *
139
+ * Действия — подписанные кнопки со значком: «Закрепить», «Без звука», «Найти в переписке»,
140
+ * «Очистить историю». Часть из них — переключатели (`toggle: true`): у них есть состояние,
141
+ * и оно объявляется `aria-pressed`, а видно по подложке. Опасное действие помечается
142
+ * `danger: true` — подписью красного цвета.
143
+ *
144
+ * Панель держит `Toolbar` внутри: стрелки ←/→ ходят по действиям, Home и End ведут к краям,
145
+ * а Tab проходит по кнопкам по очереди — каждая из них настоящий `<button>`, как у полосы
146
+ * пользователя и панели ввода. Строка клавиатуры внутри панели своей кромки не рисует:
147
+ * панель и полоса — одна поверхность, и вложенная ступень здесь была бы лишней.
148
+ *
149
+ * ```javascript
150
+ * const actions = new ActionsBar({
151
+ * title: 'Разговор',
152
+ * actions: [
153
+ * { id: 'pin', icon: Icons.CONTENT.PUSH_PIN, label: 'Закрепить', toggle: true },
154
+ * { id: 'mute', icon: Icons.SOCIAL.NOTIFICATIONS_OFF, label: 'Без звука', toggle: true, active: true },
155
+ * { id: 'find', icon: Icons.ACTIONS.SEARCH, label: 'Найти в переписке', onClick: () => find() },
156
+ * { id: 'clear', icon: Icons.ACTIONS.DELETE, label: 'Очистить историю', danger: true, onClick: () => clear() },
157
+ * ],
158
+ * onChange: (button) => Log.info(button.getId(), button.isActive()),
159
+ * });
160
+ * ```
161
+ *
162
+ * Опции: `id`, `title`, `label`, `orientation`, `actions`, `onChange`.
163
+ * Действие: `{ id, icon, label, hint, badge, toggle, active, danger, disabled, onClick }`;
164
+ * фабрика — `ActionsBar.Button(...)`.
165
+ * API: `setTitle(text)`, `getTitle()`, `setLabel(text)`, `setOrientation(o)`, `getOrientation()`,
166
+ * `addAction(options)`, `removeAction(id)`, `setActions(list)`, `clear()`, `getActions()`,
167
+ * `getAction(id)`, `setActive(id, bool)`, `toggle(id)`, `getActive()`, `setDisabled(id, bool)`,
168
+ * `setBadge(id, count)`, `getToolbar()`, `set()`, `destroy()`.
169
+ * Константа: `ActionsBar.ORIENTATION.{HORIZONTAL, VERTICAL}`.
170
+ *
171
+ * **Строка или столбец.** По умолчанию действия идут строкой с переносом — так панель стоит
172
+ * под шапкой разговора. `ORIENTATION.VERTICAL` ставит их столбцом во всю ширину, как пункты
173
+ * меню: в таком виде панель кладут в выпадающее меню — например, в кнопку «⋯» полосы
174
+ * пользователя (`UserBar({ menu: [...] })`), и отдельная полоса в шапке не нужна.
175
+ */
176
+ class ActionsBar {
177
+ /** Фабрика действия: `ActionsBar.Button({ icon, label, toggle, danger, onClick })` */
178
+ static Button = (options = {}) => new ActionsBarButton(options);
179
+ static ORIENTATION = Toolbar.ORIENTATION;
180
+ static #counter = 0;
181
+
182
+ #id = undefined;
183
+ #root = document.createElement("chui_actions_bar");
184
+ #title = document.createElement("actions_bar_title");
185
+ #toolbar = undefined;
186
+ #actions = [];
187
+ #label = undefined;
188
+ #orientation = undefined;
189
+ #onChange = undefined;
190
+
191
+ constructor(
192
+ options = {
193
+ id: String(),
194
+ title: String(),
195
+ label: String(),
196
+ orientation: String(),
197
+ actions: [],
198
+ onChange: undefined,
199
+ }
200
+ ) {
201
+ setStyles(__dirname + "/styles.css", "chUiJS_ActionsBar");
202
+ ActionsBar.#counter += 1;
203
+ this.#id = options.id === undefined ? `chui_actions_bar_${ActionsBar.#counter}` : options.id;
204
+ this.#root.id = this.#id;
205
+ this.#label = options.label;
206
+ this.#onChange = typeof options.onChange === "function" ? options.onChange : undefined;
207
+ this.#toolbar = new Toolbar({ label: this.#labelText() });
208
+ this.setOrientation(
209
+ options.orientation === undefined ? ActionsBar.ORIENTATION.HORIZONTAL : options.orientation
210
+ );
211
+ this.#title.hidden = true;
212
+ this.#root.append(this.#title, this.#toolbar.set());
213
+ if (options.title !== undefined) this.setTitle(options.title);
214
+ if (Array.isArray(options.actions)) for (const action of options.actions) this.addAction(action);
215
+ }
216
+
217
+ // GET
218
+ getId() {
219
+ return this.#id;
220
+ }
221
+ getTitle() {
222
+ return this.#title.hidden ? "" : this.#title.innerText;
223
+ }
224
+ getOrientation() {
225
+ return this.#orientation;
226
+ }
227
+ getActions() {
228
+ return this.#actions.slice();
229
+ }
230
+ getAction(id = String()) {
231
+ return this.#actions.find((button) => button.getId() === String(id));
232
+ }
233
+ /** Идентификаторы включённых переключателей — состояние панели одним списком */
234
+ getActive() {
235
+ return this.#actions.filter((button) => button.isActive() === true).map((button) => button.getId());
236
+ }
237
+ /** Полоса действий: нужна тому, кто ставит в панель своё рядом с кнопками */
238
+ getToolbar() {
239
+ return this.#toolbar;
240
+ }
241
+
242
+ // SET
243
+ /** Подпись панели: над действиями, объясняет, к чему они относятся */
244
+ setTitle(text = String()) {
245
+ this.#title.innerText = String(text);
246
+ this.#title.hidden = this.#title.innerText.trim() === "";
247
+ return this;
248
+ }
249
+ /** Имя панели для скринридера: по умолчанию — общая подпись из словаря */
250
+ setLabel(text = String()) {
251
+ this.#label = text;
252
+ this.#toolbar.setLabel(this.#labelText());
253
+ return this;
254
+ }
255
+ /**
256
+ * Строка или столбец: столбец — вид меню, в нём действия идут во всю ширину.
257
+ * Ориентацию несёт и полоса внутри (`Toolbar`), и сама панель — по ней считаются отступы
258
+ */
259
+ setOrientation(orientation = String()) {
260
+ this.#orientation =
261
+ orientation === ActionsBar.ORIENTATION.VERTICAL
262
+ ? ActionsBar.ORIENTATION.VERTICAL
263
+ : ActionsBar.ORIENTATION.HORIZONTAL;
264
+ this.#root.dataset.orientation = this.#orientation;
265
+ this.#toolbar.setOrientation(this.#orientation);
266
+ return this;
267
+ }
268
+ setActions(actions = []) {
269
+ this.clear();
270
+ for (const action of actions) this.addAction(action);
271
+ return this;
272
+ }
273
+ addAction(options = {}) {
274
+ const button =
275
+ options instanceof ActionsBarButton
276
+ ? options
277
+ : new ActionsBarButton(Object.assign({}, options, { onToggle: (instance) => this.#notify(instance) }));
278
+ this.#actions.push(button);
279
+ this.#toolbar.add(button);
280
+ return button;
281
+ }
282
+ removeAction(id = String()) {
283
+ const index = this.#actions.findIndex((button) => button.getId() === String(id));
284
+ if (index === -1) return this;
285
+ const [button] = this.#actions.splice(index, 1);
286
+ button.set().remove();
287
+ return this;
288
+ }
289
+ clear() {
290
+ for (const button of this.#actions) button.set().remove();
291
+ this.#actions = [];
292
+ return this;
293
+ }
294
+ /** Включить или выключить переключатель из кода: состояние то же, что после щелчка */
295
+ setActive(id = String(), boolean = Boolean()) {
296
+ const button = this.getAction(id);
297
+ if (button === undefined || button.isActive() === boolean) return this;
298
+ button.setActive(boolean);
299
+ this.#notify(button);
300
+ return this;
301
+ }
302
+ toggle(id = String()) {
303
+ const button = this.getAction(id);
304
+ if (button === undefined) return this;
305
+ return this.setActive(id, button.isActive() === false);
306
+ }
307
+ setDisabled(id = String(), boolean = Boolean()) {
308
+ const button = this.getAction(id);
309
+ if (button !== undefined) button.setDisabled(boolean);
310
+ return this;
311
+ }
312
+ setBadge(id = String(), count = Number()) {
313
+ const button = this.getAction(id);
314
+ if (button !== undefined) button.setBadge(count);
315
+ return this;
316
+ }
317
+
318
+ set() {
319
+ return this.#root;
320
+ }
321
+ destroy() {
322
+ this.#actions = [];
323
+ this.#onChange = undefined;
324
+ this.#root.remove();
325
+ }
326
+
327
+ // === ВНУТРЕННЕЕ ===
328
+ /** О смене состояния сообщается один раз: и после щелчка, и после правки из кода */
329
+ #notify(button) {
330
+ if (this.#onChange !== undefined) this.#onChange(button, this);
331
+ }
332
+ #labelText() {
333
+ return optionOr(this.#label, undefined) === undefined ? I18n.t("feedback.actionsBar") : String(this.#label);
334
+ }
335
+ }
336
+
337
+ exports.ActionsBar = ActionsBar;
338
+ exports.ActionsBarButton = ActionsBarButton;