chuijs 4.0.2 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +43 -644
  3. package/framework/appLayout/default/chui_app_layout.js +308 -260
  4. package/framework/appLayout/default/global_style.css +85 -48
  5. package/framework/components/chui_accordion/accordion.js +29 -26
  6. package/framework/components/chui_accordion/styles.css +6 -5
  7. package/framework/components/chui_action_sheet/action_sheet.js +59 -33
  8. package/framework/components/chui_action_sheet/styles.css +2 -1
  9. package/framework/components/chui_affix/affix.js +11 -6
  10. package/framework/components/chui_alert/alert.js +23 -14
  11. package/framework/components/chui_avatar/avatar.js +23 -22
  12. package/framework/components/chui_avatar_group/avatar_group.js +21 -19
  13. package/framework/components/chui_backtop/backtop.js +35 -19
  14. package/framework/components/chui_badge/badge.js +15 -13
  15. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  16. package/framework/components/chui_button/button.js +42 -22
  17. package/framework/components/chui_button/styles.css +2 -2
  18. package/framework/components/chui_calendar/calendar.js +12 -10
  19. package/framework/components/chui_card/card.js +43 -23
  20. package/framework/components/chui_chat/chat.js +72 -33
  21. package/framework/components/chui_clipboard_history/clipboard_history.js +30 -21
  22. package/framework/components/chui_clipboard_history/styles.css +4 -2
  23. package/framework/components/chui_code/code.js +2 -2
  24. package/framework/components/chui_code/styles.css +2 -2
  25. package/framework/components/chui_code_editor/code_editor.js +47 -31
  26. package/framework/components/chui_code_editor/styles.css +3 -2
  27. package/framework/components/chui_command_palette/command_palette.js +60 -37
  28. package/framework/components/chui_console/console.js +5 -5
  29. package/framework/components/chui_console/styles.css +1 -1
  30. package/framework/components/chui_content_block/content_block.js +33 -19
  31. package/framework/components/chui_content_block/styles.css +2 -2
  32. package/framework/components/chui_context_menu/context_menu.js +9 -4
  33. package/framework/components/chui_custom_element/custom_element.js +22 -15
  34. package/framework/components/chui_data_grid/data_grid.js +396 -234
  35. package/framework/components/chui_data_grid/styles.css +10 -8
  36. package/framework/components/chui_descriptions/descriptions.js +34 -17
  37. package/framework/components/chui_details/details.js +32 -26
  38. package/framework/components/chui_details/styles.css +5 -4
  39. package/framework/components/chui_diff_viewer/diff_viewer.js +91 -66
  40. package/framework/components/chui_diff_viewer/styles.css +1 -1
  41. package/framework/components/chui_divider/divider.js +13 -11
  42. package/framework/components/chui_drawer/drawer.js +27 -25
  43. package/framework/components/chui_drop_zone/drop_zone.js +31 -21
  44. package/framework/components/chui_empty_state/empty_state.js +20 -15
  45. package/framework/components/chui_fieldset/fieldset.js +37 -20
  46. package/framework/components/chui_fieldset/styles.css +1 -1
  47. package/framework/components/chui_file_explorer/file_explorer.js +157 -86
  48. package/framework/components/chui_file_explorer/styles.css +2 -1
  49. package/framework/components/chui_form/form.js +31 -19
  50. package/framework/components/chui_form/styles.css +1 -1
  51. package/framework/components/chui_gantt/gantt.js +64 -40
  52. package/framework/components/chui_graphs/graphs.js +301 -200
  53. package/framework/components/chui_graphs/styles.css +1 -1
  54. package/framework/components/chui_hero/hero.js +40 -22
  55. package/framework/components/chui_html_block/html_block.js +6 -6
  56. package/framework/components/chui_html_block/styles.css +2 -2
  57. package/framework/components/chui_hx/hx.js +3 -3
  58. package/framework/components/chui_hx/styles.css +11 -4
  59. package/framework/components/chui_icons/icons.js +2109 -2109
  60. package/framework/components/chui_icons/styles.css +2 -2
  61. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  62. package/framework/components/chui_inputs/chui_check_box/styles.css +18 -18
  63. package/framework/components/chui_inputs/chui_chips/chips.js +50 -40
  64. package/framework/components/chui_inputs/chui_chips/styles.css +4 -2
  65. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +36 -24
  66. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +100 -82
  67. package/framework/components/chui_inputs/chui_combo_box/styles.css +14 -12
  68. package/framework/components/chui_inputs/chui_date/date.js +102 -66
  69. package/framework/components/chui_inputs/chui_date/styles.css +12 -11
  70. package/framework/components/chui_inputs/chui_date_range/date_range.js +40 -29
  71. package/framework/components/chui_inputs/chui_datetime/datetime.js +35 -27
  72. package/framework/components/chui_inputs/chui_email/email.js +43 -31
  73. package/framework/components/chui_inputs/chui_email/styles.css +5 -5
  74. package/framework/components/chui_inputs/chui_file/file.js +68 -41
  75. package/framework/components/chui_inputs/chui_file/styles.css +13 -12
  76. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +61 -36
  77. package/framework/components/chui_inputs/chui_masked/masked.js +39 -28
  78. package/framework/components/chui_inputs/chui_mention/mention.js +77 -30
  79. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +173 -153
  80. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +9 -7
  81. package/framework/components/chui_inputs/chui_number/number.js +58 -41
  82. package/framework/components/chui_inputs/chui_number/styles.css +7 -7
  83. package/framework/components/chui_inputs/chui_otp/otp.js +38 -29
  84. package/framework/components/chui_inputs/chui_password/password.js +58 -36
  85. package/framework/components/chui_inputs/chui_password/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  87. package/framework/components/chui_inputs/chui_radio_button/styles.css +20 -20
  88. package/framework/components/chui_inputs/chui_rating/rating.js +26 -22
  89. package/framework/components/chui_inputs/chui_select_box/select_box.js +102 -78
  90. package/framework/components/chui_inputs/chui_select_box/styles.css +11 -11
  91. package/framework/components/chui_inputs/chui_slider/slider.js +29 -26
  92. package/framework/components/chui_inputs/chui_slider/styles.css +2 -1
  93. package/framework/components/chui_inputs/chui_text/styles.css +8 -8
  94. package/framework/components/chui_inputs/chui_text/text.js +65 -44
  95. package/framework/components/chui_inputs/chui_text_area/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_text_area/text_area.js +51 -28
  97. package/framework/components/chui_inputs/chui_time/styles.css +5 -3
  98. package/framework/components/chui_inputs/chui_time/time.js +38 -27
  99. package/framework/components/chui_inputs/chui_toggle/styles.css +3 -3
  100. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  101. package/framework/components/chui_json_editor/json_editor.js +53 -43
  102. package/framework/components/chui_json_viewer/json_viewer.js +52 -33
  103. package/framework/components/chui_json_viewer/styles.css +3 -2
  104. package/framework/components/chui_kanban/kanban.js +52 -34
  105. package/framework/components/chui_kbd/kbd.js +12 -10
  106. package/framework/components/chui_label/label.js +14 -12
  107. package/framework/components/chui_label/styles.css +2 -2
  108. package/framework/components/chui_link/link.js +27 -20
  109. package/framework/components/chui_list/list.js +31 -27
  110. package/framework/components/chui_list/styles.css +2 -1
  111. package/framework/components/chui_markdown_editor/markdown_editor.js +60 -44
  112. package/framework/components/chui_media/audio.js +326 -227
  113. package/framework/components/chui_media/audio_styles.css +40 -21
  114. package/framework/components/chui_media/image.js +70 -38
  115. package/framework/components/chui_media/image_compare.js +52 -21
  116. package/framework/components/chui_media/image_styles.css +3 -3
  117. package/framework/components/chui_media/video.js +155 -62
  118. package/framework/components/chui_media/video_styles.css +33 -16
  119. package/framework/components/chui_menu_bar/menu_bar.js +26 -24
  120. package/framework/components/chui_menu_bar/styles.css +4 -2
  121. package/framework/components/chui_modal/modal.js +44 -43
  122. package/framework/components/chui_modal/styles.css +3 -2
  123. package/framework/components/chui_notification/notification.js +50 -34
  124. package/framework/components/chui_notification/notification_download.js +31 -25
  125. package/framework/components/chui_notification/notification_download_progress.css +3 -2
  126. package/framework/components/chui_notification/notification_download_progress.js +47 -41
  127. package/framework/components/chui_notification/notification_update.js +23 -16
  128. package/framework/components/chui_notification/status_plate.js +2 -2
  129. package/framework/components/chui_notification/styles_download.css +1 -1
  130. package/framework/components/chui_notification/styles_update.css +1 -1
  131. package/framework/components/chui_org_chart/org_chart.js +74 -35
  132. package/framework/components/chui_pagination/pagination.js +62 -27
  133. package/framework/components/chui_paragraph/paragraph.js +2 -2
  134. package/framework/components/chui_paragraph/styles.css +1 -1
  135. package/framework/components/chui_popover/popover.js +49 -28
  136. package/framework/components/chui_popups/popups.js +137 -108
  137. package/framework/components/chui_popups/styles.css +2 -2
  138. package/framework/components/chui_print_button/print_button.js +33 -23
  139. package/framework/components/chui_progress_bar/progress_bar.js +23 -15
  140. package/framework/components/chui_progress_bar/styles.css +2 -2
  141. package/framework/components/chui_progress_ring/progress_ring.js +17 -15
  142. package/framework/components/chui_qrcode/qrcode.js +75 -31
  143. package/framework/components/chui_query_builder/query_builder.js +216 -123
  144. package/framework/components/chui_radio_group/radio_group.js +36 -26
  145. package/framework/components/chui_radio_group/styles.css +1 -1
  146. package/framework/components/chui_result/result.js +26 -16
  147. package/framework/components/chui_scheduler/scheduler.js +57 -35
  148. package/framework/components/chui_scheduler/styles.css +6 -2
  149. package/framework/components/chui_segmented_control/segmented_control.js +27 -21
  150. package/framework/components/chui_settings/settings.js +122 -48
  151. package/framework/components/chui_shortcut_help/shortcut_help.js +55 -32
  152. package/framework/components/chui_sidebar_nav/sidebar_nav.js +33 -23
  153. package/framework/components/chui_skeleton/skeleton.js +29 -24
  154. package/framework/components/chui_slideshow/slideshow.js +60 -41
  155. package/framework/components/chui_slideshow/styles.css +18 -12
  156. package/framework/components/chui_spinner/spinner.js +8 -8
  157. package/framework/components/chui_spinner/styles.css +0 -1
  158. package/framework/components/chui_split_button/split_button.js +23 -18
  159. package/framework/components/chui_split_button/styles.css +1 -1
  160. package/framework/components/chui_splitter/splitter.js +35 -28
  161. package/framework/components/chui_statistic/statistic.js +65 -38
  162. package/framework/components/chui_status_bar/status_bar.js +11 -9
  163. package/framework/components/chui_stepper/stepper.js +27 -22
  164. package/framework/components/chui_sticky_bar/sticky_bar.js +9 -4
  165. package/framework/components/chui_sticky_bar/styles.css +3 -1
  166. package/framework/components/chui_tabs/chui_tabs.js +28 -22
  167. package/framework/components/chui_tabs/styles.css +3 -3
  168. package/framework/components/chui_text_editor/styles.css +20 -19
  169. package/framework/components/chui_text_editor/text_editor.js +85 -61
  170. package/framework/components/chui_text_editor/text_editor_panel.js +346 -284
  171. package/framework/components/chui_theme_toggle/theme_toggle.js +27 -22
  172. package/framework/components/chui_timeline/timeline.js +14 -12
  173. package/framework/components/chui_toast_queue/toast_queue.js +52 -46
  174. package/framework/components/chui_toolbar/toolbar.js +20 -13
  175. package/framework/components/chui_tooltip/tooltip.js +37 -24
  176. package/framework/components/chui_tour/styles.css +8 -3
  177. package/framework/components/chui_tour/tour.js +61 -27
  178. package/framework/components/chui_transfer/styles.css +2 -1
  179. package/framework/components/chui_transfer/transfer.js +75 -42
  180. package/framework/components/chui_tree_table/tree_table.js +43 -29
  181. package/framework/components/chui_tree_view/styles.css +4 -2
  182. package/framework/components/chui_tree_view/tree_view.js +142 -99
  183. package/framework/components/chui_watermark/watermark.js +24 -16
  184. package/framework/components/chui_webview/styles.css +2 -2
  185. package/framework/components/chui_webview/webview.js +62 -50
  186. package/framework/components/telegram_bot/chui_telegram_bot.js +71 -64
  187. package/framework/modules/chui_a11y/chui_a11y.js +77 -46
  188. package/framework/modules/chui_animations/animations.js +42 -42
  189. package/framework/modules/chui_animations/styles.css +1 -1
  190. package/framework/modules/chui_bridge/preload.js +36 -25
  191. package/framework/modules/chui_functions.js +52 -50
  192. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  193. package/framework/modules/chui_i18n/chui_i18n.js +9 -7
  194. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  195. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  196. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  197. package/framework/modules/chui_i18n/locales/common.js +3 -3
  198. package/framework/modules/chui_i18n/locales/data.js +36 -26
  199. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  200. package/framework/modules/chui_i18n/locales/feedback.js +3 -3
  201. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  202. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  203. package/framework/modules/chui_i18n/locales/media.js +4 -4
  204. package/framework/modules/chui_i18n/locales/navigation.js +8 -8
  205. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  206. package/framework/modules/chui_json/chui_json.js +9 -9
  207. package/framework/modules/chui_layout/chui_layout.js +12 -10
  208. package/framework/modules/chui_logger/chui_logger.js +29 -25
  209. package/framework/modules/chui_page/page.js +33 -27
  210. package/framework/modules/chui_qr/chui_qr.js +158 -67
  211. package/framework/modules/chui_scrollbar/chui_scrollbar.js +35 -24
  212. package/framework/modules/chui_scrollbar/styles.css +3 -1
  213. package/framework/modules/chui_services/chui_channels.js +27 -13
  214. package/framework/modules/chui_services/chui_services.js +39 -31
  215. package/framework/modules/chui_services/desktop.js +32 -31
  216. package/framework/modules/chui_sortable/chui_sortable.js +17 -12
  217. package/framework/modules/chui_validate/chui_validate.js +7 -4
  218. package/framework/tray_bar/chui_menu_items.js +136 -46
  219. package/index.d.ts +4814 -0
  220. package/index.js +385 -292
  221. package/package.json +79 -68
