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
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/* ── MessageBar — лента сообщений ───────────────────────────── */
|
|
2
|
+
chui_message_bar {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
width: -webkit-fill-available;
|
|
7
|
+
height: max-content;
|
|
8
|
+
margin: var(--block_margin);
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
border-radius: var(--radius_sm);
|
|
11
|
+
background: var(--element_background);
|
|
12
|
+
border: 1px solid var(--border_color);
|
|
13
|
+
font-size: var(--font_default_size);
|
|
14
|
+
color: var(--text_color);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Лента и кнопка «Новые сообщения» живут в одной коробке: кнопка лежит поверх нижнего края,
|
|
18
|
+
а не под лентой, — поэтому она и попадает в поле зрения, и не отнимает высоту у сообщений */
|
|
19
|
+
message_bar_view {
|
|
20
|
+
position: relative;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
height: var(--message_bar_height, 320px);
|
|
24
|
+
min-height: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Лента прокручивается сама: страница под ней не растёт. Сообщения лежат отдельным слоем —
|
|
28
|
+
за его размером следит `ResizeObserver`, чтобы лента осталась у нижнего края, когда стили
|
|
29
|
+
доехали, окно изменило ширину или догрузилась картинка */
|
|
30
|
+
message_bar_feed {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
flex: 1 1 auto;
|
|
34
|
+
min-height: 0;
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
padding: var(--control_padding);
|
|
37
|
+
overflow-y: auto;
|
|
38
|
+
overflow-x: hidden;
|
|
39
|
+
background: var(--element_background_2);
|
|
40
|
+
/* Кольцо фокуса рисует общее правило темы, а смещает его внутрь общий список
|
|
41
|
+
обрезанных коробок (`message_bar_feed` рядом с `chat_log` в global_style.css):
|
|
42
|
+
лента лежит в коробке с `overflow: hidden`, внешний контур срезался бы */
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
message_bar_content {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
flex: 1 1 auto;
|
|
49
|
+
gap: 6px;
|
|
50
|
+
min-height: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
message_bar_empty {
|
|
54
|
+
margin: auto;
|
|
55
|
+
padding: var(--control_padding);
|
|
56
|
+
color: var(--text_color_disabled);
|
|
57
|
+
font-size: var(--font_labels_size);
|
|
58
|
+
text-align: center;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
message_bar_empty[hidden] {
|
|
62
|
+
display: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Кнопка «Новые сообщения»/«К низу»: показ и уборка идут переходом, поэтому кнопка
|
|
66
|
+
не мигает и в скрытом состоянии не перехватывает щелчки (видимость снимается целиком) */
|
|
67
|
+
.message_bar_jump {
|
|
68
|
+
position: absolute;
|
|
69
|
+
inset-block-end: var(--control_padding);
|
|
70
|
+
inset-inline-start: 50%;
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: row;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 4px;
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
padding: 4px var(--control_padding);
|
|
77
|
+
border: none;
|
|
78
|
+
border-radius: var(--radius_pill);
|
|
79
|
+
background: var(--blue_prime_background);
|
|
80
|
+
color: var(--text_color_hover);
|
|
81
|
+
font-family: inherit;
|
|
82
|
+
font-size: var(--font_labels_size);
|
|
83
|
+
font-weight: 500;
|
|
84
|
+
cursor: pointer;
|
|
85
|
+
box-shadow: var(--box_shadow_main);
|
|
86
|
+
visibility: hidden;
|
|
87
|
+
opacity: 0;
|
|
88
|
+
transform: translateX(-50%) translateY(4px);
|
|
89
|
+
transition:
|
|
90
|
+
opacity var(--motion_fast) var(--motion_ease),
|
|
91
|
+
transform var(--motion_fast) var(--motion_ease),
|
|
92
|
+
visibility var(--motion_fast);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.message_bar_jump[data-visible="true"] {
|
|
96
|
+
visibility: visible;
|
|
97
|
+
opacity: 1;
|
|
98
|
+
transform: translateX(-50%);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.message_bar_jump:hover {
|
|
102
|
+
background: var(--blue_prime_background_tint_strong);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.message_bar_jump_icon {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.message_bar_jump chui_icon {
|
|
111
|
+
color: inherit;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Разделитель дня: подпись-пилюля по центру ленты */
|
|
115
|
+
message_bar_day {
|
|
116
|
+
display: flex;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
padding: 2px 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
message_bar_day_label {
|
|
122
|
+
padding: 2px var(--control_padding);
|
|
123
|
+
border-radius: var(--radius_sm);
|
|
124
|
+
background: var(--element_background);
|
|
125
|
+
border: 1px solid var(--border_color);
|
|
126
|
+
color: var(--text_color_disabled);
|
|
127
|
+
font-size: var(--font_labels_size);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Группа сообщений одного автора одного дня: аватар и стопка пузырей */
|
|
131
|
+
message_bar_group {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: row;
|
|
134
|
+
align-items: flex-end;
|
|
135
|
+
gap: 8px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
message_bar_group[data-own="true"] {
|
|
139
|
+
flex-direction: row-reverse;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
message_bar_bubbles {
|
|
143
|
+
display: flex;
|
|
144
|
+
flex-direction: column;
|
|
145
|
+
gap: 4px;
|
|
146
|
+
max-width: 78%;
|
|
147
|
+
min-width: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
message_bar_bubble {
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-direction: column;
|
|
153
|
+
gap: 2px;
|
|
154
|
+
padding: 8px 10px;
|
|
155
|
+
border-radius: var(--radius_sm);
|
|
156
|
+
background: var(--element_background);
|
|
157
|
+
border: 1px solid var(--border_color);
|
|
158
|
+
color: var(--text_color);
|
|
159
|
+
/* Новое сообщение встаёт на место: кадр общий — см. `chui_appear_up` в global_style.css */
|
|
160
|
+
animation: chui_appear_up var(--motion_base) var(--motion_ease);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* Хвостик стопки: у последнего пузыря угол со стороны автора скруглён меньше — по нему
|
|
164
|
+
видно, где стопка кончается */
|
|
165
|
+
message_bar_bubble[data-last="true"][data-own="false"] {
|
|
166
|
+
border-end-start-radius: calc(var(--radius_sm) / 2);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
message_bar_bubble[data-last="true"][data-own="true"] {
|
|
170
|
+
border-end-end-radius: calc(var(--radius_sm) / 2);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Свои сообщения — акцентом и справа */
|
|
174
|
+
message_bar_bubble[data-own="true"] {
|
|
175
|
+
background: var(--blue_prime_background);
|
|
176
|
+
border-color: var(--blue_prime_background);
|
|
177
|
+
color: var(--text_color_hover);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
message_bar_author {
|
|
181
|
+
display: block;
|
|
182
|
+
font-size: var(--font_labels_size);
|
|
183
|
+
font-weight: 600;
|
|
184
|
+
color: var(--blue_prime_background);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
message_bar_text {
|
|
188
|
+
display: block;
|
|
189
|
+
white-space: pre-wrap;
|
|
190
|
+
word-break: break-word;
|
|
191
|
+
line-height: 1.35;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
message_bar_attachment {
|
|
195
|
+
display: block;
|
|
196
|
+
margin-block-start: 2px;
|
|
197
|
+
font-size: var(--font_labels_size);
|
|
198
|
+
text-decoration: underline;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
message_bar_attachment a {
|
|
202
|
+
color: inherit;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
message_bar_meta {
|
|
206
|
+
display: flex;
|
|
207
|
+
flex-direction: row;
|
|
208
|
+
align-items: center;
|
|
209
|
+
gap: 4px;
|
|
210
|
+
align-self: flex-end;
|
|
211
|
+
color: var(--text_color_disabled);
|
|
212
|
+
font-size: var(--font_labels_size);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
message_bar_bubble[data-own="true"] message_bar_meta {
|
|
216
|
+
color: var(--text_color_hover_disabled);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
message_bar_status {
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
justify-content: center;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
message_bar_status chui_icon {
|
|
226
|
+
color: inherit;
|
|
227
|
+
font-size: var(--font_labels_size);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
message_bar_status[data-status="failed"] {
|
|
231
|
+
color: var(--red_prime_background);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Строка «печатает…»: на контейнерной ступени под лентой, как у чата */
|
|
235
|
+
message_bar_typing {
|
|
236
|
+
padding: var(--control_padding) var(--block_padding);
|
|
237
|
+
color: var(--text_color_disabled);
|
|
238
|
+
font-size: var(--font_labels_size);
|
|
239
|
+
animation: chui_appear_up var(--motion_base) var(--motion_ease);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.message_bar_typing_leaving {
|
|
243
|
+
animation: chui_leave_up var(--motion_fast) var(--motion_ease) forwards;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
message_bar_typing[hidden] {
|
|
247
|
+
display: none;
|
|
248
|
+
}
|
|
@@ -14,7 +14,9 @@ class Dialog {
|
|
|
14
14
|
#footer = document.createElement("dialog_footer");
|
|
15
15
|
//
|
|
16
16
|
#a11y = undefined;
|
|
17
|
-
#
|
|
17
|
+
#outsideClickBound = false;
|
|
18
|
+
// Место, откуда слой открыли: туда он вернётся после ухода
|
|
19
|
+
#origin = undefined;
|
|
18
20
|
isOpen = false;
|
|
19
21
|
|
|
20
22
|
constructor(
|
|
@@ -44,26 +46,43 @@ class Dialog {
|
|
|
44
46
|
|
|
45
47
|
if (options.closeOutSideClick) {
|
|
46
48
|
this.#dialog.addEventListener("animationend", (evt) => {
|
|
47
|
-
if (evt.animationName === "fade-in" && !this.#
|
|
48
|
-
this.#
|
|
49
|
+
if (evt.animationName === "fade-in" && !this.#outsideClickBound) {
|
|
50
|
+
this.#outsideClickBound = true;
|
|
49
51
|
window.addEventListener("click", this.#closeOutsideEvent);
|
|
50
52
|
}
|
|
51
53
|
});
|
|
52
54
|
}
|
|
55
|
+
// Слой возвращается на место после ухода и снимает занавес из документа
|
|
56
|
+
this.#dialog.addEventListener("animationend", this.#returnHome);
|
|
53
57
|
//ADDS
|
|
54
58
|
this.#dialog.appendChild(this.#body);
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
#closeOutsideEvent = (event) => {
|
|
58
62
|
if (!this.#dialog.contains(event.target)) {
|
|
59
|
-
if (this.#
|
|
60
|
-
this.#
|
|
63
|
+
if (this.#outsideClickBound) {
|
|
64
|
+
this.#outsideClickBound = false;
|
|
61
65
|
window.removeEventListener("click", this.#closeOutsideEvent);
|
|
62
66
|
}
|
|
63
67
|
this.close();
|
|
64
68
|
}
|
|
65
69
|
};
|
|
66
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Уход доигран: диалог возвращается туда, откуда открывался, а занавес убирается из
|
|
73
|
+
* документа — закрытому слою в body делать нечего (карточку, из которой его открыли,
|
|
74
|
+
* могли уже снести), при следующем открытии занавес встанет заново.
|
|
75
|
+
* Слушатель висит постоянно: вход (`fade-in`) и чужие кадры внутри диалога пропускаем.
|
|
76
|
+
*/
|
|
77
|
+
#returnHome = (event) => {
|
|
78
|
+
if (event.target !== this.#dialog || event.animationName !== "fade-out" || this.isOpen) return;
|
|
79
|
+
this.#scrim.remove();
|
|
80
|
+
const origin = this.#origin;
|
|
81
|
+
if (origin === undefined || origin === null || origin === document.body) return;
|
|
82
|
+
if (origin.isConnected === false) return;
|
|
83
|
+
origin.appendChild(this.#dialog);
|
|
84
|
+
};
|
|
85
|
+
|
|
67
86
|
#resizeEvent = () => {
|
|
68
87
|
if (!document.contains(this.#dialog)) return;
|
|
69
88
|
this.#setCenter(this.#dialog, window);
|
|
@@ -71,28 +90,28 @@ class Dialog {
|
|
|
71
90
|
|
|
72
91
|
addToHeader(...components) {
|
|
73
92
|
this.#dialog.insertBefore(this.#header, this.#body);
|
|
74
|
-
for (
|
|
93
|
+
for (const component of components) this.#header.appendChild(component.set());
|
|
75
94
|
}
|
|
76
95
|
|
|
77
96
|
addToBody(...components) {
|
|
78
|
-
for (
|
|
97
|
+
for (const component of components) this.#body.appendChild(component.set());
|
|
79
98
|
}
|
|
80
99
|
|
|
81
100
|
addToFooter(...components) {
|
|
82
101
|
this.#dialog.appendChild(this.#footer);
|
|
83
|
-
for (
|
|
102
|
+
for (const component of components) this.#footer.appendChild(component.set());
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
removeFromHeader(...components) {
|
|
87
|
-
for (
|
|
106
|
+
for (const component of components) new Animation(component.set()).fadeOutAndRemove();
|
|
88
107
|
}
|
|
89
108
|
|
|
90
109
|
removeFromBody(...components) {
|
|
91
|
-
for (
|
|
110
|
+
for (const component of components) new Animation(component.set()).fadeOutAndRemove();
|
|
92
111
|
}
|
|
93
112
|
|
|
94
113
|
removeFromFooter(...components) {
|
|
95
|
-
for (
|
|
114
|
+
for (const component of components) new Animation(component.set()).fadeOutAndRemove();
|
|
96
115
|
}
|
|
97
116
|
|
|
98
117
|
open() {
|
|
@@ -108,6 +127,11 @@ class Dialog {
|
|
|
108
127
|
// }
|
|
109
128
|
|
|
110
129
|
window.addEventListener("resize", this.#resizeEvent);
|
|
130
|
+
// Слой встаёт в body — рядом с занавесом и шапкой окна: у обоих `backdrop-filter` и
|
|
131
|
+
// `z-index`, а внутри карточки Chromium собирает такой слой отдельной поверхностью и
|
|
132
|
+
// рисует её под слоями из body — занавес закрывал диалог целиком
|
|
133
|
+
this.#origin = this.#dialog.parentElement;
|
|
134
|
+
if (this.#dialog.parentElement !== document.body) document.body.appendChild(this.#dialog);
|
|
111
135
|
// Занавес нужен только открытому слою
|
|
112
136
|
if (document.body.contains(this.#scrim) === false) document.body.appendChild(this.#scrim);
|
|
113
137
|
new Animation(this.#dialog).fadeIn();
|
|
@@ -132,8 +156,8 @@ class Dialog {
|
|
|
132
156
|
}
|
|
133
157
|
|
|
134
158
|
close() {
|
|
135
|
-
if (this.#
|
|
136
|
-
this.#
|
|
159
|
+
if (this.#outsideClickBound) {
|
|
160
|
+
this.#outsideClickBound = false;
|
|
137
161
|
window.removeEventListener("click", this.#closeOutsideEvent);
|
|
138
162
|
}
|
|
139
163
|
window.removeEventListener("resize", this.#resizeEvent);
|
|
@@ -33,14 +33,14 @@ class Notification {
|
|
|
33
33
|
#id = require("randomstring").generate();
|
|
34
34
|
#time = 5000;
|
|
35
35
|
#notification = document.createElement(`notification`);
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
36
|
+
#notificationIcon = document.createElement("notification_icon");
|
|
37
|
+
#notificationContent = document.createElement("notification_content");
|
|
38
|
+
#notificationHeader = document.createElement("notification_header");
|
|
39
|
+
#notificationTitle = document.createElement("notification_title");
|
|
40
|
+
#notificationDate = document.createElement("notification_date");
|
|
41
|
+
#notificationText = document.createElement("notification_text");
|
|
42
|
+
#notificationProgress = document.createElement("notification_progress");
|
|
43
|
+
#notificationClose = document.createElement("button");
|
|
44
44
|
// Отсчёт автоскрытия: таймер, дедлайн и остаток — чтобы пауза не теряла время
|
|
45
45
|
#timer = undefined;
|
|
46
46
|
#deadline = 0;
|
|
@@ -60,29 +60,29 @@ class Notification {
|
|
|
60
60
|
setStyles(__dirname + "/styles.css", "chUiJS_Notification");
|
|
61
61
|
// Время показа — только настоящее число: заготовка `Number()` из описания опций
|
|
62
62
|
// раньше доезжала как значение и карточка без опций исчезала мгновенно
|
|
63
|
-
const
|
|
64
|
-
if (Number.isFinite(
|
|
63
|
+
const showTime = Number(options.showTime);
|
|
64
|
+
if (Number.isFinite(showTime)) this.#time = showTime;
|
|
65
65
|
this.#notification.id = this.#id;
|
|
66
66
|
// Пустая заготовка опции равносильна отсутствующей: иначе обе опции читались как заданные
|
|
67
67
|
const title = optionOr(options.title, undefined);
|
|
68
|
-
const
|
|
68
|
+
const markdownTitle = optionOr(options.markdownTitle, undefined);
|
|
69
69
|
const text = optionOr(options.text, undefined);
|
|
70
|
-
const
|
|
70
|
+
const markdownText = optionOr(options.markdownText, undefined);
|
|
71
71
|
// Стили заголовка уведомления
|
|
72
|
-
if (title !== undefined &&
|
|
72
|
+
if (title !== undefined && markdownTitle !== undefined) {
|
|
73
73
|
throw new Error("Должна быть установлена одна опция title или markdownTitle");
|
|
74
74
|
} else {
|
|
75
|
-
if (title !== undefined) this.#
|
|
76
|
-
if (
|
|
75
|
+
if (title !== undefined) this.#notificationTitle.innerText = title;
|
|
76
|
+
if (markdownTitle !== undefined) this.#notificationTitle.innerHTML = markdownToHtml(markdownTitle);
|
|
77
77
|
}
|
|
78
78
|
// Стили текста уведомления
|
|
79
|
-
if (text !== undefined &&
|
|
79
|
+
if (text !== undefined && markdownText !== undefined) {
|
|
80
80
|
throw new Error("Должна быть установлена одна опция text или markdownText");
|
|
81
81
|
} else {
|
|
82
|
-
if (text !== undefined) this.#
|
|
83
|
-
if (
|
|
82
|
+
if (text !== undefined) this.#notificationText.innerText = text;
|
|
83
|
+
if (markdownText !== undefined) this.#notificationText.innerHTML = markdownToHtml(markdownText);
|
|
84
84
|
}
|
|
85
|
-
this.#
|
|
85
|
+
this.#notificationDate.innerHTML = getTime();
|
|
86
86
|
// Ключ дня для группировки истории в ящике: подпись группы («Сегодня», «Вчера»,
|
|
87
87
|
// дата) считает ящик, карточке достаточно самого ключа. Записи приходят
|
|
88
88
|
// непрочитанными — ящик снимает отметку, когда его открыли.
|
|
@@ -96,32 +96,32 @@ class Notification {
|
|
|
96
96
|
this.#notification.setAttribute("role", style === Notification.STYLE.ERROR ? "alert" : "status");
|
|
97
97
|
// Иконка состояния — украшение: стиль читается и по тексту уведомления.
|
|
98
98
|
// Цвет и глиф плашки выбирает общий помощник семейства — по ключу стиля
|
|
99
|
-
this.#
|
|
99
|
+
this.#notificationIcon.setAttribute("aria-hidden", "true");
|
|
100
100
|
setStatusPlate(
|
|
101
|
-
this.#
|
|
101
|
+
this.#notificationIcon,
|
|
102
102
|
typeof style === "string" ? style.replace("notification_", "") : undefined
|
|
103
103
|
);
|
|
104
104
|
// Закрытие — настоящая кнопка: доступна мышью, с клавиатуры и скринридеру
|
|
105
|
-
this.#
|
|
106
|
-
this.#
|
|
107
|
-
this.#
|
|
108
|
-
this.#
|
|
109
|
-
this.#
|
|
105
|
+
this.#notificationClose.className = "notification_close";
|
|
106
|
+
this.#notificationClose.type = "button";
|
|
107
|
+
this.#notificationClose.setAttribute("aria-label", I18n.t("a11y.closeNotification"));
|
|
108
|
+
this.#notificationClose.setAttribute("title", I18n.t("common.close"));
|
|
109
|
+
this.#notificationClose.innerHTML = new Icon(Icons.NAVIGATION.CLOSE, "16px").getHTML();
|
|
110
110
|
//
|
|
111
|
-
this.#
|
|
112
|
-
this.#
|
|
111
|
+
this.#notificationHeader.appendChild(this.#notificationTitle);
|
|
112
|
+
this.#notificationHeader.appendChild(this.#notificationDate);
|
|
113
113
|
//
|
|
114
|
-
this.#
|
|
115
|
-
this.#
|
|
116
|
-
this.#notification.appendChild(this.#
|
|
117
|
-
this.#notification.appendChild(this.#
|
|
118
|
-
this.#notification.appendChild(this.#
|
|
114
|
+
this.#notificationContent.appendChild(this.#notificationHeader);
|
|
115
|
+
this.#notificationContent.appendChild(this.#notificationText);
|
|
116
|
+
this.#notification.appendChild(this.#notificationIcon);
|
|
117
|
+
this.#notification.appendChild(this.#notificationContent);
|
|
118
|
+
this.#notification.appendChild(this.#notificationClose);
|
|
119
119
|
// Полоса отсчёта нужна только тем уведомлениям, которые закрываются сами
|
|
120
120
|
if (this.#time > 0) {
|
|
121
|
-
this.#
|
|
121
|
+
this.#notificationProgress.style.animationDuration = `${this.#time}ms`;
|
|
122
122
|
// Отсчёт стартует вместе с таймером, а не с появлением узла в DOM
|
|
123
|
-
this.#
|
|
124
|
-
this.#notification.appendChild(this.#
|
|
123
|
+
this.#notificationProgress.style.animationPlayState = "paused";
|
|
124
|
+
this.#notification.appendChild(this.#notificationProgress);
|
|
125
125
|
}
|
|
126
126
|
// Курсор или фокус внутри карточки останавливают отсчёт
|
|
127
127
|
this.#notification.addEventListener("mouseenter", () => this.pause());
|
|
@@ -147,8 +147,8 @@ class Notification {
|
|
|
147
147
|
if (showOnSystem)
|
|
148
148
|
require("electron").ipcRenderer.send(
|
|
149
149
|
"show_system_notification",
|
|
150
|
-
this.#
|
|
151
|
-
this.#
|
|
150
|
+
this.#notificationTitle.innerText,
|
|
151
|
+
this.#notificationText.innerText
|
|
152
152
|
);
|
|
153
153
|
return this;
|
|
154
154
|
}
|
|
@@ -160,7 +160,7 @@ class Notification {
|
|
|
160
160
|
clearTimeout(this.#timer);
|
|
161
161
|
this.#timer = undefined;
|
|
162
162
|
this.#remaining = Math.max(0, this.#deadline - Date.now());
|
|
163
|
-
this.#
|
|
163
|
+
this.#notificationProgress.style.animationPlayState = "paused";
|
|
164
164
|
return this;
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -182,7 +182,7 @@ class Notification {
|
|
|
182
182
|
this.#dismissed = true;
|
|
183
183
|
this.#clearTimer();
|
|
184
184
|
// Полоса отсчёта больше не нужна: её animationend мог бы прилететь во время ухода
|
|
185
|
-
this.#
|
|
185
|
+
this.#notificationProgress.remove();
|
|
186
186
|
this.#removeNotification(this.#notification);
|
|
187
187
|
return this;
|
|
188
188
|
}
|
|
@@ -192,7 +192,7 @@ class Notification {
|
|
|
192
192
|
this.#remaining = duration;
|
|
193
193
|
this.#deadline = Date.now() + duration;
|
|
194
194
|
this.#timer = setTimeout(() => this.dismiss(), duration);
|
|
195
|
-
this.#
|
|
195
|
+
this.#notificationProgress.style.animationPlayState = "running";
|
|
196
196
|
return this;
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -204,29 +204,51 @@ class Notification {
|
|
|
204
204
|
|
|
205
205
|
#removeNotification(notification) {
|
|
206
206
|
// Анимация ухода требует уже заданного animationName — у невидимого уведомления его нет
|
|
207
|
-
if (notification.style.animationName === "")
|
|
207
|
+
if (notification.style.animationName === "") {
|
|
208
|
+
notification.style.animationName = "slide-right-in";
|
|
209
|
+
notification.dataset.motion = "enter";
|
|
210
|
+
}
|
|
208
211
|
new Animation(notification).slideRightOutAndRemove();
|
|
209
|
-
|
|
212
|
+
// Въезд в ящик — событие одноразовое: сняв себя после своего кадра, обработчик больше
|
|
213
|
+
// не трогает карточку. Без снятия его ловил любой конец кадра — включая кадр уборки:
|
|
214
|
+
// запись переселялась в начало списка и кадр начинался заново
|
|
215
|
+
const land = (event) => {
|
|
210
216
|
if (event.target !== notification) return;
|
|
211
|
-
|
|
212
|
-
//
|
|
217
|
+
notification.removeEventListener("animationend", land);
|
|
218
|
+
// Следы кадра ухода снимаем точечно: `removeAttribute("style")` снёс бы и чужие
|
|
219
|
+
// инлайновые значения (в карточке их несколько — отсчёт, отклик на наведение).
|
|
220
|
+
// Вид ухода держит конечное состояние (`fill-mode: both`), а инлайновое имя кадра
|
|
221
|
+
// перебило бы любой следующий: без этого въезд записи не проигрался бы
|
|
213
222
|
notification.style.removeProperty("animation-name");
|
|
223
|
+
notification.removeAttribute("data-motion");
|
|
214
224
|
notification.style.removeProperty("transition");
|
|
215
|
-
notification.style.display = "flex";
|
|
216
|
-
notification.style.width = "-webkit-fill-available";
|
|
217
|
-
notification.style.opacity = "0";
|
|
218
|
-
notification.style.transform = "translateX(100%)";
|
|
219
225
|
// В ящике карточка — запись истории: полоса отсчёта и закрытие там лишние
|
|
220
226
|
notification.classList.add("notification_in_box");
|
|
221
227
|
const box = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_BOX_MAIN, notification);
|
|
222
228
|
// Новые записи идут сверху: история читается от свежего к старому, и группы дней
|
|
223
229
|
// (их расставляет NotificationBox) ложатся в том же порядке — «Сегодня» первой.
|
|
224
230
|
box.prepend(notification);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
231
|
+
/*
|
|
232
|
+
* Запись встаёт на место тем же кадром, каким пришёл тост: она только что уехала вправо,
|
|
233
|
+
* поэтому и возвращается оттуда. Прежде карточка ставилась инлайновыми `opacity`
|
|
234
|
+
* и `transform` и ждала 500 мс — и слайд не проигрывался вовсе: вид `exit` держит
|
|
235
|
+
* `transform` вне переходов (`[data-motion]`), поэтому запись просто вспыхивала
|
|
236
|
+
* на месте. Кадр ведёт драйвер: время и кривую берёт вид `enter` из токенов темы.
|
|
237
|
+
*/
|
|
238
|
+
new Animation(notification).slideRightIn();
|
|
239
|
+
// Кадр въезда доигран — запись возвращается к стилям: инлайнового имени кадра
|
|
240
|
+
// и вида у неё не остаётся, иначе они спорили бы со следующим кадром (уборкой)
|
|
241
|
+
notification.addEventListener(
|
|
242
|
+
"animationend",
|
|
243
|
+
(event) => {
|
|
244
|
+
if (event.target !== notification) return;
|
|
245
|
+
notification.style.removeProperty("animation-name");
|
|
246
|
+
notification.removeAttribute("data-motion");
|
|
247
|
+
},
|
|
248
|
+
{ once: true }
|
|
249
|
+
);
|
|
250
|
+
};
|
|
251
|
+
notification.addEventListener("animationend", land);
|
|
230
252
|
}
|
|
231
253
|
|
|
232
254
|
static STYLE = { ERROR: "notification_error", SUCCESS: "notification_success", WARNING: "notification_warning" };
|