chuijs 4.0.3 → 4.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +536 -0
  2. package/framework/appLayout/default/chui_app_layout.js +361 -303
  3. package/framework/appLayout/default/global_style.css +243 -89
  4. package/framework/appLayout/default/main_theme_style.css +188 -101
  5. package/framework/components/chui_accordion/accordion.js +17 -17
  6. package/framework/components/chui_accordion/styles.css +7 -7
  7. package/framework/components/chui_action_sheet/action_sheet.js +35 -32
  8. package/framework/components/chui_action_sheet/styles.css +10 -4
  9. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  10. package/framework/components/chui_actions_bar/styles.css +139 -0
  11. package/framework/components/chui_affix/affix.js +4 -4
  12. package/framework/components/chui_affix/styles.css +5 -0
  13. package/framework/components/chui_alert/alert.js +11 -5
  14. package/framework/components/chui_alert/styles.css +7 -0
  15. package/framework/components/chui_avatar/avatar.js +13 -13
  16. package/framework/components/chui_avatar/styles.css +1 -1
  17. package/framework/components/chui_avatar_group/avatar_group.js +4 -4
  18. package/framework/components/chui_avatar_group/styles.css +1 -1
  19. package/framework/components/chui_backtop/backtop.js +25 -2
  20. package/framework/components/chui_backtop/styles.css +21 -0
  21. package/framework/components/chui_badge/badge.js +15 -15
  22. package/framework/components/chui_badge/styles.css +6 -6
  23. package/framework/components/chui_banner/banner.js +222 -0
  24. package/framework/components/chui_banner/styles.css +170 -0
  25. package/framework/components/chui_breadcrumb/styles.css +1 -1
  26. package/framework/components/chui_button/button.js +24 -28
  27. package/framework/components/chui_button/styles.css +5 -5
  28. package/framework/components/chui_calendar/calendar.js +6 -6
  29. package/framework/components/chui_card/card.js +14 -14
  30. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  31. package/framework/components/chui_card_scroll/styles.css +86 -0
  32. package/framework/components/chui_chat/chat.js +73 -51
  33. package/framework/components/chui_chat/styles.css +18 -7
  34. package/framework/components/chui_clipboard_history/clipboard_history.js +25 -20
  35. package/framework/components/chui_clipboard_history/styles.css +10 -8
  36. package/framework/components/chui_code/code.js +8 -8
  37. package/framework/components/chui_code/styles.css +2 -2
  38. package/framework/components/chui_code_editor/code_editor.js +26 -26
  39. package/framework/components/chui_code_editor/styles.css +3 -3
  40. package/framework/components/chui_command_palette/command_palette.js +29 -29
  41. package/framework/components/chui_command_palette/styles.css +5 -5
  42. package/framework/components/chui_console/console.js +9 -9
  43. package/framework/components/chui_console/styles.css +5 -2
  44. package/framework/components/chui_content_block/content_block.js +2 -2
  45. package/framework/components/chui_context_menu/context_menu.js +162 -54
  46. package/framework/components/chui_context_menu/styles.css +82 -8
  47. package/framework/components/chui_custom_element/custom_element.js +11 -11
  48. package/framework/components/chui_data_grid/data_grid.js +268 -268
  49. package/framework/components/chui_data_grid/styles.css +14 -14
  50. package/framework/components/chui_descriptions/styles.css +1 -1
  51. package/framework/components/chui_details/details.js +12 -12
  52. package/framework/components/chui_details/styles.css +7 -7
  53. package/framework/components/chui_diff_viewer/diff_viewer.js +88 -88
  54. package/framework/components/chui_diff_viewer/styles.css +9 -9
  55. package/framework/components/chui_divider/divider.js +6 -6
  56. package/framework/components/chui_divider/styles.css +2 -2
  57. package/framework/components/chui_drawer/drawer.js +37 -14
  58. package/framework/components/chui_drawer/styles.css +18 -4
  59. package/framework/components/chui_drop_zone/drop_zone.js +6 -6
  60. package/framework/components/chui_drop_zone/styles.css +10 -6
  61. package/framework/components/chui_fieldset/fieldset.js +6 -6
  62. package/framework/components/chui_fieldset/styles.css +5 -5
  63. package/framework/components/chui_file_explorer/file_explorer.js +115 -115
  64. package/framework/components/chui_file_explorer/styles.css +6 -6
  65. package/framework/components/chui_form/form.js +11 -11
  66. package/framework/components/chui_gantt/gantt.js +41 -41
  67. package/framework/components/chui_gantt/styles.css +5 -5
  68. package/framework/components/chui_graphs/graphs.js +82 -46
  69. package/framework/components/chui_graphs/styles.css +26 -5
  70. package/framework/components/chui_hero/hero.js +63 -20
  71. package/framework/components/chui_hero/styles.css +176 -7
  72. package/framework/components/chui_html_block/html_block.js +5 -5
  73. package/framework/components/chui_html_block/styles.css +1 -1
  74. package/framework/components/chui_hx/styles.css +2 -2
  75. package/framework/components/chui_icons/icons.js +7 -7
  76. package/framework/components/chui_icons/styles.css +2 -1
  77. package/framework/components/chui_inputs/chui_check_box/styles.css +12 -3
  78. package/framework/components/chui_inputs/chui_chips/chips.js +92 -31
  79. package/framework/components/chui_inputs/chui_chips/styles.css +28 -5
  80. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +20 -15
  81. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  82. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +58 -58
  83. package/framework/components/chui_inputs/chui_combo_box/styles.css +9 -9
  84. package/framework/components/chui_inputs/chui_date/date.js +93 -95
  85. package/framework/components/chui_inputs/chui_date/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_date_range/date_range.js +22 -22
  87. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  88. package/framework/components/chui_inputs/chui_datetime/datetime.js +12 -12
  89. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  90. package/framework/components/chui_inputs/chui_email/email.js +10 -10
  91. package/framework/components/chui_inputs/chui_email/styles.css +6 -6
  92. package/framework/components/chui_inputs/chui_file/file.js +8 -8
  93. package/framework/components/chui_inputs/chui_file/styles.css +12 -9
  94. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +39 -39
  95. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_masked/masked.js +44 -44
  97. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  98. package/framework/components/chui_inputs/chui_mention/mention.js +13 -13
  99. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  100. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +147 -137
  101. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +14 -8
  102. package/framework/components/chui_inputs/chui_number/number.js +42 -45
  103. package/framework/components/chui_inputs/chui_number/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_otp/otp.js +32 -32
  105. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_password/password.js +30 -36
  107. package/framework/components/chui_inputs/chui_password/styles.css +7 -7
  108. package/framework/components/chui_inputs/chui_radio_button/styles.css +2 -2
  109. package/framework/components/chui_inputs/chui_rating/rating.js +28 -28
  110. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  111. package/framework/components/chui_inputs/chui_select_box/select_box.js +54 -54
  112. package/framework/components/chui_inputs/chui_select_box/styles.css +10 -10
  113. package/framework/components/chui_inputs/chui_slider/slider.js +14 -14
  114. package/framework/components/chui_inputs/chui_slider/styles.css +5 -4
  115. package/framework/components/chui_inputs/chui_text/styles.css +7 -7
  116. package/framework/components/chui_inputs/chui_text/text.js +13 -17
  117. package/framework/components/chui_inputs/chui_text_area/styles.css +8 -8
  118. package/framework/components/chui_inputs/chui_text_area/text_area.js +23 -23
  119. package/framework/components/chui_inputs/chui_time/styles.css +13 -17
  120. package/framework/components/chui_inputs/chui_time/time.js +35 -24
  121. package/framework/components/chui_inputs/chui_toggle/styles.css +10 -3
  122. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  123. package/framework/components/chui_json_editor/json_editor.js +87 -87
  124. package/framework/components/chui_json_editor/styles.css +5 -5
  125. package/framework/components/chui_json_viewer/json_viewer.js +80 -80
  126. package/framework/components/chui_json_viewer/styles.css +6 -6
  127. package/framework/components/chui_kanban/kanban.js +27 -27
  128. package/framework/components/chui_kanban/styles.css +8 -4
  129. package/framework/components/chui_kbd/styles.css +1 -1
  130. package/framework/components/chui_label/label.js +17 -17
  131. package/framework/components/chui_label/styles.css +1 -1
  132. package/framework/components/chui_link/link.js +9 -9
  133. package/framework/components/chui_link/styles.css +11 -4
  134. package/framework/components/chui_list/list.js +11 -11
  135. package/framework/components/chui_list/styles.css +2 -2
  136. package/framework/components/chui_markdown_editor/markdown_editor.js +66 -66
  137. package/framework/components/chui_markdown_editor/styles.css +5 -5
  138. package/framework/components/chui_media/audio.js +240 -246
  139. package/framework/components/chui_media/audio_styles.css +41 -23
  140. package/framework/components/chui_media/image.js +49 -46
  141. package/framework/components/chui_media/image_compare.js +35 -35
  142. package/framework/components/chui_media/image_compare_styles.css +5 -5
  143. package/framework/components/chui_media/image_styles.css +1 -1
  144. package/framework/components/chui_media/video.js +148 -148
  145. package/framework/components/chui_media/video_styles.css +27 -11
  146. package/framework/components/chui_menu_bar/menu_bar.js +54 -54
  147. package/framework/components/chui_menu_bar/styles.css +10 -10
  148. package/framework/components/chui_message_bar/message_bar.js +551 -0
  149. package/framework/components/chui_message_bar/styles.css +248 -0
  150. package/framework/components/chui_modal/modal.js +37 -13
  151. package/framework/components/chui_notification/notification.js +76 -54
  152. package/framework/components/chui_notification/notification_download.js +26 -81
  153. package/framework/components/chui_notification/notification_download_card.js +115 -0
  154. package/framework/components/chui_notification/notification_download_progress.css +2 -2
  155. package/framework/components/chui_notification/notification_download_progress.js +70 -108
  156. package/framework/components/chui_notification/notification_update.js +31 -31
  157. package/framework/components/chui_notification/status_plate.css +3 -3
  158. package/framework/components/chui_notification/styles.css +6 -1
  159. package/framework/components/chui_notification/styles_download.css +1 -1
  160. package/framework/components/chui_notification/styles_update.css +2 -2
  161. package/framework/components/chui_org_chart/org_chart.js +29 -29
  162. package/framework/components/chui_org_chart/styles.css +2 -2
  163. package/framework/components/chui_pagination/pagination.js +3 -3
  164. package/framework/components/chui_pagination/styles.css +1 -1
  165. package/framework/components/chui_paragraph/styles.css +2 -2
  166. package/framework/components/chui_popover/popover.js +29 -23
  167. package/framework/components/chui_popover/styles.css +1 -1
  168. package/framework/components/chui_popups/popups.js +124 -124
  169. package/framework/components/chui_popups/styles.css +5 -5
  170. package/framework/components/chui_print_button/print_button.js +15 -10
  171. package/framework/components/chui_progress_bar/progress_bar.js +34 -12
  172. package/framework/components/chui_progress_bar/styles.css +4 -4
  173. package/framework/components/chui_progress_ring/progress_ring.js +15 -15
  174. package/framework/components/chui_progress_ring/styles.css +1 -1
  175. package/framework/components/chui_qrcode/qrcode.js +12 -12
  176. package/framework/components/chui_query_builder/query_builder.js +46 -46
  177. package/framework/components/chui_query_builder/styles.css +4 -4
  178. package/framework/components/chui_radio_group/styles.css +1 -1
  179. package/framework/components/chui_result/result.js +15 -15
  180. package/framework/components/chui_result/styles.css +3 -3
  181. package/framework/components/chui_scheduler/scheduler.js +74 -74
  182. package/framework/components/chui_scheduler/styles.css +5 -5
  183. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  184. package/framework/components/chui_screen_spinner/styles.css +49 -0
  185. package/framework/components/chui_segmented_control/segmented_control.js +63 -6
  186. package/framework/components/chui_segmented_control/styles.css +32 -6
  187. package/framework/components/chui_settings/settings.js +45 -46
  188. package/framework/components/chui_settings/styles.css +4 -4
  189. package/framework/components/chui_shortcut_help/shortcut_help.js +32 -34
  190. package/framework/components/chui_sidebar_nav/sidebar_nav.js +98 -29
  191. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  192. package/framework/components/chui_slideshow/slideshow.js +85 -85
  193. package/framework/components/chui_slideshow/styles.css +6 -6
  194. package/framework/components/chui_spinner/spinner.js +10 -10
  195. package/framework/components/chui_split_button/split_button.js +30 -12
  196. package/framework/components/chui_split_button/styles.css +21 -5
  197. package/framework/components/chui_splitter/splitter.js +11 -11
  198. package/framework/components/chui_splitter/styles.css +2 -2
  199. package/framework/components/chui_statistic/statistic.js +47 -47
  200. package/framework/components/chui_status_bar/styles.css +2 -2
  201. package/framework/components/chui_stepper/stepper.js +202 -31
  202. package/framework/components/chui_stepper/styles.css +79 -14
  203. package/framework/components/chui_sticky_bar/sticky_bar.js +44 -13
  204. package/framework/components/chui_sticky_bar/styles.css +10 -8
  205. package/framework/components/chui_tabs/chui_tabs.js +74 -26
  206. package/framework/components/chui_tabs/styles.css +40 -12
  207. package/framework/components/chui_text_editor/styles.css +7 -7
  208. package/framework/components/chui_text_editor/text_editor.js +56 -56
  209. package/framework/components/chui_text_editor/text_editor_panel.js +173 -174
  210. package/framework/components/chui_theme_toggle/theme_toggle.js +21 -5
  211. package/framework/components/chui_timeline/styles.css +3 -1
  212. package/framework/components/chui_toast_queue/styles.css +11 -11
  213. package/framework/components/chui_toast_queue/toast_queue.js +30 -27
  214. package/framework/components/chui_toolbar/styles.css +2 -2
  215. package/framework/components/chui_tooltip/styles.css +2 -2
  216. package/framework/components/chui_tooltip/tooltip.js +3 -3
  217. package/framework/components/chui_tour/styles.css +8 -8
  218. package/framework/components/chui_tour/tour.js +72 -72
  219. package/framework/components/chui_transfer/styles.css +6 -6
  220. package/framework/components/chui_transfer/transfer.js +93 -106
  221. package/framework/components/chui_tree_table/styles.css +4 -4
  222. package/framework/components/chui_tree_table/tree_table.js +45 -45
  223. package/framework/components/chui_tree_view/styles.css +10 -8
  224. package/framework/components/chui_tree_view/tree_view.js +185 -183
  225. package/framework/components/chui_user_bar/styles.css +145 -0
  226. package/framework/components/chui_user_bar/user_bar.js +402 -0
  227. package/framework/components/chui_user_list_bar/styles.css +173 -0
  228. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  229. package/framework/components/chui_watermark/watermark.js +17 -17
  230. package/framework/components/chui_webview/webview.js +9 -9
  231. package/framework/components/chui_write_bar/styles.css +172 -0
  232. package/framework/components/chui_write_bar/write_bar.js +320 -0
  233. package/framework/main_window.js +1234 -0
  234. package/framework/modules/chui_a11y/chui_a11y.js +78 -79
  235. package/framework/modules/chui_animations/animations.js +77 -15
  236. package/framework/modules/chui_animations/motion.js +120 -0
  237. package/framework/modules/chui_animations/styles.css +36 -3
  238. package/framework/modules/chui_functions.js +31 -27
  239. package/framework/modules/chui_highlight/styles.css +13 -10
  240. package/framework/modules/chui_i18n/chui_i18n.js +3 -3
  241. package/framework/modules/chui_i18n/locales/feedback.js +62 -0
  242. package/framework/modules/chui_i18n/locales/navigation.js +4 -0
  243. package/framework/modules/chui_json/chui_json.js +2 -2
  244. package/framework/modules/chui_logger/chui_logger.js +23 -8
  245. package/framework/modules/chui_page/page.js +10 -10
  246. package/framework/modules/chui_palette/palette.js +61 -0
  247. package/framework/modules/chui_qr/chui_qr.js +23 -23
  248. package/framework/modules/chui_scrollbar/chui_scrollbar.js +45 -45
  249. package/framework/modules/chui_scrollbar/styles.css +3 -3
  250. package/framework/modules/chui_services/chui_services.js +8 -8
  251. package/framework/modules/chui_services/desktop.js +77 -71
  252. package/framework/modules/chui_sortable/chui_sortable.js +17 -17
  253. package/framework/modules/chui_validate/chui_validate.js +3 -3
  254. package/framework/tray_bar/chui_menu_items.js +2 -2
  255. package/index.d.ts +266 -34
  256. package/index.js +20 -1168
  257. package/package.json +6 -4
  258. package/framework/components/telegram_bot/chui_telegram_bot.js +0 -191