@@ -1,9 +1,9 @@
1
1
  const { Icon, Icons } = require("../chui_icons/icons");
2
- const {Label} = require('../chui_label/label');
3
- const {makeKeyboardButton} = require("../../modules/chui_a11y/chui_a11y");
4
- const {Log} = require("../../modules/chui_logger/chui_logger");
5
- const {I18n} = require("../../modules/chui_i18n/chui_i18n");
6
- const {setStyles, optionOr} = require("../../modules/chui_functions");
2
+ const { Label } = require("../chui_label/label");
3
+ const { makeKeyboardButton } = require("../../modules/chui_a11y/chui_a11y");
4
+ const { Log } = require("../../modules/chui_logger/chui_logger");
5
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
6
+ const { setStyles, optionOr } = require("../../modules/chui_functions");
7
7
 
8
8
  /**
9
9
  * Видеоплеер: кадр и плавающая полоса управления внутри кадра.
@@ -36,15 +36,28 @@ class Video {
36
36
  #onPlay = () => this.#renderPlayState(true);
37
37
  #onPause = () => this.#renderPlayState(false);
38
38
  #onTimeUpdate = () => this.#renderProgress();
39
- #onDurationChange = () => { this.#setSliderMax(); this.#renderProgress(); };
39
+ #onDurationChange = () => {
40
+ this.#setSliderMax();
41
+ this.#renderProgress();
42
+ };
40
43
  #onBuffered = () => this.#displayBufferedAmount();
41
44
  #onEnter = () => this.#openPanel();
42
45
  #onLeave = () => this.#closePanel();
43
- constructor(options = {
44
- src: String(), autoplay: Boolean(), controls: Boolean(), loop: Boolean(), muted: Boolean(),
45
- volume: Number(), poster: String(), width: String(), height: String(), label: String()
46
- }) {
47
- setStyles(__dirname + "/video_styles.css", 'chUiJS_Video');
46
+ constructor(
47
+ options = {
48
+ src: String(),
49
+ autoplay: Boolean(),
50
+ controls: Boolean(),
51
+ loop: Boolean(),
52
+ muted: Boolean(),
53
+ volume: Number(),
54
+ poster: String(),
55
+ width: String(),
56
+ height: String(),
57
+ label: String(),
58
+ }
59
+ ) {
60
+ setStyles(__dirname + "/video_styles.css", "chUiJS_Video");
48
61
  // Плеер — именованная группа: своих ролей у панели нет, а без имени скринридер
49
62
  // читает подряд безымянные кнопки без контекста
50
63
  this.#chui_vp_main.setAttribute("role", "group");
@@ -78,7 +91,7 @@ class Video {
78
91
  this.#chui_vt.addEventListener("volumechange", () => this.#renderVolume());
79
92
  this.#chui_vt.addEventListener("error", () => {
80
93
  Log.error(`[Video] не удалось прочитать дорожку: ${this.getSrc()}`);
81
- this.#setStatus(I18n.t("media.videoNotPlaying", {reason: I18n.t("media.error.sourceFailed")}));
94
+ this.#setStatus(I18n.t("media.videoNotPlaying", { reason: I18n.t("media.error.sourceFailed") }));
82
95
  });
83
96
  this.#chui_vp_main.addEventListener("mouseenter", this.#onEnter);
84
97
  this.#chui_vp_main.addEventListener("mouseleave", this.#onLeave);
@@ -98,7 +111,7 @@ class Video {
98
111
  this.#setButton(this.#chui_vp_play_pause, I18n.t("media.play"), Icons.AUDIO_VIDEO.PLAY_ARROW);
99
112
  this.#setButton(this.#chui_vp_volume_icon, I18n.t("media.mute"), Icons.AUDIO_VIDEO.VOLUME_UP);
100
113
  this.#setButton(this.#chui_vp_full_mode, I18n.t("media.fullscreen"), Icons.NAVIGATION.FULLSCREEN);
101
- this.#chui_vp_time = new Label({text: this.#calculateTime(0)});
114
+ this.#chui_vp_time = new Label({ text: this.#calculateTime(0) });
102
115
  this.#chui_vp_seek.type = "range";
103
116
  this.#chui_vp_seek.id = "chui_vp_seek";
104
117
  this.#chui_vp_seek.max = "0";
@@ -133,15 +146,17 @@ class Video {
133
146
  if (!this.#controls) return;
134
147
  this.#chui_vp_main.classList.add("vp_panel_open");
135
148
  }
136
- #closePanel() { this.#chui_vp_main.classList.remove("vp_panel_open"); }
149
+ #closePanel() {
150
+ this.#chui_vp_main.classList.remove("vp_panel_open");
151
+ }
137
152
  #playPause = async () => {
138
153
  if (this.getPaused()) await this.play();
139
154
  else this.pause();
140
- }
155
+ };
141
156
  #toggleFullscreen = async () => {
142
157
  if (document.fullscreenElement === null) await this.requestFullscreen();
143
158
  else await this.exitFullscreen();
144
- }
159
+ };
145
160
  #renderPlayState(playing) {
146
161
  this.#setIcon(this.#chui_vp_play_pause, playing ? Icons.AUDIO_VIDEO.PAUSE : Icons.AUDIO_VIDEO.PLAY_ARROW);
147
162
  this.#setLabel(this.#chui_vp_play_pause, playing ? I18n.t("media.pause") : I18n.t("media.play"));
@@ -150,21 +165,23 @@ class Video {
150
165
  const доля = Math.min(100, Math.max(0, Math.round(this.#chui_vt.volume * 100)));
151
166
  this.#chui_vp_volume.value = String(доля);
152
167
  this.#chui_vp_volume.disabled = this.getMuted();
153
- this.#chui_vp_main.style.setProperty('--volume-before-width', `${доля}%`);
154
- this.#setIcon(this.#chui_vp_volume_icon, this.getMuted() || this.#chui_vt.volume === 0
155
- ? Icons.AUDIO_VIDEO.VOLUME_OFF : Icons.AUDIO_VIDEO.VOLUME_UP);
168
+ this.#chui_vp_main.style.setProperty("--volume-before-width", `${доля}%`);
169
+ this.#setIcon(
170
+ this.#chui_vp_volume_icon,
171
+ this.getMuted() || this.#chui_vt.volume === 0 ? Icons.AUDIO_VIDEO.VOLUME_OFF : Icons.AUDIO_VIDEO.VOLUME_UP
172
+ );
156
173
  this.#chui_vp_volume_icon.setAttribute("aria-label", I18n.t(this.getMuted() ? "media.unmute" : "media.mute"));
157
- }
174
+ };
158
175
  #displayBufferedAmount = () => {
159
176
  const max = Number(this.#chui_vp_seek.max);
160
177
  if (!(max > 0)) return;
161
178
  try {
162
- const end = Math.floor(this.#chui_vt.buffered.end(0) / max * 100);
179
+ const end = Math.floor((this.#chui_vt.buffered.end(0) / max) * 100);
163
180
  this.#chui_vp_seek_buf.style.width = `${Math.min(100, Math.max(0, end))}%`;
164
181
  } catch (_error) {
165
182
  // Буфер ещё пуст — рисовать нечего
166
183
  }
167
- }
184
+ };
168
185
  // Длительность приходит с метаданными: без неё полоса прокрутки делила бы на ноль,
169
186
  // а у живого потока её нет вовсе (duration = Infinity)
170
187
  #setSliderMax = () => {
@@ -173,7 +190,7 @@ class Video {
173
190
  this.#chui_vp_seek.max = known ? String(Math.floor(duration)) : "0";
174
191
  // Без известной длительности ползунок бессмысленен: перетаскивание отправляло бы плеер в начало
175
192
  this.#chui_vp_seek.disabled = !known;
176
- }
193
+ };
177
194
  #renderProgress = () => {
178
195
  const max = Number(this.#chui_vp_seek.max);
179
196
  const position = this.getCurrentTime();
@@ -181,24 +198,26 @@ class Video {
181
198
  if (!(max > 0)) {
182
199
  // «0:07 / 0:00» читалось бы как поломка: у источника без длительности показываем только прошедшее
183
200
  this.#chui_vp_time.setText(this.#calculateTime(position));
184
- this.#chui_vp_main.style.setProperty('--seek-before-width', '0%');
201
+ this.#chui_vp_main.style.setProperty("--seek-before-width", "0%");
185
202
  return;
186
203
  }
187
204
  this.#chui_vp_time.setText(`${this.#calculateTime(position)} / ${this.#calculateTime(duration)}`);
188
205
  this.#chui_vp_seek.value = String(Math.floor(position));
189
206
  // Доля ограничена сотней: `max` — округлённая длительность, а позиция идёт дальше,
190
207
  // и без ограничения полоса целиком заливалась акцентом
191
- const доля = Math.min(100, Math.max(0, Math.floor(position / max * 100)));
192
- this.#chui_vp_main.style.setProperty('--seek-before-width', `${доля}%`);
193
- }
208
+ const доля = Math.min(100, Math.max(0, Math.floor((position / max) * 100)));
209
+ this.#chui_vp_main.style.setProperty("--seek-before-width", `${доля}%`);
210
+ };
194
211
  #calculateTime = (secs) => {
195
212
  const seconds = Number.isFinite(Number(secs)) ? Number(secs) : 0;
196
213
  const minutes = Math.floor(seconds / 60);
197
214
  const rest = Math.floor(seconds % 60);
198
215
  const returnedSeconds = rest < 10 ? `0${rest}` : `${rest}`;
199
216
  return `${minutes}:${returnedSeconds}`;
217
+ };
218
+ #setStatus(text) {
219
+ this.#status.innerText = text;
200
220
  }
201
- #setStatus(text) { this.#status.innerText = text; }
202
221
  #setButton(node, label, icon) {
203
222
  node.innerHTML = new Icon(icon, "18px").getHTML();
204
223
  node.setAttribute("aria-label", label);
@@ -220,71 +239,143 @@ class Video {
220
239
  if (!this.#controls) this.#closePanel();
221
240
  return this;
222
241
  }
223
- getControls() { return this.#controls; }
242
+ getControls() {
243
+ return this.#controls;
244
+ }
224
245
  // === СТАНДАРТНЫЕ ВОЗМОЖНОСТИ `<video>` ===
225
246
  /** Сам элемент: для всего, чего нет в списке ниже */
