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
package/README.md
CHANGED
|
@@ -1,672 +1,71 @@
|
|
|
1
1
|
# chuijs
|
|
2
|
-
### CHROME_SANDBOX FIX
|
|
3
|
-
### CHROME\_SANDBOX FIX 1
|
|
4
|
-
```shell
|
|
5
|
-
cd node_modules/electron/dist && sudo chown root chrome-sandbox && sudo chmod 4755 chrome-sandbox
|
|
6
|
-
```
|
|
7
|
-
### Структура
|
|
8
|
-
#### exampleApp / app / views / main.js
|
|
9
|
-
```javascript
|
|
10
|
-
const { Page, Button, TextInput, Notification, Log } = require('chuijs');
|
|
11
|
-
class MainPage extends Page {
|
|
12
|
-
constructor() {
|
|
13
|
-
super();
|
|
14
|
-
this.setTitle('Сказать привет!');
|
|
15
|
-
this.setMain(false)
|
|
16
|
-
|
|
17
|
-
let name = new TextInput({
|
|
18
|
-
title: 'Введите ваше имя',
|
|
19
|
-
placeholder: 'Введите ваше имя',
|
|
20
|
-
required: false
|
|
21
|
-
});
|
|
22
|
-
let hello = new Button({
|
|
23
|
-
title: "Сказать привет!",
|
|
24
|
-
clickEvent: () => {
|
|
25
|
-
if (name.getValue() !== "") {
|
|
26
|
-
new Notification({
|
|
27
|
-
title: `Привет, ${name.getValue()}!`, text: `Привет, ${name.getValue()}!`,
|
|
28
|
-
style: Notification.STYLE.SUCCESS, showTime: 5000
|
|
29
|
-
}).show();
|
|
30
|
-
} else {
|
|
31
|
-
new Notification({
|
|
32
|
-
title: `Привет мир!`, text: `Привет мир!`,
|
|
33
|
-
style: Notification.STYLE.SUCCESS, showTime: 5000
|
|
34
|
-
}).show();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
this.add(name, hello)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
exports.MainPage = MainPage
|
|
42
|
-
```
|
|
43
|
-
#### exampleApp / app / app.js
|
|
44
|
-
```javascript
|
|
45
|
-
/** RENDERER ПРОЦЕСС */
|
|
46
|
-
/** ИМПОРТЫ */
|
|
47
|
-
const { AppLayout, render, Log } = require('chuijs');
|
|
48
|
-
/** СТРАНИЦЫ */
|
|
49
|
-
const { MainPage } = require('../app/views/main');
|
|
50
|
-
class App extends AppLayout {
|
|
51
|
-
constructor() {
|
|
52
|
-
super();
|
|
53
|
-
/** РОУТЫ */
|
|
54
|
-
this.setRoute(new MainPage());
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
render(() => new App()).catch(err => Log.error(err))
|
|
58
|
-
```
|
|
59
|
-
`render(callback)` возвращает `Promise`, который резолвится после `DOMContentLoaded` (или сразу, если документ уже загружен) результатом `callback` и реджектится его ошибкой.
|
|
60
|
-
#### exampleApp / main.js
|
|
61
|
-
```javascript
|
|
62
|
-
/** main.js */
|
|
63
|
-
const { Main, MenuItem, path, Desktop } = require('chuijs');
|
|
64
|
-
const main = new Main({
|
|
65
|
-
name: "exampleApp",
|
|
66
|
-
// размеры окна задаются вложенным объектом sizes
|
|
67
|
-
sizes: {
|
|
68
|
-
width: 1366,
|
|
69
|
-
height: 768,
|
|
70
|
-
minWidth: 960,
|
|
71
|
-
minHeight: 540
|
|
72
|
-
},
|
|
73
|
-
render: `${__dirname}/app/app.js`,
|
|
74
|
-
devTools: false,
|
|
75
|
-
resizable: true,
|
|
76
|
-
// папка загрузок: если не задана, путь выбирает Electron
|
|
77
|
-
paths: {
|
|
78
|
-
downloadPath: path.join(Desktop.app.path("userData"), "downloads")
|
|
79
|
-
}
|
|
80
|
-
/** icon: `${__dirname}/resources/icons/app/icon.png` */
|
|
81
|
-
});
|
|
82
|
-
main.start({
|
|
83
|
-
hideOnClose: false,
|
|
84
|
-
tray: [
|
|
85
|
-
new MenuItem().help(`exampleApp`),
|
|
86
|
-
new MenuItem().button('Консоль разработчика', () => main.toggleDevTools()),
|
|
87
|
-
new MenuItem().separator(),
|
|
88
|
-
new MenuItem().quit("Выход")
|
|
89
|
-
]
|
|
90
|
-
})
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
> `Main` — обычный класс, а не singleton: конструктор только сохраняет опции
|
|
94
|
-
> и настраивает `app.commandLine`. Окно создаётся в `start()` (внутри `app.whenReady()`),
|
|
95
|
-
> поэтому окно доступно через `main.getWindow()` только после старта.
|
|
96
|
-
#### Download Session в main.js
|
|
97
|
-
```javascript
|
|
98
|
-
const { Desktop } = require('chuijs');
|
|
99
|
-
const app = Desktop.app.get(); // сырой `app` — только в main-процессе
|
|
100
|
-
app.on('session-created', (session) => {
|
|
101
|
-
session.on('will-download', (e, item, contents) => {
|
|
102
|
-
// ...
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
#### TelegramBot API
|
|
107
|
-
```javascript
|
|
108
|
-
const { TelegramBot } = require('chuijs');
|
|
109
|
-
let bot = new TelegramBot("token");
|
|
110
|
-
bot.setToken("token");
|
|
111
|
-
|
|
112
|
-
// Функции
|
|
113
|
-
async function run() {
|
|
114
|
-
await bot.getMe();
|
|
115
|
-
await bot.getUpdates();
|
|
116
|
-
await bot.getChat("id");
|
|
117
|
-
/* ... */
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
### Модули
|
|
121
|
-
|
|
122
|
-
Инфраструктура и утилиты из корня пакета: `const { Main, MenuItem, Log, path } = require('chuijs');`
|
|
123
|
-
|
|
124
|
-
#### `Main`
|
|
125
|
-
Создаёт окно, трей и управляет жизненным циклом приложения.
|
|
126
|
-
|
|
127
|
-
```javascript
|
|
128
|
-
const { Main, MenuItem, Desktop } = require('chuijs');
|
|
129
|
-
const main = new Main({
|
|
130
|
-
name: 'exampleApp',
|
|
131
|
-
sizes: { width: 1366, height: 768, minWidth: 960, minHeight: 540 },
|
|
132
|
-
render: `${__dirname}/app/app.js`,
|
|
133
|
-
devTools: false,
|
|
134
|
-
resizable: true,
|
|
135
|
-
paths: { downloadPath: path.join(Desktop.app.path('userData'), 'downloads') }
|
|
136
|
-
});
|
|
137
|
-
main.start({ hideOnClose: false, tray: [new MenuItem().quit('Выход')] });
|
|
138
|
-
```
|
|
139
2
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
`security` включает безопасный режим окна (см. «Безопасный режим (preload + contextBridge + CSP)»),
|
|
144
|
-
по умолчанию режим прежний — Node в рендерере.
|
|
145
|
-
`paths.downloadPath` — папка загрузок: если она задана, `Main` подписывается на `will-download`
|
|
146
|
-
сессии и сохраняет файлы туда (папка создаётся при необходимости, существующий файл не перезаписывается).
|
|
147
|
-
Без опции Electron выбирает путь сам, как и раньше.
|
|
148
|
-
`start()` принимает `{hideOnClose, globalMenu, tray, extensions}` и создаёт окно внутри `app.whenReady()`.
|
|
149
|
-
API: `getWindow(name?)`, `getMainWindow()`, `getWindows()`, `createWindow(options)`, `focusWindow(name)`,
|
|
150
|
-
`closeWindow(name)`, `sendTo(name, channel, ...args)`, `toggleDevTools(name?)`, `enableServices()`,
|
|
151
|
-
`stop()`, `restart()`, `enableAutoUpdateApp(start)`, `sendDownload(title, body, windowName?)`,
|
|
152
|
-
`sendDownloadUpdate(...)`, `sendDownloadComplete(...)`, `sendDownloadError(...)`.
|
|
153
|
-
|
|
154
|
-
**Мультиоконность.** Главное окно регистрируется под именем `Main.MAIN_WINDOW` (`'main'`),
|
|
155
|
-
а дополнительные создаёт `createWindow()`: возвращает `BrowserWindow` и вызывается с `await`,
|
|
156
|
-
потому что окно можно создать только после `app.whenReady()`. У каждого окна свой скрипт
|
|
157
|
-
рендерера (`render`) и свой документ, поэтому `AppLayout` каждого окна ведёт свои узлы в
|
|
158
|
-
`chui_layout` (см. «Разметка и `chui_layout`») — окна не мешают друг другу.
|
|
159
|
-
|
|
160
|
-
```javascript
|
|
161
|
-
const preview = await main.createWindow({
|
|
162
|
-
name: 'preview',
|
|
163
|
-
title: 'Просмотр',
|
|
164
|
-
sizes: { width: 900, height: 600 },
|
|
165
|
-
render: `${__dirname}/app/preview.js`,
|
|
166
|
-
hideOnClose: true
|
|
167
|
-
});
|
|
168
|
-
main.sendTo('preview', 'preview_update', payload); // сообщение в конкретное окно
|
|
169
|
-
main.focusWindow('preview');
|
|
170
|
-
main.closeWindow('preview'); // закрывает окно, не приложение
|
|
171
|
-
main.getWindows(); // [{name, window}, …]
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Закрытие окна снимает его подписки на глобальные клавиши и освобождает комбинации,
|
|
175
|
-
которые больше никто не слушает.
|
|
176
|
-
|
|
177
|
-
`enableAutoUpdateApp(start)` — задержка перед первой проверкой обновления в миллисекундах;
|
|
178
|
-
подписки апдейтера и подтверждение установки ставятся один раз на экземпляр `Main`.
|
|
179
|
-
`stop()` и `restart()` снимают свои обработчики: IPC (`show_system_notification`, `SEND_LOG_TEXT`,
|
|
180
|
-
`updateInstallConfirm`), обработчики десктоп-сервисов вместе с глобальными клавишами,
|
|
181
|
-
подписку апдейтера и глобальные обработчики ошибок процессов —
|
|
182
|
-
повторный `start()` подпишет их заново по одному разу. Со страницы то же делают
|
|
183
|
-
`Desktop.app.quit()` и `Desktop.app.restart()`: страница — код самого приложения, поэтому своей
|
|
184
|
-
кнопке «Выход» не нужен отдельный канал в каждом проекте. Оба отвечают значением, а не промисом
|
|
185
|
-
(синхронный канал, как у `Desktop.app.path`), поэтому `await` не обязателен.
|
|
186
|
-
|
|
187
|
-
Пути приложения отдаёт `Desktop.app.path(name)` — и в main-процессе, и на странице, значением
|
|
188
|
-
без промиса (на странице — синхронным каналом, в main — прямо у Electron):
|
|
189
|
-
|
|
190
|
-
```javascript
|
|
191
|
-
const { Desktop } = require('chuijs');
|
|
192
|
-
Desktop.app.path('userData'); // .../AppData/<name>
|
|
193
|
-
Desktop.app.path('downloads');
|
|
194
|
-
Desktop.app.path('logs');
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
Имена берутся из белого списка: `home`, `appData`, `userData`, `sessionData`, `temp`, `exe`,
|
|
198
|
-
`module`, `desktop`, `documents`, `downloads`, `music`, `pictures`, `videos`, `logs`, `recent`,
|
|
199
|
-
`crashDumps`; всё, что вне списка, отклоняется. Со страницы то же значение доступно как
|
|
200
|
-
`window.chui.desktop.app.path('userData')`.
|
|
201
|
-
|
|
202
|
-
Сырые объекты Electron (`app`, `session`, `webContents`) странице не отдают — Electron не
|
|
203
|
-
рекомендует `remote`. В main-процессе их отдают `Desktop.app.get()`, `Desktop.app.getSession()`
|
|
204
|
-
и `Desktop.app.getWebContents()`:
|
|
205
|
-
|
|
206
|
-
```javascript
|
|
207
|
-
const app = Desktop.app.get(); // main.js
|
|
208
|
-
app.on('session-created', (session) => { /* … */ });
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
Со страницы эти методы бросают ошибку с подсказкой: вместо них берут `Desktop.session.*`,
|
|
212
|
-
`Desktop.dialog` или свой канал из `security.channels`.
|
|
213
|
-
|
|
214
|
-
#### `Log`
|
|
215
|
-
Пишет в `userData/logs/app_<date>.log`.
|
|
216
|
-
|
|
217
|
-
```javascript
|
|
218
|
-
Log.info('сообщение');
|
|
219
|
-
Log.error(new Error('что-то пошло не так'));
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
Из renderer-процесса вызов уходит в main через `ipcRenderer.send("SEND_LOG_TEXT", ...)`.
|
|
223
|
-
|
|
224
|
-
Необработанные исключения и необработанные reject’ы промисов тоже попадают в этот лог:
|
|
225
|
-
в main — `process.on("uncaughtException"/"unhandledRejection")`, в renderer —
|
|
226
|
-
`window`-события `error` и `unhandledrejection`. Приложение при этом продолжает работу
|
|
227
|
-
(обработчики снимаются в `Main.stop()`/`restart()`).
|
|
228
|
-
|
|
229
|
-
#### `sleep`, `render`, `formatBytes`
|
|
230
|
-
Утилиты из `chui_functions`.
|
|
231
|
-
|
|
232
|
-
```javascript
|
|
233
|
-
await sleep(1000); // пауза, мс
|
|
234
|
-
render(() => new App()).catch(err => Log.error(err)); // точка входа renderer
|
|
235
|
-
formatBytes(1536); // "1.5 KiB"
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
`render(callback)` ждёт `DOMContentLoaded` и резолвится результатом `callback`.
|
|
239
|
-
|
|
240
|
-
#### Шрифты
|
|
241
|
-
`AppLayout` сам подключает базовую группу (текстовый `chui_I` + иконки `chui_mir`) — это ~1.5 МБ
|
|
242
|
-
CSS из 3.67 МБ всех шрифтов. Моноширинный `chui_mono` (~2.2 МБ) вставляется по требованию:
|
|
243
|
-
его вызывает `TextEditor`, а в своём CSS можно запросить явно:
|
|
244
|
-
|
|
245
|
-
```javascript
|
|
246
|
-
require('chuijs/framework/modules/chui_fonts').installMono();
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
Повторные вызовы `install()`/`installMono()` бесплатны: если стиль уже в документе,
|
|
250
|
-
он не собирается заново.
|
|
251
|
-
|
|
252
|
-
#### Иконка приложения по умолчанию
|
|
253
|
-
`getDefaultIcon()` объявлена во внутреннем модуле `framework/modules/chui_functions` и
|
|
254
|
-
**наружу не реэкспортируется**: `require('chuijs').getDefaultIcon` — это `undefined`.
|
|
255
|
-
`Main` вызывает её сам, если опция `icon` не задана (на macOS результат дополнительно
|
|
256
|
-
прогоняется через `Main.#resizeIconTray()`). Свой путь задаётся опцией `icon`:
|
|
257
|
-
|
|
258
|
-
```javascript
|
|
259
|
-
new Main({ name: 'app', icon: `${__dirname}/resources/icon.png` });
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
#### `MenuItem`
|
|
263
|
-
Пункты меню трея и глобального меню (цепочка из 45 методов: `button`, `submenu`, `radio`,
|
|
264
|
-
`checkbox`, `help`, `quit`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `windowMenu` и др.).
|
|
265
|
-
|
|
266
|
-
```javascript
|
|
267
|
-
new MenuItem().help('exampleApp');
|
|
268
|
-
new MenuItem().button('Консоль разработчика', () => main.toggleDevTools());
|
|
269
|
-
new MenuItem().separator();
|
|
270
|
-
new MenuItem().submenu('Ещё', [new MenuItem().quit('Выход')]);
|
|
271
|
-
new MenuItem().quit('Выход');
|
|
272
|
-
```
|
|
3
|
+
Компонентный фреймворк для Electron: интерфейс, десктоп-сервисы, локализация и доступность.
|
|
4
|
+
Около 140 компонентов — от кнопок и полей ввода до сетки данных, диаграммы Ганта и расписания —
|
|
5
|
+
плюс инфраструктура: окна и трей, IPC-мост, темы, словари, журнал, валидация.
|
|
273
6
|
|
|
274
|
-
|
|
275
|
-
Обёртка над Telegram Bot HTTP API (26 методов).
|
|
7
|
+
## Установка
|
|
276
8
|
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
bot.setToken('token');
|
|
280
|
-
await bot.getMe();
|
|
281
|
-
await bot.sendMessage({ chat_id: '123', text: 'привет' });
|
|
9
|
+
```shell
|
|
10
|
+
npm install chuijs
|
|
282
11
|
```
|
|
283
12
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
канал `ipcRenderer.invoke` в обычном режиме или методы `window.chui.services` (preload +
|
|
288
|
-
`contextBridge`) в безопасном. Имена каналов лежат в одном модуле `chui_services/chui_channels`,
|
|
289
|
-
поэтому main и рендерер не расходятся. Пути приложения — единственное исключение: они идут
|
|
290
|
-
синхронным каналом (`Desktop.app.path` отвечает значением, а не промисом, см. ниже).
|
|
291
|
-
|
|
292
|
-
```javascript
|
|
293
|
-
const { Desktop } = require('chuijs');
|
|
294
|
-
await Desktop.clipboard.writeText('привет');
|
|
295
|
-
await Desktop.clipboard.readText(); // 'привет'
|
|
296
|
-
await Desktop.clipboard.readImage(); // data URL или undefined
|
|
297
|
-
await Desktop.recent.add('/path/report.pdf', 'report.pdf');
|
|
298
|
-
await Desktop.recent.list(); // [{path, name}] — своя история, см. ниже
|
|
299
|
-
await Desktop.progress.set(0.4); // 40% на иконке приложения (панель задач, док)
|
|
300
|
-
Desktop.progress.clear();
|
|
301
|
-
await Desktop.shell.openExternal('https://electronjs.org'); // ссылка — в браузере по умолчанию
|
|
302
|
-
const off = Desktop.shortcuts.on('Mod+Shift+P', () => palette.open());
|
|
303
|
-
off(); // снять подписку
|
|
304
|
-
await Desktop.theme.get(); // {theme: 'dark', source: 'light'}
|
|
305
|
-
await Desktop.theme.set(Desktop.theme.SOURCE.DARK); // 'dark' | 'light' | 'system'
|
|
306
|
-
await Desktop.theme.toggle(); // светлая ↔ тёмная
|
|
307
|
-
const offTheme = Desktop.theme.onChange((theme, source) => Log.info(theme));
|
|
308
|
-
offTheme();
|
|
309
|
-
await Desktop.print.page(); // системный диалог печати текущего окна
|
|
310
|
-
await Desktop.print.html('<h1>Отчёт</h1>'); // печать HTML из скрытого окна
|
|
311
|
-
await Desktop.print.pdf(html, {path: '/tmp/отчёт.pdf'}); // PDF без диалога (или с ним, без path)
|
|
312
|
-
const userData = Desktop.app.path('userData'); // каталог настроек приложения, сразу
|
|
313
|
-
await Desktop.app.info(); // {name, version, locale, isPackaged}
|
|
314
|
-
const app = Desktop.app.get(); // сырой `app` — только в main-процессе
|
|
315
|
-
Desktop.app.quit(); // выход: тот же, что у пункта меню «Выход»
|
|
316
|
-
Desktop.app.restart(); // перезапуск процесса (состояние не переносится)
|
|
317
|
-
const {canceled, filePaths} = await Desktop.dialog.open({properties: ['openFile']});
|
|
318
|
-
await Desktop.dialog.save({defaultPath: '/tmp/отчёт.pdf'});
|
|
319
|
-
await Desktop.dialog.message({type: 'question', message: 'Продолжить?'});
|
|
320
|
-
await Desktop.session.clearCache(); // кеш своей сессии
|
|
321
|
-
await Desktop.session.clearStorageData({storages: ['cookies']});
|
|
322
|
-
```
|
|
13
|
+
Electron ставится в само приложение, фреймворк лишь использует его. Если под Linux Electron не
|
|
14
|
+
запускается из-за песочницы Chromium — нужен разовый шаг с `chrome-sandbox`, он описан в разделе
|
|
15
|
+
[«Начало работы»](docs/guide/start.html).
|
|
323
16
|
|
|
324
|
-
|
|
325
|
-
`globalShortcut.register` вызывается один раз, событие уходит только окнам-подписчикам, а закрытие
|
|
326
|
-
окна освобождает комбинации, которые больше никто не слушает.
|
|
17
|
+
## Быстрый старт
|
|
327
18
|
|
|
328
|
-
|
|
19
|
+
`main.js` — окно и трей:
|
|
329
20
|
|
|
330
21
|
```javascript
|
|
331
|
-
const {
|
|
332
|
-
const shortcuts = new Shortcuts();
|
|
333
|
-
shortcuts.register('Mod+Shift+P', () => main.focusWindow('preview')); // false — комбинацию занял другой процесс
|
|
334
|
-
shortcuts.isRegistered('Mod+Shift+P');
|
|
335
|
-
shortcuts.destroy(); // снять клавиши и подписку на will-quit
|
|
336
|
-
|
|
337
|
-
const clipboard = new Clipboard();
|
|
338
|
-
clipboard.writeText('привет');
|
|
339
|
-
|
|
340
|
-
const shell = new Shell();
|
|
341
|
-
shell.openExternal('https://electronjs.org'); // false — схема не разрешена
|
|
342
|
-
Shell.isExternal('file:///etc/passwd'); // false: чужие схемы не открываются
|
|
343
|
-
|
|
344
|
-
const recent = new RecentDocuments({ limit: 5 });
|
|
345
|
-
recent.add('/path/report.pdf', 'report.pdf');
|
|
346
|
-
recent.menuItem(); // {role: 'recentDocuments', submenu: [{role: 'clearRecentDocuments'}]}
|
|
347
|
-
|
|
348
|
-
const progress = new TaskbarProgress(main.getWindow());
|
|
349
|
-
progress.set(0.4);
|
|
350
|
-
progress.setError();
|
|
351
|
-
progress.clear();
|
|
352
|
-
|
|
353
|
-
const printed = new Print();
|
|
354
|
-
printed.pdf('<h1>Отчёт</h1>', {path: '/tmp/отчёт.pdf'}); // без path откроется диалог сохранения
|
|
355
|
-
// прогресс загрузки на иконку приложения:
|
|
356
|
-
// session.on('will-download', (e, item) => TaskbarProgress.trackDownload(item, win));
|
|
357
|
-
```
|
|
22
|
+
const { Main, MenuItem, Desktop, path } = require("chuijs");
|
|
358
23
|
|
|
359
|
-
`main.enableServices()` вызывается сам из `start()`/`createWindow()`, регистрирует обработчики IPC
|
|
360
|
-
и создаёт сервисы; повторный вызов ничего не делает, а `stop()`/`restart()` снимают обработчики
|
|
361
|
-
вместе с глобальными клавишами. Сервисы доступны и как `main.services.{shortcuts, clipboard,
|
|
362
|
-
recent, progress, theme}`.
|
|
363
|
-
|
|
364
|
-
**Тема (`Desktop.theme`).** Палитры разложены по `@media (prefers-color-scheme)`, поэтому смена
|
|
365
|
-
`nativeTheme.themeSource` перекрашивает интерфейс во всех окнах без правок в DOM. Источник
|
|
366
|
-
(`'system'`, `'light'`, `'dark'`) хранится в настройках приложения (`electron-store`) и
|
|
367
|
-
применяется при запуске — до создания окна, поэтому вспышки системной палитры нет. Подписка
|
|
368
|
-
`onChange(listener)` отдаёт фактическую тему при её смене — как системой, так и пользователем.
|
|
369
|
-
В main-процессе тот же сервис доступен как `main.services.theme` или отдельным классом:
|
|
370
|
-
|
|
371
|
-
```javascript
|
|
372
|
-
const theme = new Theme(store);
|
|
373
|
-
theme.get(); // 'light' | 'dark' — фактическая тема
|
|
374
|
-
theme.getSource(); // 'system' | 'light' | 'dark' — выбор
|
|
375
|
-
theme.set('dark');
|
|
376
|
-
theme.toggle();
|
|
377
|
-
theme.restore(); // применить сохранённый выбор при старте
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
Границы возможностей Electron: `RecentDocuments` ведёт свою историю (у Electron есть только
|
|
381
|
-
`app.addRecentDocument()` и `app.clearRecentDocuments()`, прочитать системный список нельзя),
|
|
382
|
-
`TaskbarProgress` помнит последнее значение сам (геттера прогресса нет), а `Shortcuts.register()`
|
|
383
|
-
до `app.whenReady()` бросает исключение вместо тихой ошибки. `Shell.openExternal()` открывает
|
|
384
|
-
только `http:`, `https:` и `mailto:` — так страница не сможет запустить локальный файл или
|
|
385
|
-
произвольную команду.
|
|
386
|
-
|
|
387
|
-
#### Безопасный режим (preload + `contextBridge` + CSP)
|
|
388
|
-
По умолчанию всё работает как раньше: в рендерер выдаётся Node (`nodeIntegration`), и компоненты
|
|
389
|
-
фреймворка живут в странице. Если окно показывает недоверенное содержимое, его можно открыть
|
|
390
|
-
без Node — опцией `security`:
|
|
391
|
-
|
|
392
|
-
```javascript
|
|
393
24
|
const main = new Main({
|
|
394
|
-
name:
|
|
25
|
+
name: "exampleApp",
|
|
26
|
+
sizes: { width: 1366, height: 768, minWidth: 960, minHeight: 540 },
|
|
395
27
|
render: `${__dirname}/app/app.js`,
|
|
396
|
-
|
|
397
|
-
security: { contextIsolation: true, csp: true, channels: ['preview:save'] }
|
|
28
|
+
paths: { downloadPath: path.join(Desktop.app.path("userData"), "downloads") },
|
|
398
29
|
});
|
|
399
30
|
|
|
400
|
-
|
|
401
|
-
const preview = await main.createWindow({
|
|
402
|
-
name: 'preview',
|
|
403
|
-
title: 'Предпросмотр',
|
|
404
|
-
sizes: { width: 800, height: 600 },
|
|
405
|
-
render: `${__dirname}/app/preview-page.js`, // скрипт документа, не preload
|
|
406
|
-
security: { contextIsolation: true, channels: ['preview:save'] }
|
|
407
|
-
});
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
Что меняется в таком окне:
|
|
411
|
-
|
|
412
|
-
- `nodeIntegration: false`, `contextIsolation: true`, `nodeIntegrationInSubFrames: false`,
|
|
413
|
-
`webviewTag: false` — `require`, `process` и `module` в странице недоступны, модули
|
|
414
|
-
main-процесса (в том числе `@electron/remote`) тоже;
|
|
415
|
-
- preload'ом становится мост фреймворка (`framework/modules/chui_bridge/preload.js`),
|
|
416
|
-
а `render` — **скрипт документа**: мост подключает его как обычный `<script>` после
|
|
417
|
-
`DOMContentLoaded`. Поэтому код вроде `require('chuijs')` в таком окне не работает —
|
|
418
|
-
страница пишется на `window.chui`;
|
|
419
|
-
- CSP вставляется в документ до его скриптов. `security.csp: true` — политика
|
|
420
|
-
`Main.SECURE_CSP` (`default-src 'none'; script-src 'self' file:; style-src … 'unsafe-inline';`
|
|
421
|
-
`img-src … data: blob:; connect-src 'none'`), строкой передаётся своя, `false` отключает.
|
|
422
|
-
|
|
423
|
-
```javascript
|
|
424
|
-
// Что видно странице
|
|
425
|
-
window.chui.versions; // {node, chrome, electron}
|
|
426
|
-
window.chui.platform;
|
|
427
|
-
window.chui.render; // путь страницы, как он задан в опции render
|
|
428
|
-
window.chui.desktop.clipboard.readText(); // то же, что Desktop из require('chuijs')
|
|
429
|
-
window.chui.desktop.recent.list();
|
|
430
|
-
window.chui.desktop.progress.set(0.4);
|
|
431
|
-
const off = window.chui.desktop.shortcuts.on('Mod+Shift+P', () => {});
|
|
432
|
-
window.chui.desktop.app.path('userData'); // путь приложения — сразу, без промиса
|
|
433
|
-
await window.chui.desktop.app.info(); // {name, version, locale, isPackaged}
|
|
434
|
-
window.chui.desktop.app.quit(); // закрыть всё приложение (окно — window.chui.window)
|
|
435
|
-
window.chui.desktop.app.restart(); // перезапустить приложение (тоже без промиса)
|
|
436
|
-
const res = await window.chui.desktop.dialog.open({properties: ['openFile']});
|
|
437
|
-
await window.chui.desktop.dialog.message({type: 'question', message: 'Продолжить?'});
|
|
438
|
-
await window.chui.desktop.session.clearCache();
|
|
439
|
-
window.chui.theme.get(); // 'light' | 'dark'
|
|
440
|
-
window.chui.theme.onChange((theme) => {});
|
|
441
|
-
window.chui.window.minimize(); window.chui.window.toggleMaximize(); window.chui.window.close();
|
|
442
|
-
window.chui.window.getState(); // {isMaximized, isMinimized, isFullScreen, isFocused}
|
|
443
|
-
await window.chui.messaging.send('preview:save', payload); // только каналы из security.channels
|
|
444
|
-
window.chui.messaging.on('preview:update', (payload) => {});
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
Прикладные каналы работают в обе стороны: страница зовёт `messaging.send(channel, payload)`, а main
|
|
448
|
-
подписывается через `main.onPageMessage(channel, handler)` и отвечает/пишет сам через
|
|
449
|
-
`main.sendToPage(channel, payload, windowName?)`. Мост отказывается отправлять канал, которого нет
|
|
450
|
-
в `security.channels`, и то же самое проверяет `messaging.on`.
|
|
451
|
-
|
|
452
|
-
Ограничения: `sandbox: true` не поддерживается (мосту нужен Node в preload'е, поэтому
|
|
453
|
-
`contextIsolation` без sandbox), а окно с интерфейсом на компонентах фреймворка должно остаться
|
|
454
|
-
в привычном режиме — безопасный режим рассчитан на страницы, которым фреймворк не нужен
|
|
455
|
-
(предпросмотр, справка, внешний HTML).
|
|
456
|
-
|
|
457
|
-
#### Реэкспорт Electron и зависимостей
|
|
458
|
-
Доступны прямо из пакета, без отдельного `require`:
|
|
459
|
-
|
|
460
|
-
```javascript
|
|
461
|
-
const { BrowserWindow, ipcMain, ipcRenderer, shell, path, fs, os, request,
|
|
462
|
-
transliterate, systemPreferences, chooseFile, store, downloadSession } = require('chuijs');
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
`chooseFile` — диалоги `showOpenDialog` / `showSaveDialog` / `showMessageBox`: со страницы они идут
|
|
466
|
-
по IPC в окно, которое их вызвало (`Desktop.dialog`), а в main — напрямую `dialog` Electron.
|
|
467
|
-
`store` — готовый экземпляр `new Store()`.
|
|
468
|
-
|
|
469
|
-
#### Автоматическое обновление приложения
|
|
470
|
-
Только AppImage и NSIS.
|
|
471
|
-
|
|
472
|
-
```javascript
|
|
473
|
-
main.enableAutoUpdateApp(5000);
|
|
474
|
-
main.sendDownload('Обновление', 'Загрузка...');
|
|
475
|
-
main.sendDownloadComplete('Обновление', 'Готово');
|
|
476
|
-
main.sendDownloadError('Обновление', 'Ошибка');
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
#### Themes
|
|
480
|
-
Оформление зависит от темы приложения: светлая, тёмная или системная. Палитры живут в
|
|
481
|
-
`framework/appLayout/default/main_theme_style.css` (`@media (prefers-color-scheme: light)` / `dark`),
|
|
482
|
-
а выбор темы хранит и применяет сервис `Theme`: он меняет `nativeTheme.themeSource`, поэтому Chromium
|
|
483
|
-
перерисовывает интерфейс сам, без правок в DOM. Выбор сохраняется в настройках и возвращается при
|
|
484
|
-
следующем запуске:
|
|
485
|
-
|
|
486
|
-
```javascript
|
|
487
|
-
await Desktop.theme.set(Desktop.theme.SOURCE.DARK); // 'dark' | 'light' | 'system'
|
|
488
|
-
await Desktop.theme.toggle();
|
|
489
|
-
const off = Desktop.theme.onChange((theme) => Log.info(theme));
|
|
31
|
+
main.start({ hideOnClose: false, tray: [new MenuItem().quit("Выход")] });
|
|
490
32
|
```
|
|
491
33
|
|
|
492
|
-
|
|
493
|
-
настроек — `Settings.ThemeRow(...)`.
|
|
494
|
-
|
|
495
|
-
Токены: поверхности — `--main_background`, `--header_background`, `--modal_background`, `--modal_scrim`,
|
|
496
|
-
`--element_background` (контролы), `--element_background_2` (карточки и контент-блоки),
|
|
497
|
-
`--element_background_hover`, `--element_background_disabled`; текст — `--text_color`, `--text_color_hover`,
|
|
498
|
-
`--text_color_disabled`; акценты — `--blue_prime_background`, `--red_prime_background`, `--link_color`
|
|
499
|
-
(ссылки в контенте); геометрия и тайминги — `--border_radius`, `--radius_circle`, `--control_height`
|
|
500
|
-
(29px — высота кнопки и поля), компактный шаг контролов `--main_padding_sm` / `--control_padding_sm`,
|
|
501
|
-
`--transition_time`.
|
|
502
|
-
|
|
503
|
-
Обводка — один токен: `--border_color` (волосяные линии всей вёрстки: карточки, поля,
|
|
504
|
-
разделители). Наведение на поле — `--border_color_hover` (приметнее волосяной, но тише акцента),
|
|
505
|
-
фокус — акцентная рамка и кольцо `--blue_prime_background_tint`. Окно создаётся без системной
|
|
506
|
-
рамки (`frame: false`), и своего края приложение
|
|
507
|
-
не рисует: границу показывают рабочий стол и тень композитора. Поэтому нет ни рамки вокруг
|
|
508
|
-
окна, ни отступа `body` под неё. Скруглений у окна и шапки тоже нет: углы окна всё равно
|
|
509
|
-
режет композитор (замер на KWin — дуга ≈8px), а нарисованное приложением скругление читалось
|
|
510
|
-
бы с ним спором. Непрозрачный `--main_background` на `html` остаётся: базовый цвет окна
|
|
511
|
-
белый, и незакрашенная область дала бы белую кромку.
|
|
512
|
-
|
|
513
|
-
Схема нативных частей — `color-scheme: light dark` в `:root`: палитры разложены по
|
|
514
|
-
`prefers-color-scheme`, поэтому браузер рисует и родные мелочи (каретка, выделение, системные
|
|
515
|
-
кнопки и крутилки полей) в той же схеме. Без этого токена они оставались светлыми в тёмной теме.
|
|
516
|
-
Нативные *виджеты* компоненты скрывают сами и только у себя: индикатор календаря — `chui_date`,
|
|
517
|
-
крутилку числа — `chui_number`, индикатор часов — `chui_time`, кнопку очистки поиска — поля
|
|
518
|
-
поиска (`FileExplorer`, `JsonViewer`, `Transfer`), а выпадающие списки везде свои (см. `Select`).
|
|
519
|
-
Правила, которые раньше были общими (`input[type=number]::-webkit-inner-spin-button`,
|
|
520
|
-
`::-webkit-calendar-picker-indicator`) — «протекали» на чужие поля, поэтому теперь у каждого
|
|
521
|
-
компонента они ограничены его узлом.
|
|
522
|
-
|
|
523
|
-
Свои цвета — либо переопределением токенов своим `<style>` после загрузки темы (кандидат —
|
|
524
|
-
конструктор своего layout), либо значениями в стилях конкретного компонента.
|
|
525
|
-
|
|
526
|
-
Системные настройки (`prefers-reduced-motion`) и утилита `.chui_visually_hidden` описаны в разделе
|
|
527
|
-
«Доступность».
|
|
528
|
-
|
|
529
|
-
#### Разметка и `chui_layout` (scoped-ссылки)
|
|
530
|
-
`framework/modules/chui_layout` — реестр частей layout'а. Общие узлы (шапка,
|
|
531
|
-
`page_name`, `center`, app-меню, панель и ящик уведомлений) `AppLayout` регистрирует сам, а
|
|
532
|
-
остальные модули берут их по роли через `LAYOUT_ROLE` / `findLayoutNode()` — без поиска по всему
|
|
533
|
-
документу. Свои узлы компоненты держат приватными полями: `Dialog`, `Popup`, `ImagePopup`, `Tabs`,
|
|
534
|
-
`Select`/`ComboBox`/`MultiComboBox`, уведомления, `Audio` (полоса управления и слайдеры эквалайзера),
|
|
535
|
-
`TextEditorPanel` (редактор передаётся ссылкой, а не id).
|
|
34
|
+
`app/app.js` — страница приложения:
|
|
536
35
|
|
|
537
36
|
```javascript
|
|
538
|
-
const {
|
|
539
|
-
|
|
540
|
-
const layout = getLayout(); // последний созданный layout
|
|
541
|
-
layout.get(LAYOUT_ROLE.CENTER); // узел по роли
|
|
542
|
-
findLayoutNode(LAYOUT_ROLE.NOTIFICATION_BOX_MAIN, myNode); // layout, которому принадлежит узел
|
|
543
|
-
requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_PANEL); // то же, но с понятной ошибкой
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
`LayoutRefs.set(role, node)` / `.get(role)` / `.owns(node)` — узел принадлежит тому layout'у, в поддереве
|
|
547
|
-
которого он находится; если узел ещё не в дереве (только что созданное уведомление), берётся последний
|
|
548
|
-
созданный layout. `registerLayout(layout)` / `unregisterLayout(layout)` нужны сценариям с несколькими
|
|
549
|
-
layout'ами (новое окно, тестовый стенд).
|
|
550
|
-
|
|
551
|
-
Из-за этого в `framework/` не осталось поиска узлов по всему документу. Единственные оставшиеся
|
|
552
|
-
`getElementById` — проверка «стиль с таким id уже подключён» в `chui_functions` и `chui_fonts`
|
|
553
|
-
(у каждого окна свой документ, и это именно документная проверка), и
|
|
554
|
-
`document.querySelector('script[id=...]')` в `AppLayout.setScript()` для однократного подключения скрипта.
|
|
555
|
-
`getElementsByTagName` остался один раз — `Select.setDefaultOption()` перебирает опции в своём приватном
|
|
556
|
-
`#dropdown`, то есть внутри собственного поддерева, а не по документу.
|
|
557
|
-
|
|
558
|
-
### Локализация и RTL
|
|
559
|
-
|
|
560
|
-
Строки интерфейса берутся по ключу, а не на месте: `I18n.t("common.close")`. Один ключ — один текст
|
|
561
|
-
в словаре языка, поэтому подписи переводятся без правок кода компонентов.
|
|
562
|
-
|
|
563
|
-
```javascript
|
|
564
|
-
const { I18n, Desktop } = require('chuijs');
|
|
565
|
-
|
|
566
|
-
I18n.setLocale('en'); // 'ru' (по умолчанию) или 'en' — тексты и `lang` документа
|
|
567
|
-
I18n.t('validate.max', {max: 5}); // 'Value must be at most 5'
|
|
568
|
-
I18n.getLocales(); // ['ru', 'en'] — плюс добавленные приложением
|
|
569
|
-
I18n.extend('de', {'common.close': 'Schließen'}); // свой или дополненный словарь
|
|
570
|
-
I18n.getDirection(); // 'ltr' | 'rtl'
|
|
571
|
-
const off = I18n.onChange((locale, direction) => render()); // пересобрать экран после смены языка
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
Словари лежат в `framework/modules/chui_i18n/locales/` по пространствам имён (один файл — одна
|
|
575
|
-
группа компонентов):
|
|
576
|
-
|
|
577
|
-
| Пространство | Что переводит |
|
|
578
|
-
|---|---|
|
|
579
|
-
| `common`, `validate`, `a11y` | общие подписи («Закрыть», «Отмена»), тексты проверок и имена элементов доступности |
|
|
580
|
-
| `app_layout` | каркас окна: кнопки окна, меню, поиск, панель уведомлений, профиль, диалог обновления, а также меню «Открыть последние» и уведомления об обновлении из main-процесса |
|
|
581
|
-
| `calendar` | `DateInput`, `TimeInput`, `DateTimeInput`, `DateRangeInput`, `Calendar`, `Scheduler`, `Gantt` |
|
|
582
|
-
| `media` | `Audio` (включая пресеты эквалайзера), `Video` |
|
|
583
|
-
| `editors` | `TextEditor`, `CodeEditor`, `MarkdownEditor`, `DiffViewer`, `JsonViewer`, `JsonEditor`, разбор JSON (`Json.errorText`) |
|
|
584
|
-
| `data` | `DataGrid`, `TreeView`, `TreeTable`, `OrgChart`, `Transfer`, `FileExplorer`, `QueryBuilder` |
|
|
585
|
-
| `navigation` | вкладки, меню-бар, пагинация, хлебные крошки, шаги, `SidebarNav`, `CommandPalette`, `Toolbar`, `StatusBar`, `SplitButton`, `List` |
|
|
586
|
-
| `forms` | поля ввода: `Slider`, `Rating`, `ColorPicker`, `HotkeyInput`, `MaskedInput`, `OtpInput`, `Chips`, `NumberInput`, `DropZone` |
|
|
587
|
-
| `feedback` | сообщения и состояния: `Alert`, `Notification`, `ToastQueue`, `Drawer`, `Spinner`, `Skeleton`, `ProgressRing`, `SlideShow`, `Avatar`, панель истории буфера, индикатор печати |
|
|
588
|
-
| `graphics` | графики (`BarGraph`, `PieGraph`, `LineGraph`, `AreaGraph`, `ScatterGraph`, `Sparkline`, `RadarGraph`, `HeatmapGraph`, `Gauge` — включая подписи скрытых таблиц-альтернатив), `Kanban`, `QRCode`, `Settings`, `ThemeToggle`, `Timeline`, `PrintButton` |
|
|
589
|
-
|
|
590
|
-
Незнакомый ключ отдаётся как есть, а ключ, которого нет в текущем языке, падает на резервный (`ru`) —
|
|
591
|
-
интерфейс не ломается. Полноту словарей стережёт тест `test/chui_i18n_keys.test.js`: каждый
|
|
592
|
-
литеральный ключ `I18n.t("...")` из кода должен быть в обоих языках, любая строка вида
|
|
593
|
-
«пространство.ключ» (в том числе ключ из тернарного выражения или таблицы) тоже должна быть
|
|
594
|
-
в словаре, наборы ключей `ru` и `en` обязаны совпадать, а один и тот же ключ не может быть
|
|
595
|
-
объявлен дважды. Общие подписи живут в `common` и `a11y`: один и тот же текст (например,
|
|
596
|
-
«Развернуть «Имя»» у дерева-таблицы и просмотра JSON) описан один раз и переводится везде сразу.
|
|
597
|
-
|
|
598
|
-
**Что осталось на русском.** Служебные тексты, которые не видит пользователь: сообщения `Log`,
|
|
599
|
-
исключения конструкторов о неверных опциях, демонстрационное приложение (`app/app.js`, `main.js`)
|
|
600
|
-
и тестовые данные витрины (`app/views/0_maket.js`).
|
|
37
|
+
const { AppLayout, Page, Button, Log, render } = require("chuijs");
|
|
601
38
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
```javascript
|
|
610
|
-
I18n.setLocale('ar'); // dir="rtl" lang="ar" — вся вёрстка зеркалится
|
|
611
|
-
I18n.setDirection('rtl'); // то же без смены языка
|
|
612
|
-
```
|
|
39
|
+
class MainPage extends Page {
|
|
40
|
+
constructor() {
|
|
41
|
+
super();
|
|
42
|
+
this.setTitle("Сказать привет!");
|
|
43
|
+
this.add(new Button({ title: "Привет", clickEvent: () => Log.info("привет") }));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
613
46
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
47
|
+
class App extends AppLayout {
|
|
48
|
+
constructor() {
|
|
49
|
+
super();
|
|
50
|
+
this.setRoute(new MainPage());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
619
53
|
|
|
620
|
-
|
|
621
|
-
await Desktop.locale.set('en'); // main сохраннит выбор
|
|
622
|
-
Desktop.locale.onChange((locale) => I18n.setLocale(locale));
|
|
54
|
+
render(() => new App()).catch((err) => Log.error(err));
|
|
623
55
|
```
|
|
624
56
|
|
|
625
|
-
|
|
626
|
-
и
|
|
627
|
-
|
|
628
|
-
### Компоненты
|
|
629
|
-
|
|
630
|
-
Все классы и модули интерфейса из `require('chuijs')` (таблица иконок `Icons`, константы `Styles` и
|
|
631
|
-
`AcceptTypes`, а также `Desktop` — доступ к десктоп-сервисам, у него `set()` нет — описаны рядом отдельно).
|
|
632
|
-
Любой компонент реализует `set()` — возвращает готовый
|
|
633
|
-
DOM-элемент, поэтому внутри `Page.add(...)`, `Card.add(...)`, `ContentBlock.add(...)` передаётся
|
|
634
|
-
сам объект, а в `Form.components` / `SlideShow.SLIDE` / `FieldSet.components` — тоже объекты.
|
|
635
|
-
|
|
636
|
-
**Разметка `markdownText`.** Компоненты с этой опцией (`Label`, `Tooltip`, `Badge`, `Alert`,
|
|
637
|
-
`Notification`, `ToastQueue`, `Chat`, `Tour`, `MarkdownEditor`) рендерят её `markdown-it` в безопасном
|
|
638
|
-
режиме: сырой HTML из разметки не исполняется, а показывается текстом — так закрыт XSS через
|
|
639
|
-
`markdownText`. Таблицы и `~~зачёркивание~~` поддерживаются, авто-ссылок нет: адрес становится
|
|
640
|
-
ссылкой только явным `[текст](адрес)`. Обратный разбор (`htmlToMarkdown`) делает `turndown`.
|
|
641
|
-
|
|
642
|
-
Описание каждого компонента — отдельная страница статического сайта документации в [`docs/`](docs/):
|
|
643
|
-
[`docs/index.html`](docs/index.html) — полный индекс по группам и алфавиту, а у каждой страницы сверху
|
|
644
|
-
ссылка на группу и общий список. Сайт собирается генератором `node docs/build.js`
|
|
645
|
-
(`npm run docs:build`) из разметки `docs/content/*.md`, разделов этого README и скана кода
|
|
646
|
-
(`framework/**`); как открыть его локально и опубликовать — в [`docs/README.md`](docs/README.md).
|
|
647
|
-
Здесь — только вход в группы:
|
|
648
|
-
|
|
649
|
-
- [Компоновка и навигация](docs/groups/layout-navigation.html) — 12: `AppLayout`, `Route`, `Page`, `MenuBar`, `SidebarNav`, `ContextMenu`, `CommandPalette`, `Backtop`, `Affix`, `Styles`, `Icon`, `Icons`
|
|
650
|
-
- [Поля ввода](docs/groups/inputs.html) — 29: `TextInput`, `TextArea`, `NumberInput`, `Slider`, `Chips`, `DateInput`, `Select`, `ComboBox`, `MultiComboBox`, `Transfer`, `CheckBox`, `RadioGroup`, `Form`, `FieldSet` и другие
|
|
651
|
-
- [Отображение](docs/groups/display.html) — 73: `Button`, `Card`, `List`, `DataGrid`, `TreeView`, `TreeTable`, `Tabs`, `Kanban`, `Gantt`, `Scheduler`, `OrgChart`, `QRCode`, `QueryBuilder`, графики и другое
|
|
652
|
-
- [Окна, уведомления, медиа](docs/groups/overlays.html) — 21: `Dialog`, `Drawer`, `Popup`, `Alert`, `Notification`, `ToastQueue`, `Calendar`, `SlideShow`, `TextEditor`, `MarkdownEditor`, `Image`, `Audio`, `Video`, `WebView`, `Console`, `CustomElement`
|
|
57
|
+
Дальше — [«Начало работы»](docs/guide/start.html): структура проекта, все опции `Main`, страницы
|
|
58
|
+
и сервисы.
|
|
653
59
|
|
|
654
|
-
|
|
655
|
-
[Жизненный цикл `destroy()`](docs/topics/lifecycle.html), [Доступность](docs/topics/a11y.html),
|
|
656
|
-
[Константы и статические фабрики](docs/topics/constants.html), [Сценарии целиком](docs/topics/scenarios.html),
|
|
657
|
-
[Витрина компонентов](docs/topics/showcase.html).
|
|
60
|
+
## Документация
|
|
658
61
|
|
|
659
|
-
|
|
62
|
+
[`docs/index.html`](docs/index.html) — справочник по фреймворку: страница на каждый компонент с
|
|
63
|
+
примером, составом API и заметками о доступности, а также
|
|
64
|
+
[модули и сервисы](docs/modules/index.html) (`Main`, `Log`, `Desktop`, безопасный режим,
|
|
65
|
+
автообновление), [локализация и RTL](docs/guide/i18n.html),
|
|
66
|
+
[общие правила компонентов](docs/topics/options.html),
|
|
67
|
+
[планы](docs/guide/roadmap.html) и [история изменений](docs/changelog.html).
|
|
660
68
|
|
|
661
|
-
|
|
69
|
+
## Лицензия
|
|
662
70
|
|
|
663
|
-
|
|
664
|
-
Компоненты по-прежнему проверяются витриной `app/views/0_maket.js` и стендами Electron.
|
|
665
|
-
- Локализация охватывает все словари по пространствам имён: строки интерфейса framework берутся
|
|
666
|
-
по ключу (`I18n.t`). Непереведёнными остаются служебные тексты (журнал, исключения конструкторов),
|
|
667
|
-
демонстрационное приложение `app/`, меню демо-приложения в `main.js` и данные витрины; дописать
|
|
668
|
-
словарь для нового компонента — это добавить ключи в его пространство имён.
|
|
669
|
-
- RTL: вёрстка зеркалится логическими свойствами CSS; позиционирование всплывающих слоёв, которое
|
|
670
|
-
считает JavaScript (`left`/`right` в пикселях), и анимации-сдвиги пока не учитывают направление.
|
|
671
|
-
Запятые-кавычки в текстовом представлении `QueryBuilder.getText()` остались русскими «ёлочками»
|
|
672
|
-
(это текст-представление запроса, а не подпись интерфейса).
|
|
71
|
+
MIT — см. [LICENSE](LICENSE).
|