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.
- package/CHANGELOG.md +536 -0
- package/framework/appLayout/default/chui_app_layout.js +361 -303
- package/framework/appLayout/default/global_style.css +243 -89
- package/framework/appLayout/default/main_theme_style.css +188 -101
- package/framework/components/chui_accordion/accordion.js +17 -17
- package/framework/components/chui_accordion/styles.css +7 -7
- package/framework/components/chui_action_sheet/action_sheet.js +35 -32
- package/framework/components/chui_action_sheet/styles.css +10 -4
- package/framework/components/chui_actions_bar/actions_bar.js +338 -0
- package/framework/components/chui_actions_bar/styles.css +139 -0
- package/framework/components/chui_affix/affix.js +4 -4
- package/framework/components/chui_affix/styles.css +5 -0
- package/framework/components/chui_alert/alert.js +11 -5
- package/framework/components/chui_alert/styles.css +7 -0
- package/framework/components/chui_avatar/avatar.js +13 -13
- package/framework/components/chui_avatar/styles.css +1 -1
- package/framework/components/chui_avatar_group/avatar_group.js +4 -4
- package/framework/components/chui_avatar_group/styles.css +1 -1
- package/framework/components/chui_backtop/backtop.js +25 -2
- package/framework/components/chui_backtop/styles.css +21 -0
- package/framework/components/chui_badge/badge.js +15 -15
- package/framework/components/chui_badge/styles.css +6 -6
- package/framework/components/chui_banner/banner.js +222 -0
- package/framework/components/chui_banner/styles.css +170 -0
- package/framework/components/chui_breadcrumb/styles.css +1 -1
- package/framework/components/chui_button/button.js +24 -28
- package/framework/components/chui_button/styles.css +5 -5
- package/framework/components/chui_calendar/calendar.js +6 -6
- package/framework/components/chui_card/card.js +14 -14
- package/framework/components/chui_card_scroll/card_scroll.js +169 -0
- package/framework/components/chui_card_scroll/styles.css +86 -0
- package/framework/components/chui_chat/chat.js +73 -51
- package/framework/components/chui_chat/styles.css +18 -7
- package/framework/components/chui_clipboard_history/clipboard_history.js +25 -20
- package/framework/components/chui_clipboard_history/styles.css +10 -8
- package/framework/components/chui_code/code.js +8 -8
- package/framework/components/chui_code/styles.css +2 -2
- package/framework/components/chui_code_editor/code_editor.js +26 -26
- package/framework/components/chui_code_editor/styles.css +3 -3
- package/framework/components/chui_command_palette/command_palette.js +29 -29
- package/framework/components/chui_command_palette/styles.css +5 -5
- package/framework/components/chui_console/console.js +9 -9
- package/framework/components/chui_console/styles.css +5 -2
- package/framework/components/chui_content_block/content_block.js +2 -2
- package/framework/components/chui_context_menu/context_menu.js +162 -54
- package/framework/components/chui_context_menu/styles.css +82 -8
- package/framework/components/chui_custom_element/custom_element.js +11 -11
- package/framework/components/chui_data_grid/data_grid.js +268 -268
- package/framework/components/chui_data_grid/styles.css +14 -14
- package/framework/components/chui_descriptions/styles.css +1 -1
- package/framework/components/chui_details/details.js +12 -12
- package/framework/components/chui_details/styles.css +7 -7
- package/framework/components/chui_diff_viewer/diff_viewer.js +88 -88
- package/framework/components/chui_diff_viewer/styles.css +9 -9
- package/framework/components/chui_divider/divider.js +6 -6
- package/framework/components/chui_divider/styles.css +2 -2
- package/framework/components/chui_drawer/drawer.js +37 -14
- package/framework/components/chui_drawer/styles.css +18 -4
- package/framework/components/chui_drop_zone/drop_zone.js +6 -6
- package/framework/components/chui_drop_zone/styles.css +10 -6
- package/framework/components/chui_fieldset/fieldset.js +6 -6
- package/framework/components/chui_fieldset/styles.css +5 -5
- package/framework/components/chui_file_explorer/file_explorer.js +115 -115
- package/framework/components/chui_file_explorer/styles.css +6 -6
- package/framework/components/chui_form/form.js +11 -11
- package/framework/components/chui_gantt/gantt.js +41 -41
- package/framework/components/chui_gantt/styles.css +5 -5
- package/framework/components/chui_graphs/graphs.js +82 -46
- package/framework/components/chui_graphs/styles.css +26 -5
- package/framework/components/chui_hero/hero.js +63 -20
- package/framework/components/chui_hero/styles.css +176 -7
- package/framework/components/chui_html_block/html_block.js +5 -5
- package/framework/components/chui_html_block/styles.css +1 -1
- package/framework/components/chui_hx/styles.css +2 -2
- package/framework/components/chui_icons/icons.js +7 -7
- package/framework/components/chui_icons/styles.css +2 -1
- package/framework/components/chui_inputs/chui_check_box/styles.css +12 -3
- package/framework/components/chui_inputs/chui_chips/chips.js +92 -31
- package/framework/components/chui_inputs/chui_chips/styles.css +28 -5
- package/framework/components/chui_inputs/chui_color_picker/color_picker.js +20 -15
- package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
- package/framework/components/chui_inputs/chui_combo_box/combo_box.js +58 -58
- package/framework/components/chui_inputs/chui_combo_box/styles.css +9 -9
- package/framework/components/chui_inputs/chui_date/date.js +93 -95
- package/framework/components/chui_inputs/chui_date/styles.css +8 -8
- package/framework/components/chui_inputs/chui_date_range/date_range.js +22 -22
- package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
- package/framework/components/chui_inputs/chui_datetime/datetime.js +12 -12
- package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
- package/framework/components/chui_inputs/chui_email/email.js +10 -10
- package/framework/components/chui_inputs/chui_email/styles.css +6 -6
- package/framework/components/chui_inputs/chui_file/file.js +8 -8
- package/framework/components/chui_inputs/chui_file/styles.css +12 -9
- package/framework/components/chui_inputs/chui_hotkey/hotkey.js +39 -39
- package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
- package/framework/components/chui_inputs/chui_masked/masked.js +44 -44
- package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
- package/framework/components/chui_inputs/chui_mention/mention.js +13 -13
- package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
- package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +147 -137
- package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +14 -8
- package/framework/components/chui_inputs/chui_number/number.js +42 -45
- package/framework/components/chui_inputs/chui_number/styles.css +6 -6
- package/framework/components/chui_inputs/chui_otp/otp.js +32 -32
- package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
- package/framework/components/chui_inputs/chui_password/password.js +30 -36
- package/framework/components/chui_inputs/chui_password/styles.css +7 -7
- package/framework/components/chui_inputs/chui_radio_button/styles.css +2 -2
- package/framework/components/chui_inputs/chui_rating/rating.js +28 -28
- package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
- package/framework/components/chui_inputs/chui_select_box/select_box.js +54 -54
- package/framework/components/chui_inputs/chui_select_box/styles.css +10 -10
- package/framework/components/chui_inputs/chui_slider/slider.js +14 -14
- package/framework/components/chui_inputs/chui_slider/styles.css +5 -4
- package/framework/components/chui_inputs/chui_text/styles.css +7 -7
- package/framework/components/chui_inputs/chui_text/text.js +13 -17
- package/framework/components/chui_inputs/chui_text_area/styles.css +8 -8
- package/framework/components/chui_inputs/chui_text_area/text_area.js +23 -23
- package/framework/components/chui_inputs/chui_time/styles.css +13 -17
- package/framework/components/chui_inputs/chui_time/time.js +35 -24
- package/framework/components/chui_inputs/chui_toggle/styles.css +10 -3
- package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
- package/framework/components/chui_json_editor/json_editor.js +87 -87
- package/framework/components/chui_json_editor/styles.css +5 -5
- package/framework/components/chui_json_viewer/json_viewer.js +80 -80
- package/framework/components/chui_json_viewer/styles.css +6 -6
- package/framework/components/chui_kanban/kanban.js +27 -27
- package/framework/components/chui_kanban/styles.css +8 -4
- package/framework/components/chui_kbd/styles.css +1 -1
- package/framework/components/chui_label/label.js +17 -17
- package/framework/components/chui_label/styles.css +1 -1
- package/framework/components/chui_link/link.js +9 -9
- package/framework/components/chui_link/styles.css +11 -4
- package/framework/components/chui_list/list.js +11 -11
- package/framework/components/chui_list/styles.css +2 -2
- package/framework/components/chui_markdown_editor/markdown_editor.js +66 -66
- package/framework/components/chui_markdown_editor/styles.css +5 -5
- package/framework/components/chui_media/audio.js +240 -246
- package/framework/components/chui_media/audio_styles.css +41 -23
- package/framework/components/chui_media/image.js +49 -46
- package/framework/components/chui_media/image_compare.js +35 -35
- package/framework/components/chui_media/image_compare_styles.css +5 -5
- package/framework/components/chui_media/image_styles.css +1 -1
- package/framework/components/chui_media/video.js +148 -148
- package/framework/components/chui_media/video_styles.css +27 -11
- package/framework/components/chui_menu_bar/menu_bar.js +54 -54
- package/framework/components/chui_menu_bar/styles.css +10 -10
- package/framework/components/chui_message_bar/message_bar.js +551 -0
- package/framework/components/chui_message_bar/styles.css +248 -0
- package/framework/components/chui_modal/modal.js +37 -13
- package/framework/components/chui_notification/notification.js +76 -54
- package/framework/components/chui_notification/notification_download.js +26 -81
- package/framework/components/chui_notification/notification_download_card.js +115 -0
- package/framework/components/chui_notification/notification_download_progress.css +2 -2
- package/framework/components/chui_notification/notification_download_progress.js +70 -108
- package/framework/components/chui_notification/notification_update.js +31 -31
- package/framework/components/chui_notification/status_plate.css +3 -3
- package/framework/components/chui_notification/styles.css +6 -1
- package/framework/components/chui_notification/styles_download.css +1 -1
- package/framework/components/chui_notification/styles_update.css +2 -2
- package/framework/components/chui_org_chart/org_chart.js +29 -29
- package/framework/components/chui_org_chart/styles.css +2 -2
- package/framework/components/chui_pagination/pagination.js +3 -3
- package/framework/components/chui_pagination/styles.css +1 -1
- package/framework/components/chui_paragraph/styles.css +2 -2
- package/framework/components/chui_popover/popover.js +29 -23
- package/framework/components/chui_popover/styles.css +1 -1
- package/framework/components/chui_popups/popups.js +124 -124
- package/framework/components/chui_popups/styles.css +5 -5
- package/framework/components/chui_print_button/print_button.js +15 -10
- package/framework/components/chui_progress_bar/progress_bar.js +34 -12
- package/framework/components/chui_progress_bar/styles.css +4 -4
- package/framework/components/chui_progress_ring/progress_ring.js +15 -15
- package/framework/components/chui_progress_ring/styles.css +1 -1
- package/framework/components/chui_qrcode/qrcode.js +12 -12
- package/framework/components/chui_query_builder/query_builder.js +46 -46
- package/framework/components/chui_query_builder/styles.css +4 -4
- package/framework/components/chui_radio_group/styles.css +1 -1
- package/framework/components/chui_result/result.js +15 -15
- package/framework/components/chui_result/styles.css +3 -3
- package/framework/components/chui_scheduler/scheduler.js +74 -74
- package/framework/components/chui_scheduler/styles.css +5 -5
- package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
- package/framework/components/chui_screen_spinner/styles.css +49 -0
- package/framework/components/chui_segmented_control/segmented_control.js +63 -6
- package/framework/components/chui_segmented_control/styles.css +32 -6
- package/framework/components/chui_settings/settings.js +45 -46
- package/framework/components/chui_settings/styles.css +4 -4
- package/framework/components/chui_shortcut_help/shortcut_help.js +32 -34
- package/framework/components/chui_sidebar_nav/sidebar_nav.js +98 -29
- package/framework/components/chui_sidebar_nav/styles.css +9 -3
- package/framework/components/chui_slideshow/slideshow.js +85 -85
- package/framework/components/chui_slideshow/styles.css +6 -6
- package/framework/components/chui_spinner/spinner.js +10 -10
- package/framework/components/chui_split_button/split_button.js +30 -12
- package/framework/components/chui_split_button/styles.css +21 -5
- package/framework/components/chui_splitter/splitter.js +11 -11
- package/framework/components/chui_splitter/styles.css +2 -2
- package/framework/components/chui_statistic/statistic.js +47 -47
- package/framework/components/chui_status_bar/styles.css +2 -2
- package/framework/components/chui_stepper/stepper.js +202 -31
- package/framework/components/chui_stepper/styles.css +79 -14
- package/framework/components/chui_sticky_bar/sticky_bar.js +44 -13
- package/framework/components/chui_sticky_bar/styles.css +10 -8
- package/framework/components/chui_tabs/chui_tabs.js +74 -26
- package/framework/components/chui_tabs/styles.css +40 -12
- package/framework/components/chui_text_editor/styles.css +7 -7
- package/framework/components/chui_text_editor/text_editor.js +56 -56
- package/framework/components/chui_text_editor/text_editor_panel.js +173 -174
- package/framework/components/chui_theme_toggle/theme_toggle.js +21 -5
- package/framework/components/chui_timeline/styles.css +3 -1
- package/framework/components/chui_toast_queue/styles.css +11 -11
- package/framework/components/chui_toast_queue/toast_queue.js +30 -27
- package/framework/components/chui_toolbar/styles.css +2 -2
- package/framework/components/chui_tooltip/styles.css +2 -2
- package/framework/components/chui_tooltip/tooltip.js +3 -3
- package/framework/components/chui_tour/styles.css +8 -8
- package/framework/components/chui_tour/tour.js +72 -72
- package/framework/components/chui_transfer/styles.css +6 -6
- package/framework/components/chui_transfer/transfer.js +93 -106
- package/framework/components/chui_tree_table/styles.css +4 -4
- package/framework/components/chui_tree_table/tree_table.js +45 -45
- package/framework/components/chui_tree_view/styles.css +10 -8
- package/framework/components/chui_tree_view/tree_view.js +185 -183
- package/framework/components/chui_user_bar/styles.css +145 -0
- package/framework/components/chui_user_bar/user_bar.js +402 -0
- package/framework/components/chui_user_list_bar/styles.css +173 -0
- package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
- package/framework/components/chui_watermark/watermark.js +17 -17
- package/framework/components/chui_webview/webview.js +9 -9
- package/framework/components/chui_write_bar/styles.css +172 -0
- package/framework/components/chui_write_bar/write_bar.js +320 -0
- package/framework/main_window.js +1234 -0
- package/framework/modules/chui_a11y/chui_a11y.js +78 -79
- package/framework/modules/chui_animations/animations.js +77 -15
- package/framework/modules/chui_animations/motion.js +120 -0
- package/framework/modules/chui_animations/styles.css +36 -3
- package/framework/modules/chui_functions.js +31 -27
- package/framework/modules/chui_highlight/styles.css +13 -10
- package/framework/modules/chui_i18n/chui_i18n.js +3 -3
- package/framework/modules/chui_i18n/locales/feedback.js +62 -0
- package/framework/modules/chui_i18n/locales/navigation.js +4 -0
- package/framework/modules/chui_json/chui_json.js +2 -2
- package/framework/modules/chui_logger/chui_logger.js +23 -8
- package/framework/modules/chui_page/page.js +10 -10
- package/framework/modules/chui_palette/palette.js +61 -0
- package/framework/modules/chui_qr/chui_qr.js +23 -23
- package/framework/modules/chui_scrollbar/chui_scrollbar.js +45 -45
- package/framework/modules/chui_scrollbar/styles.css +3 -3
- package/framework/modules/chui_services/chui_services.js +8 -8
- package/framework/modules/chui_services/desktop.js +77 -71
- package/framework/modules/chui_sortable/chui_sortable.js +17 -17
- package/framework/modules/chui_validate/chui_validate.js +3 -3
- package/framework/tray_bar/chui_menu_items.js +2 -2
- package/index.d.ts +266 -34
- package/index.js +20 -1168
- package/package.json +6 -4
- package/framework/components/telegram_bot/chui_telegram_bot.js +0 -191
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { setStyles } = require("../../modules/chui_functions");
|
|
2
|
+
const { reducedMotion } = require("../../modules/chui_animations/motion");
|
|
2
3
|
const { Icon, Icons } = require("../chui_icons/icons");
|
|
3
4
|
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
4
5
|
|
|
@@ -61,13 +62,13 @@ class SidebarNav {
|
|
|
61
62
|
#collapsed = false;
|
|
62
63
|
#collapsible = false;
|
|
63
64
|
#id = undefined;
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
65
|
+
#titleText = undefined;
|
|
66
|
+
#labelText = undefined;
|
|
67
|
+
#onSelect = undefined;
|
|
68
|
+
#onToggle = undefined;
|
|
68
69
|
#listeners = [];
|
|
69
|
-
#
|
|
70
|
-
#
|
|
70
|
+
#activeId = undefined;
|
|
71
|
+
#focusId = undefined;
|
|
71
72
|
|
|
72
73
|
constructor(
|
|
73
74
|
options = {
|
|
@@ -88,8 +89,8 @@ class SidebarNav {
|
|
|
88
89
|
this.#id = options.id === undefined ? `chui_sidebar_nav_${SidebarNav.#counter}` : options.id;
|
|
89
90
|
this.#root.id = this.#id;
|
|
90
91
|
this.#root.setAttribute("role", "navigation");
|
|
91
|
-
this.#
|
|
92
|
-
this.#
|
|
92
|
+
this.#onSelect = options.onSelect;
|
|
93
|
+
this.#onToggle = options.onToggle;
|
|
93
94
|
this.#collapsible = options.collapsible === true;
|
|
94
95
|
if (options.changeEvent !== undefined) this.addChangeListener(options.changeEvent);
|
|
95
96
|
this.#title.className = "sidebar_nav_title";
|
|
@@ -118,12 +119,12 @@ class SidebarNav {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
getTitle() {
|
|
121
|
-
return this.#
|
|
122
|
+
return this.#titleText;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
/** Доступное имя навигации, заданное в `label` */
|
|
125
126
|
getLabel() {
|
|
126
|
-
return this.#
|
|
127
|
+
return this.#labelText;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
/** Пункты деревом: `{id, title, icon, badge, disabled, expanded, children}`; разделы — `{type: "section", title, children}` */
|
|
@@ -176,7 +177,7 @@ class SidebarNav {
|
|
|
176
177
|
|
|
177
178
|
/** Подпись в шапке навигации; `undefined` её убирает */
|
|
178
179
|
setTitle(text = undefined) {
|
|
179
|
-
this.#
|
|
180
|
+
this.#titleText = text;
|
|
180
181
|
if (text === undefined || text === "") {
|
|
181
182
|
this.#title.innerText = "";
|
|
182
183
|
this.#title.hidden = true;
|
|
@@ -191,7 +192,7 @@ class SidebarNav {
|
|
|
191
192
|
|
|
192
193
|
/** Имя навигации, когда подписи в шапке нет */
|
|
193
194
|
setLabel(text = undefined) {
|
|
194
|
-
this.#
|
|
195
|
+
this.#labelText = text;
|
|
195
196
|
this.#syncLabel();
|
|
196
197
|
return this;
|
|
197
198
|
}
|
|
@@ -276,8 +277,76 @@ class SidebarNav {
|
|
|
276
277
|
if (next === this.#expanded.has(node.id)) return this;
|
|
277
278
|
if (next) this.#expanded.add(node.id);
|
|
278
279
|
else this.#expanded.delete(node.id);
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
// Панель переключается на месте, а не пересборкой списка: новый узел не помнит прошлого
|
|
281
|
+
// состояния, поэтому и стрелка, и содержимое появлялись готовыми — без движения
|
|
282
|
+
this.#setPanel(node, next);
|
|
283
|
+
if (!silent && this.#onToggle !== undefined) this.#onToggle(this.#describe(node), next, this);
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Узел панели пункта — по её id, тому же, что в `aria-controls` пункта */
|
|
288
|
+
#panelNode(node = Object()) {
|
|
289
|
+
return this.#root.querySelector(`[id="${this.#id}_panel_${node.id}"]`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** Узел пункта: он несёт `aria-expanded` (по нему поворачивается стрелка)
|
|
293
|
+
и панель */
|
|
294
|
+
#linkNode(node = Object()) {
|
|
295
|
+
return this.#links().find((link) => link.dataset.id === node.id) ?? null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Раскрытие и сворачивание панели пункта.
|
|
300
|
+
*
|
|
301
|
+
* Высоту списка ведёт компонент, а время и кривую берут токены движения из стилей: высоту
|
|
302
|
+
* кадром не задать — её знает только раскладка, поэтому её считает JS и переводит переходом.
|
|
303
|
+
* `overflow` на время движения прячет содержимое, которое ещё не помещается в панель,
|
|
304
|
+
* а после снимается: иначе вложенные списки и счётчики обрезались бы по краю.
|
|
305
|
+
*/
|
|
306
|
+
#setPanel(node = Object(), open = Boolean()) {
|
|
307
|
+
const panel = this.#panelNode(node);
|
|
308
|
+
const link = this.#linkNode(node);
|
|
309
|
+
// В свёрнутой навигации подписи скрыты, поэтому пункт всегда заявляет себя свёрнутым
|
|
310
|
+
if (link !== null) link.setAttribute("aria-expanded", open && !this.#collapsed ? "true" : "false");
|
|
311
|
+
if (panel === null) return this;
|
|
312
|
+
if (open) {
|
|
313
|
+
panel.hidden = false;
|
|
314
|
+
this.#slidePanel(panel, 0, panel.scrollHeight);
|
|
315
|
+
} else {
|
|
316
|
+
this.#slidePanel(panel, panel.scrollHeight, 0, () => {
|
|
317
|
+
panel.hidden = true;
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
this.#applyStop();
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Перевод высоты панели от `from` к `to`; `done` — по концу перехода */
|
|
325
|
+
#slidePanel(panel = undefined, from = Number(), to = Number(), done = () => {}) {
|
|
326
|
+
const finish = (event) => {
|
|
327
|
+
if (event !== undefined && event.propertyName !== "max-height") return;
|
|
328
|
+
panel.removeEventListener("transitionend", finish);
|
|
329
|
+
panel.style.removeProperty("max-height");
|
|
330
|
+
panel.style.removeProperty("opacity");
|
|
331
|
+
panel.style.removeProperty("overflow");
|
|
332
|
+
done();
|
|
333
|
+
};
|
|
334
|
+
// Уменьшенное движение: состояние применяется сразу — перехода не будет,
|
|
335
|
+
// и `transitionend` не придёт
|
|
336
|
+
if (reducedMotion()) {
|
|
337
|
+
finish();
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
panel.style.overflow = "hidden";
|
|
341
|
+
panel.style.maxHeight = `${from}px`;
|
|
342
|
+
panel.style.opacity = from === 0 ? "0" : "1";
|
|
343
|
+
panel.addEventListener("transitionend", finish);
|
|
344
|
+
// Следующий кадр — уже с конечными значениями: в том же кадре браузер не увидел бы
|
|
345
|
+
// перехода, и панель встала бы готовой
|
|
346
|
+
requestAnimationFrame(() => {
|
|
347
|
+
panel.style.maxHeight = `${to}px`;
|
|
348
|
+
panel.style.opacity = to === 0 ? "0" : "1";
|
|
349
|
+
});
|
|
281
350
|
return this;
|
|
282
351
|
}
|
|
283
352
|
|
|
@@ -329,9 +398,9 @@ class SidebarNav {
|
|
|
329
398
|
for (const key of Object.keys(source === null ? {} : source)) {
|
|
330
399
|
if (!SERVICE_KEYS.includes(key)) data[key] = source[key];
|
|
331
400
|
}
|
|
332
|
-
SidebarNav.#
|
|
401
|
+
SidebarNav.#itemCounter += 1;
|
|
333
402
|
return {
|
|
334
|
-
id: source.id === undefined ? `sidebar_nav_item_${SidebarNav.#
|
|
403
|
+
id: source.id === undefined ? `sidebar_nav_item_${SidebarNav.#itemCounter}` : String(source.id),
|
|
335
404
|
title: source.title === undefined ? "" : String(source.title),
|
|
336
405
|
icon: source.icon,
|
|
337
406
|
badge: source.badge === undefined ? undefined : String(source.badge),
|
|
@@ -342,7 +411,7 @@ class SidebarNav {
|
|
|
342
411
|
};
|
|
343
412
|
}
|
|
344
413
|
|
|
345
|
-
static #
|
|
414
|
+
static #itemCounter = 0;
|
|
346
415
|
|
|
347
416
|
#describeEntry(node) {
|
|
348
417
|
if (node.type === "section") {
|
|
@@ -392,13 +461,13 @@ class SidebarNav {
|
|
|
392
461
|
}
|
|
393
462
|
|
|
394
463
|
#accessibleName() {
|
|
395
|
-
if (this.#
|
|
396
|
-
if (this.#
|
|
464
|
+
if (this.#titleText !== undefined && this.#titleText !== "") return this.#titleText;
|
|
465
|
+
if (this.#labelText !== undefined && this.#labelText !== "") return this.#labelText;
|
|
397
466
|
return I18n.t("navigation.sidebarNav");
|
|
398
467
|
}
|
|
399
468
|
|
|
400
469
|
#syncLabel() {
|
|
401
|
-
if (this.#
|
|
470
|
+
if (this.#titleText !== undefined && this.#titleText !== "") {
|
|
402
471
|
this.#root.setAttribute("aria-labelledby", this.#title.id);
|
|
403
472
|
this.#root.removeAttribute("aria-label");
|
|
404
473
|
return;
|
|
@@ -430,7 +499,7 @@ class SidebarNav {
|
|
|
430
499
|
// Пункты пересобираются: запоминаем, где стоял фокус, чтобы вернуть его
|
|
431
500
|
const active = document.activeElement;
|
|
432
501
|
const focused = active === null || !this.#root.contains(active) ? null : active.closest(".sidebar_nav_link");
|
|
433
|
-
if (focused !== null) this.#
|
|
502
|
+
if (focused !== null) this.#focusId = focused.dataset.id;
|
|
434
503
|
this.#body.innerHTML = "";
|
|
435
504
|
this.#head.hidden = this.#title.hidden === true && this.#collapse === undefined;
|
|
436
505
|
this.#body.appendChild(this.#listsNode(this.#items));
|
|
@@ -559,13 +628,13 @@ class SidebarNav {
|
|
|
559
628
|
const list = this.#visibleLinks();
|
|
560
629
|
if (list.length === 0) return;
|
|
561
630
|
const stop =
|
|
562
|
-
list.find((link) => link.dataset.id === this.#
|
|
563
|
-
list.find((link) => link.dataset.id === this.#
|
|
631
|
+
list.find((link) => link.dataset.id === this.#activeId) ??
|
|
632
|
+
list.find((link) => link.dataset.id === this.#focusId) ??
|
|
564
633
|
list[0];
|
|
565
|
-
this.#
|
|
634
|
+
this.#activeId = stop.dataset.id;
|
|
566
635
|
for (const link of this.#links()) link.setAttribute("tabindex", link === stop ? "0" : "-1");
|
|
567
|
-
if (this.#
|
|
568
|
-
this.#
|
|
636
|
+
if (this.#focusId !== undefined && stop.dataset.id === this.#focusId) {
|
|
637
|
+
this.#focusId = undefined;
|
|
569
638
|
stop.focus();
|
|
570
639
|
}
|
|
571
640
|
return this;
|
|
@@ -574,7 +643,7 @@ class SidebarNav {
|
|
|
574
643
|
#focusLink(id = String()) {
|
|
575
644
|
const link = this.#links().find((node) => node.dataset.id === id);
|
|
576
645
|
if (link === undefined) return;
|
|
577
|
-
this.#
|
|
646
|
+
this.#activeId = id;
|
|
578
647
|
for (const other of this.#links()) other.setAttribute("tabindex", other === link ? "0" : "-1");
|
|
579
648
|
link.focus();
|
|
580
649
|
}
|
|
@@ -607,13 +676,13 @@ class SidebarNav {
|
|
|
607
676
|
const node = this.#value === undefined ? undefined : this.#index.get(this.#value);
|
|
608
677
|
const item = node === undefined ? undefined : this.#describe(node);
|
|
609
678
|
for (const listener of [...this.#listeners]) listener(item, this);
|
|
610
|
-
if (this.#
|
|
679
|
+
if (this.#onSelect !== undefined) this.#onSelect(item, this);
|
|
611
680
|
}
|
|
612
681
|
|
|
613
682
|
#currentLink(target = undefined) {
|
|
614
683
|
const link = target === undefined ? null : target.closest(".sidebar_nav_link");
|
|
615
684
|
if (link !== null && link !== undefined) return link;
|
|
616
|
-
const id = this.#
|
|
685
|
+
const id = this.#activeId;
|
|
617
686
|
return id === undefined ? null : (this.#links().find((node) => node.dataset.id === id) ?? null);
|
|
618
687
|
}
|
|
619
688
|
|
|
@@ -8,9 +8,9 @@ chui_sidebar_nav {
|
|
|
8
8
|
width: 260px;
|
|
9
9
|
max-width: 100%;
|
|
10
10
|
height: max-content;
|
|
11
|
-
margin: var(--
|
|
11
|
+
margin: var(--block_margin);
|
|
12
12
|
border: 1px solid var(--border_color);
|
|
13
|
-
border-radius: var(--
|
|
13
|
+
border-radius: var(--radius_sm);
|
|
14
14
|
background: var(--element_background_2);
|
|
15
15
|
color: var(--text_color);
|
|
16
16
|
}
|
|
@@ -223,7 +223,7 @@ chui_sidebar_nav {
|
|
|
223
223
|
.sidebar_nav_arrow chui_icon {
|
|
224
224
|
color: inherit;
|
|
225
225
|
font-size: 18px;
|
|
226
|
-
transition: transform var(--
|
|
226
|
+
transition: transform var(--motion_base) var(--motion_ease);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
/* Раскрытие показывает стрелка: состояние берётся из aria-expanded самого пункта */
|
|
@@ -238,6 +238,12 @@ chui_sidebar_nav {
|
|
|
238
238
|
.sidebar_nav_panel {
|
|
239
239
|
display: block;
|
|
240
240
|
padding-inline-start: 14px;
|
|
241
|
+
/* Высоту списка ведёт компонент (`max-height` инлайном: её знает только раскладка),
|
|
242
|
+
а время и кривую берут токены движения. Свойство `transition` на элементе заменяет
|
|
243
|
+
общий список целиком — у самой панели других переходов нет, список короткий и намеренный */
|
|
244
|
+
transition:
|
|
245
|
+
max-height var(--motion_base) var(--motion_ease),
|
|
246
|
+
opacity var(--motion_base) var(--motion_ease);
|
|
241
247
|
}
|
|
242
248
|
|
|
243
249
|
.sidebar_nav_panel[hidden] {
|
|
@@ -5,31 +5,31 @@ const { makeKeyboardButton } = require("../../modules/chui_a11y/chui_a11y");
|
|
|
5
5
|
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
6
6
|
|
|
7
7
|
class SlideShow {
|
|
8
|
-
#
|
|
9
|
-
#
|
|
8
|
+
#defaultSlide = 0;
|
|
9
|
+
#chuiSlidesMain = document.createElement("chui_slides_main");
|
|
10
10
|
//
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
11
|
+
#chuiSlidesList = document.createElement("chui_slides_list");
|
|
12
|
+
#chuiNextSlide = document.createElement("chui_next_slide");
|
|
13
|
+
#chuiPrevSlide = document.createElement("chui_prev_slide");
|
|
14
|
+
#chuiSlideshowControls = document.createElement("chui_slideshow_controls");
|
|
15
|
+
#chuiSlideshowDots = document.createElement("chui_slideshow_dots");
|
|
16
|
+
#chuiSlideshowPause = document.createElement("chui_slideshow_pause");
|
|
17
17
|
//
|
|
18
|
-
#
|
|
18
|
+
#slidesList = undefined;
|
|
19
19
|
#autoplay = undefined;
|
|
20
|
-
#
|
|
21
|
-
#
|
|
20
|
+
#autoplayTimer = undefined;
|
|
21
|
+
#userPaused = false;
|
|
22
22
|
constructor(options = {}) {
|
|
23
23
|
require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_SlideShow");
|
|
24
24
|
// Частичный объект опций: у каждого поля своё значение по умолчанию
|
|
25
25
|
const width = optionOr(options.width, undefined);
|
|
26
26
|
const height = optionOr(options.height, undefined);
|
|
27
|
-
if (width !== undefined) this.#
|
|
28
|
-
if (height !== undefined) this.#
|
|
27
|
+
if (width !== undefined) this.#chuiSlidesMain.style.width = width;
|
|
28
|
+
if (height !== undefined) this.#chuiSlidesMain.style.height = height;
|
|
29
29
|
|
|
30
|
-
this.#
|
|
30
|
+
this.#slidesList = Array.isArray(options.slides) ? options.slides : [];
|
|
31
31
|
// Карусель без слайдов — не картинка: показывать нечего, но и падать TypeError незачем
|
|
32
|
-
if (this.#
|
|
32
|
+
if (this.#slidesList.length === 0) {
|
|
33
33
|
throw new Error("SlideShow: нужен хотя бы один слайд — опция slides");
|
|
34
34
|
}
|
|
35
35
|
// Частичный объект опций: у каждого поля своё значение по умолчанию. Без этого
|
|
@@ -45,44 +45,44 @@ class SlideShow {
|
|
|
45
45
|
interval: Number.isFinite(interval) && interval > 0 ? interval : 10,
|
|
46
46
|
};
|
|
47
47
|
// Доступность: регион-карусель, подписи у кнопок, живое объявление смены слайда
|
|
48
|
-
this.#
|
|
49
|
-
this.#
|
|
50
|
-
this.#
|
|
51
|
-
this.#
|
|
52
|
-
this.#
|
|
53
|
-
this.#
|
|
54
|
-
makeKeyboardButton(this.#
|
|
55
|
-
makeKeyboardButton(this.#
|
|
56
|
-
this.#
|
|
57
|
-
this.#
|
|
58
|
-
this.#
|
|
48
|
+
this.#chuiSlidesMain.setAttribute("role", "region");
|
|
49
|
+
this.#chuiSlidesMain.setAttribute("aria-roledescription", I18n.t("feedback.carousel"));
|
|
50
|
+
this.#chuiSlidesMain.setAttribute("aria-label", I18n.t("feedback.slideshow"));
|
|
51
|
+
this.#chuiSlidesList.setAttribute("aria-live", "polite");
|
|
52
|
+
this.#chuiNextSlide.setAttribute("aria-label", I18n.t("feedback.nextSlide"));
|
|
53
|
+
this.#chuiPrevSlide.setAttribute("aria-label", I18n.t("feedback.previousSlide"));
|
|
54
|
+
makeKeyboardButton(this.#chuiNextSlide);
|
|
55
|
+
makeKeyboardButton(this.#chuiPrevSlide);
|
|
56
|
+
this.#chuiNextSlide.addEventListener("click", () => this.#changeSlide(1));
|
|
57
|
+
this.#chuiPrevSlide.addEventListener("click", () => this.#changeSlide(-1));
|
|
58
|
+
this.#chuiSlidesMain.appendChild(this.#chuiSlidesList);
|
|
59
59
|
// Шевроны, а не изогнутые redo/undo: в круглой кнопке они читаются как «назад/вперёд».
|
|
60
60
|
// Цвет не задаём — его берёт глиф из кнопки (`color: inherit` в styles.css), поэтому
|
|
61
61
|
// нажатие окрашивает и значок
|
|
62
|
-
this.#
|
|
63
|
-
this.#
|
|
64
|
-
this.#
|
|
65
|
-
this.#
|
|
62
|
+
this.#chuiNextSlide.appendChild(new Icon(Icons.NAVIGATION.CHEVRON_RIGHT, "18px").set());
|
|
63
|
+
this.#chuiPrevSlide.appendChild(new Icon(Icons.NAVIGATION.CHEVRON_LEFT, "18px").set());
|
|
64
|
+
this.#chuiSlidesMain.appendChild(this.#chuiNextSlide);
|
|
65
|
+
this.#chuiSlidesMain.appendChild(this.#chuiPrevSlide);
|
|
66
66
|
// Индикаторы слайдов + кнопка паузы (автопрокрутка)
|
|
67
|
-
this.#
|
|
68
|
-
this.#
|
|
67
|
+
this.#chuiSlideshowControls.setAttribute("role", "group");
|
|
68
|
+
this.#chuiSlideshowControls.setAttribute("aria-label", I18n.t("feedback.slideshowControls"));
|
|
69
69
|
this.#buildDots();
|
|
70
|
-
this.#
|
|
70
|
+
this.#chuiSlideshowControls.appendChild(this.#chuiSlideshowDots);
|
|
71
71
|
if (this.#autoplay.status === true) {
|
|
72
|
-
makeKeyboardButton(this.#
|
|
72
|
+
makeKeyboardButton(this.#chuiSlideshowPause);
|
|
73
73
|
this.#updatePauseButton();
|
|
74
|
-
this.#
|
|
75
|
-
this.#
|
|
74
|
+
this.#chuiSlideshowPause.addEventListener("click", () => this.#toggleAutoplay());
|
|
75
|
+
this.#chuiSlideshowControls.appendChild(this.#chuiSlideshowPause);
|
|
76
76
|
// Останавливаем прокрутку, пока на неё смотрят или в ней есть фокус
|
|
77
|
-
this.#
|
|
78
|
-
this.#
|
|
79
|
-
this.#
|
|
80
|
-
this.#
|
|
77
|
+
this.#chuiSlidesMain.addEventListener("mouseenter", () => this.#stopAutoplay());
|
|
78
|
+
this.#chuiSlidesMain.addEventListener("mouseleave", () => this.#resumeAutoplay());
|
|
79
|
+
this.#chuiSlidesMain.addEventListener("focusin", () => this.#stopAutoplay());
|
|
80
|
+
this.#chuiSlidesMain.addEventListener("focusout", () => this.#resumeAutoplay());
|
|
81
81
|
this.#startAutoplay();
|
|
82
82
|
}
|
|
83
|
-
this.#
|
|
83
|
+
this.#chuiSlidesMain.appendChild(this.#chuiSlideshowControls);
|
|
84
84
|
// Стрелки переключают слайды, когда фокус внутри карусели
|
|
85
|
-
this.#
|
|
85
|
+
this.#chuiSlidesMain.addEventListener("keydown", (event) => {
|
|
86
86
|
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
87
87
|
event.preventDefault();
|
|
88
88
|
this.#changeSlide(event.key === "ArrowRight" ? 1 : -1);
|
|
@@ -92,90 +92,90 @@ class SlideShow {
|
|
|
92
92
|
//
|
|
93
93
|
}
|
|
94
94
|
#buildDots() {
|
|
95
|
-
this.#
|
|
95
|
+
this.#slidesList.forEach((_, index) => {
|
|
96
96
|
const dot = document.createElement("chui_slideshow_dot");
|
|
97
97
|
dot.setAttribute("role", "button");
|
|
98
98
|
dot.setAttribute(
|
|
99
99
|
"aria-label",
|
|
100
|
-
I18n.t("feedback.slideOf", { index: index + 1, total: this.#
|
|
100
|
+
I18n.t("feedback.slideOf", { index: index + 1, total: this.#slidesList.length })
|
|
101
101
|
);
|
|
102
102
|
makeKeyboardButton(dot);
|
|
103
103
|
dot.addEventListener("click", () => this.#goToSlide(index));
|
|
104
|
-
this.#
|
|
104
|
+
this.#chuiSlideshowDots.appendChild(dot);
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
#syncIndicators() {
|
|
108
|
-
[...this.#
|
|
109
|
-
if (index === this.#
|
|
108
|
+
[...this.#chuiSlideshowDots.children].forEach((dot, index) => {
|
|
109
|
+
if (index === this.#defaultSlide) dot.setAttribute("aria-current", "true");
|
|
110
110
|
else dot.removeAttribute("aria-current");
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
#goToSlide(index = Number()) {
|
|
114
|
-
this.#
|
|
114
|
+
this.#defaultSlide = index;
|
|
115
115
|
this.#renderSlide();
|
|
116
116
|
}
|
|
117
117
|
#changeSlide(n = Number()) {
|
|
118
|
-
|
|
119
|
-
this.#
|
|
120
|
-
if (this.#
|
|
121
|
-
if (this.#
|
|
118
|
+
const slideTotal = this.#slidesList.length;
|
|
119
|
+
this.#defaultSlide = this.#defaultSlide + n;
|
|
120
|
+
if (this.#defaultSlide > slideTotal - 1) this.#defaultSlide = 0;
|
|
121
|
+
if (this.#defaultSlide < 0) this.#defaultSlide = slideTotal - 1;
|
|
122
122
|
this.#renderSlide();
|
|
123
123
|
}
|
|
124
|
-
#renderSlide(
|
|
125
|
-
for (
|
|
126
|
-
this.#
|
|
124
|
+
#renderSlide(isInitial = false) {
|
|
125
|
+
for (const child of this.#chuiSlidesList.childNodes) {
|
|
126
|
+
this.#chuiSlidesList.removeChild(child);
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
const slide = this.#slidesList[this.#defaultSlide].set();
|
|
129
129
|
slide.setAttribute("role", "group");
|
|
130
130
|
slide.setAttribute("aria-roledescription", I18n.t("feedback.slide"));
|
|
131
131
|
slide.setAttribute(
|
|
132
132
|
"aria-label",
|
|
133
|
-
I18n.t("feedback.slideOf", { index: this.#
|
|
133
|
+
I18n.t("feedback.slideOf", { index: this.#defaultSlide + 1, total: this.#slidesList.length })
|
|
134
134
|
);
|
|
135
|
-
this.#
|
|
135
|
+
this.#chuiSlidesList.appendChild(slide);
|
|
136
136
|
// Первый слайд показываем так же, как раньше (display: flex до анимации)
|
|
137
|
-
if (
|
|
137
|
+
if (isInitial) slide.style.display = "flex";
|
|
138
138
|
else slide.style.display = "none";
|
|
139
139
|
new Animation(slide).fadeIn();
|
|
140
140
|
this.#syncIndicators();
|
|
141
141
|
}
|
|
142
142
|
// === АВТОПРОКРУТКА ===
|
|
143
143
|
#startAutoplay() {
|
|
144
|
-
if (this.#
|
|
144
|
+
if (this.#autoplayTimer !== undefined || this.#userPaused) return;
|
|
145
145
|
if (this.#autoplay === undefined || !this.#autoplay.status) return;
|
|
146
|
-
this.#
|
|
146
|
+
this.#autoplayTimer = setInterval(() => this.#changeSlide(1), this.#autoplay.interval * 1000);
|
|
147
147
|
}
|
|
148
148
|
#stopAutoplay() {
|
|
149
|
-
if (this.#
|
|
150
|
-
clearInterval(this.#
|
|
151
|
-
this.#
|
|
149
|
+
if (this.#autoplayTimer === undefined) return;
|
|
150
|
+
clearInterval(this.#autoplayTimer);
|
|
151
|
+
this.#autoplayTimer = undefined;
|
|
152
152
|
}
|
|
153
153
|
#resumeAutoplay() {
|
|
154
|
-
if (this.#
|
|
154
|
+
if (this.#userPaused) return;
|
|
155
155
|
this.#startAutoplay();
|
|
156
156
|
}
|
|
157
157
|
#toggleAutoplay() {
|
|
158
|
-
this.#
|
|
159
|
-
if (this.#
|
|
158
|
+
this.#userPaused = !this.#userPaused;
|
|
159
|
+
if (this.#userPaused) this.#stopAutoplay();
|
|
160
160
|
else this.#startAutoplay();
|
|
161
161
|
this.#updatePauseButton();
|
|
162
162
|
}
|
|
163
163
|
#updatePauseButton() {
|
|
164
|
-
const icon = this.#
|
|
165
|
-
this.#
|
|
166
|
-
this.#
|
|
164
|
+
const icon = this.#userPaused ? Icons.AUDIO_VIDEO.PLAY_ARROW : Icons.AUDIO_VIDEO.PAUSE;
|
|
165
|
+
this.#chuiSlideshowPause.innerHTML = new Icon(icon, "14pt", "var(--button_text_color)").getHTML();
|
|
166
|
+
this.#chuiSlideshowPause.setAttribute(
|
|
167
167
|
"aria-label",
|
|
168
|
-
this.#
|
|
168
|
+
this.#userPaused ? I18n.t("feedback.autoplayStart") : I18n.t("feedback.autoplayPause")
|
|
169
169
|
);
|
|
170
|
-
this.#
|
|
170
|
+
this.#chuiSlideshowPause.setAttribute("aria-pressed", this.#userPaused ? "true" : "false");
|
|
171
171
|
}
|
|
172
172
|
/** Полное удаление: остановить автопрокрутку (остальные слушатели — на элементах компонента) */
|
|
173
173
|
destroy() {
|
|
174
|
-
this.#
|
|
174
|
+
this.#userPaused = true;
|
|
175
175
|
this.#stopAutoplay();
|
|
176
176
|
}
|
|
177
177
|
set() {
|
|
178
|
-
return this.#
|
|
178
|
+
return this.#chuiSlidesMain;
|
|
179
179
|
}
|
|
180
180
|
static SLIDE(options = { width: String(), height: String(), components: [] }) {
|
|
181
181
|
return new Slide(options);
|
|
@@ -184,8 +184,8 @@ class SlideShow {
|
|
|
184
184
|
exports.SlideShow = SlideShow;
|
|
185
185
|
|
|
186
186
|
class Slide {
|
|
187
|
-
#
|
|
188
|
-
#
|
|
187
|
+
#chuiSlide = document.createElement("chui_slide");
|
|
188
|
+
#chuiSlideContent = document.createElement("chui_slide_content");
|
|
189
189
|
constructor(
|
|
190
190
|
options = {
|
|
191
191
|
size: { width: String(), height: String() },
|
|
@@ -197,16 +197,16 @@ class Slide {
|
|
|
197
197
|
const size = options.size === undefined ? {} : options.size;
|
|
198
198
|
const style = options.style === undefined ? {} : options.style;
|
|
199
199
|
const components = Array.isArray(options.components) ? options.components : [];
|
|
200
|
-
if (size.width !== undefined) this.#
|
|
201
|
-
if (size.height !== undefined) this.#
|
|
202
|
-
if (style.direction !== undefined) this.#
|
|
203
|
-
if (style.wrap !== undefined) this.#
|
|
204
|
-
if (style.align !== undefined) this.#
|
|
205
|
-
if (style.justify !== undefined) this.#
|
|
206
|
-
for (
|
|
207
|
-
this.#
|
|
200
|
+
if (size.width !== undefined) this.#chuiSlideContent.style.width = size.width;
|
|
201
|
+
if (size.height !== undefined) this.#chuiSlideContent.style.height = size.height;
|
|
202
|
+
if (style.direction !== undefined) this.#chuiSlideContent.style.flexDirection = style.direction;
|
|
203
|
+
if (style.wrap !== undefined) this.#chuiSlideContent.style.flexWrap = style.wrap;
|
|
204
|
+
if (style.align !== undefined) this.#chuiSlideContent.style.alignItems = style.align;
|
|
205
|
+
if (style.justify !== undefined) this.#chuiSlideContent.style.justifyContent = style.justify;
|
|
206
|
+
for (const child of components) this.#chuiSlideContent.appendChild(child.set());
|
|
207
|
+
this.#chuiSlide.appendChild(this.#chuiSlideContent);
|
|
208
208
|
}
|
|
209
209
|
set() {
|
|
210
|
-
return this.#
|
|
210
|
+
return this.#chuiSlide;
|
|
211
211
|
}
|
|
212
212
|
}
|
|
@@ -6,8 +6,8 @@ chui_slides_list {
|
|
|
6
6
|
|
|
7
7
|
chui_slides_main {
|
|
8
8
|
position: relative;
|
|
9
|
-
margin: var(--
|
|
10
|
-
border-radius: var(--
|
|
9
|
+
margin: var(--block_margin);
|
|
10
|
+
border-radius: var(--radius_sm);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/* Стрелки — круглые кнопки-стёкла на середине высоты: полоса во всю высоту читалась
|
|
@@ -93,8 +93,8 @@ chui_slideshow_dot {
|
|
|
93
93
|
border-radius: var(--radius_pill);
|
|
94
94
|
background: var(--element_background);
|
|
95
95
|
transition:
|
|
96
|
-
width var(--
|
|
97
|
-
background-color var(--
|
|
96
|
+
width var(--motion_base) var(--motion_spring),
|
|
97
|
+
background-color var(--motion_fast) var(--motion_ease);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/* Наведение — нейтральная ступень, кружок текущего слайда — акцент */
|
|
@@ -142,7 +142,7 @@ chui_slideshow_pause:hover {
|
|
|
142
142
|
chui_slide {
|
|
143
143
|
display: none;
|
|
144
144
|
color: var(--text_color);
|
|
145
|
-
border-radius: var(--
|
|
145
|
+
border-radius: var(--radius_sm);
|
|
146
146
|
width: 100%;
|
|
147
147
|
height: -webkit-fill-available;
|
|
148
148
|
}
|
|
@@ -150,7 +150,7 @@ chui_slide {
|
|
|
150
150
|
chui_slide_content {
|
|
151
151
|
display: flex;
|
|
152
152
|
color: var(--text_color);
|
|
153
|
-
border-radius: var(--
|
|
153
|
+
border-radius: var(--radius_sm);
|
|
154
154
|
width: -webkit-fill-available;
|
|
155
155
|
height: -webkit-fill-available;
|
|
156
156
|
overflow: auto;
|
|
@@ -15,15 +15,15 @@ const ARC_SHARE = 0.25;
|
|
|
15
15
|
* Слушателей и таймеров нет: `remove()` убирает узел и повторный вызов уже ничего не делает.
|
|
16
16
|
*/
|
|
17
17
|
class Spinner {
|
|
18
|
-
#
|
|
18
|
+
#spinnerMain = document.createElement("chui_spiner");
|
|
19
19
|
#spinner = document.createElement("spinner");
|
|
20
20
|
#label = I18n.t("feedback.loading");
|
|
21
21
|
#removed = false;
|
|
22
22
|
constructor(size = Spinner.SIZE.DEFAULT, margin = String(), label = I18n.t("feedback.loading")) {
|
|
23
23
|
require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_Spinner");
|
|
24
|
-
this.#
|
|
25
|
-
this.#
|
|
26
|
-
this.#
|
|
24
|
+
this.#spinnerMain.style.margin = margin;
|
|
25
|
+
this.#spinnerMain.setAttribute("role", "status");
|
|
26
|
+
this.#spinnerMain.setAttribute("aria-live", "polite");
|
|
27
27
|
this.setLabel(label);
|
|
28
28
|
//
|
|
29
29
|
const diameter = size.SIZE;
|
|
@@ -47,7 +47,7 @@ class Spinner {
|
|
|
47
47
|
arc.setAttribute("stroke-dasharray", `${circumference * ARC_SHARE} ${circumference}`);
|
|
48
48
|
svg.appendChild(arc);
|
|
49
49
|
this.#spinner.appendChild(svg);
|
|
50
|
-
this.#
|
|
50
|
+
this.#spinnerMain.appendChild(this.#spinner);
|
|
51
51
|
}
|
|
52
52
|
/** Окружность по центру квадрата: общая разметка дорожки и дуги */
|
|
53
53
|
#circle(radius, diameter, className) {
|
|
@@ -64,8 +64,8 @@ class Spinner {
|
|
|
64
64
|
}
|
|
65
65
|
setLabel(text = String()) {
|
|
66
66
|
this.#label = text === undefined || text === "" ? undefined : text;
|
|
67
|
-
if (this.#label === undefined) this.#
|
|
68
|
-
else this.#
|
|
67
|
+
if (this.#label === undefined) this.#spinnerMain.removeAttribute("aria-label");
|
|
68
|
+
else this.#spinnerMain.setAttribute("aria-label", this.#label);
|
|
69
69
|
return this;
|
|
70
70
|
}
|
|
71
71
|
isRemoved() {
|
|
@@ -79,12 +79,12 @@ class Spinner {
|
|
|
79
79
|
remove() {
|
|
80
80
|
if (this.#removed) return this;
|
|
81
81
|
this.#removed = true;
|
|
82
|
-
if (this.#
|
|
83
|
-
else this.#
|
|
82
|
+
if (this.#spinnerMain.style.animationName) new Animation(this.#spinnerMain).fadeOutAndRemove();
|
|
83
|
+
else this.#spinnerMain.remove();
|
|
84
84
|
return this;
|
|
85
85
|
}
|
|
86
86
|
set() {
|
|
87
|
-
return this.#
|
|
87
|
+
return this.#spinnerMain;
|
|
88
88
|
}
|
|
89
89
|
static SIZE = {
|
|
90
90
|
V_SMALL: { SIZE: 30, BORDER: 3 },
|