@@ -45,11 +45,11 @@ class Scheduler {
45
45
 
46
46
  #root = document.createElement("chui_scheduler");
47
47
  #title = document.createElement("scheduler_title");
48
- #prev_button = document.createElement("button");
49
- #next_button = document.createElement("button");
50
- #today_button = document.createElement("button");
51
- #view_buttons = new Map();
52
- #days_head = document.createElement("scheduler_days_head");
48
+ #prevButton = document.createElement("button");
49
+ #nextButton = document.createElement("button");
50
+ #todayButton = document.createElement("button");
51
+ #viewButtons = new Map();
52
+ #daysHead = document.createElement("scheduler_days_head");
53
53
  #scroll = document.createElement("scheduler_scroll");
54
54
  #times = document.createElement("scheduler_times");
55
55
  #days = document.createElement("scheduler_days");
@@ -57,15 +57,15 @@ class Scheduler {
57
57
  #date = new Date();
58
58
  #view = Scheduler.VIEW.WEEK;
59
59
  #events = [];
60
- #start_hour = 8;
61
- #end_hour = 20;
62
- #slot_minutes = Scheduler.DEFAULT_SLOT_MINUTES;
63
- #hour_height = Scheduler.DEFAULT_HOUR_HEIGHT;
64
- #first_day = Scheduler.DEFAULT_FIRST_DAY;
60
+ #startHour = 8;
61
+ #endHour = 20;
62
+ #slotMinutes = Scheduler.DEFAULT_SLOT_MINUTES;
63
+ #hourHeight = Scheduler.DEFAULT_HOUR_HEIGHT;
64
+ #firstDay = Scheduler.DEFAULT_FIRST_DAY;
65
65
  #label = undefined;
66
- #on_event_click = undefined;
67
- #on_slot_click = undefined;
68
- #on_period_change = undefined;
66
+ #onEventClick = undefined;
67
+ #onSlotClick = undefined;
68
+ #onPeriodChangeCallback = undefined;
69
69
 
70
70
  constructor(
71
71
  options = {
@@ -95,18 +95,18 @@ class Scheduler {
95
95
  // вид, которого сетка не рисует
96
96
  this.#view = options.view === Scheduler.VIEW.DAY ? Scheduler.VIEW.DAY : Scheduler.VIEW.WEEK;
97
97
  this.#events = Array.isArray(options.events) ? [...options.events] : [];
98
- this.#start_hour = options.startHour === undefined ? this.#start_hour : options.startHour;
99
- this.#end_hour = options.endHour === undefined ? this.#end_hour : options.endHour;
100
- this.#slot_minutes = options.slotMinutes === undefined ? this.#slot_minutes : options.slotMinutes;
101
- this.#hour_height = options.hourHeight === undefined ? this.#hour_height : options.hourHeight;
102
- this.#first_day = options.firstDay === undefined ? this.#first_day : options.firstDay;
103
- this.#on_event_click = options.onEventClick;
104
- this.#on_slot_click = options.onSlotClick;
105
- this.#on_period_change = options.onPeriodChange;
98
+ this.#startHour = options.startHour === undefined ? this.#startHour : options.startHour;
99
+ this.#endHour = options.endHour === undefined ? this.#endHour : options.endHour;
100
+ this.#slotMinutes = options.slotMinutes === undefined ? this.#slotMinutes : options.slotMinutes;
101
+ this.#hourHeight = options.hourHeight === undefined ? this.#hourHeight : options.hourHeight;
102
+ this.#firstDay = options.firstDay === undefined ? this.#firstDay : options.firstDay;
103
+ this.#onEventClick = options.onEventClick;
104
+ this.#onSlotClick = options.onSlotClick;
105
+ this.#onPeriodChangeCallback = options.onPeriodChange;
106
106
  this.setLabel(optionOr(options.label, I18n.t("scheduler.title")));
107
107
  if (options.height !== undefined) this.setHeight(options.height);
108
108
  this.#buildHead();
109
- this.#root.appendChild(this.#days_head);
109
+ this.#root.appendChild(this.#daysHead);
110
110
  this.#scroll.appendChild(this.#times);
111
111
  this.#scroll.appendChild(this.#days);
112
112
  this.#root.appendChild(this.#scroll);
@@ -139,15 +139,15 @@ class Scheduler {
139
139
  }
140
140
 
141
141
  getStartHour() {
142
- return this.#start_hour;
142
+ return this.#startHour;
143
143
  }
144
144
 
145
145
  getEndHour() {
146
- return this.#end_hour;
146
+ return this.#endHour;
147
147
  }
148
148
 
149
149
  getSlotMinutes() {
150
- return this.#slot_minutes;
150
+ return this.#slotMinutes;
151
151
  }
152
152
 
153
153
  /** События, попавшие на день (с учётом пересечения полуночи) */
@@ -266,7 +266,7 @@ class Scheduler {
266
266
  #startOfPeriod() {
267
267
  const day = Scheduler.#startOfDay(this.#date);
268
268
  if (this.#view === Scheduler.VIEW.DAY) return day;
269
- const offset = (day.getDay() - this.#first_day + 7) % 7;
269
+ const offset = (day.getDay() - this.#firstDay + 7) % 7;
270
270
  day.setDate(day.getDate() - offset);
271
271
  return day;
272
272
  }
@@ -305,13 +305,13 @@ class Scheduler {
305
305
  */
306
306
  #layout(date = new Date()) {
307
307
  const dayStart = this.#startOfDayMinutes();
308
- const dayEnd = this.#end_hour * 60;
308
+ const dayEnd = this.#endHour * 60;
309
309
  const items = [];
310
310
  for (const event of this.#events) {
311
311
  if (!this.#overlapsDay(event, date)) continue;
312
312
  const start = Scheduler.#eventDate(event, "start");
313
313
  const end = Scheduler.#eventDate(event, "end");
314
- const finished = Number.isNaN(end.getTime()) ? new Date(start.getTime() + this.#slot_minutes * 60000) : end;
314
+ const finished = Number.isNaN(end.getTime()) ? new Date(start.getTime() + this.#slotMinutes * 60000) : end;
315
315
  const sameStartDay = Scheduler.#sameDay(Scheduler.#startOfDay(start), date);
316
316
  const sameEndDay = Scheduler.#sameDay(Scheduler.#startOfDay(finished), date);
317
317
  let from = sameStartDay ? Scheduler.#minutesOf(start) : 0;
@@ -320,7 +320,7 @@ class Scheduler {
320
320
  from = 0;
321
321
  to = 24 * 60;
322
322
  }
323
- if (to <= from) to = from + this.#slot_minutes;
323
+ if (to <= from) to = from + this.#slotMinutes;
324
324
  from = Math.max(from, dayStart);
325
325
  to = Math.min(to, dayEnd);
326
326
  if (to <= from) continue;
@@ -329,7 +329,7 @@ class Scheduler {
329
329
  items.sort((left, right) => left.start - right.start || left.end - right.end);
330
330
  // Кластеры пересекающихся событий и дорожки внутри них
331
331
  let cluster = [];
332
- let cluster_end = -1;
332
+ let clusterEnd = -1;
333
333
  const flush = () => {
334
334
  if (cluster.length === 0) return;
335
335
  const lanes = [];
@@ -345,38 +345,38 @@ class Scheduler {
345
345
  }
346
346
  for (const item of cluster) item.lanes = lanes.length;
347
347
  cluster = [];
348
- cluster_end = -1;
348
+ clusterEnd = -1;
349
349
  };
350
350
  for (const item of items) {
351
- if (cluster.length > 0 && item.start >= cluster_end) flush();
351
+ if (cluster.length > 0 && item.start >= clusterEnd) flush();
352
352
  cluster.push(item);
353
- cluster_end = Math.max(cluster_end, item.end);
353
+ clusterEnd = Math.max(clusterEnd, item.end);
354
354
  }
355
355
  flush();
356
356
  return items;
357
357
  }
358
358
 
359
359
  #startOfDayMinutes() {
360
- return this.#start_hour * 60;
360
+ return this.#startHour * 60;
361
361
  }
362
362
 
363
363
  // === РЕНДЕР ===
364
364
  #buildHead() {
365
365
  const head = document.createElement("scheduler_head");
366
- this.#prev_button.type = "button";
367
- this.#next_button.type = "button";
368
- this.#today_button.type = "button";
369
- this.#prev_button.className = "scheduler_nav";
370
- this.#next_button.className = "scheduler_nav";
371
- this.#today_button.className = "scheduler_today";
372
- this.#prev_button.dataset.action = "prev";
373
- this.#next_button.dataset.action = "next";
374
- this.#today_button.dataset.action = "today";
375
- this.#prev_button.innerText = "‹";
376
- this.#next_button.innerText = "›";
377
- this.#today_button.innerText = I18n.t("scheduler.today");
378
- this.#prev_button.setAttribute("aria-label", I18n.t("scheduler.previousPeriod"));
379
- this.#next_button.setAttribute("aria-label", I18n.t("scheduler.nextPeriod"));
366
+ this.#prevButton.type = "button";
367
+ this.#nextButton.type = "button";
368
+ this.#todayButton.type = "button";
369
+ this.#prevButton.className = "scheduler_nav";
370
+ this.#nextButton.className = "scheduler_nav";
371
+ this.#todayButton.className = "scheduler_today";
372
+ this.#prevButton.dataset.action = "prev";
373
+ this.#nextButton.dataset.action = "next";
374
+ this.#todayButton.dataset.action = "today";
375
+ this.#prevButton.innerText = "‹";
376
+ this.#nextButton.innerText = "›";
377
+ this.#todayButton.innerText = I18n.t("scheduler.today");
378
+ this.#prevButton.setAttribute("aria-label", I18n.t("scheduler.previousPeriod"));
379
+ this.#nextButton.setAttribute("aria-label", I18n.t("scheduler.nextPeriod"));
380
380
  this.#title.setAttribute("aria-live", "polite");
381
381
  const views = document.createElement("scheduler_views");
382
382
  views.setAttribute("role", "group");
@@ -391,11 +391,11 @@ class Scheduler {
391
391
  button.dataset.view = view;
392
392
  button.innerText = label;
393
393
  views.appendChild(button);
394
- this.#view_buttons.set(view, button);
394
+ this.#viewButtons.set(view, button);
395
395
  }
396
- head.appendChild(this.#prev_button);
397
- head.appendChild(this.#next_button);
398
- head.appendChild(this.#today_button);
396
+ head.appendChild(this.#prevButton);
397
+ head.appendChild(this.#nextButton);
398
+ head.appendChild(this.#todayButton);
399
399
  head.appendChild(this.#title);
400
400
  head.appendChild(views);
401
401
  this.#root.appendChild(head);
@@ -405,25 +405,25 @@ class Scheduler {
405
405
  const days = this.#dayDates();
406
406
  const today = new Date();
407
407
  this.#title.innerText = this.#periodTitle(days);
408
- for (const [view, button] of this.#view_buttons)
408
+ for (const [view, button] of this.#viewButtons)
409
409
  button.setAttribute("aria-pressed", view === this.#view ? "true" : "false");
410
- this.#prev_button.setAttribute(
410
+ this.#prevButton.setAttribute(
411
411
  "aria-label",
412
412
  this.#view === Scheduler.VIEW.DAY ? I18n.t("scheduler.previousDay") : I18n.t("scheduler.previousWeek")
413
413
  );
414
- this.#next_button.setAttribute(
414
+ this.#nextButton.setAttribute(
415
415
  "aria-label",
416
416
  this.#view === Scheduler.VIEW.DAY ? I18n.t("scheduler.nextDay") : I18n.t("scheduler.nextWeek")
417
417
  );
418
418
  // Заголовки дней лежат вне области прокрутки и повторяют колонки сетки; ширина
419
419
  // вертикальной полосы прокрутки компенсируется, иначе заголовки уехали бы вправо
420
420
  const scrollbar = Math.max(0, this.#scroll.offsetWidth - this.#scroll.clientWidth);
421
- this.#days_head.style.paddingRight = `${scrollbar}px`;
422
- this.#days_head.innerHTML = "";
423
- this.#days_head.style.gridTemplateColumns = `56px repeat(${days.length}, minmax(0, 1fr))`;
421
+ this.#daysHead.style.paddingRight = `${scrollbar}px`;
422
+ this.#daysHead.innerHTML = "";
423
+ this.#daysHead.style.gridTemplateColumns = `56px repeat(${days.length}, minmax(0, 1fr))`;
424
424
  const corner = document.createElement("scheduler_corner");
425
425
  corner.setAttribute("aria-hidden", "true");
426
- this.#days_head.appendChild(corner);
426
+ this.#daysHead.appendChild(corner);
427
427
  for (const day of days) {
428
428
  const head = document.createElement("scheduler_day_head");
429
429
  if (Scheduler.#sameDay(day, today)) head.classList.add("scheduler_today_head");
@@ -433,7 +433,7 @@ class Scheduler {
433
433
  number.innerText = String(day.getDate());
434
434
  head.appendChild(name);
435
435
  head.appendChild(number);
436
- this.#days_head.appendChild(head);
436
+ this.#daysHead.appendChild(head);
437
437
  }
438
438
  this.#renderTimes();
439
439
  this.#renderDays(days, today);
@@ -441,9 +441,9 @@ class Scheduler {
441
441
 
442
442
  #renderTimes() {
443
443
  this.#times.innerHTML = "";
444
- for (let hour = this.#start_hour; hour < this.#end_hour; hour++) {
444
+ for (let hour = this.#startHour; hour < this.#endHour; hour++) {
445
445
  const cell = document.createElement("scheduler_hour");
446
- cell.style.height = `${this.#hour_height}px`;
446
+ cell.style.height = `${this.#hourHeight}px`;
447
447
  cell.innerText = `${String(hour).padStart(2, "0")}:00`;
448
448
  this.#times.appendChild(cell);
449
449
  }
@@ -455,10 +455,10 @@ class Scheduler {
455
455
  for (const day of days) {
456
456
  const column = document.createElement("scheduler_day");
457
457
  column.dataset.day = Scheduler.#key(day);
458
- column.style.height = `${(this.#end_hour - this.#start_hour) * this.#hour_height}px`;
458
+ column.style.height = `${(this.#endHour - this.#startHour) * this.#hourHeight}px`;
459
459
  if (Scheduler.#sameDay(day, today)) column.classList.add("scheduler_today");
460
460
  // Часовые линии рисует фон: узлы на каждый час не нужны
461
- column.style.backgroundSize = `100% ${this.#hour_height}px`;
461
+ column.style.backgroundSize = `100% ${this.#hourHeight}px`;
462
462
  for (const item of this.#layout(day)) column.appendChild(this.#createEvent(item, day));
463
463
  this.#days.appendChild(column);
464
464
  }
@@ -470,8 +470,8 @@ class Scheduler {
470
470
 
471
471
  #createEvent(item = Object(), day = new Date()) {
472
472
  const event = item.event;
473
- const top = ((item.start - this.#startOfDayMinutes()) / 60) * this.#hour_height;
474
- const height = Math.max(18, ((item.end - item.start) / 60) * this.#hour_height);
473
+ const top = ((item.start - this.#startOfDayMinutes()) / 60) * this.#hourHeight;
474
+ const height = Math.max(18, ((item.end - item.start) / 60) * this.#hourHeight);
475
475
  const lanes = Math.max(1, item.lanes);
476
476
  const width = 100 / lanes;
477
477
  const node = document.createElement("button");
@@ -544,19 +544,19 @@ class Scheduler {
544
544
  const eventNode = target.closest(".scheduler_event");
545
545
  if (eventNode !== null) {
546
546
  const found = this.#events[Number(eventNode.dataset.index)];
547
- if (this.#on_event_click !== undefined)
548
- this.#on_event_click(found === undefined ? undefined : found, eventNode);
547
+ if (this.#onEventClick !== undefined)
548
+ this.#onEventClick(found === undefined ? undefined : found, eventNode);
549
549
  return;
550
550
  }
551
551
  const dayNode = target.closest("scheduler_day");
552
552
  if (dayNode !== null) {
553
553
  const column = dayNode.getBoundingClientRect();
554
554
  const offset = Math.max(0, Math.min(event.clientY - column.top, column.height));
555
- const raw = this.#startOfDayMinutes() + (offset / this.#hour_height) * 60;
556
- const minutes = Math.round(raw / this.#slot_minutes) * this.#slot_minutes;
555
+ const raw = this.#startOfDayMinutes() + (offset / this.#hourHeight) * 60;
556
+ const minutes = Math.round(raw / this.#slotMinutes) * this.#slotMinutes;
557
557
  const date = this.#dayDates().find((day) => Scheduler.#key(day) === dayNode.dataset.day);
558
- if (date !== undefined && this.#on_slot_click !== undefined) {
559
- this.#on_slot_click({ date: date, minutes: minutes, time: Scheduler.#timeText(minutes) });
558
+ if (date !== undefined && this.#onSlotClick !== undefined) {
559
+ this.#onSlotClick({ date: date, minutes: minutes, time: Scheduler.#timeText(minutes) });
560
560
  }
561
561
  }
562
562
  };
@@ -579,9 +579,9 @@ class Scheduler {
579
579
  };
580
580
 
581
581
  #onPeriodChange() {
582
- if (this.#on_period_change === undefined) return;
582
+ if (this.#onPeriodChangeCallback === undefined) return;
583
583
  const range = this.getRange();
584
- this.#on_period_change(range.from, range.to);
584
+ this.#onPeriodChangeCallback(range.from, range.to);
585
585
  }
586
586
  }
587
587
 
@@ -4,12 +4,12 @@ chui_scheduler {
4
4
  flex-direction: column;
5
5
  width: -webkit-fill-available;
6
6
  box-sizing: border-box;
7
- margin: var(--margin);
7
+ margin: var(--block_margin);
8
8
  color: var(--text_color);
9
9
  font-size: var(--font_default_size);
10
10
  background: var(--element_background_2);
11
11
  border: 1px solid var(--border_color);
12
- border-radius: var(--border_radius);
12
+ border-radius: var(--radius_sm);
13
13
  overflow: hidden;
14
14
  }
15
15
 
@@ -17,7 +17,7 @@ scheduler_head {
17
17
  display: flex;
18
18
  align-items: center;
19
19
  gap: 6px;
20
- padding: var(--main_padding);
20
+ padding: var(--block_padding);
21
21
  border-bottom: 1px solid var(--border_color);
22
22
  }
23
23
 
@@ -25,7 +25,7 @@ button.scheduler_nav,
25
25
  button.scheduler_today,
26
26
  button.scheduler_view {
27
27
  border: none;
28
- border-radius: var(--border_radius);
28
+ border-radius: var(--radius_sm);
29
29
  background: var(--element_background);
30
30
  color: var(--text_color);
31
31
  font-family: inherit;
@@ -157,7 +157,7 @@ button.scheduler_event {
157
157
  overflow: hidden;
158
158
  text-align: start;
159
159
  border: none;
160
- border-radius: var(--border_radius);
160
+ border-radius: var(--radius_sm);
161
161
  background: var(--blue_prime_background);
162
162
  color: var(--text_color_hover);
163
163
  font-family: inherit;
@@ -0,0 +1,167 @@
1
+ const { Spinner } = require("../chui_spinner/spinner");
2
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
3
+ const { setStyles, optionOr } = require("../../modules/chui_functions");
4
+ const { Animation } = require("../../modules/chui_animations/animations");
5
+ const { OverlayA11y } = require("../../modules/chui_a11y/chui_a11y");
6
+ const { tokenTime } = require("../../modules/chui_animations/motion");
7
+
8
+ /**
9
+ * Экран занят: слой поверх всего окна с индикатором загрузки. Пока он открыт, до содержимого
10
+ * под ним не добраться — ни мышью, ни клавиатурой, ни скринридером.
11
+ *
12
+ * От `Spinner` отличается тем, что тот просто рисует индикатор в потоке, а этот занимает экран:
13
+ * слой встаёт в `body` (в карточке с `backdrop-filter` Chromium собирает такой узел отдельной
14
+ * поверхностью и рисует её под слоями из `body` — так уже теряли диалог), фокус удерживается
15
+ * внутри, а фон становится инертным. Роль слоя — `dialog` с именем загрузки, внутри объявляется
16
+ * `progressbar`; Escape слой не закрывает: это не сообщение, а признак занятости.
17
+ *
18
+ * Опции: `id`, `label` (подпись и имя для скринридера, по умолчанию «{loading}» из словаря),
19
+ * `delay` (мс до появления — против мигания на коротких операциях).
20
+ *
21
+ * Методы: `show()`, `hide()`, `isShown()`, `setLabel(text)`, `destroy()`, `set()`.
22
+ * Статические: `ScreenSpinner.show(options)` (создать и показать), `ScreenSpinner.hide()`,
23
+ * `ScreenSpinner.current`.
24
+ *
25
+ * ```javascript
26
+ * const busy = new ScreenSpinner({ delay: 200 });
27
+ * busy.show();
28
+ * await load();
29
+ * busy.hide();
30
+ * ```
31
+ */
32
+ class ScreenSpinner {
33
+ // На экране один такой слой: два спиннера наложились бы друг на друга
34
+ static #current = undefined;
35
+
36
+ #root = document.createElement("chui_screen_spinner");
37
+ #card = document.createElement("screen_spinner_card");
38
+ #labelNode = document.createElement("screen_spinner_label");
39
+ #spinner = undefined;
40
+ #a11y = undefined;
41
+ #delay = 0;
42
+ #timer = undefined;
43
+ #shown = false;
44
+ #removed = false;
45
+
46
+ constructor(options = {}) {
47
+ setStyles(__dirname + "/styles.css", "chUiJS_ScreenSpinner");
48
+ if (options.id !== undefined) this.#root.id = options.id;
49
+ const delay = Number(options.delay);
50
+ this.#delay = Number.isFinite(delay) && delay > 0 ? delay : 0;
51
+ this.#spinner = new Spinner();
52
+ this.#card.append(this.#spinner.set(), this.#labelNode);
53
+ this.#root.appendChild(this.#card);
54
+ this.#root.setAttribute("aria-busy", "true");
55
+ this.setLabel(optionOr(options.label, I18n.t("feedback.loading")));
56
+ this.#a11y = new OverlayA11y(this.#root, {
57
+ role: "dialog",
58
+ label: this.#labelNode.innerText,
59
+ // Escape здесь ничего не закрывает: занятость — не сообщение, которое можно отклонить
60
+ onEscape: () => {},
61
+ });
62
+ }
63
+
64
+ isShown() {
65
+ return this.#shown;
66
+ }
67
+ getLabel() {
68
+ return this.#labelNode.innerText;
69
+ }
70
+
71
+ setLabel(text = String()) {
72
+ const value = String(text);
73
+ this.#labelNode.innerText = value;
74
+ // Подпись пуста — под ней и места не надо: индикатор говорит сам
75
+ this.#labelNode.hidden = value.trim() === "";
76
+ if (this.#a11y !== undefined) this.#a11y.setLabel(value.trim() === "" ? I18n.t("feedback.loading") : value);
77
+ return this;
78
+ }
79
+
80
+ /**
81
+ * Показ: слой встаёт в `body` и объявляет себя слоем. Задержка нужна против мигания —
82
+ * короткая операция успевает закончиться раньше, чем слой появится, и экран не дрожит.
83
+ */
84
+ show() {
85
+ if (this.#shown === true) return this;
86
+ this.#shown = true;
87
+ // Слой показывают заново: след уборки прошлого показа снимаем, иначе новый слой
88
+ // не уберётся по концу кадра (`finish` посчитал бы работу сделанной)
89
+ this.#removed = false;
90
+ if (ScreenSpinner.#current !== undefined && ScreenSpinner.#current !== this) ScreenSpinner.#current.hide();
91
+ ScreenSpinner.#current = this;
92
+ const reveal = () => {
93
+ this.#timer = undefined;
94
+ if (this.#shown === false) return;
95
+ if (document.body.contains(this.#root) === false) document.body.appendChild(this.#root);
96
+ new Animation(this.#root).fadeIn();
97
+ new Animation(this.#card).panelIn();
98
+ this.#a11y.open();
99
+ this.#focusIn();
100
+ };
101
+ if (this.#delay > 0) this.#timer = setTimeout(reveal, this.#delay);
102
+ else reveal();
103
+ return this;
104
+ }
105
+
106
+ /**
107
+ * Уход: слой гаснет, узел убирается по концу кадра. Слушатель одноразовый (проверка цели) —
108
+ * иначе он поймал бы любой конец кадра на слое, а срок из токена страхует случай, когда
109
+ * кадр не проиграется вовсе (слой скрыт вместе с родителем).
110
+ */
111
+ hide() {
112
+ if (this.#shown === false) return this;
113
+ this.#shown = false;
114
+ if (this.#timer !== undefined) {
115
+ clearTimeout(this.#timer);
116
+ this.#timer = undefined;
117
+ }
118
+ if (ScreenSpinner.#current === this) ScreenSpinner.#current = undefined;
119
+ // Слой ещё не успел появиться (сработала задержка) — убирать нечего
120
+ if (this.#root.parentElement === null) return this;
121
+ this.#a11y.close();
122
+ new Animation(this.#root).fadeOut();
123
+ new Animation(this.#card).fadeOut();
124
+ const finish = () => {
125
+ if (this.#removed === true) return;
126
+ this.#removed = true;
127
+ this.#root.removeEventListener("animationend", finish);
128
+ this.#root.remove();
129
+ };
130
+ this.#root.addEventListener("animationend", finish);
131
+ setTimeout(finish, tokenTime("--motion_fast"));
132
+ return this;
133
+ }
134
+
135
+ set() {
136
+ return this.#root;
137
+ }
138
+ /** Полное удаление: снять слой (вместе с инертным фоном и слушателями) и убрать узел */
139
+ destroy() {
140
+ this.hide();
141
+ this.#removed = true;
142
+ this.#root.remove();
143
+ }
144
+
145
+ // === СТАТИЧЕСКОЕ ===
146
+ /** Показать спиннер, не заводя переменную: `ScreenSpinner.show({ label: "Сохраняем" })` */
147
+ static show(options = {}) {
148
+ const spinner = new ScreenSpinner(options);
149
+ spinner.show();
150
+ return spinner;
151
+ }
152
+ static hide() {
153
+ if (ScreenSpinner.#current !== undefined) ScreenSpinner.#current.hide();
154
+ }
155
+ static get current() {
156
+ return ScreenSpinner.#current;
157
+ }
158
+
159
+ // === ВНУТРЕННЕЕ ===
160
+ /** Фокус — в слой: иначе он остался бы на кнопке под ним, и Tab уходил бы в фон */
161
+ #focusIn() {
162
+ this.#root.setAttribute("tabindex", "-1");
163
+ this.#root.focus({ preventScroll: true });
164
+ }
165
+ }
166
+
167
+ exports.ScreenSpinner = ScreenSpinner;
@@ -0,0 +1,49 @@
1
+ /* Экран занят: слой поверх окна с индикатором загрузки.
2
+ Занавес держит сам слой (он и есть затемнение), а материал карточки — размытие: у слоя
3
+ `backdrop-filter` нет, иначе карточка внутри не увидела бы страницу (элемент с фильтром
4
+ становится собственным «backdrop root»). */
5
+
6
+ chui_screen_spinner {
7
+ position: fixed;
8
+ inset: 0;
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ box-sizing: border-box;
13
+ /* Выше модальных слоёв (у диалога 1000, у занавеса 999): занятость перекрывает всё */
14
+ z-index: 1100;
15
+ background: var(--modal_scrim);
16
+ /* Слой принимает на себя мышь и клавиатуру: под ним ничего не нажать */
17
+ cursor: progress;
18
+ }
19
+
20
+ chui_screen_spinner:focus-visible {
21
+ outline: none;
22
+ }
23
+
24
+ screen_spinner_card {
25
+ display: flex;
26
+ flex-direction: column;
27
+ align-items: center;
28
+ gap: 10px;
29
+ box-sizing: border-box;
30
+ padding: 18px 22px;
31
+ border: 1px solid var(--border_color);
32
+ border-radius: var(--radius_md);
33
+ background: var(--modal_background);
34
+ backdrop-filter: var(--global_blur);
35
+ -webkit-backdrop-filter: var(--global_blur);
36
+ box-shadow: var(--box_shadow_modal);
37
+ color: var(--text_color);
38
+ }
39
+
40
+ screen_spinner_label {
41
+ font-size: var(--font_labels_size);
42
+ color: var(--text_color_disabled);
43
+ text-align: center;
44
+ }
45
+
46
+ /* Подписи нет — под неё не остаётся и зазора */
47
+ screen_spinner_label[hidden] {
48
+ display: none;
49
+ }