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,24 +1,40 @@
|
|
|
1
1
|
const { setStyles, optionOr } = require("../../modules/chui_functions");
|
|
2
2
|
const { Icon, Icons } = require("../chui_icons/icons");
|
|
3
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()` не нужен.
|
|
@@ -32,6 +48,12 @@ class Stepper {
|
|
|
32
48
|
SMALL: "small",
|
|
33
49
|
DEFAULT: "default",
|
|
34
50
|
};
|
|
51
|
+
/** Состояния шага: пройден, ошибка и ожидание выполнения */
|
|
52
|
+
static STATUS = {
|
|
53
|
+
DONE: "done",
|
|
54
|
+
ERROR: "error",
|
|
55
|
+
PENDING: "pending",
|
|
56
|
+
};
|
|
35
57
|
static #counter = 0;
|
|
36
58
|
|
|
37
59
|
#root = document.createElement("chui_stepper");
|
|
@@ -39,11 +61,14 @@ 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
|
-
#
|
|
69
|
+
#statusListeners = [];
|
|
70
|
+
#onChange = undefined;
|
|
71
|
+
#onStatus = undefined;
|
|
47
72
|
|
|
48
73
|
constructor(
|
|
49
74
|
options = {
|
|
@@ -56,6 +81,8 @@ class Stepper {
|
|
|
56
81
|
label: String(),
|
|
57
82
|
onChange: undefined,
|
|
58
83
|
changeEvent: undefined,
|
|
84
|
+
onStatus: undefined,
|
|
85
|
+
statusEvent: undefined,
|
|
59
86
|
}
|
|
60
87
|
) {
|
|
61
88
|
setStyles(__dirname + "/styles.css", "chUiJS_Stepper");
|
|
@@ -67,8 +94,10 @@ class Stepper {
|
|
|
67
94
|
this.#status.classList.add("chui_visually_hidden");
|
|
68
95
|
this.#status.setAttribute("role", "status");
|
|
69
96
|
this.#status.setAttribute("aria-live", "polite");
|
|
70
|
-
this.#
|
|
97
|
+
this.#onChange = options.onChange;
|
|
71
98
|
if (options.changeEvent !== undefined) this.addChangeListener(options.changeEvent);
|
|
99
|
+
this.#onStatus = options.onStatus;
|
|
100
|
+
if (options.statusEvent !== undefined) this.addStatusListener(options.statusEvent);
|
|
72
101
|
this.setOrientation(options.orientation === undefined ? Stepper.ORIENTATION.HORIZONTAL : options.orientation);
|
|
73
102
|
this.setSize(options.size === undefined ? Stepper.SIZE.DEFAULT : options.size);
|
|
74
103
|
this.setClickable(options.clickable === true);
|
|
@@ -104,6 +133,20 @@ class Stepper {
|
|
|
104
133
|
return item === undefined ? undefined : item.title;
|
|
105
134
|
}
|
|
106
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
|
+
|
|
107
150
|
getOrientation() {
|
|
108
151
|
return this.#root.dataset.orientation;
|
|
109
152
|
}
|
|
@@ -119,7 +162,7 @@ class Stepper {
|
|
|
119
162
|
return this;
|
|
120
163
|
}
|
|
121
164
|
|
|
122
|
-
/** Шаги: `[{title, description, icon, disabled}]` */
|
|
165
|
+
/** Шаги: `[{title, description, icon, disabled, status}]` */
|
|
123
166
|
setSteps(steps = Array()) {
|
|
124
167
|
this.#items = Array.isArray(steps) ? steps.map((item) => Object.assign({}, item)) : [];
|
|
125
168
|
this.#active = Stepper.#clamp(this.#active, this.#items.length);
|
|
@@ -142,13 +185,37 @@ class Stepper {
|
|
|
142
185
|
const next = Stepper.#clamp(index, this.#items.length);
|
|
143
186
|
const changed = next !== this.#active;
|
|
144
187
|
this.#active = next;
|
|
145
|
-
|
|
188
|
+
// Состояние применяется на месте: узлы те же, поэтому переход читается движением,
|
|
189
|
+
// а фокус и прокрутка остаются на месте
|
|
190
|
+
this.#refresh();
|
|
146
191
|
if (silent || !changed) return this;
|
|
147
192
|
this.#announce();
|
|
148
193
|
this.#notify();
|
|
149
194
|
return this;
|
|
150
195
|
}
|
|
151
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
|
+
|
|
152
219
|
/** Направление шагов: `Stepper.ORIENTATION.{HORIZONTAL, VERTICAL}` */
|
|
153
220
|
setOrientation(orientation = String()) {
|
|
154
221
|
this.#root.dataset.orientation =
|
|
@@ -184,13 +251,28 @@ class Stepper {
|
|
|
184
251
|
return this;
|
|
185
252
|
}
|
|
186
253
|
|
|
254
|
+
/** Слушатель состояния шага: `(index, status, stepper) => {}` */
|
|
255
|
+
addStatusListener(listener = () => {}) {
|
|
256
|
+
this.#statusListeners.push(listener);
|
|
257
|
+
return this;
|
|
258
|
+
}
|
|
259
|
+
|
|
187
260
|
// RENDER
|
|
188
261
|
set() {
|
|
189
262
|
return this.#root;
|
|
190
263
|
}
|
|
191
264
|
|
|
192
265
|
// === ВНУТРЕННЕЕ ===
|
|
266
|
+
/**
|
|
267
|
+
* Состояние шага. Своё состояние шага сильнее состояния по месту: шаг с ошибкой остаётся
|
|
268
|
+
* с ошибкой, даже когда человек ушёл дальше, — иначе знак ошибки пропадал бы со сменой шага
|
|
269
|
+
*/
|
|
193
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
|
+
}
|
|
194
276
|
if (index < this.#active) return "done";
|
|
195
277
|
if (index === this.#active) return "current";
|
|
196
278
|
return "todo";
|
|
@@ -198,7 +280,9 @@ class Stepper {
|
|
|
198
280
|
|
|
199
281
|
#stateWord(index = Number()) {
|
|
200
282
|
const state = this.#state(index);
|
|
201
|
-
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");
|
|
202
286
|
if (state === "current") return I18n.t("navigation.stepCurrent");
|
|
203
287
|
return I18n.t("navigation.stepTodo");
|
|
204
288
|
}
|
|
@@ -217,34 +301,70 @@ class Stepper {
|
|
|
217
301
|
const focused = this.#markers.indexOf(document.activeElement);
|
|
218
302
|
this.#list.innerHTML = "";
|
|
219
303
|
this.#markers = [];
|
|
220
|
-
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
|
+
});
|
|
221
310
|
if (focused !== -1 && this.#markers[focused] !== undefined) this.#markers[focused].focus();
|
|
222
311
|
}
|
|
223
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
|
+
|
|
224
351
|
#item(item = Object(), index = Number()) {
|
|
225
352
|
const node = document.createElement("li");
|
|
226
353
|
node.className = "stepper_item";
|
|
227
354
|
node.dataset.index = String(index);
|
|
228
|
-
|
|
229
|
-
node.setAttribute("aria-current", "step");
|
|
230
|
-
node.classList.add("stepper_item_current");
|
|
231
|
-
}
|
|
232
|
-
if (this.#state(index) === "done") node.classList.add("stepper_item_done");
|
|
233
|
-
if (this.#state(index) === "todo") node.classList.add("stepper_item_todo");
|
|
234
|
-
if (this.#clickable) node.classList.add("stepper_item_clickable");
|
|
235
|
-
node.appendChild(this.#line("before", index - 1));
|
|
355
|
+
node.appendChild(this.#line("before"));
|
|
236
356
|
node.appendChild(this.#marker(item, index));
|
|
237
|
-
node.appendChild(this.#line("after"
|
|
357
|
+
node.appendChild(this.#line("after"));
|
|
238
358
|
node.appendChild(this.#text(item));
|
|
359
|
+
this.#apply(node, item, index);
|
|
239
360
|
return node;
|
|
240
361
|
}
|
|
241
362
|
|
|
242
363
|
// Полулиния соединителя: слева от маркера идёт шаг до него, справа — после
|
|
243
|
-
#line(position = String()
|
|
364
|
+
#line(position = String()) {
|
|
244
365
|
const line = document.createElement("stepper_line");
|
|
245
366
|
line.className = `stepper_line stepper_line_${position}`;
|
|
246
367
|
line.setAttribute("aria-hidden", "true");
|
|
247
|
-
if (stateIndex >= 0 && stateIndex < this.#active) line.classList.add("stepper_line_done");
|
|
248
368
|
return line;
|
|
249
369
|
}
|
|
250
370
|
|
|
@@ -255,26 +375,62 @@ class Stepper {
|
|
|
255
375
|
marker.dataset.index = String(index);
|
|
256
376
|
if (clickable) {
|
|
257
377
|
marker.type = "button";
|
|
258
|
-
// Кнопка означает «шаг можно выбрать», поэтому у неё есть и название шага
|
|
259
|
-
marker.setAttribute("aria-label", this.#markerLabel(index));
|
|
260
378
|
marker.addEventListener("click", () => this.setActive(index));
|
|
261
379
|
} else {
|
|
262
380
|
// Маркер без действия — картинка со своим именем: номер и состояние не дублируются
|
|
263
381
|
marker.setAttribute("role", "img");
|
|
264
|
-
marker.setAttribute("aria-label", this.#markerLabel(index));
|
|
265
|
-
if (item.disabled === true) marker.setAttribute("aria-disabled", "true");
|
|
266
|
-
}
|
|
267
|
-
const glyph = this.#state(index) === "done" && item.icon === undefined ? Icons.NAVIGATION.CHECK : item.icon;
|
|
268
|
-
if (glyph === undefined) marker.innerText = String(index + 1);
|
|
269
|
-
else {
|
|
270
|
-
const icon = new Icon(glyph, this.#iconSize()).set();
|
|
271
|
-
icon.setAttribute("aria-hidden", "true");
|
|
272
|
-
marker.appendChild(icon);
|
|
273
382
|
}
|
|
274
383
|
this.#markers.push(marker);
|
|
275
384
|
return marker;
|
|
276
385
|
}
|
|
277
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
|
+
|
|
278
434
|
#text(item = Object()) {
|
|
279
435
|
const text = document.createElement("stepper_text");
|
|
280
436
|
text.className = "stepper_text";
|
|
@@ -295,15 +451,30 @@ class Stepper {
|
|
|
295
451
|
return this.#root.dataset.size === Stepper.SIZE.SMALL ? Stepper.SMALL_ICON_SIZE : Stepper.ICON_SIZE;
|
|
296
452
|
}
|
|
297
453
|
|
|
454
|
+
// Спиннер шага — по размеру знака: размеры те же, что у значков маркера
|
|
455
|
+
#spinnerSize() {
|
|
456
|
+
return this.#root.dataset.size === Stepper.SIZE.SMALL ? { SIZE: 14, BORDER: 2 } : { SIZE: 18, BORDER: 2 };
|
|
457
|
+
}
|
|
458
|
+
|
|
298
459
|
#announce() {
|
|
299
460
|
const title = this.#items[this.#active] === undefined ? undefined : this.#items[this.#active].title;
|
|
300
461
|
const head = I18n.t("navigation.stepOf", { index: this.#active + 1, total: this.#items.length });
|
|
301
462
|
this.#status.innerText = title === undefined ? head : `${head}: ${title}`;
|
|
302
463
|
}
|
|
303
464
|
|
|
465
|
+
// О смене состояния сообщается тем же именем, что у маркера: шаг, название и состояние
|
|
466
|
+
#announceStatus(index = Number()) {
|
|
467
|
+
this.#status.innerText = this.#markerLabel(index);
|
|
468
|
+
}
|
|
469
|
+
|
|
304
470
|
#notify() {
|
|
305
471
|
for (const listener of [...this.#listeners]) listener(this.#active, this);
|
|
306
|
-
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);
|
|
307
478
|
}
|
|
308
479
|
|
|
309
480
|
static #clamp(value = Number(), count = Number()) {
|
|
@@ -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;
|