chuijs 4.0.2 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +597 -0
- package/README.md +43 -644
- package/framework/appLayout/default/chui_app_layout.js +602 -496
- package/framework/appLayout/default/global_style.css +288 -97
- package/framework/appLayout/default/main_theme_style.css +188 -101
- package/framework/components/chui_accordion/accordion.js +38 -35
- package/framework/components/chui_accordion/styles.css +13 -12
- package/framework/components/chui_action_sheet/action_sheet.js +93 -64
- package/framework/components/chui_action_sheet/styles.css +12 -5
- 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 +16 -11
- package/framework/components/chui_affix/styles.css +5 -0
- package/framework/components/chui_alert/alert.js +34 -19
- package/framework/components/chui_alert/styles.css +7 -0
- package/framework/components/chui_avatar/avatar.js +36 -35
- package/framework/components/chui_avatar/styles.css +1 -1
- package/framework/components/chui_avatar_group/avatar_group.js +25 -23
- package/framework/components/chui_avatar_group/styles.css +1 -1
- package/framework/components/chui_backtop/backtop.js +60 -21
- package/framework/components/chui_backtop/styles.css +21 -0
- package/framework/components/chui_badge/badge.js +30 -28
- 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/breadcrumb.js +15 -13
- package/framework/components/chui_breadcrumb/styles.css +1 -1
- package/framework/components/chui_button/button.js +52 -36
- package/framework/components/chui_button/styles.css +7 -7
- package/framework/components/chui_calendar/calendar.js +18 -16
- package/framework/components/chui_card/card.js +52 -32
- 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 +140 -79
- package/framework/components/chui_chat/styles.css +18 -7
- package/framework/components/chui_clipboard_history/clipboard_history.js +53 -39
- package/framework/components/chui_clipboard_history/styles.css +13 -9
- package/framework/components/chui_code/code.js +10 -10
- package/framework/components/chui_code/styles.css +4 -4
- package/framework/components/chui_code_editor/code_editor.js +73 -57
- package/framework/components/chui_code_editor/styles.css +6 -5
- package/framework/components/chui_command_palette/command_palette.js +87 -64
- package/framework/components/chui_command_palette/styles.css +5 -5
- package/framework/components/chui_console/console.js +13 -13
- package/framework/components/chui_console/styles.css +6 -3
- package/framework/components/chui_content_block/content_block.js +35 -21
- package/framework/components/chui_content_block/styles.css +2 -2
- package/framework/components/chui_context_menu/context_menu.js +171 -58
- package/framework/components/chui_context_menu/styles.css +82 -8
- package/framework/components/chui_custom_element/custom_element.js +25 -18
- package/framework/components/chui_data_grid/data_grid.js +633 -471
- package/framework/components/chui_data_grid/styles.css +24 -22
- package/framework/components/chui_descriptions/descriptions.js +34 -17
- package/framework/components/chui_descriptions/styles.css +1 -1
- package/framework/components/chui_details/details.js +42 -36
- package/framework/components/chui_details/styles.css +12 -11
- package/framework/components/chui_diff_viewer/diff_viewer.js +172 -147
- package/framework/components/chui_diff_viewer/styles.css +10 -10
- package/framework/components/chui_divider/divider.js +19 -17
- package/framework/components/chui_divider/styles.css +2 -2
- package/framework/components/chui_drawer/drawer.js +63 -38
- package/framework/components/chui_drawer/styles.css +18 -4
- package/framework/components/chui_drop_zone/drop_zone.js +37 -27
- package/framework/components/chui_drop_zone/styles.css +10 -6
- package/framework/components/chui_empty_state/empty_state.js +20 -15
- package/framework/components/chui_fieldset/fieldset.js +40 -23
- package/framework/components/chui_fieldset/styles.css +6 -6
- package/framework/components/chui_file_explorer/file_explorer.js +260 -189
- package/framework/components/chui_file_explorer/styles.css +8 -7
- package/framework/components/chui_form/form.js +40 -28
- package/framework/components/chui_form/styles.css +1 -1
- package/framework/components/chui_gantt/gantt.js +102 -78
- package/framework/components/chui_gantt/styles.css +5 -5
- package/framework/components/chui_graphs/graphs.js +376 -239
- package/framework/components/chui_graphs/styles.css +27 -6
- package/framework/components/chui_hero/hero.js +98 -37
- package/framework/components/chui_hero/styles.css +176 -7
- package/framework/components/chui_html_block/html_block.js +8 -8
- package/framework/components/chui_html_block/styles.css +3 -3
- package/framework/components/chui_hx/hx.js +3 -3
- package/framework/components/chui_hx/styles.css +13 -6
- package/framework/components/chui_icons/icons.js +2115 -2115
- package/framework/components/chui_icons/styles.css +4 -3
- package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
- package/framework/components/chui_inputs/chui_check_box/styles.css +30 -21
- package/framework/components/chui_inputs/chui_chips/chips.js +141 -70
- package/framework/components/chui_inputs/chui_chips/styles.css +32 -7
- package/framework/components/chui_inputs/chui_color_picker/color_picker.js +55 -38
- package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
- package/framework/components/chui_inputs/chui_combo_box/combo_box.js +127 -109
- package/framework/components/chui_inputs/chui_combo_box/styles.css +23 -21
- package/framework/components/chui_inputs/chui_date/date.js +161 -127
- package/framework/components/chui_inputs/chui_date/styles.css +20 -19
- package/framework/components/chui_inputs/chui_date_range/date_range.js +61 -50
- package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
- package/framework/components/chui_inputs/chui_datetime/datetime.js +47 -39
- package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
- package/framework/components/chui_inputs/chui_email/email.js +48 -36
- package/framework/components/chui_inputs/chui_email/styles.css +11 -11
- package/framework/components/chui_inputs/chui_file/file.js +71 -44
- package/framework/components/chui_inputs/chui_file/styles.css +23 -19
- package/framework/components/chui_inputs/chui_hotkey/hotkey.js +101 -76
- package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
- package/framework/components/chui_inputs/chui_masked/masked.js +83 -72
- package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
- package/framework/components/chui_inputs/chui_mention/mention.js +87 -40
- package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
- package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +242 -212
- package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +23 -15
- package/framework/components/chui_inputs/chui_number/number.js +84 -70
- package/framework/components/chui_inputs/chui_number/styles.css +13 -13
- package/framework/components/chui_inputs/chui_otp/otp.js +71 -62
- package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
- package/framework/components/chui_inputs/chui_password/password.js +72 -56
- package/framework/components/chui_inputs/chui_password/styles.css +15 -15
- package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
- package/framework/components/chui_inputs/chui_radio_button/styles.css +22 -22
- package/framework/components/chui_inputs/chui_rating/rating.js +54 -50
- package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
- package/framework/components/chui_inputs/chui_select_box/select_box.js +132 -108
- package/framework/components/chui_inputs/chui_select_box/styles.css +21 -21
- package/framework/components/chui_inputs/chui_slider/slider.js +41 -38
- package/framework/components/chui_inputs/chui_slider/styles.css +7 -5
- package/framework/components/chui_inputs/chui_text/styles.css +14 -14
- package/framework/components/chui_inputs/chui_text/text.js +69 -52
- package/framework/components/chui_inputs/chui_text_area/styles.css +14 -14
- package/framework/components/chui_inputs/chui_text_area/text_area.js +59 -36
- package/framework/components/chui_inputs/chui_time/styles.css +18 -20
- package/framework/components/chui_inputs/chui_time/time.js +71 -49
- package/framework/components/chui_inputs/chui_toggle/styles.css +13 -6
- package/framework/components/chui_inputs/chui_toggle/toggle.js +27 -27
- package/framework/components/chui_json_editor/json_editor.js +137 -127
- package/framework/components/chui_json_editor/styles.css +5 -5
- package/framework/components/chui_json_viewer/json_viewer.js +133 -114
- package/framework/components/chui_json_viewer/styles.css +9 -8
- package/framework/components/chui_kanban/kanban.js +78 -60
- package/framework/components/chui_kanban/styles.css +8 -4
- package/framework/components/chui_kbd/kbd.js +12 -10
- package/framework/components/chui_kbd/styles.css +1 -1
- package/framework/components/chui_label/label.js +31 -29
- package/framework/components/chui_label/styles.css +3 -3
- package/framework/components/chui_link/link.js +36 -29
- package/framework/components/chui_link/styles.css +11 -4
- package/framework/components/chui_list/list.js +42 -38
- package/framework/components/chui_list/styles.css +4 -3
- package/framework/components/chui_markdown_editor/markdown_editor.js +125 -109
- package/framework/components/chui_markdown_editor/styles.css +5 -5
- package/framework/components/chui_media/audio.js +457 -364
- package/framework/components/chui_media/audio_styles.css +74 -37
- package/framework/components/chui_media/image.js +99 -64
- package/framework/components/chui_media/image_compare.js +86 -55
- package/framework/components/chui_media/image_compare_styles.css +5 -5
- package/framework/components/chui_media/image_styles.css +4 -4
- package/framework/components/chui_media/video.js +264 -171
- package/framework/components/chui_media/video_styles.css +57 -24
- package/framework/components/chui_menu_bar/menu_bar.js +67 -65
- package/framework/components/chui_menu_bar/styles.css +14 -12
- 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 +81 -56
- package/framework/components/chui_modal/styles.css +3 -2
- package/framework/components/chui_notification/notification.js +107 -69
- package/framework/components/chui_notification/notification_download.js +28 -77
- package/framework/components/chui_notification/notification_download_card.js +115 -0
- package/framework/components/chui_notification/notification_download_progress.css +5 -4
- package/framework/components/chui_notification/notification_download_progress.js +73 -105
- package/framework/components/chui_notification/notification_update.js +44 -37
- package/framework/components/chui_notification/status_plate.css +3 -3
- package/framework/components/chui_notification/status_plate.js +2 -2
- package/framework/components/chui_notification/styles.css +6 -1
- package/framework/components/chui_notification/styles_download.css +2 -2
- package/framework/components/chui_notification/styles_update.css +3 -3
- package/framework/components/chui_org_chart/org_chart.js +101 -62
- package/framework/components/chui_org_chart/styles.css +2 -2
- package/framework/components/chui_pagination/pagination.js +65 -30
- package/framework/components/chui_pagination/styles.css +1 -1
- package/framework/components/chui_paragraph/paragraph.js +2 -2
- package/framework/components/chui_paragraph/styles.css +3 -3
- package/framework/components/chui_popover/popover.js +77 -50
- package/framework/components/chui_popover/styles.css +1 -1
- package/framework/components/chui_popups/popups.js +210 -181
- package/framework/components/chui_popups/styles.css +7 -7
- package/framework/components/chui_print_button/print_button.js +48 -33
- package/framework/components/chui_progress_bar/progress_bar.js +49 -19
- package/framework/components/chui_progress_bar/styles.css +6 -6
- package/framework/components/chui_progress_ring/progress_ring.js +32 -30
- package/framework/components/chui_progress_ring/styles.css +1 -1
- package/framework/components/chui_qrcode/qrcode.js +85 -41
- package/framework/components/chui_query_builder/query_builder.js +263 -170
- package/framework/components/chui_query_builder/styles.css +4 -4
- package/framework/components/chui_radio_group/radio_group.js +36 -26
- package/framework/components/chui_radio_group/styles.css +2 -2
- package/framework/components/chui_result/result.js +41 -31
- package/framework/components/chui_result/styles.css +3 -3
- package/framework/components/chui_scheduler/scheduler.js +126 -104
- package/framework/components/chui_scheduler/styles.css +11 -7
- 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 +90 -27
- package/framework/components/chui_segmented_control/styles.css +32 -6
- package/framework/components/chui_settings/settings.js +160 -87
- package/framework/components/chui_settings/styles.css +4 -4
- package/framework/components/chui_shortcut_help/shortcut_help.js +82 -61
- package/framework/components/chui_sidebar_nav/sidebar_nav.js +132 -53
- package/framework/components/chui_sidebar_nav/styles.css +9 -3
- package/framework/components/chui_skeleton/skeleton.js +29 -24
- package/framework/components/chui_slideshow/slideshow.js +122 -103
- package/framework/components/chui_slideshow/styles.css +22 -16
- package/framework/components/chui_spinner/spinner.js +17 -17
- package/framework/components/chui_spinner/styles.css +0 -1
- package/framework/components/chui_split_button/split_button.js +53 -30
- package/framework/components/chui_split_button/styles.css +22 -6
- package/framework/components/chui_splitter/splitter.js +46 -39
- package/framework/components/chui_splitter/styles.css +2 -2
- package/framework/components/chui_statistic/statistic.js +111 -84
- package/framework/components/chui_status_bar/status_bar.js +11 -9
- package/framework/components/chui_status_bar/styles.css +2 -2
- package/framework/components/chui_stepper/stepper.js +230 -54
- package/framework/components/chui_stepper/styles.css +79 -14
- package/framework/components/chui_sticky_bar/sticky_bar.js +53 -17
- package/framework/components/chui_sticky_bar/styles.css +11 -7
- package/framework/components/chui_tabs/chui_tabs.js +100 -46
- package/framework/components/chui_tabs/styles.css +43 -15
- package/framework/components/chui_text_editor/styles.css +24 -23
- package/framework/components/chui_text_editor/text_editor.js +103 -79
- package/framework/components/chui_text_editor/text_editor_panel.js +428 -367
- package/framework/components/chui_theme_toggle/theme_toggle.js +46 -25
- package/framework/components/chui_timeline/styles.css +3 -1
- package/framework/components/chui_timeline/timeline.js +14 -12
- package/framework/components/chui_toast_queue/styles.css +11 -11
- package/framework/components/chui_toast_queue/toast_queue.js +82 -73
- package/framework/components/chui_toolbar/styles.css +2 -2
- package/framework/components/chui_toolbar/toolbar.js +20 -13
- package/framework/components/chui_tooltip/styles.css +2 -2
- package/framework/components/chui_tooltip/tooltip.js +40 -27
- package/framework/components/chui_tour/styles.css +12 -7
- package/framework/components/chui_tour/tour.js +132 -98
- package/framework/components/chui_transfer/styles.css +8 -7
- package/framework/components/chui_transfer/transfer.js +143 -123
- package/framework/components/chui_tree_table/styles.css +4 -4
- package/framework/components/chui_tree_table/tree_table.js +88 -74
- package/framework/components/chui_tree_view/styles.css +14 -10
- package/framework/components/chui_tree_view/tree_view.js +298 -253
- 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 +41 -33
- package/framework/components/chui_webview/styles.css +2 -2
- package/framework/components/chui_webview/webview.js +64 -52
- 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 +153 -123
- package/framework/modules/chui_animations/animations.js +105 -43
- package/framework/modules/chui_animations/motion.js +120 -0
- package/framework/modules/chui_animations/styles.css +37 -4
- package/framework/modules/chui_bridge/preload.js +36 -25
- package/framework/modules/chui_functions.js +69 -63
- package/framework/modules/chui_highlight/chui_highlight.js +25 -22
- package/framework/modules/chui_highlight/styles.css +13 -10
- package/framework/modules/chui_i18n/chui_i18n.js +12 -10
- package/framework/modules/chui_i18n/locales/a11y.js +5 -5
- package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
- package/framework/modules/chui_i18n/locales/calendar.js +3 -3
- package/framework/modules/chui_i18n/locales/common.js +3 -3
- package/framework/modules/chui_i18n/locales/data.js +36 -26
- package/framework/modules/chui_i18n/locales/editors.js +40 -13
- package/framework/modules/chui_i18n/locales/feedback.js +65 -3
- package/framework/modules/chui_i18n/locales/forms.js +8 -8
- package/framework/modules/chui_i18n/locales/graphics.js +8 -8
- package/framework/modules/chui_i18n/locales/media.js +4 -4
- package/framework/modules/chui_i18n/locales/navigation.js +12 -8
- package/framework/modules/chui_i18n/locales/validate.js +3 -3
- package/framework/modules/chui_json/chui_json.js +11 -11
- package/framework/modules/chui_layout/chui_layout.js +12 -10
- package/framework/modules/chui_logger/chui_logger.js +47 -28
- package/framework/modules/chui_page/page.js +39 -33
- package/framework/modules/chui_palette/palette.js +61 -0
- package/framework/modules/chui_qr/chui_qr.js +179 -88
- package/framework/modules/chui_scrollbar/chui_scrollbar.js +79 -68
- package/framework/modules/chui_scrollbar/styles.css +4 -2
- package/framework/modules/chui_services/chui_channels.js +27 -13
- package/framework/modules/chui_services/chui_services.js +47 -39
- package/framework/modules/chui_services/desktop.js +108 -101
- package/framework/modules/chui_sortable/chui_sortable.js +33 -28
- package/framework/modules/chui_validate/chui_validate.js +10 -7
- package/framework/tray_bar/chui_menu_items.js +136 -46
- package/index.d.ts +5046 -0
- package/index.js +199 -1254
- package/package.json +81 -68
- package/framework/components/telegram_bot/chui_telegram_bot.js +0 -184
|
@@ -1,24 +1,40 @@
|
|
|
1
|
-
const {setStyles, optionOr} = require("../../modules/chui_functions");
|
|
2
|
-
const {Icon, Icons} = require("../chui_icons/icons");
|
|
3
|
-
const {I18n} = require("../../modules/chui_i18n/chui_i18n");
|
|
1
|
+
const { setStyles, optionOr } = require("../../modules/chui_functions");
|
|
2
|
+
const { Icon, Icons } = require("../chui_icons/icons");
|
|
3
|
+
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
4
|
+
const { Animation } = require("../../modules/chui_animations/animations");
|
|
5
|
+
const { Spinner } = require("../chui_spinner/spinner");
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* Шаги процесса: пройденные, текущий и
|
|
8
|
+
* Шаги процесса: пройденные, текущий и предстоящие — и их состояния.
|
|
7
9
|
*
|
|
8
10
|
* Разметка — настоящий `<ol>` со `<li>`, поэтому скринридер читает «список из N шагов», имя
|
|
9
11
|
* списка задаёт опция `label` (по умолчанию «Шаги»). Линии между маркерами — по две полулинии
|
|
10
12
|
* у каждого шага (до и после маркера): так они сходятся без дыр, растягиваются на любую ширину
|
|
11
13
|
* и остаются внутри `<li>` — список не ломается посторонними узлами.
|
|
12
14
|
*
|
|
15
|
+
* **Состояние шага.** Обычно оно идёт по месту: пройденный, текущий, предстоящий. Но шаг
|
|
16
|
+
* может нести и своё — `status` у шага или `setStatus(index, status)`: `Stepper.STATUS.DONE`
|
|
17
|
+
* (зелёная подсветка и галочка), `Stepper.STATUS.ERROR` (красная подсветка и крест)
|
|
18
|
+
* и `Stepper.STATUS.PENDING` (спиннер: шаг выполняется). `undefined` возвращает шаг
|
|
19
|
+
* к состоянию по месту. Состояния сообщаются слушателям — `addStatusListener` и опция
|
|
20
|
+
* `onStatus`: по ним приложение возвращает человека на шаг, где что-то пошло не так,
|
|
21
|
+
* а сам `setStatus` переход не делает.
|
|
22
|
+
*
|
|
23
|
+
* **Переходы идут движением.** Состояние применяется на месте, не пересборкой: узлы те же,
|
|
24
|
+
* поэтому смена цвета маркера и рост заливки линии читаются переходом, знак состояния
|
|
25
|
+
* появляется кадром, а фокус и прокрутка остаются на месте.
|
|
26
|
+
*
|
|
13
27
|
* Доступность: текущий шаг помечен `aria-current="step"`, маркер имеет имя «Шаг 2 из 4.
|
|
14
28
|
* Текущий шаг», а у кликабельного шага маркер — настоящий `<button>` (Tab и Enter/Space родные)
|
|
15
|
-
* с тем же именем и названием шага. Смена шага объявляется скрытым `role="status"`.
|
|
29
|
+
* с тем же именем и названием шага. Смена шага и состояния объявляется скрытым `role="status"`.
|
|
16
30
|
*
|
|
17
31
|
* ```javascript
|
|
18
32
|
* const steps = new Stepper({steps: [{title: 'Корзина'}, {title: 'Доставка'}, {title: 'Оплата'}],
|
|
19
33
|
* active: 1, clickable: true, onChange: (index) => wizard.go(index)});
|
|
20
34
|
* steps.setActive(2); // программный переход (уведомляет)
|
|
21
35
|
* steps.setActive(2, true); // тихий: только вид, без уведомления
|
|
36
|
+
* steps.setStatus(2, Stepper.STATUS.PENDING);
|
|
37
|
+
* steps.setStatus(2, Stepper.STATUS.ERROR); // уведомляет слушателей состояния
|
|
22
38
|
* ```
|
|
23
39
|
*
|
|
24
40
|
* Слушателей и таймеров вне своих узлов нет, поэтому `destroy()` не нужен.
|
|
@@ -26,11 +42,17 @@ const {I18n} = require("../../modules/chui_i18n/chui_i18n");
|
|
|
26
42
|
class Stepper {
|
|
27
43
|
static ORIENTATION = {
|
|
28
44
|
HORIZONTAL: "horizontal",
|
|
29
|
-
VERTICAL: "vertical"
|
|
45
|
+
VERTICAL: "vertical",
|
|
30
46
|
};
|
|
31
47
|
static SIZE = {
|
|
32
48
|
SMALL: "small",
|
|
33
|
-
DEFAULT: "default"
|
|
49
|
+
DEFAULT: "default",
|
|
50
|
+
};
|
|
51
|
+
/** Состояния шага: пройден, ошибка и ожидание выполнения */
|
|
52
|
+
static STATUS = {
|
|
53
|
+
DONE: "done",
|
|
54
|
+
ERROR: "error",
|
|
55
|
+
PENDING: "pending",
|
|
34
56
|
};
|
|
35
57
|
static #counter = 0;
|
|
36
58
|
|
|
@@ -39,23 +61,30 @@ class Stepper {
|
|
|
39
61
|
#status = document.createElement("stepper_status");
|
|
40
62
|
#id = undefined;
|
|
41
63
|
#items = [];
|
|
64
|
+
#nodes = [];
|
|
42
65
|
#markers = [];
|
|
43
66
|
#active = 0;
|
|
44
67
|
#clickable = false;
|
|
45
68
|
#listeners = [];
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
#statusListeners = [];
|
|
70
|
+
#onChange = undefined;
|
|
71
|
+
#onStatus = undefined;
|
|
72
|
+
|
|
73
|
+
constructor(
|
|
74
|
+
options = {
|
|
75
|
+
id: String(),
|
|
76
|
+
steps: [],
|
|
77
|
+
active: Number(),
|
|
78
|
+
orientation: String(),
|
|
79
|
+
size: String(),
|
|
80
|
+
clickable: Boolean(),
|
|
81
|
+
label: String(),
|
|
82
|
+
onChange: undefined,
|
|
83
|
+
changeEvent: undefined,
|
|
84
|
+
onStatus: undefined,
|
|
85
|
+
statusEvent: undefined,
|
|
86
|
+
}
|
|
87
|
+
) {
|
|
59
88
|
setStyles(__dirname + "/styles.css", "chUiJS_Stepper");
|
|
60
89
|
Stepper.#counter += 1;
|
|
61
90
|
this.#id = options.id === undefined ? `chui_stepper_${Stepper.#counter}` : options.id;
|
|
@@ -65,8 +94,10 @@ class Stepper {
|
|
|
65
94
|
this.#status.classList.add("chui_visually_hidden");
|
|
66
95
|
this.#status.setAttribute("role", "status");
|
|
67
96
|
this.#status.setAttribute("aria-live", "polite");
|
|
68
|
-
this.#
|
|
97
|
+
this.#onChange = options.onChange;
|
|
69
98
|
if (options.changeEvent !== undefined) this.addChangeListener(options.changeEvent);
|
|
99
|
+
this.#onStatus = options.onStatus;
|
|
100
|
+
if (options.statusEvent !== undefined) this.addStatusListener(options.statusEvent);
|
|
70
101
|
this.setOrientation(options.orientation === undefined ? Stepper.ORIENTATION.HORIZONTAL : options.orientation);
|
|
71
102
|
this.setSize(options.size === undefined ? Stepper.SIZE.DEFAULT : options.size);
|
|
72
103
|
this.setClickable(options.clickable === true);
|
|
@@ -102,6 +133,20 @@ class Stepper {
|
|
|
102
133
|
return item === undefined ? undefined : item.title;
|
|
103
134
|
}
|
|
104
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Состояние шага: `done`, `error`, `pending`, `current` или `todo`; `undefined`,
|
|
138
|
+
* если шага нет. Состояние по месту (`current`, `todo`) и заданное шагом (`done`,
|
|
139
|
+
* `error`, `pending`) приходят сюда одинаково
|
|
140
|
+
*/
|
|
141
|
+
getStatus(index = Number()) {
|
|
142
|
+
return this.#items[index] === undefined ? undefined : this.#state(index);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Состояния всех шагов: годится для сводки «3 из 4 готовы» */
|
|
146
|
+
getStatuses() {
|
|
147
|
+
return this.#items.map((item, index) => this.#state(index));
|
|
148
|
+
}
|
|
149
|
+
|
|
105
150
|
getOrientation() {
|
|
106
151
|
return this.#root.dataset.orientation;
|
|
107
152
|
}
|
|
@@ -117,7 +162,7 @@ class Stepper {
|
|
|
117
162
|
return this;
|
|
118
163
|
}
|
|
119
164
|
|
|
120
|
-
/** Шаги: `[{title, description, icon, disabled}]` */
|
|
165
|
+
/** Шаги: `[{title, description, icon, disabled, status}]` */
|
|
121
166
|
setSteps(steps = Array()) {
|
|
122
167
|
this.#items = Array.isArray(steps) ? steps.map((item) => Object.assign({}, item)) : [];
|
|
123
168
|
this.#active = Stepper.#clamp(this.#active, this.#items.length);
|
|
@@ -140,18 +185,43 @@ class Stepper {
|
|
|
140
185
|
const next = Stepper.#clamp(index, this.#items.length);
|
|
141
186
|
const changed = next !== this.#active;
|
|
142
187
|
this.#active = next;
|
|
143
|
-
|
|
188
|
+
// Состояние применяется на месте: узлы те же, поэтому переход читается движением,
|
|
189
|
+
// а фокус и прокрутка остаются на месте
|
|
190
|
+
this.#refresh();
|
|
144
191
|
if (silent || !changed) return this;
|
|
145
192
|
this.#announce();
|
|
146
193
|
this.#notify();
|
|
147
194
|
return this;
|
|
148
195
|
}
|
|
149
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Состояние шага: `Stepper.STATUS.{DONE, ERROR, PENDING}`; `undefined` возвращает шаг
|
|
199
|
+
* к состоянию по месту — пройден, текущий или предстоящий.
|
|
200
|
+
*
|
|
201
|
+
* Слушатели состояния (`addStatusListener`, `onStatus`) получают номер шага и его
|
|
202
|
+
* состояние. Сам `setStatus` на шаг не переходит: переход делает приложение — по событию
|
|
203
|
+
* оно возвращает человека туда, где что-то пошло не так.
|
|
204
|
+
*/
|
|
205
|
+
setStatus(index = Number(), status = undefined) {
|
|
206
|
+
const item = this.#items[index];
|
|
207
|
+
if (item === undefined) return this;
|
|
208
|
+
const before = this.#state(index);
|
|
209
|
+
if (status === undefined || status === null) delete item.status;
|
|
210
|
+
else item.status = status;
|
|
211
|
+
const state = this.#state(index);
|
|
212
|
+
this.#refresh();
|
|
213
|
+
if (state === before) return this;
|
|
214
|
+
this.#announceStatus(index);
|
|
215
|
+
this.#notifyStatus(index, state);
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
218
|
+
|
|
150
219
|
/** Направление шагов: `Stepper.ORIENTATION.{HORIZONTAL, VERTICAL}` */
|
|
151
220
|
setOrientation(orientation = String()) {
|
|
152
|
-
this.#root.dataset.orientation =
|
|
153
|
-
|
|
154
|
-
|
|
221
|
+
this.#root.dataset.orientation =
|
|
222
|
+
orientation === Stepper.ORIENTATION.VERTICAL
|
|
223
|
+
? Stepper.ORIENTATION.VERTICAL
|
|
224
|
+
: Stepper.ORIENTATION.HORIZONTAL;
|
|
155
225
|
return this;
|
|
156
226
|
}
|
|
157
227
|
|
|
@@ -181,13 +251,28 @@ class Stepper {
|
|
|
181
251
|
return this;
|
|
182
252
|
}
|
|
183
253
|
|
|
254
|
+
/** Слушатель состояния шага: `(index, status, stepper) => {}` */
|
|
255
|
+
addStatusListener(listener = () => {}) {
|
|
256
|
+
this.#statusListeners.push(listener);
|
|
257
|
+
return this;
|
|
258
|
+
}
|
|
259
|
+
|
|
184
260
|
// RENDER
|
|
185
261
|
set() {
|
|
186
262
|
return this.#root;
|
|
187
263
|
}
|
|
188
264
|
|
|
189
265
|
// === ВНУТРЕННЕЕ ===
|
|
266
|
+
/**
|
|
267
|
+
* Состояние шага. Своё состояние шага сильнее состояния по месту: шаг с ошибкой остаётся
|
|
268
|
+
* с ошибкой, даже когда человек ушёл дальше, — иначе знак ошибки пропадал бы со сменой шага
|
|
269
|
+
*/
|
|
190
270
|
#state(index = Number()) {
|
|
271
|
+
const item = this.#items[index];
|
|
272
|
+
const status = item === undefined ? undefined : item.status;
|
|
273
|
+
if (status === Stepper.STATUS.DONE || status === Stepper.STATUS.ERROR || status === Stepper.STATUS.PENDING) {
|
|
274
|
+
return status;
|
|
275
|
+
}
|
|
191
276
|
if (index < this.#active) return "done";
|
|
192
277
|
if (index === this.#active) return "current";
|
|
193
278
|
return "todo";
|
|
@@ -195,7 +280,9 @@ class Stepper {
|
|
|
195
280
|
|
|
196
281
|
#stateWord(index = Number()) {
|
|
197
282
|
const state = this.#state(index);
|
|
198
|
-
if (state ===
|
|
283
|
+
if (state === Stepper.STATUS.DONE) return I18n.t("navigation.stepDone");
|
|
284
|
+
if (state === Stepper.STATUS.ERROR) return I18n.t("navigation.stepError");
|
|
285
|
+
if (state === Stepper.STATUS.PENDING) return I18n.t("navigation.stepPending");
|
|
199
286
|
if (state === "current") return I18n.t("navigation.stepCurrent");
|
|
200
287
|
return I18n.t("navigation.stepTodo");
|
|
201
288
|
}
|
|
@@ -203,7 +290,9 @@ class Stepper {
|
|
|
203
290
|
// Имя маркера: номер шага, название и состояние — иначе глиф читался бы как мусор
|
|
204
291
|
#markerLabel(index = Number()) {
|
|
205
292
|
const title = this.#items[index].title;
|
|
206
|
-
const head =
|
|
293
|
+
const head =
|
|
294
|
+
I18n.t("navigation.stepOf", { index: index + 1, total: this.#items.length }) +
|
|
295
|
+
(title === undefined ? "" : `: ${title}`);
|
|
207
296
|
return `${head} — ${this.#stateWord(index)}`;
|
|
208
297
|
}
|
|
209
298
|
|
|
@@ -212,34 +301,70 @@ class Stepper {
|
|
|
212
301
|
const focused = this.#markers.indexOf(document.activeElement);
|
|
213
302
|
this.#list.innerHTML = "";
|
|
214
303
|
this.#markers = [];
|
|
215
|
-
this.#
|
|
304
|
+
this.#nodes = [];
|
|
305
|
+
this.#items.forEach((item, index) => {
|
|
306
|
+
const node = this.#item(item, index);
|
|
307
|
+
this.#nodes.push(node);
|
|
308
|
+
this.#list.appendChild(node);
|
|
309
|
+
});
|
|
216
310
|
if (focused !== -1 && this.#markers[focused] !== undefined) this.#markers[focused].focus();
|
|
217
311
|
}
|
|
218
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Применить состояния заново — на тех же узлах (смена шага и состояния шага). Пересборка
|
|
315
|
+
* здесь была бы видна как вспышка: новый узел не помнит прошлого состояния, поэтому и цвет
|
|
316
|
+
* маркера, и заливка линии менялись бы рывком, а фокус терялся бы вовсе
|
|
317
|
+
*/
|
|
318
|
+
#refresh() {
|
|
319
|
+
this.#items.forEach((item, index) => {
|
|
320
|
+
const node = this.#nodes[index];
|
|
321
|
+
if (node !== undefined) this.#apply(node, item, index);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Состояние одного шага: вид, роли и подписи */
|
|
326
|
+
#apply(node = undefined, item = Object(), index = Number()) {
|
|
327
|
+
const state = this.#state(index);
|
|
328
|
+
for (const name of ["done", "error", "pending", "current", "todo"]) {
|
|
329
|
+
node.classList.toggle(`stepper_item_${name}`, state === name);
|
|
330
|
+
}
|
|
331
|
+
node.dataset.state = state;
|
|
332
|
+
// Текущий шаг — тот, где мы стоим, и он остаётся им даже со своим состоянием:
|
|
333
|
+
// по нему идёт `aria-current`, а вид может быть занят ошибкой или спиннером
|
|
334
|
+
node.dataset.active = index === this.#active ? "true" : "false";
|
|
335
|
+
node.classList.toggle("stepper_item_clickable", this.#clickable && item.disabled !== true);
|
|
336
|
+
if (index === this.#active) node.setAttribute("aria-current", "step");
|
|
337
|
+
else node.removeAttribute("aria-current");
|
|
338
|
+
// Линия заполняется по шагу, от которого идёт: до маркера — предыдущим, после — им самим
|
|
339
|
+
node.querySelector(".stepper_line_before").classList.toggle(
|
|
340
|
+
"stepper_line_done",
|
|
341
|
+
index > 0 && this.#state(index - 1) === Stepper.STATUS.DONE
|
|
342
|
+
);
|
|
343
|
+
node.querySelector(".stepper_line_after").classList.toggle("stepper_line_done", state === Stepper.STATUS.DONE);
|
|
344
|
+
const marker = node.querySelector(".stepper_marker");
|
|
345
|
+
marker.setAttribute("aria-label", this.#markerLabel(index));
|
|
346
|
+
if (item.disabled === true) marker.setAttribute("aria-disabled", "true");
|
|
347
|
+
else marker.removeAttribute("aria-disabled");
|
|
348
|
+
this.#glyph(marker, item, index, state);
|
|
349
|
+
}
|
|
350
|
+
|
|
219
351
|
#item(item = Object(), index = Number()) {
|
|
220
352
|
const node = document.createElement("li");
|
|
221
353
|
node.className = "stepper_item";
|
|
222
354
|
node.dataset.index = String(index);
|
|
223
|
-
|
|
224
|
-
node.setAttribute("aria-current", "step");
|
|
225
|
-
node.classList.add("stepper_item_current");
|
|
226
|
-
}
|
|
227
|
-
if (this.#state(index) === "done") node.classList.add("stepper_item_done");
|
|
228
|
-
if (this.#state(index) === "todo") node.classList.add("stepper_item_todo");
|
|
229
|
-
if (this.#clickable) node.classList.add("stepper_item_clickable");
|
|
230
|
-
node.appendChild(this.#line("before", index - 1));
|
|
355
|
+
node.appendChild(this.#line("before"));
|
|
231
356
|
node.appendChild(this.#marker(item, index));
|
|
232
|
-
node.appendChild(this.#line("after"
|
|
357
|
+
node.appendChild(this.#line("after"));
|
|
233
358
|
node.appendChild(this.#text(item));
|
|
359
|
+
this.#apply(node, item, index);
|
|
234
360
|
return node;
|
|
235
361
|
}
|
|
236
362
|
|
|
237
363
|
// Полулиния соединителя: слева от маркера идёт шаг до него, справа — после
|
|
238
|
-
#line(position = String()
|
|
364
|
+
#line(position = String()) {
|
|
239
365
|
const line = document.createElement("stepper_line");
|
|
240
366
|
line.className = `stepper_line stepper_line_${position}`;
|
|
241
367
|
line.setAttribute("aria-hidden", "true");
|
|
242
|
-
if (stateIndex >= 0 && stateIndex < this.#active) line.classList.add("stepper_line_done");
|
|
243
368
|
return line;
|
|
244
369
|
}
|
|
245
370
|
|
|
@@ -250,26 +375,62 @@ class Stepper {
|
|
|
250
375
|
marker.dataset.index = String(index);
|
|
251
376
|
if (clickable) {
|
|
252
377
|
marker.type = "button";
|
|
253
|
-
// Кнопка означает «шаг можно выбрать», поэтому у неё есть и название шага
|
|
254
|
-
marker.setAttribute("aria-label", this.#markerLabel(index));
|
|
255
378
|
marker.addEventListener("click", () => this.setActive(index));
|
|
256
379
|
} else {
|
|
257
380
|
// Маркер без действия — картинка со своим именем: номер и состояние не дублируются
|
|
258
381
|
marker.setAttribute("role", "img");
|
|
259
|
-
marker.setAttribute("aria-label", this.#markerLabel(index));
|
|
260
|
-
if (item.disabled === true) marker.setAttribute("aria-disabled", "true");
|
|
261
|
-
}
|
|
262
|
-
const glyph = this.#state(index) === "done" && item.icon === undefined ? Icons.NAVIGATION.CHECK : item.icon;
|
|
263
|
-
if (glyph === undefined) marker.innerText = String(index + 1);
|
|
264
|
-
else {
|
|
265
|
-
const icon = new Icon(glyph, this.#iconSize()).set();
|
|
266
|
-
icon.setAttribute("aria-hidden", "true");
|
|
267
|
-
marker.appendChild(icon);
|
|
268
382
|
}
|
|
269
383
|
this.#markers.push(marker);
|
|
270
384
|
return marker;
|
|
271
385
|
}
|
|
272
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Знак маркера по состоянию: галочка у пройденного, крест у ошибки, спиннер у шага,
|
|
389
|
+
* который выполняется, а в остальных случаях — свой значок шага или его номер.
|
|
390
|
+
*
|
|
391
|
+
* Знак пересобирается только когда он и впрямь сменился (`data-glyph` помнит прошлый):
|
|
392
|
+
* иначе кадр появления перезапускался бы при каждом переходе и все знаки мигали бы
|
|
393
|
+
*/
|
|
394
|
+
#glyph(marker = undefined, item = Object(), index = Number(), state = String()) {
|
|
395
|
+
const key = this.#glyphKey(item, state);
|
|
396
|
+
if (marker.dataset.glyph === key) return;
|
|
397
|
+
marker.dataset.glyph = key;
|
|
398
|
+
marker.innerHTML = "";
|
|
399
|
+
if (state === Stepper.STATUS.PENDING) {
|
|
400
|
+
marker.classList.add("stepper_marker_spinner");
|
|
401
|
+
const spinner = new Spinner(this.#spinnerSize(), "0", "").set();
|
|
402
|
+
// Маркер назван сам («… — ожидает выполнения»): здесь спиннер — картинка,
|
|
403
|
+
// а не отдельный живой регион, иначе загрузка объявлялась бы на каждом переходе
|
|
404
|
+
spinner.setAttribute("aria-hidden", "true");
|
|
405
|
+
marker.appendChild(spinner);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
marker.classList.remove("stepper_marker_spinner");
|
|
409
|
+
const glyph = this.#glyphName(item, state);
|
|
410
|
+
if (glyph === undefined) {
|
|
411
|
+
marker.innerText = String(index + 1);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const icon = new Icon(glyph, this.#iconSize()).set();
|
|
415
|
+
icon.setAttribute("aria-hidden", "true");
|
|
416
|
+
marker.appendChild(icon);
|
|
417
|
+
// Знак состояния приходит кадром: смена номера на галочку иначе читается вспышкой
|
|
418
|
+
new Animation(icon).scaleIn();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
#glyphKey(item = Object(), state = String()) {
|
|
422
|
+
if (state === Stepper.STATUS.DONE) return "done";
|
|
423
|
+
if (state === Stepper.STATUS.ERROR) return "error";
|
|
424
|
+
if (state === Stepper.STATUS.PENDING) return "pending";
|
|
425
|
+
return item.icon === undefined ? "number" : `icon:${item.icon}`;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
#glyphName(item = Object(), state = String()) {
|
|
429
|
+
if (state === Stepper.STATUS.DONE) return Icons.NAVIGATION.CHECK;
|
|
430
|
+
if (state === Stepper.STATUS.ERROR) return Icons.NAVIGATION.CLOSE;
|
|
431
|
+
return item.icon;
|
|
432
|
+
}
|
|
433
|
+
|
|
273
434
|
#text(item = Object()) {
|
|
274
435
|
const text = document.createElement("stepper_text");
|
|
275
436
|
text.className = "stepper_text";
|
|
@@ -290,15 +451,30 @@ class Stepper {
|
|
|
290
451
|
return this.#root.dataset.size === Stepper.SIZE.SMALL ? Stepper.SMALL_ICON_SIZE : Stepper.ICON_SIZE;
|
|
291
452
|
}
|
|
292
453
|
|
|
454
|
+
// Спиннер шага — по размеру знака: размеры те же, что у значков маркера
|
|
455
|
+
#spinnerSize() {
|
|
456
|
+
return this.#root.dataset.size === Stepper.SIZE.SMALL ? { SIZE: 14, BORDER: 2 } : { SIZE: 18, BORDER: 2 };
|
|
457
|
+
}
|
|
458
|
+
|
|
293
459
|
#announce() {
|
|
294
460
|
const title = this.#items[this.#active] === undefined ? undefined : this.#items[this.#active].title;
|
|
295
|
-
const head = I18n.t("navigation.stepOf", {index: this.#active + 1, total: this.#items.length});
|
|
461
|
+
const head = I18n.t("navigation.stepOf", { index: this.#active + 1, total: this.#items.length });
|
|
296
462
|
this.#status.innerText = title === undefined ? head : `${head}: ${title}`;
|
|
297
463
|
}
|
|
298
464
|
|
|
465
|
+
// О смене состояния сообщается тем же именем, что у маркера: шаг, название и состояние
|
|
466
|
+
#announceStatus(index = Number()) {
|
|
467
|
+
this.#status.innerText = this.#markerLabel(index);
|
|
468
|
+
}
|
|
469
|
+
|
|
299
470
|
#notify() {
|
|
300
471
|
for (const listener of [...this.#listeners]) listener(this.#active, this);
|
|
301
|
-
if (this.#
|
|
472
|
+
if (this.#onChange !== undefined) this.#onChange(this.#active, this);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
#notifyStatus(index = Number(), status = String()) {
|
|
476
|
+
for (const listener of [...this.#statusListeners]) listener(index, status, this);
|
|
477
|
+
if (this.#onStatus !== undefined) this.#onStatus(index, status, this);
|
|
302
478
|
}
|
|
303
479
|
|
|
304
480
|
static #clamp(value = Number(), count = Number()) {
|
|
@@ -311,4 +487,4 @@ class Stepper {
|
|
|
311
487
|
static SMALL_ICON_SIZE = "14px";
|
|
312
488
|
}
|
|
313
489
|
|
|
314
|
-
exports.Stepper = Stepper
|
|
490
|
+
exports.Stepper = Stepper;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
chui_stepper {
|
|
3
3
|
display: block;
|
|
4
4
|
width: -webkit-fill-available;
|
|
5
|
-
margin: var(--
|
|
5
|
+
margin: var(--block_margin);
|
|
6
6
|
color: var(--text_color);
|
|
7
7
|
font-size: var(--font_default_size);
|
|
8
8
|
}
|
|
@@ -33,7 +33,12 @@ chui_stepper[data-size="small"] {
|
|
|
33
33
|
min-width: 0;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/* Полулиния соединителя: приглушённая дорожка и слой заливки поверх неё. Заливка растёт
|
|
37
|
+
переходом по токену движения — путь шагов читается пройденным, а не загорается сразу.
|
|
38
|
+
Полулинии у краёв списка не рисуются, но место остаётся, иначе крайние маркеры уехали бы
|
|
39
|
+
к краям карточки */
|
|
36
40
|
.stepper_line {
|
|
41
|
+
position: relative;
|
|
37
42
|
height: 2px;
|
|
38
43
|
min-width: 12px;
|
|
39
44
|
align-self: center;
|
|
@@ -42,6 +47,18 @@ chui_stepper[data-size="small"] {
|
|
|
42
47
|
border-radius: var(--radius_pill);
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
/* Заливка идёт от того края, где стоит маркер-предшественник: так видно, что шаг пройден */
|
|
51
|
+
.stepper_line::after {
|
|
52
|
+
content: "";
|
|
53
|
+
position: absolute;
|
|
54
|
+
inset: 0;
|
|
55
|
+
background: var(--green_prime_background);
|
|
56
|
+
border-radius: inherit;
|
|
57
|
+
transform: scaleX(0);
|
|
58
|
+
transform-origin: left center;
|
|
59
|
+
transition: transform var(--motion_base) var(--motion_ease);
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
.stepper_line_before {
|
|
46
63
|
grid-column: 1;
|
|
47
64
|
grid-row: 1;
|
|
@@ -52,6 +69,10 @@ chui_stepper[data-size="small"] {
|
|
|
52
69
|
grid-row: 1;
|
|
53
70
|
}
|
|
54
71
|
|
|
72
|
+
.stepper_line_done::after {
|
|
73
|
+
transform: scaleX(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
55
76
|
/* Края списка никуда не ведут: полулинии у них не рисуются, но место остаётся,
|
|
56
77
|
иначе крайние маркеры уехали бы к краям карточки */
|
|
57
78
|
.stepper_item:first-child .stepper_line_before,
|
|
@@ -59,10 +80,6 @@ chui_stepper[data-size="small"] {
|
|
|
59
80
|
visibility: hidden;
|
|
60
81
|
}
|
|
61
82
|
|
|
62
|
-
.stepper_line_done {
|
|
63
|
-
background: var(--blue_prime_background);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
83
|
.stepper_marker {
|
|
67
84
|
grid-column: 2;
|
|
68
85
|
grid-row: 1;
|
|
@@ -81,6 +98,11 @@ chui_stepper[data-size="small"] {
|
|
|
81
98
|
font-size: var(--font_default_size);
|
|
82
99
|
font-weight: 500;
|
|
83
100
|
line-height: 1;
|
|
101
|
+
/* Цвета маркера ведёт переход: смена шага и состояния читается движением, а не вспышкой */
|
|
102
|
+
transition:
|
|
103
|
+
background-color var(--motion_base) var(--motion_ease),
|
|
104
|
+
border-color var(--motion_base) var(--motion_ease),
|
|
105
|
+
color var(--motion_base) var(--motion_ease);
|
|
84
106
|
}
|
|
85
107
|
|
|
86
108
|
.stepper_marker chui_icon {
|
|
@@ -93,10 +115,34 @@ chui_stepper[data-size="small"] .stepper_marker {
|
|
|
93
115
|
font-size: var(--font_labels_size);
|
|
94
116
|
}
|
|
95
117
|
|
|
96
|
-
/* Пройденный шаг:
|
|
118
|
+
/* Пройденный шаг: зелёная подсветка и галочка — готовность, а не текущее место */
|
|
97
119
|
.stepper_item_done .stepper_marker {
|
|
98
|
-
border-color: var(--
|
|
99
|
-
background: var(--
|
|
120
|
+
border-color: var(--green_prime_background);
|
|
121
|
+
background: color-mix(in srgb, var(--green_prime_background) 16%, transparent);
|
|
122
|
+
color: var(--green_prime_background);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Ошибка: красная подсветка и крест — тот же цвет у знака и у строки шага */
|
|
126
|
+
.stepper_item_error .stepper_marker {
|
|
127
|
+
border-color: var(--red_prime_background);
|
|
128
|
+
background: color-mix(in srgb, var(--red_prime_background) 16%, transparent);
|
|
129
|
+
color: var(--red_prime_background);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Шаг выполняется — в маркере спиннер: кольцо берёт цвет маркера (`currentColor`) */
|
|
133
|
+
.stepper_item_pending .stepper_marker {
|
|
134
|
+
border-color: var(--border_color);
|
|
135
|
+
background: var(--element_background_2);
|
|
136
|
+
color: var(--blue_prime_background);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.stepper_marker spinner {
|
|
140
|
+
margin: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Ошибка видна и строкой шага: цвет знака и подписи — один на всю строку */
|
|
144
|
+
.stepper_item_error .stepper_title {
|
|
145
|
+
color: var(--red_prime_background);
|
|
100
146
|
}
|
|
101
147
|
|
|
102
148
|
/* Текущий шаг — единственный залитый акцентом: он и есть место, где мы находимся */
|
|
@@ -106,6 +152,12 @@ chui_stepper[data-size="small"] .stepper_marker {
|
|
|
106
152
|
color: var(--text_color_hover);
|
|
107
153
|
}
|
|
108
154
|
|
|
155
|
+
/* Шаг, на котором мы стоим, виден и тогда, когда маркер занят своим состоянием
|
|
156
|
+
(ошибкой или спиннером): его выдаёт акцентное кольцо вокруг маркера */
|
|
157
|
+
.stepper_item[data-active="true"]:not(.stepper_item_current) .stepper_marker {
|
|
158
|
+
box-shadow: 0 0 0 2px var(--blue_prime_background_tint);
|
|
159
|
+
}
|
|
160
|
+
|
|
109
161
|
.stepper_item_todo .stepper_marker {
|
|
110
162
|
color: var(--text_color_disabled);
|
|
111
163
|
}
|
|
@@ -124,7 +176,7 @@ chui_stepper[data-size="small"] .stepper_marker {
|
|
|
124
176
|
outline-offset: var(--focus_outline_offset);
|
|
125
177
|
}
|
|
126
178
|
|
|
127
|
-
.stepper_marker
|
|
179
|
+
.stepper_marker[aria-disabled="true"] {
|
|
128
180
|
cursor: not-allowed;
|
|
129
181
|
color: var(--text_color_disabled);
|
|
130
182
|
background: var(--element_background_disabled);
|
|
@@ -143,11 +195,8 @@ chui_stepper[data-size="small"] .stepper_marker {
|
|
|
143
195
|
font-weight: 500;
|
|
144
196
|
overflow: hidden;
|
|
145
197
|
text-overflow: ellipsis;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
.stepper_item_todo .stepper_title {
|
|
149
|
-
color: var(--text_color_disabled);
|
|
150
|
-
font-weight: 400;
|
|
198
|
+
/* Цвет подписи и пояснения тоже ведёт переход: ошибка и выбор шага не мигают */
|
|
199
|
+
transition: color var(--motion_base) var(--motion_ease);
|
|
151
200
|
}
|
|
152
201
|
|
|
153
202
|
.stepper_description {
|
|
@@ -155,6 +204,12 @@ chui_stepper[data-size="small"] .stepper_marker {
|
|
|
155
204
|
margin-top: 2px;
|
|
156
205
|
color: var(--text_color_disabled);
|
|
157
206
|
font-size: var(--font_labels_size);
|
|
207
|
+
transition: color var(--motion_base) var(--motion_ease);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.stepper_item_todo .stepper_title {
|
|
211
|
+
color: var(--text_color_disabled);
|
|
212
|
+
font-weight: 400;
|
|
158
213
|
}
|
|
159
214
|
|
|
160
215
|
.stepper_description[hidden] {
|
|
@@ -167,6 +222,16 @@ chui_stepper[data-orientation="vertical"] .stepper_list {
|
|
|
167
222
|
grid-auto-columns: auto;
|
|
168
223
|
}
|
|
169
224
|
|
|
225
|
+
/* Заливка в столбце растёт сверху вниз — от маркера-предшественника к следующему */
|
|
226
|
+
chui_stepper[data-orientation="vertical"] .stepper_line::after {
|
|
227
|
+
transform: scaleY(0);
|
|
228
|
+
transform-origin: center top;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
chui_stepper[data-orientation="vertical"] .stepper_line_done::after {
|
|
232
|
+
transform: scaleY(1);
|
|
233
|
+
}
|
|
234
|
+
|
|
170
235
|
chui_stepper[data-orientation="vertical"] .stepper_item {
|
|
171
236
|
grid-template-columns: auto 1fr;
|
|
172
237
|
grid-template-rows: 1fr auto 1fr;
|