226
- getVideo() { return this.#chui_vt; }
247
+ getVideo() {
248
+ return this.#chui_vt;
249
+ }
227
250
  /** Воспроизведение: промис, как у `<video>` (разрешается, когда воспроизведение началось) */
228
- play() { return this.#chui_vt.play(); }
229
- pause() { this.#chui_vt.pause(); return this; }
230
- load() { this.#chui_vt.load(); return this; }
231
- canPlayType(type = String()) { return this.#chui_vt.canPlayType(type); }
232
- getSrc() { return this.#chui_vt.getAttribute("src") ?? ""; }
251
+ play() {
252
+ return this.#chui_vt.play();
253
+ }
254
+ pause() {
255
+ this.#chui_vt.pause();
256
+ return this;
257
+ }
258
+ load() {
259
+ this.#chui_vt.load();
260
+ return this;
261
+ }
262
+ canPlayType(type = String()) {
263
+ return this.#chui_vt.canPlayType(type);
264
+ }
265
+ getSrc() {
266
+ return this.#chui_vt.getAttribute("src") ?? "";
267
+ }
233
268
  setSrc(url = String()) {
234
269
  this.#chui_vt.setAttribute("src", url);
235
270
  this.#chui_vt.load();
236
271
  return this;
237
272
  }
238
- getSrcObject() { return this.#chui_vt.srcObject; }
273
+ getSrcObject() {
274
+ return this.#chui_vt.srcObject;
275
+ }
239
276
  /** Живой поток (камера, `getUserMedia`) — штатное `srcObject`, а не путь */
240
277
  setSrcObject(object) {
241
278
  this.#chui_vt.srcObject = object;
242
279
  return this;
243
280
  }
244
- getPoster() { return this.#chui_vt.getAttribute("poster") ?? ""; }
281
+ getPoster() {
282
+ return this.#chui_vt.getAttribute("poster") ?? "";
283
+ }
245
284
  setPoster(url = String()) {
246
285
  if (url === "") this.#chui_vt.removeAttribute("poster");
247
286
  else this.#chui_vt.setAttribute("poster", url);
248
287
  return this;
249
288
  }
250
- getCurrentTime() { return this.#chui_vt.currentTime; }
289
+ getCurrentTime() {
290
+ return this.#chui_vt.currentTime;
291
+ }
251
292
  setCurrentTime(seconds = Number()) {
252
293
  this.#chui_vt.currentTime = Number(seconds);
253
294
  // Подписи и заливка не ждут `timeupdate`: перемотка из кода видна сразу
254
295
  this.#renderProgress();
255
296
  return this;
256
297
  }
257
- getDuration() { return this.#chui_vt.duration; }
258
- getBuffered() { return this.#chui_vt.buffered; }
259
- getPaused() { return this.#chui_vt.paused; }
260
- getEnded() { return this.#chui_vt.ended; }
261
- getReadyState() { return this.#chui_vt.readyState; }
262
- getVolume() { return this.#chui_vt.volume; }
298
+ getDuration() {
299
+ return this.#chui_vt.duration;
300
+ }
301
+ getBuffered() {
302
+ return this.#chui_vt.buffered;
303
+ }
304
+ getPaused() {
305
+ return this.#chui_vt.paused;
306
+ }
307
+ getEnded() {
308
+ return this.#chui_vt.ended;
309
+ }
310
+ getReadyState() {
311
+ return this.#chui_vt.readyState;
312
+ }
313
+ getVolume() {
314
+ return this.#chui_vt.volume;
315
+ }
263
316
  setVolume(value = Number()) {
264
317
  this.#chui_vt.volume = Math.min(1, Math.max(0, Number(value)));
265
318
  return this;
266
319
  }
267
- getMuted() { return this.#chui_vt.muted; }
320
+ getMuted() {
321
+ return this.#chui_vt.muted;
322
+ }
268
323
  setMuted(boolean = Boolean()) {
269
324
  this.#chui_vt.muted = boolean === true;
270
325
  return this;
271
326
  }
272
- getPlaybackRate() { return this.#chui_vt.playbackRate; }
273
- setPlaybackRate(rate = Number()) { this.#chui_vt.playbackRate = Number(rate); return this; }
274
- getDefaultPlaybackRate() { return this.#chui_vt.defaultPlaybackRate; }
275
- setDefaultPlaybackRate(rate = Number()) { this.#chui_vt.defaultPlaybackRate = Number(rate); return this; }
276
- getLoop() { return this.#chui_vt.loop; }
277
- setLoop(boolean = Boolean()) { this.#chui_vt.loop = boolean === true; return this; }
278
- getAutoplay() { return this.#chui_vt.autoplay; }
279
- setAutoplay(boolean = Boolean()) { this.#chui_vt.autoplay = boolean === true; return this; }
280
- getWidth() { return getComputedStyle(this.#chui_vt).width; }
281
- setWidth(value = String()) { this.#chui_vt.style.width = value; return this; }
282
- getHeight() { return getComputedStyle(this.#chui_vt).height; }
283
- setHeight(value = String()) { this.#chui_vt.style.height = value; return this; }
284
- getFullscreen() { return this.#chui_vp_main === document.fullscreenElement; }
327
+ getPlaybackRate() {
328
+ return this.#chui_vt.playbackRate;
329
+ }
330
+ setPlaybackRate(rate = Number()) {
331
+ this.#chui_vt.playbackRate = Number(rate);
332
+ return this;
333
+ }
334
+ getDefaultPlaybackRate() {
335
+ return this.#chui_vt.defaultPlaybackRate;
336
+ }
337
+ setDefaultPlaybackRate(rate = Number()) {
338
+ this.#chui_vt.defaultPlaybackRate = Number(rate);
339
+ return this;
340
+ }
341
+ getLoop() {
342
+ return this.#chui_vt.loop;
343
+ }
344
+ setLoop(boolean = Boolean()) {
345
+ this.#chui_vt.loop = boolean === true;
346
+ return this;
347
+ }
348
+ getAutoplay() {
349
+ return this.#chui_vt.autoplay;
350
+ }
351
+ setAutoplay(boolean = Boolean()) {
352
+ this.#chui_vt.autoplay = boolean === true;
353
+ return this;
354
+ }
355
+ getWidth() {
356
+ return getComputedStyle(this.#chui_vt).width;
357
+ }
358
+ setWidth(value = String()) {
359
+ this.#chui_vt.style.width = value;
360
+ return this;
361
+ }
362
+ getHeight() {
363
+ return getComputedStyle(this.#chui_vt).height;
364
+ }
365
+ setHeight(value = String()) {
366
+ this.#chui_vt.style.height = value;
367
+ return this;
368
+ }
369
+ getFullscreen() {
370
+ return this.#chui_vp_main === document.fullscreenElement;
371
+ }
285
372
  /** Полный экран — на весь плеер, а не на кадр: иначе полоса управления осталась бы снаружи */
286
- requestFullscreen() { return this.#chui_vp_main.requestFullscreen({ navigationUI: "hide" }); }
287
- exitFullscreen() { return document.exitFullscreen(); }
373
+ requestFullscreen() {
374
+ return this.#chui_vp_main.requestFullscreen({ navigationUI: "hide" });
375
+ }
376
+ exitFullscreen() {
377
+ return document.exitFullscreen();
378
+ }
288
379
  addEventListener(type = String(), listener = () => {}) {
289
380
  this.#chui_vt.addEventListener(type, listener);
290
381
  return this;
@@ -293,7 +384,9 @@ class Video {
293
384
  this.#chui_vt.removeEventListener(type, listener);
294
385
  return this;
295
386
  }
296
- set() { return this.#chui_vp_main; }
387
+ set() {
388
+ return this.#chui_vp_main;
389
+ }
297
390
  detach() {
298
391
  this.pause();
299
392
  this.#chui_vp_main.remove();
@@ -320,4 +413,4 @@ class Video {
320
413
  }
321
414
  }
322
415
 
323
- exports.Video = Video
416
+ exports.Video = Video;
@@ -64,7 +64,9 @@ chui_vp_main.vp_controls_off chui_vp_panel {
64
64
  }
65
65
 
66
66
  /* КНОПКИ: площадка 32px с глифом 18px */
67
- chui_vp_play_pause, chui_vp_volume_icon, chui_vp_full_mode {
67
+ chui_vp_play_pause,
68
+ chui_vp_volume_icon,
69
+ chui_vp_full_mode {
68
70
  display: flex;
69
71
  align-items: center;
70
72
  justify-content: center;
@@ -97,12 +99,13 @@ chui_vp_play_pause:hover {
97
99
  }
98
100
 
99
101
  chui_vp_play_pause:active {
100
- transform: scale(.96);
102
+ transform: scale(0.96);
101
103
  }
102
104
 
103
105
  /* Глифы отвечают на курсор акцентом — у всех, кроме главной кнопки: она сама светлая,
104
106
  и её глиф должен остаться читаемым */
105
- chui_vp_volume_icon:hover chui_icon, chui_vp_full_mode:hover chui_icon {
107
+ chui_vp_volume_icon:hover chui_icon,
108
+ chui_vp_full_mode:hover chui_icon {
106
109
  color: var(--blue_prime_background);
107
110
  }
108
111
 
@@ -113,7 +116,7 @@ chui_vp_play_pause:active chui_icon {
113
116
 
114
117
  chui_vp_volume_icon:active,
115
118
  chui_vp_full_mode:active {
116
- transform: scale(.94);
119
+ transform: scale(0.94);
117
120
  }
118
121
 
119
122
  chui_vp_volume_icon:active chui_icon,
@@ -123,8 +126,11 @@ chui_vp_full_mode:active chui_icon {
123
126
 
124
127
  /* Кнопки полосы — кастомные теги, поэтому обводку фокуса рисуем сами.
125
128
  `outline` не сдвигает вёрстку */
126
- chui_vp_play_pause:focus-visible, chui_vp_volume_icon:focus-visible,
127
- chui_vp_full_mode:focus-visible, #chui_vp_seek:focus-visible, #chui_vp_volume:focus-visible {
129
+ chui_vp_play_pause:focus-visible,
130
+ chui_vp_volume_icon:focus-visible,
131
+ chui_vp_full_mode:focus-visible,
132
+ #chui_vp_seek:focus-visible,
133
+ #chui_vp_volume:focus-visible {
128
134
  outline: var(--focus_outline);
129
135
  outline-offset: var(--focus_outline_offset);
130
136
  }
@@ -162,7 +168,8 @@ chui_vp_seek_buf {
162
168
  /* Прогресс и громкость — та же шкала, что у Audio: дорожка `--player_track_height`,
163
169
  заливка градиентом по доле, ползунок виден и в покое и не выезжает за дорожку
164
170
  (`padding-inline` на половину кружка) */
165
- #chui_vp_seek, #chui_vp_volume {
171
+ #chui_vp_seek,
172
+ #chui_vp_volume {
166
173
  margin: 0;
167
174
  -webkit-appearance: none;
168
175
  border-radius: var(--radius_pill);
@@ -194,24 +201,30 @@ chui_vp_seek_buf {
194
201
  }
195
202
 
196
203
  #chui_vp_seek {
197
- background-image: linear-gradient(to right,
204
+ background-image: linear-gradient(
205
+ to right,
198
206
  var(--blue_prime_background) 0 var(--seek-before-width, 0%),
199
- var(--ap_slider_background) var(--seek-before-width, 0%) 100%);
207
+ var(--ap_slider_background) var(--seek-before-width, 0%) 100%
208
+ );
200
209
  }
201
210
 
202
211
  /* Громкость — ступень звука, а не время: заливка нейтральная, чтобы не читалась второй
203
212
  полосой прогресса */
204
213
  #chui_vp_volume {
205
- background-image: linear-gradient(to right,
214
+ background-image: linear-gradient(
215
+ to right,
206
216
  var(--text_color) 0 var(--volume-before-width, 0%),
207
- var(--ap_slider_background) var(--volume-before-width, 0%) 100%);
217
+ var(--ap_slider_background) var(--volume-before-width, 0%) 100%
218
+ );
208
219
  }
209
220
 
210
221
  /* Выключенная громкость (нет звука) — заливка ступени приглушается, как у Audio */
211
222
  #chui_vp_volume:disabled {
212
- background-image: linear-gradient(to right,
223
+ background-image: linear-gradient(
224
+ to right,
213
225
  var(--ap_slider_buf_background) 0 var(--volume-before-width, 0%),
214
- var(--ap_slider_background) var(--volume-before-width, 0%) 100%);
226
+ var(--ap_slider_background) var(--volume-before-width, 0%) 100%
227
+ );
215
228
  }
216
229
 
217
230
  #chui_vp_seek::-webkit-slider-runnable-track,
@@ -224,7 +237,8 @@ chui_vp_seek_buf {
224
237
 
225
238
  /* Ползунок виден всегда, но в покое он меньше — как у Audio. Ободок цвета полосы
226
239
  управления нужен там, где заливка белая */
227
- #chui_vp_seek::-webkit-slider-thumb, #chui_vp_volume::-webkit-slider-thumb {
240
+ #chui_vp_seek::-webkit-slider-thumb,
241
+ #chui_vp_volume::-webkit-slider-thumb {
228
242
  -webkit-appearance: none;
229
243
  border: none;
230
244
  height: 9px;
@@ -254,10 +268,13 @@ chui_vp_main:hover #chui_vp_volume:not(:disabled)::-webkit-slider-thumb,
254
268
  width: 12px;
255
269
  margin-top: calc((var(--player_track_height) - 12px) / 2);
256
270
  background-color: var(--player_thumb_background);
257
- box-shadow: 0 0 0 2px var(--header_background), var(--box_shadow_main);
271
+ box-shadow:
272
+ 0 0 0 2px var(--header_background),
273
+ var(--box_shadow_main);
258
274
  }
259
275
 
260
- #chui_vp_seek:focus, #chui_vp_volume:focus,
276
+ #chui_vp_seek:focus,
277
+ #chui_vp_volume:focus,
261
278
  #chui_vp_seek:focus::-webkit-slider-runnable-track,
262
279
  #chui_vp_volume:focus::-webkit-slider-runnable-track {
263
280
  outline: none;
@@ -1,5 +1,5 @@
1
- const {Animation} = require("../../modules/chui_animations/animations");
2
- const {MenuKeyboard, makeKeyboardButton} = require("../../modules/chui_a11y/chui_a11y");
1
+ const { Animation } = require("../../modules/chui_animations/animations");
2
+ const { MenuKeyboard, makeKeyboardButton } = require("../../modules/chui_a11y/chui_a11y");
3
3
 
4
4
  const MENU_BAR_DROP_DOWN_ACTIVE_CLASS = "menu_bar_drop_down_button";
5
5
  // Панель открывается под кнопкой с зазором и не подходит к краю окна ближе этого отступа
@@ -10,13 +10,13 @@ class MenuBar {
10
10
  // Панели выпадающих списков лежат в body, а не в полосе (см. MenuBarDropDown), поэтому
11
11
  // снятие полосы обязано убирать и их: экземпляр находится по узлу полосы
12
12
  static #instances = new WeakMap();
13
- #chui_menu_bar_main = document.createElement("chui_menu_bar_main")
13
+ #chui_menu_bar_main = document.createElement("chui_menu_bar_main");
14
14
  #dropdowns = [];
15
15
  constructor(options = { test: Boolean() }) {
16
- require('../../modules/chui_functions').setStyles(__dirname + "/styles.css", 'chUiJS_MenuBar');
16
+ require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_MenuBar");
17
17
  MenuBar.#instances.set(this.#chui_menu_bar_main, this);
18
- if (options.test !== undefined) this.#chui_menu_bar_main.setAttribute("test", options.test)
19
- this.#chui_menu_bar_main.addEventListener("wheel", this.#wheel_event, {passive: true});
18
+ if (options.test !== undefined) this.#chui_menu_bar_main.setAttribute("test", options.test);
19
+ this.#chui_menu_bar_main.addEventListener("wheel", this.#wheel_event, { passive: true });
20
20
  }
21
21
  /*
22
22
  * Колесо мыши прокручивает полосу вбок.
@@ -33,8 +33,8 @@ class MenuBar {
33
33
  };
34
34
  addMenuItems(...components) {
35
35
  for (let component of components) {
36
- let element = component.set()
37
- new Animation(element).fadeIn()
36
+ let element = component.set();
37
+ new Animation(element).fadeIn();
38
38
  this.#chui_menu_bar_main.appendChild(element);
39
39
  if (component instanceof MenuBarDropDown) this.#dropdowns.push(component);
40
40
  }
@@ -59,8 +59,8 @@ class MenuBar {
59
59
  set() {
60
60
  return this.#chui_menu_bar_main;
61
61
  }
62
- static DROPDOWN(options = {title: String(), items: []}) {
63
- return new MenuBarDropDown(options)
62
+ static DROPDOWN(options = { title: String(), items: [] }) {
63
+ return new MenuBarDropDown(options);
64
64
  }
65
65
  }
66
66
 
@@ -70,14 +70,15 @@ class MenuBarDropDown {
70
70
  #mb_dd_dropdown = document.createElement("menu_bar_dropdown");
71
71
  #is_open = false;
72
72
  #keyboard = undefined;
73
- constructor(options = {title: String(), items: []}) {
73
+ constructor(options = { title: String(), items: [] }) {
74
74
  // Панель собирают и отдельно от полосы (`MenuBar.DROPDOWN`) — свои стили нужны здесь же
75
- require('../../modules/chui_functions').setStyles(__dirname + "/styles.css", 'chUiJS_MenuBar');
75
+ require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_MenuBar");
76
76
  // Пустой заголовок остаётся пустым: подстановка заготовки опции рисовала слово «undefined»
77
77
  this.#mb_dd_button.innerText = options.title === undefined || options.title === null ? "" : options.title;
78
78
  this.#mb_dd_dropdown.id = require("randomstring").generate();
79
- this.#mb_dd_main.appendChild(this.#mb_dd_button)
80
- for (let item of Array.isArray(options.items) ? options.items : []) this.#mb_dd_dropdown.appendChild(item.set());
79
+ this.#mb_dd_main.appendChild(this.#mb_dd_button);
80
+ for (let item of Array.isArray(options.items) ? options.items : [])
81
+ this.#mb_dd_dropdown.appendChild(item.set());
81
82
  // Панель лежит в document.body, а не рядом с кнопкой: шапка — сама с backdrop-filter,
82
83
  // а элемент с backdrop-filter становится «backdrop root» — вложенная панель тогда не
83
84
  // блюрит содержимое под собой (замер: детальность 33.4 и с блюром, и без него; вне шапки
@@ -89,7 +90,7 @@ class MenuBarDropDown {
89
90
  this.#keyboard = new MenuKeyboard(this.#mb_dd_dropdown, {
90
91
  itemSelector: "button",
91
92
  onEscape: () => this.#close(),
92
- trigger: this.#mb_dd_button
93
+ trigger: this.#mb_dd_button,
93
94
  });
94
95
  makeKeyboardButton(this.#mb_dd_button);
95
96
  // Закрытый список тоже должен быть объявлен как закрытый: без этого у кнопки,
@@ -115,8 +116,8 @@ class MenuBarDropDown {
115
116
  // fadeIn показывает панель (display: flex), и только после этого её можно измерить
116
117
  new Animation(this.#mb_dd_dropdown).fadeIn();
117
118
  this.#positionDropdown();
118
- window.addEventListener('click', this.#window_click_event);
119
- window.addEventListener('resize', this.#position_dropdown_event);
119
+ window.addEventListener("click", this.#window_click_event);
120
+ window.addEventListener("resize", this.#position_dropdown_event);
120
121
  this.#keyboard.setExpanded(true);
121
122
  }
122
123
  #close() {
@@ -124,8 +125,8 @@ class MenuBarDropDown {
124
125
  this.#is_open = false;
125
126
  this.#mb_dd_button.classList.remove(MENU_BAR_DROP_DOWN_ACTIVE_CLASS);
126
127
  new Animation(this.#mb_dd_dropdown).fadeOut();
127
- window.removeEventListener('click', this.#window_click_event);
128
- window.removeEventListener('resize', this.#position_dropdown_event);
128
+ window.removeEventListener("click", this.#window_click_event);
129
+ window.removeEventListener("resize", this.#position_dropdown_event);
129
130
  this.#keyboard.setExpanded(false);
130
131
  }
131
132
  // position: fixed — координаты считаются от окна, поэтому панель пересчитывается и на resize
@@ -142,17 +143,18 @@ class MenuBarDropDown {
142
143
  this.#mb_dd_dropdown.style.top = `${Math.round(button.bottom + MENU_BAR_DROPDOWN_GAP)}px`;
143
144
  }
144
145
  #mb_dd_button_click_event = () => {
145
- if (this.#is_open) this.#close(); else this.#open();
146
- }
146
+ if (this.#is_open) this.#close();
147
+ else this.#open();
148
+ };
147
149
  #mb_dd_dropdown_click_event = () => {
148
150
  this.#close();
149
- }
151
+ };
150
152
  // «Снаружи» — это и кнопка с обёрткой, и сама панель: она теперь не их потомок
151
153
  #window_click_event = (event) => {
152
154
  if (!this.#is_open) return;
153
155
  if (this.#mb_dd_main.contains(event.target) || this.#mb_dd_dropdown.contains(event.target)) return;
154
156
  this.#close();
155
- }
157
+ };
156
158
  #position_dropdown_event = () => this.#positionDropdown();
157
159
  /**
158
160
  * Убрать панель из body, не трогая клавиатурный слой: панель живёт в body, а не в полосе,
@@ -175,4 +177,4 @@ class MenuBarDropDown {
175
177
  }
176
178
  }
177
179
 
178
- exports.MenuBar = MenuBar
180
+ exports.MenuBar = MenuBar;
@@ -57,7 +57,8 @@ chui_menu_bar_main .chui_button:hover {
57
57
  }
58
58
 
59
59
  chui_menu_bar_main .chui_button:active:not(:disabled) {
60
- background: var(--element_background_prime); color: var(--text_color_hover);
60
+ background: var(--element_background_prime);
61
+ color: var(--text_color_hover);
61
62
  border: none;
62
63
  }
63
64
 
@@ -173,7 +174,8 @@ menu_bar_dropdown .chui_button:hover {
173
174
  }
174
175
 
175
176
  menu_bar_dropdown .chui_button:active:not(:disabled) {
176
- background: var(--element_background_prime); color: var(--text_color_hover);
177
+ background: var(--element_background_prime);
178
+ color: var(--text_color_hover);
177
179
  border: none;
178
180
  }
179
181